~ubuntu-branches/ubuntu/trusty/fcitx/trusty-proposed

« back to all changes in this revision

Viewing changes to src/module/unicode/charselectdata.c

  • Committer: Package Import Robot
  • Author(s): Aron Xu
  • Date: 2013-02-10 17:03:56 UTC
  • mfrom: (1.3.18) (33.1.3 experimental)
  • Revision ID: package-import@ubuntu.com-20130210170356-2yuv6xy3ed378kn0
Tags: 1:4.2.7-1
* New upstream release.
* New binary packages:
  - fcitx-libs-gclient: D-Bus client library for Glib
  - fcitx-libs-qt: D-Bus client library for Qt
  - fcitx-module-quickphrase-editor: Quick Phrase editor module

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * this file is ported from kdelibs/kdeui/kcharselectdata.cpp
 
3
 *
 
4
 * original file is licensed under GPLv2+
 
5
 */
 
6
 
 
7
#include <stdint.h>
 
8
#include <ctype.h>
 
9
#include <libintl.h>
 
10
#include <fcitx-utils/uthash.h>
 
11
#include <fcitx-utils/utils.h>
 
12
#include <fcitx-config/xdg.h>
 
13
#include <fcitx/fcitx.h>
 
14
#if defined(__linux__) || defined(__GLIBC__)
 
15
#include <endian.h>
 
16
#else
 
17
#include <sys/endian.h>
 
18
#endif
 
19
#include "charselectdata.h"
 
20
 
 
21
/* constants for hangul (de)composition, see UAX #15 */
 
22
#define SBase 0xAC00
 
23
#define LBase 0x1100
 
24
#define VBase 0x1161
 
25
#define TBase 0x11A7
 
26
#define LCount 19
 
27
#define VCount 21
 
28
#define TCount 28
 
29
#define NCount (VCount * TCount)
 
30
#define SCount (LCount * NCount)
 
31
#define HASH_FIND_UNICODE(head,findint,out)                                         \
 
32
    HASH_FIND(hh,head,findint,sizeof(uint16_t),out)
 
33
#define HASH_ADD_UNICODE(head,intfield,add)                                         \
 
34
    HASH_ADD(hh,head,intfield,sizeof(uint16_t),add)
 
35
 
 
36
typedef struct _UnicodeSet {
 
37
    uint16_t unicode;
 
38
    UT_hash_handle hh;
 
39
} UnicodeSet;
 
40
 
 
41
static const UT_icd int16_icd = { sizeof(int16_t), NULL, NULL, NULL };
 
42
 
 
43
static const char JAMO_L_TABLE[][4] = {
 
44
        "G", "GG", "N", "D", "DD", "R", "M", "B", "BB",
 
45
        "S", "SS", "", "J", "JJ", "C", "K", "T", "P", "H"
 
46
    };
 
47
 
 
48
static const char JAMO_V_TABLE[][4] = {
 
49
        "A", "AE", "YA", "YAE", "EO", "E", "YEO", "YE", "O",
 
50
        "WA", "WAE", "OE", "YO", "U", "WEO", "WE", "WI",
 
51
        "YU", "EU", "YI", "I"
 
52
    };
 
53
 
 
54
static const char JAMO_T_TABLE[][4] = {
 
55
        "", "G", "GG", "GS", "N", "NJ", "NH", "D", "L", "LG", "LM",
 
56
        "LB", "LS", "LT", "LP", "LH", "M", "B", "BS",
 
57
        "S", "SS", "NG", "J", "C", "K", "T", "P", "H"
 
58
    };
 
59
 
 
60
int uni_cmp(const void* a, const void* b) {
 
61
    const UnicodeSet* sa = a;
 
62
    const UnicodeSet* sb = b;
 
63
    return sa->unicode - sb->unicode;
 
64
}
 
65
 
 
66
int pindex_cmp(const void* a, const void* b) {
 
67
    CharSelectDataIndex* const* pa = a;
 
68
    CharSelectDataIndex* const* pb = b;
 
69
 
 
70
    return strcasecmp((*pa)->key, (*pb)->key);
 
71
}
 
72
 
 
73
int index_search_cmp(const void* a, const void* b) {
 
74
    const char* s = a;
 
75
    CharSelectDataIndex* const* pb = b;
 
76
 
 
77
    return strcasecmp(s, (*pb)->key);
 
78
}
 
