• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
kcm_is_eol(char ch)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
kcm_is_token_separator(char ch)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
kcm_is_path_separator(char ch)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*
kcm_skip_spaces(const char * str)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*
kcm_skip_non_spaces(const char * str)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*
kcm_get_token(const char * line,char * token,size_t max_token_len)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
kcm_is_token_comment(const char * token)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
kcm_get_key_code(const char * key_name,unsigned short * key_code)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
kcm_get_ushort_hex_val(const char * token,unsigned short * val)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
kcm_get_char_or_hex_val(const char * token,unsigned short * val)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*
kcm_get_char_or_hex_token_value(const char * line,unsigned short * val)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
kcm_parse_line(const char * line,int line_index,AKeyEntry * key_entry,const char * kcm_file_path)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
kcm_extract_charmap_name(const char * kcm_file_path,char * charmap_name,int max_len)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
kcm_get_charmap_name(const char * kcm_file_path,AKeyCharmap * char_map)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
parse_kcm_file(const char * kcm_file_path,AKeyCharmap * char_map)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
android_charmap_setup(const char * kcm_file_path)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
android_charmap_done(void)647 android_charmap_done(void) {
648     if (android_charmap != &_default_charmap)
649         AFREE((void*)android_charmap->entries);
650 }
651 
652 const AKeyCharmap*
android_get_charmap_by_name(const char * name)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
android_charmap_reverse_map_unicode(const AKeyCharmap * cmap,unsigned int unicode,int down,AKeycodeBuffer * keycodes)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 
android_get_default_charmap(void)730 const AKeyCharmap* android_get_default_charmap(void)
731 {
732     return &_default_charmap;
733 }
734 
android_get_charmap(void)735 const AKeyCharmap* android_get_charmap(void)
736 {
737     return android_charmap;
738 }
739 
android_get_charmap_name(void)740 const char* android_get_charmap_name(void)
741 {
742     return android_get_charmap()->name;
743 }
744