Home | History | Annotate | Download | only in android
      1 /* Copyright (C) 2007-2008 The Android Open Source Project
      2 **
      3 ** This software is licensed under the terms of the GNU General Public
      4 ** License version 2, as published by the Free Software Foundation, and
      5 ** may be copied, distributed, and modified under those terms.
      6 **
      7 ** This program is distributed in the hope that it will be useful,
      8 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
      9 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     10 ** GNU General Public License for more details.
     11 */
     12 #include "android/utils/path.h"
     13 #include "android/utils/misc.h"
     14 #include "android/utils/debug.h"
     15 #include "android/utils/system.h"
     16 #include "android/charmap.h"
     17 #include <stdio.h>
     18 #include <errno.h>
     19 
     20 /* Parses .kcm file producing key characters map.
     21  * .kcm file parsed by this module is expected to contain 4 types of
     22  * lines:
     23  * 1. An empty line (containing no characters, or only space or tab
     24  *    characters).
     25  * 2. A comment line (begins with '#')
     26  * 3. A type section line (begins with '[')
     27  * 4. Character map line, formatted as such:
     28  * Key code value, followed by one or more space or tab characters.
     29  * Display value, followed by one or more space or tab characters.
     30  * Number value, followed by one or more space or tab characters.
     31  * Base value, followed by one or more space or tab characters.
     32  * Caps value, followed by one or more space or tab characters.
     33  * Fn value, followed by one or more space or tab characters.
     34  * Caps_fn value, followed by one or more space or tab characters.
     35  * All values, except for the key code value must be either in character
     36  * form ('X', where X is the value), or in hexadecimal form (0xXXXX, where
     37  * XXXX is hexadecimal representation of the value). Note that if value is
     38  * in hexadecimal form, it must not exceed value that can be contained in
     39  * variable of 'unsigned short' type.
     40  * Bellow are a couple of examples of valid .kcm file lines:
     41  * # keycode       display number  base    caps    fn      caps_fn
     42  * A               'A'     '2'     'a'     'A'     '#'     0x00
     43  * PERIOD          '.'     '.'     '.'     ':'     ':'     0x2026
     44  * SPACE           0x20    0x20    0x20    0x20    0xEF01  0xEF01
     45 */
     46 
     47 /* Maximum length of a line expected in .kcm file. */
     48 #define KCM_MAX_LINE_LEN    1024
     49 
     50 /* Maximum length of a token in a key map line. */
     51 #define KCM_MAX_TOKEN_LEN   512
     52 
     53 /* Maps symbol name from .kcm file to a keycode value. */
     54 typedef struct AKeycodeMapEntry {
     55     /* Symbol name from .kcm file. */
     56     const char* key_name;
     57 
     58     /* Key code value for the symbol. */
     59     int         key_code;
     60 } AKeycodeMapEntry;
     61 
     62 /* Result of parsing a line in a .kcm file. */
     63 typedef enum {
     64     /* Line format was bad. */
     65     BAD_FORMAT,
     66 
     67     /* Line had been skipped (an empty line, or a comment, etc.). */
     68     SKIP_LINE,
     69 
     70     /* Line represents an entry in the key map. */
     71     KEY_ENTRY,
     72 } ParseStatus;
     73 
     74 static const AKeycodeMapEntry keycode_map[] = {
     75     /*  Symbol           Key code */
     76 
     77       { "A",             kKeyCodeA },
     78       { "B",             kKeyCodeB },
     79       { "C",             kKeyCodeC },
     80       { "D",             kKeyCodeD },
     81       { "E",             kKeyCodeE },
     82       { "F",             kKeyCodeF },
     83       { "G",             kKeyCodeG },
     84       { "H",             kKeyCodeH },
     85       { "I",             kKeyCodeI },
     86       { "J",             kKeyCodeJ },
     87       { "K",             kKeyCodeK },
     88       { "L",             kKeyCodeL },
     89       { "M",             kKeyCodeM },
     90       { "N",             kKeyCodeN },
     91       { "O",             kKeyCodeO },
     92       { "P",             kKeyCodeP },
     93       { "Q",             kKeyCodeQ },
     94       { "R",             kKeyCodeR },
     95       { "S",             kKeyCodeS },
     96       { "T",             kKeyCodeT },
     97       { "U",             kKeyCodeU },
     98       { "V",             kKeyCodeV },
     99       { "W",             kKeyCodeW },
    100       { "X",             kKeyCodeX },
    101       { "Y",             kKeyCodeY },
    102       { "Z",             kKeyCodeZ },
    103       { "0",             kKeyCode0 },
    104       { "1",             kKeyCode1 },
    105       { "2",             kKeyCode2 },
    106       { "3",             kKeyCode3 },
    107       { "4",             kKeyCode4 },
    108       { "5",             kKeyCode5 },
    109       { "6",             kKeyCode6 },
    110       { "7",             kKeyCode7 },
    111       { "8",             kKeyCode8 },
    112       { "9",             kKeyCode9 },
    113       { "COMMA",         kKeyCodeComma },
    114       { "PERIOD",        kKeyCodePeriod },
    115       { "AT",            kKeyCodeAt },
    116       { "SLASH",         kKeyCodeSlash },
    117       { "SPACE",         kKeyCodeSpace },
    118       { "ENTER",         kKeyCodeNewline },
    119       { "TAB",           kKeyCodeTab },
    120       { "GRAVE",         kKeyCodeGrave },
    121       { "MINUS",         kKeyCodeMinus },
    122       { "EQUALS",        kKeyCodeEquals },
    123       { "LEFT_BRACKET",  kKeyCodeLeftBracket },
    124       { "RIGHT_BRACKET", kKeyCodeRightBracket },
    125       { "BACKSLASH",     kKeyCodeBackslash },
    126       { "SEMICOLON",     kKeyCodeSemicolon },
    127       { "APOSTROPHE",    kKeyCodeApostrophe },
    128       { "STAR",          kKeyCodeStar },
    129       { "POUND",         kKeyCodePound },
    130       { "PLUS",          kKeyCodePlus },
    131       { "DEL",           kKeyCodeDel },
    132 };
    133 
    134 /* the following is automatically generated by the 'gen-charmap.py' script
    135  * do not touch. the generation command was:
    136  *   gen-charmap.py qwerty2.kcm
    137  */
    138 
    139 static const AKeyEntry  _qwerty2_keys[] =
    140 {
    141    /* keycode                   base   caps    fn  caps+fn   number */
    142 
    143     { kKeyCodeA             ,   'a',   'A',   'a',    'A',   'a' },
    144     { kKeyCodeB             ,   'b',   'B',   'b',    'B',   'b' },
    145     { kKeyCodeC             ,   'c',   'C', 0x00e7, 0x00E7,   'c' },
    146     { kKeyCodeD             ,   'd',   'D',  '\'',   '\'',  '\'' },
    147     { kKeyCodeE             ,   'e',   'E',   '"', 0x0301,   '"' },
    148     { kKeyCodeF             ,   'f',   'F',   '[',    '[',   '[' },
    149     { kKeyCodeG             ,   'g',   'G',   ']',    ']',   ']' },
    150     { kKeyCodeH             ,   'h',   'H',   '<',    '<',   '<' },
    151     { kKeyCodeI             ,   'i',   'I',   '-', 0x0302,   '-' },
    152     { kKeyCodeJ             ,   'j',   'J',   '>',    '>',   '>' },
    153     { kKeyCodeK             ,   'k',   'K',   ';',    '~',   ';' },
    154     { kKeyCodeL             ,   'l',   'L',   ':',    '`',   ':' },
    155     { kKeyCodeM             ,   'm',   'M',   '%',   0x00,   '%' },
    156     { kKeyCodeN             ,   'n',   'N',  0x00, 0x0303,   'n' },
    157     { kKeyCodeO             ,   'o',   'O',   '+',    '+',   '+' },
    158     { kKeyCodeP             ,   'p',   'P',   '=', 0x00A5,   '=' },
    159     { kKeyCodeQ             ,   'q',   'Q',   '|', 0x0300,   '|' },
    160     { kKeyCodeR             ,   'r',   'R',   '`', 0x20AC,   '`' },
    161     { kKeyCodeS             ,   's',   'S',  '\\', 0x00DF,  '\\' },
    162     { kKeyCodeT             ,   't',   'T',   '{', 0x00A3,   '}' },
    163     { kKeyCodeU             ,   'u',   'U',   '_', 0x0308,   '_' },
    164     { kKeyCodeV             ,   'v',   'V',   'v',    'V',   'v' },
    165     { kKeyCodeW             ,   'w',   'W',   '~',    '~',   '~' },
    166     { kKeyCodeX             ,   'x',   'X',   'x',    'X',   'x' },
    167     { kKeyCodeY             ,   'y',   'Y',   '}', 0x00A1,   '}' },
    168     { kKeyCodeZ             ,   'z',   'Z',   'z',    'Z',   'z' },
    169     { kKeyCodeComma         ,   ',',   '<',   ',',    ',',   ',' },
    170     { kKeyCodePeriod        ,   '.',   '>',   '.', 0x2026,   '.' },
    171     { kKeyCodeAt            ,   '@',   '@',   '@', 0x2022,   '@' },
    172     { kKeyCodeSlash         ,   '/',   '?',   '?',    '?',   '/' },
    173     { kKeyCodeSpace         ,  0x20,  0x20,   0x9,    0x9,  0x20 },
    174     { kKeyCodeNewline       ,   0xa,   0xa,   0xa,    0xa,   0xa },
    175     { kKeyCode0             ,   '0',   ')',   ')',    ')',   '0' },
    176     { kKeyCode1             ,   '1',   '!',   '!',    '!',   '1' },
    177     { kKeyCode2             ,   '2',   '@',   '@',    '@',   '2' },
    178     { kKeyCode3             ,   '3',   '#',   '#',    '#',   '3' },
    179     { kKeyCode4             ,   '4',   '$',   '$',    '$',   '4' },
    180     { kKeyCode5             ,   '5',   '%',   '%',    '%',   '5' },
    181     { kKeyCode6             ,   '6',   '^',   '^',    '^',   '6' },
    182     { kKeyCode7             ,   '7',   '&',   '&',    '&',   '7' },
    183     { kKeyCode8             ,   '8',   '*',   '*',    '*',   '8' },
    184     { kKeyCode9             ,   '9',   '(',   '(',    '(',   '9' },
    185     { kKeyCodeTab           ,   0x9,   0x9,   0x9,    0x9,   0x9 },
    186     { kKeyCodeGrave         ,   '`',   '~',   '`',    '~',   '`' },
    187     { kKeyCodeMinus         ,   '-',   '_',   '-',    '_',   '-' },
    188     { kKeyCodeEquals        ,   '=',   '+',   '=',    '+',   '=' },
    189     { kKeyCodeLeftBracket   ,   '[',   '{',   '[',    '{',   '[' },
    190     { kKeyCodeRightBracket  ,   ']',   '}',   ']',    '}',   ']' },
    191     { kKeyCodeBackslash     ,  '\\',   '|',  '\\',    '|',  '\\' },
    192     { kKeyCodeSemicolon     ,   ';',   ':',   ';',    ':',   ';' },
    193     { kKeyCodeApostrophe    ,  '\'',   '"',  '\'',    '"',  '\'' },
    194 };
    195 
    196 static const AKeyCharmap  _default_charmap =
    197 {
    198     _qwerty2_keys,
    199     51,
    200     "qwerty2"
    201 };
    202 
    203 /* Custom character map created with -charmap option. */
    204 static AKeyCharmap android_custom_charmap = { 0 };
    205 
    206 static const AKeyCharmap* android_charmap = &_default_charmap;
    207 
    208 /* Checks if a character represents an end of the line.
    209  * Returns a non-zero value if ch is an EOL character. Returns
    210  * zero value if ch is not an EOL character.
    211 */
    212 static int
    213 kcm_is_eol(char ch) {
    214     // EOLs are 0, \r and \n chars.
    215     return ('\0' == ch) || ('\n' == ch) || ('\r' == ch);
    216 }
    217 
    218 /* Checks if a character represents a token separator.
    219  * Returns a non-zero value if ch is a token separator.
    220  * Returns zero value if ch is not a token separator.
    221 */
    222 static int
    223 kcm_is_token_separator(char ch) {
    224     // Spaces and tabs are the only separators allowed
    225     // between tokens in .kcm files.
    226     return (' ' == ch) || ('\t' == ch);
    227 }
    228 
    229 /* Checks if a character represents a path separator.
    230  * Returns a non-zero value if ch is a path separator.
    231  * Returns zero value if ch is not a path separator.
    232 */
    233 static int
    234 kcm_is_path_separator(char ch) {
    235 #ifdef _WIN32
    236     return '/' == ch || '\\' == ch;
    237 #else
    238     return '/' == ch;
    239 #endif  // _WIN32
    240 }
    241 
    242 /* Skips space separators in a string.
    243  * str - string to advance past space separators.
    244  * Returns pointer to the first character in the string, that is
    245  * not a space separator. Note that this routine may return
    246  * pointer to EOL in case if all characters in the string were
    247  * space separators.
    248 */
    249 static const char*
    250 kcm_skip_spaces(const char* str) {
    251     while (!kcm_is_eol(*str) && kcm_is_token_separator(*str)) {
    252         str++;
    253     }
    254     return str;
    255 }
    256 
    257 /* Advances string to the first space separator character.
    258  * str - string to advance.
    259  * Returns pointer to the first space separator character in the string.
    260  * Note that this routine may return pointer to EOL in case if all
    261  * characters in the string were not space separators.
    262 */
    263 static const char*
    264 kcm_skip_non_spaces(const char* str) {
    265     while (!kcm_is_eol(*str) && !kcm_is_token_separator(*str)) {
    266         str++;
    267     }
    268     return str;
    269 }
    270 
    271 /* Gets first token from a string.
    272  * line - String to get token from. End of the string should be
    273  * determined using kcm_is_eol() routine.
    274  * token - String where to copy token. Token, copied to this
    275  * string will be zero-terminated. Note that buffer for the
    276  * token string must be large enough to fit token of any size.
    277  * max_token_len - character size of the buffer addressed by
    278  * the 'token' parameter.
    279  * Returns NULL if there were no tokens found in the string, or
    280  * a pointer to the line string, advanced past the found token.
    281 */
    282 static const char*
    283 kcm_get_token(const char* line, char* token, size_t max_token_len) {
    284     // Pass spaces and tabs.
    285     const char* token_starts = kcm_skip_spaces(line);
    286     // Advance to next space.
    287     const char* token_ends = kcm_skip_non_spaces(token_starts);
    288     // Calc token length
    289     size_t token_len = token_ends - token_starts;
    290     if ((0 == token_len) || (token_len >= max_token_len)) {
    291       return NULL;
    292     }
    293     memcpy(token, token_starts, token_len);
    294     token[token_len] = '\0';
    295     return token_ends;
    296 }
    297 
    298 /* Checks if token represents a comment.
    299  * Returns non-zero value if token represents a comment, or zero otherwise.
    300 */
    301 static int
    302 kcm_is_token_comment(const char* token) {
    303     return '#' == *token;
    304 }
    305 
    306 /* Converts a key name to a key code as defined by AndroidKeyCode enum.
    307  * key_name - Key name to convert.
    308  * key_code - Upon success contains key code value for the key_name.
    309  * Returns a zero value on success, or -1 if key code was not found
    310  * for the given key_name.
    311 */
    312 static int
    313 kcm_get_key_code(const char* key_name, unsigned short* key_code) {
    314     int n;
    315     // Iterate through the key code map, matching key names.
    316     for (n = 0; n < sizeof(keycode_map) / sizeof(keycode_map[0]); n++) {
    317         if (0 == strcmp(key_name, keycode_map[n].key_name)) {
    318             *key_code = keycode_map[n].key_code;
    319             return 0;
    320         }
    321     }
    322     return -1;
    323 }
    324 
    325 /* Gets unsigned short hexadecimal value for a token.
    326  * token - Token to get hexadecimal value for. Note that this
    327  * routine expects a "clean" (i.e. no "0x" prefix) hex number
    328  * represented by the token string.
    329  * val - Upon success contains hexadecimal value for the token.
    330  * Returns a zero value on success, or -1 on error.
    331 */
    332 static int
    333 kcm_get_ushort_hex_val(const char* token, unsigned short* val) {
    334     int hex_val = hex2int((const uint8_t*)token, strlen(token));
    335     // Make sure token format was ok and value doesn't exceed unsigned short.
    336     if (-1 == hex_val || 0 != (hex_val & ~0xFFFF)) {
    337       return -1;
    338     }
    339 
    340     *val = (unsigned short)hex_val;
    341 
    342     return 0;
    343 }
    344 
    345 /* Gets a character or hexadecimal value represented by a token.
    346  * token - Token to get value from.
    347  * val - Upon success will contain a character or hexadecimal
    348  * value represented by a token.
    349  * Returns a zero value on success, or -1 on error.
    350 */
    351 static int
    352 kcm_get_char_or_hex_val(const char* token, unsigned short* val) {
    353     // For chars token must begin with ' followed by character followed by '
    354     if ('\'' == *token) {
    355         if ('\0' == token[1] || '\'' != token[2] || '\0' != token[3]) {
    356             return 0;
    357         }
    358         *val = token[1];
    359         return 0;
    360     } else {
    361         // Make sure that hex token is prefixed with "0x"
    362         if (('0' != *token) || ('x' != token[1])) {
    363             return -1;
    364         }
    365         // Past 0x
    366         return kcm_get_ushort_hex_val(token + 2, val);
    367     }
    368 }
    369 
    370 /* Gets first token for the line and calculates its value.
    371  * line - Line to get token's value from.
    372  * val - Upon success will contain a character or hexadecimal
    373  * value represented by the first token in the line.
    374  * returns NULL on error, or a pointer to the line string,
    375  * advanced past the found token.
    376 */
    377 static const char*
    378 kcm_get_char_or_hex_token_value(const char* line, unsigned short* val) {
    379     char token[KCM_MAX_TOKEN_LEN];
    380     line = kcm_get_token(line, token, KCM_MAX_TOKEN_LEN);
    381     if (NULL != line) {
    382         // Token must be a char, or a hex number.
    383         if (kcm_get_char_or_hex_val(token, val)) {
    384             return NULL;
    385         }
    386     }
    387 
    388     return line;
    389 }
    390 
    391 /* Parses a line in .kcm file extracting key information.
    392  * line - Line in .kcm file to parse.
    393  * line_index - Index of the parsing line in .kcm file.
    394  * key_entry - Upon success contains key information extracted from
    395  * the line.
    396  * kcm_file_path - Path to the charmap file, where paresed line was taken from.
    397  * returns BAD_FORMAT if line format was not recognized, SKIP_LINE if line
    398  * format was ok, but it didn't contain key information, or KEY_ENTRY
    399  * if key information was successfuly extracted from the line.
    400 */
    401 static ParseStatus
    402 kcm_parse_line(const char* line,
    403                int line_index,
    404                AKeyEntry* key_entry,
    405                const char* kcm_file_path) {
    406       char token[KCM_MAX_TOKEN_LEN];
    407       unsigned short disp;
    408 
    409       // Get first token, and see if it's an empty, or a comment line.
    410       line = kcm_get_token(line, token, KCM_MAX_TOKEN_LEN);
    411       if ((NULL == line) || kcm_is_token_comment(token)) {
    412           // Empty line, or a comment.
    413           return SKIP_LINE;
    414       }
    415 
    416       // Here we expect either [type=XXXX], or a key string.
    417       if ('[' == token[0]) {
    418           return SKIP_LINE;
    419       }
    420 
    421       // It must be a key string.
    422       // First token is key code.
    423       if (kcm_get_key_code(token, &key_entry->code)) {
    424           derror("Invalid format of charmap file %s. Unknown key %s in line %d",
    425                  kcm_file_path, token, line_index);
    426           return BAD_FORMAT;
    427       }
    428 
    429       // 2-nd token is display character, which is ignored.
    430       line = kcm_get_char_or_hex_token_value(line, &disp);
    431       if (NULL == line) {
    432           derror("Invalid format of charmap file %s. Invalid display value in line %d",
    433                  kcm_file_path, line_index);
    434           return BAD_FORMAT;
    435       }
    436 
    437       // 3-rd token is number.
    438       line = kcm_get_char_or_hex_token_value(line, &key_entry->number);
    439       if (NULL == line) {
    440           derror("Invalid format of charmap file %s. Invalid number value in line %d",
    441                  kcm_file_path, line_index);
    442           return BAD_FORMAT;
    443       }
    444 
    445       // 4-th token is base.
    446       line = kcm_get_char_or_hex_token_value(line, &key_entry->base);
    447       if (NULL == line) {
    448           derror("Invalid format of charmap file %s. Invalid base value in line %d",
    449                  kcm_file_path, line_index);
    450           return BAD_FORMAT;
    451       }
    452 
    453       // 5-th token is caps.
    454       line = kcm_get_char_or_hex_token_value(line, &key_entry->caps);
    455       if (NULL == line) {
    456           derror("Invalid format of charmap file %s. Invalid caps value in line %d",
    457                  kcm_file_path, line_index);
    458           return BAD_FORMAT;
    459       }
    460 
    461       // 6-th token is fn.
    462       line = kcm_get_char_or_hex_token_value(line, &key_entry->fn);
    463       if (NULL == line) {
    464           derror("Invalid format of charmap file %s. Invalid fn value in line %d",
    465                  kcm_file_path, line_index);
    466           return BAD_FORMAT;
    467       }
    468 
    469       // 7-th token is caps_fn.
    470       line = kcm_get_char_or_hex_token_value(line, &key_entry->caps_fn);
    471       if (NULL == line) {
    472           derror("Invalid format of charmap file %s. Invalid caps_fn value in line %d",
    473                  kcm_file_path, line_index);
    474           return BAD_FORMAT;
    475       }
    476 
    477       // Make sure that line doesn't contain anything else,
    478       // except (may be) a comment token.
    479       line = kcm_get_token(line, token, KCM_MAX_TOKEN_LEN);
    480       if ((NULL == line) || kcm_is_token_comment(token)) {
    481           return KEY_ENTRY;
    482       } else {
    483           derror("Invalid format of charmap file %s in line %d",
    484                  kcm_file_path, line_index);
    485           return BAD_FORMAT;
    486       }
    487 }
    488 
    489 void
    490 kcm_extract_charmap_name(const char* kcm_file_path,
    491                          char* charmap_name,
    492                          int max_len) {
    493     const char* ext_separator;
    494     size_t to_copy;
    495 
    496     // Initialize charmap name with name of .kcm file.
    497     // First, get file name from the full path to .kcm file.
    498     const char* file_name = kcm_file_path + strlen(kcm_file_path);
    499     while (!kcm_is_path_separator(*file_name) &&
    500            (file_name != kcm_file_path)) {
    501         file_name--;
    502     }
    503     if (kcm_is_path_separator(*file_name)) {
    504         file_name++;
    505     }
    506 
    507     // Cut off file name extension.
    508     ext_separator = strrchr(file_name, '.');
    509     if (NULL == ext_separator) {
    510       // "filename" is legal name.
    511       ext_separator = file_name + strlen(file_name);
    512     } else if (ext_separator == file_name) {
    513       // ".filename" is legal name too. In this case we will use
    514       // "filename" as our custom charmap name.
    515       file_name++;
    516       ext_separator = file_name + strlen(file_name);
    517     }
    518 
    519     // Copy file name to charmap name.
    520     to_copy = ext_separator - file_name;
    521     if (to_copy > (max_len - 1)) {
    522         to_copy = max_len - 1;
    523     }
    524     memcpy(charmap_name, file_name, to_copy);
    525     charmap_name[to_copy] = '\0';
    526 }
    527 
    528 /* Extracts charmap name from .kcm file name,
    529  * and saves it into char_map as its name.
    530 */
    531 static void
    532 kcm_get_charmap_name(const char* kcm_file_path, AKeyCharmap* char_map) {
    533     kcm_extract_charmap_name(kcm_file_path, char_map->name,
    534                              sizeof(char_map->name));
    535 }
    536 
    537 /* Parses .kcm file producing key characters map.
    538  * See comments to this module for .kcm file format information.
    539  * This routine checks format only for character map lines. It will not check
    540  * format for empty lines, comments, and type section lines.
    541  * Note that line length in .kcm file should not exceed 1024 characters,
    542  * including newline character.
    543  *
    544  * Parameters:
    545  * kcm_file_path - Full path to the .kcm file to parse.
    546  * char_map - Upon success will contain initialized characters map.
    547  * Returns a zero value on success, or -1 on failure.
    548 */
    549 static int
    550 parse_kcm_file(const char* kcm_file_path, AKeyCharmap* char_map) {
    551     // A line read from .kcm file.
    552     char line[KCM_MAX_LINE_LEN];
    553     // Return code.
    554     int err = 0;
    555     // Number of the currently parsed line.
    556     int cur_line = 1;
    557     // Initial size of the charmap's array of keys.
    558     int map_size = 52;
    559     FILE* kcm_file;
    560 
    561     char_map->num_entries = 0;
    562     char_map->entries = 0;
    563 
    564     kcm_file = fopen(kcm_file_path, "r");
    565     if (NULL == kcm_file) {
    566         derror("Unable to open charmap file %s : %s",
    567                kcm_file_path, strerror(errno));
    568         return -1;
    569     }
    570 
    571     // Calculate charmap name.
    572     kcm_get_charmap_name(kcm_file_path, char_map);
    573 
    574     // Preallocate map.
    575     char_map->num_entries = 0;
    576     AARRAY_NEW0(char_map->entries, map_size);
    577 
    578     // Line by line parse the file.
    579     for (; 0 != fgets(line, sizeof(line), kcm_file); cur_line++) {
    580         AKeyEntry key_entry;
    581         ParseStatus parse_res =
    582             kcm_parse_line(line, cur_line, &key_entry, kcm_file_path);
    583         if (BAD_FORMAT == parse_res) {
    584             err = -1;
    585             break;
    586         } else if (KEY_ENTRY == parse_res) {
    587             AKeyEntry* entries;
    588             // Key information has been extracted. Add it to the map.
    589             // Lets see if we need to reallocate map.
    590             if (map_size == char_map->num_entries) {
    591                 AKeyEntry* entries = (AKeyEntry*)char_map->entries;
    592                 map_size += 10;
    593                 AARRAY_RENEW(entries, map_size);
    594                 char_map->entries = (const AKeyEntry*)entries;
    595             }
    596             entries = (AKeyEntry*)char_map->entries;
    597             entries[char_map->num_entries] = key_entry;
    598             char_map->num_entries++;
    599         }
    600     }
    601 
    602     if (!err) {
    603         // Make sure we exited the loop on EOF condition. Any other
    604         // condition is an error.
    605         if (0 == feof(kcm_file)) {
    606             err = -1;
    607         }
    608         if (err) {
    609           derror("Error reading charmap file %s : %s",
    610                   kcm_file_path, strerror(errno));
    611         }
    612     }
    613 
    614     fclose(kcm_file);
    615 
    616     if (err) {
    617         // Cleanup on failure.
    618         if (0 != char_map->entries) {
    619             AFREE((void*)char_map->entries);
    620             char_map->entries = 0;
    621         }
    622         char_map->num_entries = 0;
    623     }
    624 
    625     return err;
    626 }
    627 
    628 int
    629 android_charmap_setup(const char* kcm_file_path) {
    630 
    631     /* Return if we already loaded a charmap */
    632     if (android_charmap != &_default_charmap || kcm_file_path == NULL)
    633         return 0;
    634 
    635     if (!parse_kcm_file(kcm_file_path, &android_custom_charmap)) {
    636         // Here we have the default charmap and the custom one.
    637         android_charmap = &android_custom_charmap;
    638     } else {
    639         derror("Unable to parse kcm file.");
    640         return -1;
    641     }
    642 
    643     return 0;
    644 }
    645 
    646 void
    647 android_charmap_done(void) {
    648     if (android_charmap != &_default_charmap)
    649         AFREE((void*)android_charmap->entries);
    650 }
    651 
    652 const AKeyCharmap*
    653 android_get_charmap_by_name(const char* name) {
    654     if (name != NULL) {
    655         if (!strcmp(android_charmap->name, name))
    656             return android_charmap;
    657         if (!strcmp(_default_charmap.name, name))
    658             return &_default_charmap;
    659     }
    660     return NULL;
    661 }
    662 
    663 int
    664 android_charmap_reverse_map_unicode(const AKeyCharmap* cmap,
    665                                     unsigned int unicode,
    666                                     int  down,
    667                                     AKeycodeBuffer* keycodes)
    668 {
    669     int                 n;
    670 
    671     if (unicode == 0)
    672         return 0;
    673 
    674     /* check base keys */
    675     for (n = 0; n < cmap->num_entries; n++) {
    676         if (cmap->entries[n].base == unicode) {
    677             android_keycodes_add_key_event(keycodes, cmap->entries[n].code, down);
    678             return 1;
    679         }
    680     }
    681 
    682     /* check caps + keys */
    683     for (n = 0; n < cmap->num_entries; n++) {
    684         if (cmap->entries[n].caps == unicode) {
    685             if (down) {
    686                 android_keycodes_add_key_event(keycodes, kKeyCodeCapLeft, down);
    687             }
    688             android_keycodes_add_key_event(keycodes, cmap->entries[n].code, down);
    689             if (!down) {
    690                 android_keycodes_add_key_event(keycodes, kKeyCodeCapLeft, down);
    691             }
    692             return 2;
    693         }
    694     }
    695 
    696     /* check fn + keys */
    697     for (n = 0; n < cmap->num_entries; n++) {
    698         if (cmap->entries[n].fn == unicode) {
    699             if (down) {
    700                 android_keycodes_add_key_event(keycodes, kKeyCodeAltLeft, down);
    701             }
    702             android_keycodes_add_key_event(keycodes, cmap->entries[n].code, down);
    703             if (!down) {
    704                 android_keycodes_add_key_event(keycodes, kKeyCodeAltLeft, down);
    705             }
    706             return 2;
    707         }
    708     }
    709 
    710     /* check caps + fn + keys */
    711     for (n = 0; n < cmap->num_entries; n++) {
    712         if (cmap->entries[n].caps_fn == unicode) {
    713             if (down) {
    714                 android_keycodes_add_key_event(keycodes, kKeyCodeAltLeft, down);
    715                 android_keycodes_add_key_event(keycodes, kKeyCodeCapLeft, down);
    716             }
    717             android_keycodes_add_key_event(keycodes, cmap->entries[n].code, down);
    718             if (!down) {
    719                 android_keycodes_add_key_event(keycodes, kKeyCodeCapLeft, down);
    720                 android_keycodes_add_key_event(keycodes, kKeyCodeAltLeft, down);
    721             }
    722             return 3;
    723         }
    724     }
    725 
    726     /* no match */
    727     return 0;
    728 }
    729 
    730 const AKeyCharmap* android_get_default_charmap(void)
    731 {
    732     return &_default_charmap;
    733 }
    734 
    735 const AKeyCharmap* android_get_charmap(void)
    736 {
    737     return android_charmap;
    738 }
    739 
    740 const char* android_get_charmap_name(void)
    741 {
    742     return android_get_charmap()->name;
    743 }
    744