79
 
 
80
int index_search_a_cmp(const void* a, const void* b) {
 
81
    const char* s = a;
 
82
    CharSelectDataIndex* const* pb = b;
 
83
 
 
84
    int res, len;
 
85
    len = strlen(s);
 
86
    res = strncasecmp(s, (*pb)->key, len);
 
87
    if (res)
 
88
        return res;
 
89
    else
 
90
        return 1;
 
91
}
 
92
 
 
93
UT_array* SplitString(const char* s);
 
94
 
 
95
char* FormatCode(uint16_t code, int length, const char* prefix);
 
96
UnicodeSet* CharSelectDataGetMatchingChars(CharSelectData* charselect, const char* s);
 
97
 
 
98
uint32_t FromLittleEndian32(const char* d)
 
99
{
 
100
    const uint8_t* data = (const uint8_t*) d;
 
101
    uint32_t t;
 
102
    memcpy(&t, data, sizeof(t));
 
103
    return le32toh(t);
 
104
}
 
105
 
 
106
uint16_t FromLittleEndian16(const char* d)
 
107
{
 
108
    const uint8_t* data = (const uint8_t*) d;
 
109
    uint16_t t;
 
110
    memcpy(&t, data, sizeof(t));
 
111
    return le16toh(t);
 
112
}
 
113
 
 
114
CharSelectData* CharSelectDataCreate()
 
115
{
 
116
    CharSelectData* charselect = fcitx_utils_new(CharSelectData);
 
117
 
 
118
    do {
 
119
 
 
120
        FILE* fp = FcitxXDGGetFileWithPrefix("data", "charselectdata", "r", NULL);
 
121
        if (!fp)
 
122
            break;
 
123
 
 
124
        fseek(fp, 0, SEEK_END);
 
125
        long int size = ftell(fp);
 
126
        fseek(fp, 0, SEEK_SET);
 
127
 
 
128
        charselect->size = size;
 
129
        charselect->dataFile = fcitx_utils_malloc0(size);
 
130
        fread(charselect->dataFile, 1, size, fp);
 
131
 
 
132
        fclose(fp);
 
133
 
 
134
        CharSelectDataCreateIndex(charselect);
 
135
 
 
136
        return charselect;
 
137
    } while(0);
 
138
 
 
139
    free(charselect);
 
140
    return NULL;
 
141
}
 
142
 
 
143
UT_array* CharSelectDataUnihanInfo(CharSelectData* charselect, uint16_t unicode)
 
144
{
 
145
    UT_array* res = fcitx_utils_new_string_list();
 
146
 
 
147
    const char* data = charselect->dataFile;
 
148
    const uint32_t offsetBegin = FromLittleEndian32(data+36);
 
149
    const uint32_t offsetEnd = charselect->size;
 
150
 
 
151
    int min = 0;
 
152
    int mid;
 
153
    int max = ((offsetEnd - offsetBegin) / 30) - 1;
 
154
 
 
155
    while (max >= min) {
 
156
        mid = (min + max) / 2;
 
157
        const uint16_t midUnicode = FromLittleEndian16(data + offsetBegin + mid*30);
 
158
        if (unicode > midUnicode)
 
159
            min = mid + 1;
 
160
        else if (unicode < midUnicode)
 
161
            max = mid - 1;
 
162
        else {
 
163
            int i;
 
164
            for(i = 0; i < 7; i++) {
 
165
                uint32_t offset = FromLittleEndian32(data + offsetBegin + mid*30 + 2 + i*4);
 
166
                const char* empty = "";
 
167
                if(offset != 0) {
 
168
                    const char* r = data + offset;
 
169
                    utarray_push_back(res, &r);
 
170
                } else {
 
171
                    utarray_push_back(res, &empty);
 
172
                }
 
173
            }
 
174
            return res;
 
175
        }
 
176
    }
 
177
 
 
178
    return res;
 
179
}
 
180
 
 
181
uint32_t CharSelectDataGetDetailIndex(CharSelectData* charselect, uint16_t unicode)
 
