19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define LOG_TAG "KeyCharacterMap"
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <ui/KeyCharacterMap.h>
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <cutils/properties.h>
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <utils/Log.h>
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <sys/types.h>
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <unistd.h>
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <stdlib.h>
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <fcntl.h>
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <limits.h>
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <string.h>
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstruct Header
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    char magic[8];
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    unsigned int endian;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    unsigned int version;
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    unsigned int keycount;
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    unsigned char kbdtype;
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    char padding[11];
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project};
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source ProjectKeyCharacterMap::KeyCharacterMap()
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source ProjectKeyCharacterMap::~KeyCharacterMap()
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    free(m_keys);
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectunsigned short
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source ProjectKeyCharacterMap::get(int keycode, int meta)
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    Key* k = find_key(keycode);
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (k != NULL) {
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return k->data[meta & META_MASK];
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return 0;
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectunsigned short
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source ProjectKeyCharacterMap::getNumber(int keycode)
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    Key* k = find_key(keycode);
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (k != NULL) {
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return k->number;
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return 0;
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectunsigned short
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source ProjectKeyCharacterMap::getMatch(int keycode, const unsigned short* chars,
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                          int charsize, uint32_t modifiers)
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    Key* k = find_key(keycode);
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    modifiers &= 3; // ignore the SYM key because we don't have keymap entries for it
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (k != NULL) {
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        const uint16_t* data = k->data;
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int j=0; j<charsize; j++) {
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            uint16_t c = chars[j];
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i=0; i<(META_MASK + 1); i++) {
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if ((modifiers == 0) || ((modifiers & i) != 0)) {
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (c == data[i]) {
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        return c;
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return 0;
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectunsigned short
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source ProjectKeyCharacterMap::getDisplayLabel(int keycode)
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    Key* k = find_key(keycode);
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (k != NULL) {
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return k->display_label;
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return 0;
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectbool
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source ProjectKeyCharacterMap::getKeyData(int keycode, unsigned short *displayLabel,
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            unsigned short *number, unsigned short* results)
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    Key* k = find_key(keycode);
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (k != NULL) {
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        memcpy(results, k->data, sizeof(short)*(META_MASK + 1));
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        *number = k->number;
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        *displayLabel = k->display_label;
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } else {
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectbool
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source ProjectKeyCharacterMap::find_char(uint16_t c, uint32_t* key, uint32_t* mods)
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    uint32_t N = m_keyCount;
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    for (int j=0; j<(META_MASK + 1); j++) {
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Key const* keys = m_keys;
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (uint32_t i=0; i<N; i++) {
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (keys->data[j] == c) {
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                *key = keys->keycode;
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                *mods = j;
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            keys++;
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return false;
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectbool
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source ProjectKeyCharacterMap::getEvents(uint16_t* chars, size_t len,
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                           Vector<int32_t>* keys, Vector<uint32_t>* modifiers)
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    for (size_t i=0; i<len; i++) {
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        uint32_t k, mods;
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (find_char(chars[i], &k, &mods)) {
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            keys->add(k);
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            modifiers->add(mods);
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return true;
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source ProjectKeyCharacterMap::Key*
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source ProjectKeyCharacterMap::find_key(int keycode)
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    Key* keys = m_keys;
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int low = 0;
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int high = m_keyCount - 1;
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int mid;
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int n;
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    while (low <= high) {
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mid = (low + high) / 2;
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        n = keys[mid].keycode;
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (keycode < n) {
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            high = mid - 1;
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (keycode > n) {
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            low = mid + 1;
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return keys + mid;
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return NULL;
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source ProjectKeyCharacterMap*
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source ProjectKeyCharacterMap::load(int id)
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    KeyCharacterMap* rv = NULL;
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    char path[PATH_MAX];
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    char propName[100];
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    char dev[PROPERTY_VALUE_MAX];
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    char tmpfn[PROPERTY_VALUE_MAX];
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int err;
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    const char* root = getenv("ANDROID_ROOT");
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    sprintf(propName, "hw.keyboards.%u.devname", id);
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    err = property_get(propName, dev, "");
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (err > 0) {
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // replace all the spaces with underscores
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        strcpy(tmpfn, dev);
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (char *p = strchr(tmpfn, ' '); p && *p; p = strchr(tmpfn, ' '))
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            *p = '_';
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        snprintf(path, sizeof(path), "%s/usr/keychars/%s.kcm.bin", root, tmpfn);
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        //LOGD("load: dev='%s' path='%s'\n", dev, path);
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        rv = try_file(path);
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (rv != NULL) {
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return rv;
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOGW("Error loading keycharmap file '%s'. %s='%s'", path, propName, dev);
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } else {
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOGW("No keyboard for id %d", id);
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    snprintf(path, sizeof(path), "%s/usr/keychars/qwerty.kcm.bin", root);
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    rv = try_file(path);
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (rv == NULL) {
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOGE("Can't find any keycharmaps (also tried %s)", path);
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return NULL;
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    LOGW("Using default keymap: %s", path);
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return rv;
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source ProjectKeyCharacterMap*
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source ProjectKeyCharacterMap::try_file(const char* filename)
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    KeyCharacterMap* rv = NULL;
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    Key* keys;
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int fd;
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    off_t filesize;
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    Header header;
2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int err;
2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    fd = open(filename, O_RDONLY);
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (fd == -1) {
2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOGW("Can't open keycharmap file");
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return NULL;
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    filesize = lseek(fd, 0, SEEK_END);
2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    lseek(fd, 0, SEEK_SET);
2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // validate the header
2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (filesize <= (off_t)sizeof(header)) {
2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOGW("Bad keycharmap - filesize=%d\n", (int)filesize);
2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto cleanup1;
2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    err = read(fd, &header, sizeof(header));
2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (err == -1) {
2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOGW("Error reading keycharmap file");
2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto cleanup1;
2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (0 != memcmp(header.magic, "keychar", 8)) {
2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOGW("Bad keycharmap magic token");
2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto cleanup1;
2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (header.endian != 0x12345678) {
2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOGW("Bad keycharmap endians");
2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto cleanup1;
2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if ((header.version & 0xff) != 2) {
2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOGW("Only support keycharmap version 2 (got 0x%08x)", header.version);
2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto cleanup1;
2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (filesize < (off_t)(sizeof(Header)+(sizeof(Key)*header.keycount))) {
2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOGW("Bad keycharmap file size\n");
2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto cleanup1;
2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // read the key data
2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    keys = (Key*)malloc(sizeof(Key)*header.keycount);
2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    err = read(fd, keys, sizeof(Key)*header.keycount);
2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (err == -1) {
2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOGW("Error reading keycharmap file");
2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        free(keys);
2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto cleanup1;
2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // return the object
2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    rv = new KeyCharacterMap;
2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    rv->m_keyCount = header.keycount;
2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    rv->m_keys = keys;
2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    rv->m_type = header.kbdtype;
2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectcleanup1:
2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    close(fd);
2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return rv;
2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
264