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. */
54typedef 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. */
63typedef 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
74static 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
139static 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
196static const AKeyCharmap  _default_charmap =
197{
198    _qwerty2_keys,
199    51,
200    "qwerty2"
201};
202
203/* Custom character map created with -charmap option. */
204static AKeyCharmap android_custom_charmap = { 0 };
205
206static 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*/
212static int
213kcm_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*/
222static int
223kcm_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*/
233static int
234kcm_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*/
249static const char*
250kcm_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*/
263static const char*
264kcm_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*/
282static const char*
283kcm_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*/
301static int
302kcm_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*/
312static int
313kcm_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*/
332static int
333kcm_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*/
351static int
352kcm_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*/
377static const char*
378kcm_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*/
401static ParseStatus
402kcm_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
489void
490kcm_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*/
531static void
532kcm_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*/
549static int
550parse_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
628int
629android_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
646void
647android_charmap_done(void) {
648    if (android_charmap != &_default_charmap)
649        AFREE((void*)android_charmap->entries);
650}
651
652const AKeyCharmap*
653android_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
663int
664android_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
730const AKeyCharmap* android_get_default_charmap(void)
731{
732    return &_default_charmap;
733}
734
735const AKeyCharmap* android_get_charmap(void)
736{
737    return android_charmap;
738}
739
740const char* android_get_charmap_name(void)
741{
742    return android_get_charmap()->name;
743}
744