182
{
 
183
    const char* data = charselect->dataFile;
 
184
    // Convert from little-endian, so that this code works on PPC too.
 
185
    // http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=482286
 
186
    const uint32_t offsetBegin = FromLittleEndian32(data+12);
 
187
    const uint32_t offsetEnd = FromLittleEndian32(data+16);
 
188
 
 
189
    int min = 0;
 
190
    int mid;
 
191
    int max = ((offsetEnd - offsetBegin) / 27) - 1;
 
192
 
 
193
    static uint16_t most_recent_searched;
 
194
    static uint32_t most_recent_result;
 
195
 
 
196
 
 
197
    if (unicode == most_recent_searched)
 
198
        return most_recent_result;
 
199
 
 
200
    most_recent_searched = unicode;
 
201
 
 
202
    while (max >= min) {
 
203
        mid = (min + max) / 2;
 
204
        const uint16_t midUnicode = FromLittleEndian16(data + offsetBegin + mid*27);
 
205
        if (unicode > midUnicode)
 
206
            min = mid + 1;
 
207
        else if (unicode < midUnicode)
 
208
            max = mid - 1;
 
209
        else {
 
210
            most_recent_result = offsetBegin + mid*27;
 
211
 
 
212
            return most_recent_result;
 
213
        }
 
214
    }
 
215
 
 
216
    most_recent_result = 0;
 
217
    return 0;
 
218
}
 
219
 
 
220
char* CharSelectDataName(CharSelectData* charselect, uint16_t unicode)
 
221
{
 
222
    char* result = NULL;
 
223
    do {
 
224
        if ((unicode >= 0x3400 && unicode <= 0x4DB5)
 
225
                || (unicode >= 0x4e00 && unicode <= 0x9fa5)) {
 
226
            // || (unicode >= 0x20000 && unicode <= 0x2A6D6) // useless, since limited to 16 bit
 
227
            asprintf(&result, "CJK UNIFIED IDEOGRAPH-%x", unicode);
 
228
        } else if (unicode >= 0xac00 && unicode <= 0xd7af) {
 
229
            /* compute hangul syllable name as per UAX #15 */
 
230
            int SIndex = unicode - SBase;
 
231
            int LIndex, VIndex, TIndex;
 
232
 
 
233
            if (SIndex < 0 || SIndex >= SCount) {
 
234
                result = strdup("");
 
235
                break;
 
236
            }
 
237
 
 
238
            LIndex = SIndex / NCount;
 
239
            VIndex = (SIndex % NCount) / TCount;
 
240
            TIndex = SIndex % TCount;
 
241
 
 
242
            fcitx_utils_alloc_cat_str(result, "HANGUL SYLLABLE ",
 
243
                                      JAMO_L_TABLE[LIndex],
 
244
                                      JAMO_V_TABLE[VIndex],
 
245
                                      JAMO_T_TABLE[TIndex]);
 
246
        } else if (unicode >= 0xD800 && unicode <= 0xDB7F)
 
247
            result = strdup(_("<Non Private Use High Surrogate>"));
 
248
        else if (unicode >= 0xDB80 && unicode <= 0xDBFF)
 
249
            result = strdup(_("<Private Use High Surrogate>"));
 
250
        else if (unicode >= 0xDC00 && unicode <= 0xDFFF)
 
251
            result = strdup(_("<Low Surrogate>"));
 
252
        else if (unicode >= 0xE000 && unicode <= 0xF8FF)
 
253
            result = strdup(_("<Private Use>"));
 
254
        else {
 
255
 
 
256
        const char* data = charselect->dataFile;
 
257
            const uint32_t offsetBegin = FromLittleEndian32(data+4);
 
258
            const uint32_t offsetEnd = FromLittleEndian32(data+8);
 
259
 
 
260
            int min = 0;
 
261
            int mid;
 
262
            int max = ((offsetEnd - offsetBegin) / 6) - 1;
 
263
 
 
264
            while (max >= min) {
 
265
                mid = (min + max) / 2;
 
266
                const uint16_t midUnicode = FromLittleEndian16(data + offsetBegin + mid*6);
 
267
                if (unicode > midUnicode)
 
268
                    min = mid + 1;
 
269
                else if (unicode < midUnicode)
 
270
                    max = mid - 1;
 
271
                else {
 
272
                    uint32_t offset = FromLittleEndian32(data + offsetBegin + mid*6 + 2);
 
273
                    result = strdup(charselect->dataFile + offset + 1);
 
274
                    break;
 
275
                }
 
276
            }
 
277
        }
 
278
    } while(0);
 
279
 
 
280
    if (!result) {
 
281
        result = strdup(_("<not assigned>"));
 
282
    }
 
283
    return result;
 
284
}
 
285
 
 
286
char* Simplified(const char* src)
 
287
{
 
288
    char* s = strdup(src);
 
289
    char* o = s;
 
290
    char* p = s;
 
291
    int lastIsSpace = 0;
 
292
    while(*s) {
 
293
        char c = *s;
 
294
 
 
295
        if (isspace(c)) {
 
296
            if (!lastIsSpace) {
 
297
                *p = ' ';
 
298
                p ++;
 
299
            }
 
300
            lastIsSpace = 1;
 
301
        }
 
302
        else {
 
303
            *p = c;
 
304
            p++;
 
305
            lastIsSpace = 0;
 
306
        }
 
307
        s++;
 
308
    }
 
309
    return o;
 
310
}
 
311
 
 
312
int IsHexString(const char* s)
 
313
{
 
314
    size_t l = strlen(s);
 
315
    if (l != 6)
 
316
        return 0;
 
317
    if (!((s[0] == '0' && s[1] == 'x')
 
318
      || (s[0] == '0' && s[1] == 'X')
 
319
      || (s[0] == 'u' && s[1] == '+')
 
320
      || (s[0] == 'U' && s[1] == '+'))) {
 
321
        return 0;
 
322
    }
 
323
 
 
324
    s += 2;
 
325
    while (*s) {
 
326
        if (!isxdigit(*s))
 
327
            return 0;
 
328
        s++;
 
329
    }
 
330
    return 1;
 
331
}
 
332
 
 
333
void UnicodeSetFree(UnicodeSet* set) {
 
334
    while (set) {
 
335
        UnicodeSet* p = set;
 
336
        HASH_DEL(set, p);
 
337
        free(p);
 
338
    }
 
339
}
 
340
 
 
341
UnicodeSet* UnicodeSetIntersect(UnicodeSet* left, UnicodeSet* right)
 
342
{
 
343
    do {
 
344
        if (!left)
 
345
            break;
 
346
 
 
347
        if (!right)
 
348
            break;
 
349
 
 
350
        UnicodeSet* p = left;
 
351
        while (p) {
 
352
            UnicodeSet* find = NULL;
 
353
            HASH_FIND_UNICODE(right, &p->unicode, find);
 
354
            UnicodeSet* next = p->hh.next;
 
355
            if (!find) {
 
356
                HASH_DEL(left, p);
 
357
                free(p);
 
358
            }
 
359
            else {
 
360
                HASH_DEL(right, find);
 
361
                free(find);
 
362
            }
 
363
 
 
364
            p = next;
 
365
        }
 
366
 
 
367
        UnicodeSetFree(right);
 
368
        return left;
 
369
    } while(0);
 
370
 
 
371
    if (left)
 
372
        UnicodeSetFree(left);
 
373
 
 
374
    if (right)
 
375
        UnicodeSetFree(right);
 
376
 
 
377
    return NULL;
 
378
}
 
379
 
 
380
UT_array* CharSelectDataFind(CharSelectData* charselect, const char* needle)
 
381
{
 
382
    UnicodeSet *result = NULL;
 
383
 
 
384
    UT_array* returnRes;
 
385
    utarray_new(returnRes, &int16_icd);
 
386
    char* simplified = Simplified(needle);
 
387
    UT_array* searchStrings = SplitString(simplified);
 
388
 
 
389
    if (strlen(simplified) == 1) {
 
390
        // search for hex representation of the character
 
391
        utarray_clear(searchStrings);
 
392
        char* format = FormatCode(simplified[0], 4, "U+");
 
393
        utarray_push_back(searchStrings, &format);
 
394
        free(format);
 
395
    }
 
396
    free(simplified);
 
397
 
 
398
    if (utarray_len(searchStrings) == 0) {
 
399
        return returnRes;
 
400
    }
 
401
 
 
402
    utarray_foreach(s, searchStrings, char*) {
 
403
        char* end = NULL;
 
404
        if(IsHexString(*s)) {
 
405
            end = NULL;
 
406
            uint16_t uni = (uint16_t) strtol(*s + 2, &end, 16);
 
407
            utarray_push_back(returnRes, &uni);
 
408
 
 
409
            // search for "1234" instead of "0x1234"
 
410
            char* news = strdup(*s + 2);
 
411
            free(*s);
 
412
            *s = news;
 
413
        }
 
414
        // try to parse string as decimal number
 
415
        end = NULL;
 
416
        int unicode = strtol(*s, &end, 10);
 
417
        if (end == NULL && unicode >= 0 && unicode <= 0xFFFF) {
 
418
            utarray_push_back(returnRes, &unicode);
 
419
        }
 
420
    }
 
421
 
 
422
    int firstSubString = 1;
 
423
    utarray_foreach(s2, searchStrings, char* ) {
 
424
        UnicodeSet* partResult = CharSelectDataGetMatchingChars(charselect, *s2);
 
425
        if (firstSubString) {
 
426
            result = partResult;
 
427
            firstSubString = 0;
 
428
        } else {
 
429
            result = UnicodeSetIntersect(result, partResult);
 
430
        }
 
431
        if (!result)
 
432
            break;
 
433
    }
 
434
 
 
435
    // remove results found by matching the code point to prevent duplicate results
 
436
    // while letting these characters stay at the beginning
 
437
    utarray_foreach(c, returnRes, uint16_t) {
 
438
        UnicodeSet* dup = NULL;
 
439
        HASH_FIND_UNICODE(result, c, dup);
 
440
        if (dup)
 
441
            HASH_DEL(result, dup);
 
442
    }
 
443
 
 
444
    HASH_SORT(result, uni_cmp);
 
445
 
 
446
    while (result) {
 
447
        UnicodeSet* p = result;
 
448
        HASH_DEL(result, p);
 
449
        utarray_push_back(returnRes, &p->unicode);
 
450
        free(p);
 
451
    }
 
452
 
 
453
    utarray_free(searchStrings);
 
454
 
 
455
    return returnRes;
 
456
}
 
457
 
 
458
UnicodeSet* InsertResult(UnicodeSet* set, uint16_t unicode) {
 
459
    UnicodeSet* find = NULL;
 
460
    HASH_FIND_UNICODE(set, &unicode, find);
 
461
    if (!find) {
 
462
        find = fcitx_utils_new(UnicodeSet);
 
463
        find->unicode = unicode;
 
464
        HASH_ADD_UNICODE(set, unicode, find);
 
465
    }
 
466
    return set;
 
467
}
 
468
 
 
469
UnicodeSet* CharSelectDataGetMatchingChars(CharSelectData* charselect, const char* s)
 
470
{
 
471
    UnicodeSet *result = NULL;
 
472
    size_t s_l = strlen(s);
 
473
    CharSelectDataIndex **pos;
 
474
    CharSelectDataIndex **last;
 
475
    pos = utarray_custom_bsearch(s, charselect->indexList, 0, index_search_cmp);
 
476
    last = utarray_custom_bsearch(s, charselect->indexList,
 
477
                                  0, index_search_a_cmp);
 
478
    if (!pos)
 
479
        return NULL;
 
480
    if (!last)
 
481
        last = (CharSelectDataIndex**)utarray_back(charselect->indexList);
 
482
    while (pos != last && strncasecmp(s, (*pos)->key, s_l) == 0) {
 
483
        utarray_foreach (c, (*pos)->items, uint16_t) {
 
484
            result = InsertResult(result, *c);
 
485
        }
 
486
        ++pos;
 
487
    }
 
488
 
 
489
    return result;
 
490
}
 
491
 
 
492
UT_array* CharSelectDataAliases(CharSelectData* charselect, uint16_t unicode)
 
493
{
 
494
    const char* data = charselect->dataFile;
 
495
    const int detailIndex = CharSelectDataGetDetailIndex(charselect, unicode);
 
496
    if(detailIndex == 0) {
 
497
        return fcitx_utils_new_string_list();
 
498
    }
 
499
 
 
500
    const uint8_t count = * (uint8_t *)(data + detailIndex + 6);
 
501
    uint32_t offset = FromLittleEndian32(data + detailIndex + 2);
 
502
 
 
503
    UT_array* aliases = fcitx_utils_new_string_list();
 
504
 
 
505
    int i;
 
506
    for (i = 0;  i < count;  i++) {
 
507
        const char* r = data + offset;
 
508
        utarray_push_back(aliases, &r);
 
509
        offset += strlen(data + offset) + 1;
 
510
    }
 
511
    return aliases;
 
512
}
 
513
 
 
514
 
 
515
UT_array* CharSelectDataNotes(CharSelectData* charselect, uint16_t unicode)
 
516
{
 
517
    const int detailIndex = CharSelectDataGetDetailIndex(charselect, unicode);
 
518
    if(detailIndex == 0) {
 
519
        return fcitx_utils_new_string_list();
 
520
    }
 
521
 
 
522
    const char* data = charselect->dataFile;
 
523
    const uint8_t count = * (uint8_t *)(data + detailIndex + 11);
 
524
    uint32_t offset = FromLittleEndian32(data + detailIndex + 7);
 
525
 
 
526
    UT_array* notes = fcitx_utils_new_string_list();
 
527
 
 
528
    int i;
 
529
    for (i = 0;  i < count;  i++) {
 
530
        const char* r = data + offset;
 
531
        utarray_push_back(notes, &r);
 
532
        offset += strlen(data + offset) + 1;
 
533
    }
 
534
 
 
535
    return notes;
 
536
}
 
537
 
 
538
UT_array* CharSelectDataSeeAlso(CharSelectData* charselect, uint16_t unicode)
 
539
{
 
540
    UT_array* seeAlso;
 
541
    utarray_new(seeAlso, &int16_icd);
 
542
    const int detailIndex = CharSelectDataGetDetailIndex(charselect, unicode);
 
543
    if(detailIndex == 0) {
 
544
        return seeAlso;
 
545
    }
 
546
 
 
547
    const char* data = charselect->dataFile;
 
548
    const uint8_t count = * (uint8_t *)(data + detailIndex + 26);
 
549
    uint32_t offset = FromLittleEndian32(data + detailIndex + 22);
 
550
 
 
551
    int i;
 
552
    for (i = 0;  i < count;  i++) {
 
553
        uint16_t c = FromLittleEndian16 (data + offset);
 
554
        utarray_push_back(seeAlso, &c);
 
555
        offset += 2;
 
556
    }
 
557
 
 
558
    return seeAlso;
 
559
}
 
560
 
 
561
UT_array* CharSelectDataEquivalents(CharSelectData* charselect, uint16_t unicode)
 
562
{
 
563
    const int detailIndex = CharSelectDataGetDetailIndex(charselect, unicode);
 
564
    if(detailIndex == 0) {
 
565
        return fcitx_utils_new_string_list();
 
566
    }
 
567
 
 
568
    const char* data = charselect->dataFile;
 
569
    const uint8_t count = * (uint8_t *)(data + detailIndex + 21);
 
570
    uint32_t offset = FromLittleEndian32(data + detailIndex + 17);
 
571
 
 
572
    UT_array* equivalents = fcitx_utils_new_string_list();
 
573
 
 
574
    int i;
 
575
    for (i = 0;  i < count;  i++) {
 
576
        const char* r = data + offset;
 
577
        utarray_push_back(equivalents, &r);
 
578
        offset += strlen(data + offset) + 1;
 
579
    }
 
580
 
 
581
    return equivalents;
 
582
}
 
583
 
 
584
UT_array* CharSelectDataApproximateEquivalents(CharSelectData* charselect, uint16_t unicode)
 
585
{
 
586
    const int detailIndex = CharSelectDataGetDetailIndex(charselect, unicode);
 
587
    if(detailIndex == 0) {
 
588
        return fcitx_utils_new_string_list();
 
589
    }
 
590
 
 
591
    const char* data = charselect->dataFile;
 
592
    const uint8_t count = * (uint8_t *)(data + detailIndex + 16);
 
593
    uint32_t offset = FromLittleEndian32(data + detailIndex + 12);
 
594
 
 
595
    UT_array* approxEquivalents = fcitx_utils_new_string_list();
 
596
 
 
597
    int i;
 
598
    for (i = 0;  i < count;  i++) {
 
599
        const char* r = data + offset;
 
600
        utarray_push_back(approxEquivalents, &r);
 
601
        offset += strlen(data + offset) + 1;
 
602
    }
 
603
 
 
604
    return approxEquivalents;
 
605
}
 
606
 
 
607
 
 
608
char* FormatCode(uint16_t code, int length, const char* prefix)
 
609
{
 
610
    char* s = NULL;
 
611
    char* fmt = NULL;
 
612
    asprintf(&fmt, "%%s%%0%dX", length);
 
613
    asprintf(&s, fmt, prefix, code);
 
614
    free(fmt);
 
615
    return s;
 
616
}
 
617
 
 
618
UT_array* SplitString(const char* s)
 
619
{
 
620
    UT_array* result = fcitx_utils_new_string_list();
 
621
    int start = 0;
 
622
    int end = 0;
 
623
    int length = strlen(s);
 
624
    while (end < length) {
 
625
        while (end < length && (isdigit(s[end]) || isalpha(s[end]) || s[end] == '+')) {
 
626
            end++;
 
627
        }
 
628
        if (start != end) {
 
629
            char* p = strndup(&s[start], end - start);
 
630
            utarray_push_back(result, &p);
 
631
            free(p);
 
632
        }
 
633
        start = end;
 
634
        while (end < length && !(isdigit(s[end]) || isalpha(s[end]) || s[end] == '+')) {
 
635
            end++;
 
636
            start++;
 
637
        }
 
638
    }
 
639
    return result;
 
640
}
 
641
 
 
642
CharSelectDataIndex* CharSelectDataIndexNew(const char* key)
 
643
{
 
644
    CharSelectDataIndex* idx = fcitx_utils_new(CharSelectDataIndex);
 
645
    idx->key = strdup(key);
 
646
    utarray_new(idx->items, &int16_icd);
 
647
    return idx;
 
648
}
 
649
 
 
650
void CharSelectDataAppendToIndex(CharSelectData* charselect, uint16_t unicode, const char* str)
 
651
{
 
652
    UT_array* strings = SplitString(str);
 
653
    utarray_foreach(s, strings, char*) {
 
654
        CharSelectDataIndex* item = NULL;
 
655
        HASH_FIND_STR(charselect->index, *s, item);
 
656
        if (!item) {
 
657
            item = CharSelectDataIndexNew(*s);
 
658
            HASH_ADD_KEYPTR(hh, charselect->index, item->key, strlen(item->key), item);
 
659
        }
 
660
        utarray_push_back(item->items, &unicode);
 
661
    }
 
662
    utarray_free(strings);
 
663
}
 
664
 
 
665
void CharSelectDataDump(CharSelectData* charselect)
 
666
{
 
667
    //CharSelectDataIndex* item = charselect->index;
 
668
    /*
 
669
    while(item) {
 
670
        fprintf(stderr, "%s\n", item->key);
 
671
        item = item->hh.next;
 
672
    } */
 
673
 
 
674
    utarray_foreach(p, charselect->indexList, CharSelectDataIndex*) {
 
675
        fprintf(stderr, "%s\n", (*p)->key);
 
676
    }
 
677
}
 
678
 
 
679
void CharSelectDataCreateIndex(CharSelectData* charselect)
 
680
{
 
681
    // character names
 
682
    const char* data = charselect->dataFile;
 
683
    const uint32_t nameOffsetBegin = FromLittleEndian32(data+4);
 
684
    const uint32_t nameOffsetEnd = FromLittleEndian32(data+8);
 
685
 
 
686
    int max = ((nameOffsetEnd - nameOffsetBegin) / 6) - 1;
 
687
 
 
688
    int pos, j;
 
689
 
 
690
    for (pos = 0; pos <= max; pos++) {
 
691
        const uint16_t unicode = FromLittleEndian16(data + nameOffsetBegin + pos*6);
 
692
        uint32_t offset = FromLittleEndian32(data + nameOffsetBegin + pos*6 + 2);
 
693
        // TODO
 
694
        CharSelectDataAppendToIndex(charselect, unicode, (data + offset + 1));
 
695
    }
 
696
 
 
697
    // details
 
698
    const uint32_t detailsOffsetBegin = FromLittleEndian32(data+12);
 
699
    const uint32_t detailsOffsetEnd = FromLittleEndian32(data+16);
 
700
 
 
701
    max = ((detailsOffsetEnd - detailsOffsetBegin) / 27) - 1;
 
702
    for (pos = 0; pos <= max; pos++) {
 
703
        const uint16_t unicode = FromLittleEndian16(data + detailsOffsetBegin + pos*27);
 
704
 
 
705
        // aliases
 
706
        const uint8_t aliasCount = * (uint8_t *)(data + detailsOffsetBegin + pos*27 + 6);
 
707
        uint32_t aliasOffset = FromLittleEndian32(data + detailsOffsetBegin + pos*27 + 2);
 
708
 
 
709
        for (j = 0;  j < aliasCount;  j++) {
 
710
            CharSelectDataAppendToIndex(charselect, unicode, data + aliasOffset);
 
711
            aliasOffset += strlen(data + aliasOffset) + 1;
 
712
        }
 
713
 
 
714
        // notes
 
715
        const uint8_t notesCount = * (uint8_t *)(data + detailsOffsetBegin + pos*27 + 11);
 
716
        uint32_t notesOffset = FromLittleEndian32(data + detailsOffsetBegin + pos*27 + 7);
 
717
 
 
718
        for (j = 0;  j < notesCount;  j++) {
 
719
            CharSelectDataAppendToIndex(charselect, unicode, data + notesOffset);
 
720
            notesOffset += strlen(data + notesOffset) + 1;
 
721
        }
 
722
 
 
723
        // approximate equivalents
 
724
        const uint8_t apprCount = * (uint8_t *)(data + detailsOffsetBegin + pos*27 + 16);
 
725
        uint32_t apprOffset = FromLittleEndian32(data + detailsOffsetBegin + pos*27 + 12);
 
726
 
 
727
        for (j = 0;  j < apprCount;  j++) {
 
728
            CharSelectDataAppendToIndex(charselect, unicode,data + apprOffset);
 
729
            apprOffset += strlen(data + apprOffset) + 1;
 
730
        }
 
731
 
 
732
        // equivalents
 
733
        const uint8_t equivCount = * (uint8_t *)(data + detailsOffsetBegin + pos*27 + 21);
 
734
        uint32_t equivOffset = FromLittleEndian32(data + detailsOffsetBegin + pos*27 + 17);
 
735
 
 
736
        for (j = 0;  j < equivCount;  j++) {
 
737
            CharSelectDataAppendToIndex(charselect, unicode, data + equivOffset);
 
738
            equivOffset += strlen(data + equivOffset) + 1;
 
739
        }
 
740
 
 
741
        // see also - convert to string (hex)
 
742
        const uint8_t seeAlsoCount = * (uint8_t *)(data + detailsOffsetBegin + pos*27 + 26);
 
743
        uint32_t seeAlsoOffset = FromLittleEndian32(data + detailsOffsetBegin + pos*27 + 22);
 
744
 
 
745
        for (j = 0;  j < seeAlsoCount;  j++) {
 
746
            uint16_t seeAlso = FromLittleEndian16 (data + seeAlsoOffset);
 
747
            char* code = FormatCode(seeAlso, 4, "");
 
748
            CharSelectDataAppendToIndex(charselect, unicode, code);
 
749
            free(code);
 
750
            equivOffset += strlen(data + equivOffset) + 1;
 
751
        }
 
752
    }
 
753
 
 
754
    // unihan data
 
755
    // temporary disabled due to the huge amount of data
 
756
     const uint32_t unihanOffsetBegin = FromLittleEndian32(data+36);
 
757
     const uint32_t unihanOffsetEnd = charselect->size;
 
758
     max = ((unihanOffsetEnd - unihanOffsetBegin) / 30) - 1;
 
759
 
 
760
     for (pos = 0; pos <= max; pos++) {
 
761
         const uint16_t unicode = FromLittleEndian16(data + unihanOffsetBegin + pos*30);
 
762
         for(j = 0; j < 7; j++) {
 
763
             uint32_t offset = FromLittleEndian32(data + unihanOffsetBegin + pos*30 + 2 + j*4);
 
764
             if(offset != 0) {
 
765
                 CharSelectDataAppendToIndex(charselect, unicode, (data + offset));
 
766
             }
 
767
         }
 
768
     }
 
769
 
 
770
     utarray_new(charselect->indexList, fcitx_ptr_icd);
 
771
 
 
772
     CharSelectDataIndex* idx = charselect->index;
 
773
     while(idx) {
 
774
         utarray_push_back(charselect->indexList, &idx);
 
775
         idx = idx->hh.next;
 
776
     }
 
777
 
 
778
     utarray_sort(charselect->indexList, pindex_cmp);
 
779
}
 
780
 
 
781
void CharSelectDataFree(CharSelectData* charselect)
 
782
{
 
783
    utarray_free(charselect->indexList);
 
784
    while(charselect->index) {
 
785
        CharSelectDataIndex* p = charselect->index;
 
786
        HASH_DEL(charselect->index, p);
 
787
        free(p->key);
 
788
        utarray_free(p->items);
 
789
        free(p);
 
790
    }
 
791
    free(charselect->dataFile);
 
792
    free(charselect);
 
793
}