]> git.sur5r.net Git - openldap/blob - libraries/liblunicode/ucdata/ucdata.c
Happy new year!
[openldap] / libraries / liblunicode / ucdata / ucdata.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1998-2006 The OpenLDAP Foundation.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted only as authorized by the OpenLDAP
9  * Public License.
10  *
11  * A copy of this license is available in file LICENSE in the
12  * top-level directory of the distribution or, alternatively, at
13  * <http://www.OpenLDAP.org/license.html>.
14  */
15 /* Copyright 2001 Computing Research Labs, New Mexico State University
16  *
17  * Permission is hereby granted, free of charge, to any person obtaining a
18  * copy of this software and associated documentation files (the "Software"),
19  * to deal in the Software without restriction, including without limitation
20  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
21  * and/or sell copies of the Software, and to permit persons to whom the
22  * Software is furnished to do so, subject to the following conditions:
23  *
24  * The above copyright notice and this permission notice shall be included in
25  * all copies or substantial portions of the Software.
26  *
27  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
30  * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY
31  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
32  * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
33  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34  */
35 /* $Id: ucdata.c,v 1.4 2001/01/02 18:46:20 mleisher Exp $" */
36
37 #include "portable.h"
38 #include "ldap_config.h"
39
40 #include <stdio.h>
41 #include <ac/stdlib.h>
42 #include <ac/string.h>
43 #include <ac/unistd.h>
44
45 #include <ac/bytes.h>
46
47 #include "lber_pvt.h"
48 #include "ucdata.h"
49
50 #ifndef HARDCODE_DATA
51 #define HARDCODE_DATA   1
52 #endif
53
54 #if HARDCODE_DATA
55 #include "uctable.h"
56 #endif
57
58 /**************************************************************************
59  *
60  * Miscellaneous types, data, and support functions.
61  *
62  **************************************************************************/
63
64 typedef struct {
65     ac_uint2 bom;
66     ac_uint2 cnt;
67     union {
68         ac_uint4 bytes;
69         ac_uint2 len[2]; 
70     } size;
71 } _ucheader_t;
72
73 /*
74  * A simple array of 32-bit masks for lookup.
75  */
76 static ac_uint4 masks32[32] = {
77         0x00000001UL, 0x00000002UL, 0x00000004UL, 0x00000008UL,
78         0x00000010UL, 0x00000020UL, 0x00000040UL, 0x00000080UL,
79         0x00000100UL, 0x00000200UL, 0x00000400UL, 0x00000800UL,
80         0x00001000UL, 0x00002000UL, 0x00004000UL, 0x00008000UL,
81         0x00010000UL, 0x00020000UL, 0x00040000UL, 0x00080000UL,
82         0x00100000UL, 0x00200000UL, 0x00400000UL, 0x00800000UL,
83         0x01000000UL, 0x02000000UL, 0x04000000UL, 0x08000000UL,
84         0x10000000UL, 0x20000000UL, 0x40000000UL, 0x80000000UL
85 };
86
87 #define endian_short(cc) (((cc) >> 8) | (((cc) & 0xff) << 8))
88 #define endian_long(cc) ((((cc) & 0xff) << 24)|((((cc) >> 8) & 0xff) << 16)|\
89                         ((((cc) >> 16) & 0xff) << 8)|((cc) >> 24))
90
91 #if !HARDCODE_DATA
92 static FILE *
93 _ucopenfile(char *paths, char *filename, char *mode)
94 {
95     FILE *f;
96     char *fp, *dp, *pp, path[BUFSIZ];
97
98     if (filename == 0 || *filename == 0)
99       return 0;
100
101     dp = paths;
102     while (dp && *dp) {
103         pp = path;
104         while (*dp && *dp != ':')
105           *pp++ = *dp++;
106         *pp++ = *LDAP_DIRSEP;
107
108         fp = filename;
109         while (*fp)
110           *pp++ = *fp++;
111         *pp = 0;
112
113         if ((f = fopen(path, mode)) != 0)
114           return f;
115
116         if (*dp == ':')
117           dp++;
118     }
119
120     return 0;
121 }
122 #endif
123
124 /**************************************************************************
125  *
126  * Support for the character properties.
127  *
128  **************************************************************************/
129
130 #if !HARDCODE_DATA
131
132 static ac_uint4 _ucprop_size;
133 static ac_uint2 *_ucprop_offsets;
134 static ac_uint4 *_ucprop_ranges;
135
136 /*
137  * Return -1 on error, 0 if okay
138  */
139 static int
140 _ucprop_load(char *paths, int reload)
141 {
142     FILE *in;
143     ac_uint4 size, i;
144     _ucheader_t hdr;
145
146     if (_ucprop_size > 0) {
147         if (!reload)
148           /*
149            * The character properties have already been loaded.
150            */
151           return 0;
152
153         /*
154          * Unload the current character property data in preparation for
155          * loading a new copy.  Only the first array has to be deallocated
156          * because all the memory for the arrays is allocated as a single
157          * block.
158          */
159         free((char *) _ucprop_offsets);
160         _ucprop_size = 0;
161     }
162
163     if ((in = _ucopenfile(paths, "ctype.dat", "rb")) == 0)
164       return -1;
165
166     /*
167      * Load the header.
168      */
169     fread((char *) &hdr, sizeof(_ucheader_t), 1, in);
170
171     if (hdr.bom == 0xfffe) {
172         hdr.cnt = endian_short(hdr.cnt);
173         hdr.size.bytes = endian_long(hdr.size.bytes);
174     }
175
176     if ((_ucprop_size = hdr.cnt) == 0) {
177         fclose(in);
178         return -1;
179     }
180
181     /*
182      * Allocate all the storage needed for the lookup table.
183      */
184     _ucprop_offsets = (ac_uint2 *) malloc(hdr.size.bytes);
185
186     /*
187      * Calculate the offset into the storage for the ranges.  The offsets
188      * array is on a 4-byte boundary and one larger than the value provided in
189      * the header count field.  This means the offset to the ranges must be
190      * calculated after aligning the count to a 4-byte boundary.
191      */
192     if ((size = ((hdr.cnt + 1) * sizeof(ac_uint2))) & 3)
193       size += 4 - (size & 3);
194     size >>= 1;
195     _ucprop_ranges = (ac_uint4 *) (_ucprop_offsets + size);
196
197     /*
198      * Load the offset array.
199      */
200     fread((char *) _ucprop_offsets, sizeof(ac_uint2), size, in);
201
202     /*
203      * Do an endian swap if necessary.  Don't forget there is an extra node on
204      * the end with the final index.
205      */
206     if (hdr.bom == 0xfffe) {
207         for (i = 0; i <= _ucprop_size; i++)
208           _ucprop_offsets[i] = endian_short(_ucprop_offsets[i]);
209     }
210
211     /*
212      * Load the ranges.  The number of elements is in the last array position
213      * of the offsets.
214      */
215     fread((char *) _ucprop_ranges, sizeof(ac_uint4),
216           _ucprop_offsets[_ucprop_size], in);
217
218     fclose(in);
219
220     /*
221      * Do an endian swap if necessary.
222      */
223     if (hdr.bom == 0xfffe) {
224         for (i = 0; i < _ucprop_offsets[_ucprop_size]; i++)
225           _ucprop_ranges[i] = endian_long(_ucprop_ranges[i]);
226     }
227     return 0;
228 }
229
230 static void
231 _ucprop_unload(void)
232 {
233     if (_ucprop_size == 0)
234       return;
235
236     /*
237      * Only need to free the offsets because the memory is allocated as a
238      * single block.
239      */
240     free((char *) _ucprop_offsets);
241     _ucprop_size = 0;
242 }
243 #endif
244
245 static int
246 _ucprop_lookup(ac_uint4 code, ac_uint4 n)
247 {
248     long l, r, m;
249
250     if (_ucprop_size == 0)
251       return 0;
252
253     /*
254      * There is an extra node on the end of the offsets to allow this routine
255      * to work right.  If the index is 0xffff, then there are no nodes for the
256      * property.
257      */
258     if ((l = _ucprop_offsets[n]) == 0xffff)
259       return 0;
260
261     /*
262      * Locate the next offset that is not 0xffff.  The sentinel at the end of
263      * the array is the max index value.
264      */
265     for (m = 1;
266          n + m < _ucprop_size && _ucprop_offsets[n + m] == 0xffff; m++) ;
267
268     r = _ucprop_offsets[n + m] - 1;
269
270     while (l <= r) {
271         /*
272          * Determine a "mid" point and adjust to make sure the mid point is at
273          * the beginning of a range pair.
274          */
275         m = (l + r) >> 1;
276         m -= (m & 1);
277         if (code > _ucprop_ranges[m + 1])
278           l = m + 2;
279         else if (code < _ucprop_ranges[m])
280           r = m - 2;
281         else if (code >= _ucprop_ranges[m] && code <= _ucprop_ranges[m + 1])
282           return 1;
283     }
284     return 0;
285 }
286
287 int
288 ucisprop(ac_uint4 code, ac_uint4 mask1, ac_uint4 mask2)
289 {
290     ac_uint4 i;
291
292     if (mask1 == 0 && mask2 == 0)
293       return 0;
294
295     for (i = 0; mask1 && i < 32; i++) {
296         if ((mask1 & masks32[i]) && _ucprop_lookup(code, i))
297           return 1;
298     }
299
300     for (i = 32; mask2 && i < _ucprop_size; i++) {
301         if ((mask2 & masks32[i & 31]) && _ucprop_lookup(code, i))
302           return 1;
303     }
304
305     return 0;
306 }
307
308 /**************************************************************************
309  *
310  * Support for case mapping.
311  *
312  **************************************************************************/
313
314 #if !HARDCODE_DATA
315
316 static ac_uint4 _uccase_size;
317 static ac_uint2 _uccase_len[2];
318 static ac_uint4 *_uccase_map;
319
320 /*
321  * Return -1 on error, 0 if okay
322  */
323 static int
324 _uccase_load(char *paths, int reload)
325 {
326     FILE *in;
327     ac_uint4 i;
328     _ucheader_t hdr;
329
330     if (_uccase_size > 0) {
331         if (!reload)
332           /*
333            * The case mappings have already been loaded.
334            */
335           return 0;
336
337         free((char *) _uccase_map);
338         _uccase_size = 0;
339     }
340
341     if ((in = _ucopenfile(paths, "case.dat", "rb")) == 0)
342       return -1;
343
344     /*
345      * Load the header.
346      */
347     fread((char *) &hdr, sizeof(_ucheader_t), 1, in);
348
349     if (hdr.bom == 0xfffe) {
350         hdr.cnt = endian_short(hdr.cnt);
351         hdr.size.len[0] = endian_short(hdr.size.len[0]);
352         hdr.size.len[1] = endian_short(hdr.size.len[1]);
353     }
354
355     /*
356      * Set the node count and lengths of the upper and lower case mapping
357      * tables.
358      */
359     _uccase_size = hdr.cnt * 3;
360     _uccase_len[0] = hdr.size.len[0] * 3;
361     _uccase_len[1] = hdr.size.len[1] * 3;
362
363     _uccase_map = (ac_uint4 *)
364         malloc(_uccase_size * sizeof(ac_uint4));
365
366     /*
367      * Load the case mapping table.
368      */
369     fread((char *) _uccase_map, sizeof(ac_uint4), _uccase_size, in);
370
371     /*
372      * Do an endian swap if necessary.
373      */
374     if (hdr.bom == 0xfffe) {
375         for (i = 0; i < _uccase_size; i++)
376           _uccase_map[i] = endian_long(_uccase_map[i]);
377     }
378     fclose(in);
379     return 0;
380 }
381
382 static void
383 _uccase_unload(void)
384 {
385     if (_uccase_size == 0)
386       return;
387
388     free((char *) _uccase_map);
389     _uccase_size = 0;
390 }
391 #endif
392
393 static ac_uint4
394 _uccase_lookup(ac_uint4 code, long l, long r, int field)
395 {
396     long m;
397
398     /*
399      * Do the binary search.
400      */
401     while (l <= r) {
402         /*
403          * Determine a "mid" point and adjust to make sure the mid point is at
404          * the beginning of a case mapping triple.
405          */
406         m = (l + r) >> 1;
407         m -= (m % 3);
408         if (code > _uccase_map[m])
409           l = m + 3;
410         else if (code < _uccase_map[m])
411           r = m - 3;
412         else if (code == _uccase_map[m])
413           return _uccase_map[m + field];
414     }
415
416     return code;
417 }
418
419 ac_uint4
420 uctoupper(ac_uint4 code)
421 {
422     int field;
423     long l, r;
424
425     if (ucisupper(code))
426       return code;
427
428     if (ucislower(code)) {
429         /*
430          * The character is lower case.
431          */
432         field = 2;
433         l = _uccase_len[0];
434         r = (l + _uccase_len[1]) - 3;
435     } else {
436         /*
437          * The character is title case.
438          */
439         field = 1;
440         l = _uccase_len[0] + _uccase_len[1];
441         r = _uccase_size - 3;
442     }
443     return _uccase_lookup(code, l, r, field);
444 }
445
446 ac_uint4
447 uctolower(ac_uint4 code)
448 {
449     int field;
450     long l, r;
451
452     if (ucislower(code))
453       return code;
454
455     if (ucisupper(code)) {
456         /*
457          * The character is upper case.
458          */
459         field = 1;
460         l = 0;
461         r = _uccase_len[0] - 3;
462     } else {
463         /*
464          * The character is title case.
465          */
466         field = 2;
467         l = _uccase_len[0] + _uccase_len[1];
468         r = _uccase_size - 3;
469     }
470     return _uccase_lookup(code, l, r, field);
471 }
472
473 ac_uint4
474 uctotitle(ac_uint4 code)
475 {
476     int field;
477     long l, r;
478
479     if (ucistitle(code))
480       return code;
481
482     /*
483      * The offset will always be the same for converting to title case.
484      */
485     field = 2;
486
487     if (ucisupper(code)) {
488         /*
489          * The character is upper case.
490          */
491         l = 0;
492         r = _uccase_len[0] - 3;
493     } else {
494         /*
495          * The character is lower case.
496          */
497         l = _uccase_len[0];
498         r = (l + _uccase_len[1]) - 3;
499     }
500     return _uccase_lookup(code, l, r, field);
501 }
502
503 /**************************************************************************
504  *
505  * Support for compositions.
506  *
507  **************************************************************************/
508
509 #if !HARDCODE_DATA
510
511 static ac_uint4  _uccomp_size;
512 static ac_uint4 *_uccomp_data;
513
514 /*
515  * Return -1 on error, 0 if okay
516  */
517 static int
518 _uccomp_load(char *paths, int reload)
519 {
520     FILE *in;
521     ac_uint4 size, i;
522     _ucheader_t hdr;
523
524     if (_uccomp_size > 0) {
525         if (!reload)
526             /*
527              * The compositions have already been loaded.
528              */
529             return 0;
530
531         free((char *) _uccomp_data);
532         _uccomp_size = 0;
533     }
534
535     if ((in = _ucopenfile(paths, "comp.dat", "rb")) == 0)
536         return -1;
537
538     /*
539      * Load the header.
540      */
541     fread((char *) &hdr, sizeof(_ucheader_t), 1, in);
542
543     if (hdr.bom == 0xfffe) {
544         hdr.cnt = endian_short(hdr.cnt);
545         hdr.size.bytes = endian_long(hdr.size.bytes);
546     }
547
548     _uccomp_size = hdr.cnt;
549     _uccomp_data = (ac_uint4 *) malloc(hdr.size.bytes);
550
551     /*
552      * Read the composition data in.
553      */
554     size = hdr.size.bytes / sizeof(ac_uint4);
555     fread((char *) _uccomp_data, sizeof(ac_uint4), size, in);
556
557     /*
558      * Do an endian swap if necessary.
559      */
560     if (hdr.bom == 0xfffe) {
561         for (i = 0; i < size; i++)
562             _uccomp_data[i] = endian_long(_uccomp_data[i]);
563     }
564
565     /*
566      * Assume that the data is ordered on count, so that all compositions
567      * of length 2 come first. Only handling length 2 for now.
568      */
569     for (i = 1; i < size; i += 4)
570       if (_uccomp_data[i] != 2)
571         break;
572     _uccomp_size = i - 1;
573
574     fclose(in);
575     return 0;
576 }
577
578 static void
579 _uccomp_unload(void)
580 {
581     if (_uccomp_size == 0)
582         return;
583
584     free((char *) _uccomp_data);
585     _uccomp_size = 0;
586 }
587 #endif
588
589 int
590 uccomp(ac_uint4 node1, ac_uint4 node2, ac_uint4 *comp)
591 {
592     int l, r, m;
593
594     l = 0;
595     r = _uccomp_size - 1;
596
597     while (l <= r) {
598         m = ((r + l) >> 1);
599         m -= m & 3;
600         if (node1 > _uccomp_data[m+2])
601           l = m + 4;
602         else if (node1 < _uccomp_data[m+2])
603           r = m - 4;
604         else if (node2 > _uccomp_data[m+3])
605           l = m + 4;
606         else if (node2 < _uccomp_data[m+3])
607           r = m - 4;
608         else {
609             *comp = _uccomp_data[m];
610             return 1;
611         }
612     }
613     return 0;
614 }
615
616 int
617 uccomp_hangul(ac_uint4 *str, int len)
618 {
619     const int SBase = 0xAC00, LBase = 0x1100,
620         VBase = 0x1161, TBase = 0x11A7,
621         LCount = 19, VCount = 21, TCount = 28,
622         NCount = VCount * TCount,   /* 588 */
623         SCount = LCount * NCount;   /* 11172 */
624     
625     int i, rlen;
626     ac_uint4 ch, last, lindex, sindex;
627
628     last = str[0];
629     rlen = 1;
630     for ( i = 1; i < len; i++ ) {
631         ch = str[i];
632
633         /* check if two current characters are L and V */
634         lindex = last - LBase;
635         if (lindex < (ac_uint4) LCount) {
636             ac_uint4 vindex = ch - VBase;
637             if (vindex < (ac_uint4) VCount) {
638                 /* make syllable of form LV */
639                 last = SBase + (lindex * VCount + vindex) * TCount;
640                 str[rlen-1] = last; /* reset last */
641                 continue;
642             }
643         }
644         
645         /* check if two current characters are LV and T */
646         sindex = last - SBase;
647         if (sindex < (ac_uint4) SCount
648                         && (sindex % TCount) == 0)
649                 {
650             ac_uint4 tindex = ch - TBase;
651             if (tindex <= (ac_uint4) TCount) {
652                 /* make syllable of form LVT */
653                 last += tindex;
654                 str[rlen-1] = last; /* reset last */
655                 continue;
656             }
657         }
658
659         /* if neither case was true, just add the character */
660         last = ch;
661         str[rlen] = ch;
662         rlen++;
663     }
664     return rlen;
665 }
666
667 int
668 uccanoncomp(ac_uint4 *str, int len)
669 {
670     int i, stpos, copos;
671     ac_uint4 cl, prevcl, st, ch, co;
672
673     st = str[0];
674     stpos = 0;
675     copos = 1;
676     prevcl = uccombining_class(st) == 0 ? 0 : 256;
677         
678     for (i = 1; i < len; i++) {
679         ch = str[i];
680         cl = uccombining_class(ch);
681         if (uccomp(st, ch, &co) && (prevcl < cl || prevcl == 0))
682           st = str[stpos] = co;
683         else {
684             if (cl == 0) {
685                 stpos = copos;
686                 st = ch;
687             }
688             prevcl = cl;
689             str[copos++] = ch;
690         }
691     }
692
693     return uccomp_hangul(str, copos);
694 }
695
696 /**************************************************************************
697  *
698  * Support for decompositions.
699  *
700  **************************************************************************/
701
702 #if !HARDCODE_DATA
703
704 static ac_uint4  _ucdcmp_size;
705 static ac_uint4 *_ucdcmp_nodes;
706 static ac_uint4 *_ucdcmp_decomp;
707
708 static ac_uint4  _uckdcmp_size;
709 static ac_uint4 *_uckdcmp_nodes;
710 static ac_uint4 *_uckdcmp_decomp;
711
712 /*
713  * Return -1 on error, 0 if okay
714  */
715 static int
716 _ucdcmp_load(char *paths, int reload)
717 {
718     FILE *in;
719     ac_uint4 size, i;
720     _ucheader_t hdr;
721
722     if (_ucdcmp_size > 0) {
723         if (!reload)
724             /*
725              * The decompositions have already been loaded.
726              */
727           return 0;
728
729         free((char *) _ucdcmp_nodes);
730         _ucdcmp_size = 0;
731     }
732
733     if ((in = _ucopenfile(paths, "decomp.dat", "rb")) == 0)
734         return -1;
735
736     /*
737      * Load the header.
738      */
739     fread((char *) &hdr, sizeof(_ucheader_t), 1, in);
740
741     if (hdr.bom == 0xfffe) {
742         hdr.cnt = endian_short(hdr.cnt);
743         hdr.size.bytes = endian_long(hdr.size.bytes);
744     }
745
746     _ucdcmp_size = hdr.cnt << 1;
747     _ucdcmp_nodes = (ac_uint4 *) malloc(hdr.size.bytes);
748     _ucdcmp_decomp = _ucdcmp_nodes + (_ucdcmp_size + 1);
749
750     /*
751      * Read the decomposition data in.
752      */
753     size = hdr.size.bytes / sizeof(ac_uint4);
754     fread((char *) _ucdcmp_nodes, sizeof(ac_uint4), size, in);
755
756     /*
757      * Do an endian swap if necessary.
758      */
759     if (hdr.bom == 0xfffe) {
760         for (i = 0; i < size; i++)
761             _ucdcmp_nodes[i] = endian_long(_ucdcmp_nodes[i]);
762     }
763     fclose(in);
764     return 0;
765 }
766
767 /*
768  * Return -1 on error, 0 if okay
769  */
770 static int
771 _uckdcmp_load(char *paths, int reload)
772 {
773     FILE *in;
774     ac_uint4 size, i;
775     _ucheader_t hdr;
776
777     if (_uckdcmp_size > 0) {
778         if (!reload)
779             /*
780              * The decompositions have already been loaded.
781              */
782           return 0;
783
784         free((char *) _uckdcmp_nodes);
785         _uckdcmp_size = 0;
786     }
787
788     if ((in = _ucopenfile(paths, "kdecomp.dat", "rb")) == 0)
789         return -1;
790
791     /*
792      * Load the header.
793      */
794     fread((char *) &hdr, sizeof(_ucheader_t), 1, in);
795
796     if (hdr.bom == 0xfffe) {
797         hdr.cnt = endian_short(hdr.cnt);
798         hdr.size.bytes = endian_long(hdr.size.bytes);
799     }
800
801     _uckdcmp_size = hdr.cnt << 1;
802     _uckdcmp_nodes = (ac_uint4 *) malloc(hdr.size.bytes);
803     _uckdcmp_decomp = _uckdcmp_nodes + (_uckdcmp_size + 1);
804
805     /*
806      * Read the decomposition data in.
807      */
808     size = hdr.size.bytes / sizeof(ac_uint4);
809     fread((char *) _uckdcmp_nodes, sizeof(ac_uint4), size, in);
810
811     /*
812      * Do an endian swap if necessary.
813      */
814     if (hdr.bom == 0xfffe) {
815         for (i = 0; i < size; i++)
816             _uckdcmp_nodes[i] = endian_long(_uckdcmp_nodes[i]);
817     }
818     fclose(in);
819     return 0;
820 }
821
822 static void
823 _ucdcmp_unload(void)
824 {
825     if (_ucdcmp_size == 0)
826       return;
827
828     /*
829      * Only need to free the offsets because the memory is allocated as a
830      * single block.
831      */
832     free((char *) _ucdcmp_nodes);
833     _ucdcmp_size = 0;
834 }
835
836 static void
837 _uckdcmp_unload(void)
838 {
839     if (_uckdcmp_size == 0)
840       return;
841
842     /*
843      * Only need to free the offsets because the memory is allocated as a
844      * single block.
845      */
846     free((char *) _uckdcmp_nodes);
847     _uckdcmp_size = 0;
848 }
849 #endif
850
851 int
852 ucdecomp(ac_uint4 code, ac_uint4 *num, ac_uint4 **decomp)
853 {
854     long l, r, m;
855
856     if (code < _ucdcmp_nodes[0]) {
857         return 0;
858     }
859
860     l = 0;
861     r = _ucdcmp_nodes[_ucdcmp_size] - 1;
862
863     while (l <= r) {
864         /*
865          * Determine a "mid" point and adjust to make sure the mid point is at
866          * the beginning of a code+offset pair.
867          */
868         m = (l + r) >> 1;
869         m -= (m & 1);
870         if (code > _ucdcmp_nodes[m])
871           l = m + 2;
872         else if (code < _ucdcmp_nodes[m])
873           r = m - 2;
874         else if (code == _ucdcmp_nodes[m]) {
875             *num = _ucdcmp_nodes[m + 3] - _ucdcmp_nodes[m + 1];
876             *decomp = (ac_uint4*)&_ucdcmp_decomp[_ucdcmp_nodes[m + 1]];
877             return 1;
878         }
879     }
880     return 0;
881 }
882
883 int
884 uckdecomp(ac_uint4 code, ac_uint4 *num, ac_uint4 **decomp)
885 {
886     long l, r, m;
887
888     if (code < _uckdcmp_nodes[0]) {
889         return 0;
890     }
891     
892     l = 0;
893     r = _uckdcmp_nodes[_uckdcmp_size] - 1;
894
895     while (l <= r) {
896         /*
897          * Determine a "mid" point and adjust to make sure the mid point is at
898          * the beginning of a code+offset pair.
899          */
900         m = (l + r) >> 1;
901         m -= (m & 1);
902         if (code > _uckdcmp_nodes[m])
903           l = m + 2;
904         else if (code < _uckdcmp_nodes[m])
905           r = m - 2;
906         else if (code == _uckdcmp_nodes[m]) {
907             *num = _uckdcmp_nodes[m + 3] - _uckdcmp_nodes[m + 1];
908             *decomp = (ac_uint4*)&_uckdcmp_decomp[_uckdcmp_nodes[m + 1]];
909             return 1;
910         }
911     }
912     return 0;
913 }
914
915 int
916 ucdecomp_hangul(ac_uint4 code, ac_uint4 *num, ac_uint4 decomp[])
917 {
918     if (!ucishangul(code))
919       return 0;
920
921     code -= 0xac00;
922     decomp[0] = 0x1100 + (ac_uint4) (code / 588);
923     decomp[1] = 0x1161 + (ac_uint4) ((code % 588) / 28);
924     decomp[2] = 0x11a7 + (ac_uint4) (code % 28);
925     *num = (decomp[2] != 0x11a7) ? 3 : 2;
926
927     return 1;
928 }
929
930 /* mode == 0 for canonical, mode == 1 for compatibility */
931 static int
932 uccanoncompatdecomp(const ac_uint4 *in, int inlen,
933                     ac_uint4 **out, int *outlen, short mode, void *ctx)
934 {
935     int l, size;
936         unsigned i, j, k;
937     ac_uint4 num, class, *decomp, hangdecomp[3];
938
939     size = inlen * 2;
940     *out = (ac_uint4 *) ber_memalloc_x(size * sizeof(**out), ctx);
941     if (*out == NULL)
942         return *outlen = -1;
943
944     i = 0;
945     for (j = 0; j < (unsigned) inlen; j++) {
946         if (mode ? uckdecomp(in[j], &num, &decomp) : ucdecomp(in[j], &num, &decomp)) {
947             if ( size - i < num) {
948                 size = inlen + i - j + num - 1;
949                 *out = (ac_uint4 *) ber_memrealloc_x(*out, size * sizeof(**out), ctx );
950                 if (*out == NULL)
951                     return *outlen = -1;
952             }
953             for (k = 0; k < num; k++) {
954                 class = uccombining_class(decomp[k]);
955                 if (class == 0) {
956                     (*out)[i] = decomp[k];
957                 } else {
958                     for (l = i; l > 0; l--)
959                         if (class >= uccombining_class((*out)[l-1]))
960                             break;
961                     AC_MEMCPY(*out + l + 1, *out + l, (i - l) * sizeof(**out));
962                     (*out)[l] = decomp[k];
963                 }
964                 i++;
965             }
966         } else if (ucdecomp_hangul(in[j], &num, hangdecomp)) {
967             if (size - i < num) {
968                 size = inlen + i - j + num - 1;
969                 *out = (ac_uint4 *) ber_memrealloc_x(*out, size * sizeof(**out), ctx);
970                 if (*out == NULL)
971                     return *outlen = -1;
972             }
973             for (k = 0; k < num; k++) {
974                 (*out)[i] = hangdecomp[k];
975                 i++;
976             }
977         } else {
978             if (size - i < 1) {
979                 size = inlen + i - j;
980                 *out = (ac_uint4 *) ber_memrealloc_x(*out, size * sizeof(**out), ctx);
981                 if (*out == NULL)
982                     return *outlen = -1;
983             }
984             class = uccombining_class(in[j]);
985             if (class == 0) {
986                 (*out)[i] = in[j];
987             } else {
988                 for (l = i; l > 0; l--)
989                     if (class >= uccombining_class((*out)[l-1]))
990                         break;
991                 AC_MEMCPY(*out + l + 1, *out + l, (i - l) * sizeof(**out));
992                 (*out)[l] = in[j];
993             }
994             i++;
995         }
996     }
997     return *outlen = i;
998 }
999
1000 int
1001 uccanondecomp(const ac_uint4 *in, int inlen,
1002               ac_uint4 **out, int *outlen, void *ctx)
1003 {
1004     return uccanoncompatdecomp(in, inlen, out, outlen, 0, ctx);
1005 }
1006
1007 int
1008 uccompatdecomp(const ac_uint4 *in, int inlen,
1009                ac_uint4 **out, int *outlen, void *ctx)
1010 {
1011     return uccanoncompatdecomp(in, inlen, out, outlen, 1, ctx);
1012 }
1013
1014 /**************************************************************************
1015  *
1016  * Support for combining classes.
1017  *
1018  **************************************************************************/
1019
1020 #if !HARDCODE_DATA
1021 static ac_uint4  _uccmcl_size;
1022 static ac_uint4 *_uccmcl_nodes;
1023
1024 /*
1025  * Return -1 on error, 0 if okay
1026  */
1027 static int
1028 _uccmcl_load(char *paths, int reload)
1029 {
1030     FILE *in;
1031     ac_uint4 i;
1032     _ucheader_t hdr;
1033
1034     if (_uccmcl_size > 0) {
1035         if (!reload)
1036             /*
1037              * The combining classes have already been loaded.
1038              */
1039             return 0;
1040
1041         free((char *) _uccmcl_nodes);
1042         _uccmcl_size = 0;
1043     }
1044
1045     if ((in = _ucopenfile(paths, "cmbcl.dat", "rb")) == 0)
1046         return -1;
1047
1048     /*
1049      * Load the header.
1050      */
1051     fread((char *) &hdr, sizeof(_ucheader_t), 1, in);
1052
1053     if (hdr.bom == 0xfffe) {
1054         hdr.cnt = endian_short(hdr.cnt);
1055         hdr.size.bytes = endian_long(hdr.size.bytes);
1056     }
1057
1058     _uccmcl_size = hdr.cnt * 3;
1059     _uccmcl_nodes = (ac_uint4 *) malloc(hdr.size.bytes);
1060
1061     /*
1062      * Read the combining classes in.
1063      */
1064     fread((char *) _uccmcl_nodes, sizeof(ac_uint4), _uccmcl_size, in);
1065
1066     /*
1067      * Do an endian swap if necessary.
1068      */
1069     if (hdr.bom == 0xfffe) {
1070         for (i = 0; i < _uccmcl_size; i++)
1071             _uccmcl_nodes[i] = endian_long(_uccmcl_nodes[i]);
1072     }
1073     fclose(in);
1074     return 0;
1075 }
1076
1077 static void
1078 _uccmcl_unload(void)
1079 {
1080     if (_uccmcl_size == 0)
1081       return;
1082
1083     free((char *) _uccmcl_nodes);
1084     _uccmcl_size = 0;
1085 }
1086 #endif
1087
1088 ac_uint4
1089 uccombining_class(ac_uint4 code)
1090 {
1091     long l, r, m;
1092
1093     l = 0;
1094     r = _uccmcl_size - 1;
1095
1096     while (l <= r) {
1097         m = (l + r) >> 1;
1098         m -= (m % 3);
1099         if (code > _uccmcl_nodes[m + 1])
1100           l = m + 3;
1101         else if (code < _uccmcl_nodes[m])
1102           r = m - 3;
1103         else if (code >= _uccmcl_nodes[m] && code <= _uccmcl_nodes[m + 1])
1104           return _uccmcl_nodes[m + 2];
1105     }
1106     return 0;
1107 }
1108
1109 /**************************************************************************
1110  *
1111  * Support for numeric values.
1112  *
1113  **************************************************************************/
1114
1115 #if !HARDCODE_DATA
1116 static ac_uint4 *_ucnum_nodes;
1117 static ac_uint4 _ucnum_size;
1118 static short *_ucnum_vals;
1119
1120 /*
1121  * Return -1 on error, 0 if okay
1122  */
1123 static int
1124 _ucnumb_load(char *paths, int reload)
1125 {
1126     FILE *in;
1127     ac_uint4 size, i;
1128     _ucheader_t hdr;
1129
1130     if (_ucnum_size > 0) {
1131         if (!reload)
1132           /*
1133            * The numbers have already been loaded.
1134            */
1135           return 0;
1136
1137         free((char *) _ucnum_nodes);
1138         _ucnum_size = 0;
1139     }
1140
1141     if ((in = _ucopenfile(paths, "num.dat", "rb")) == 0)
1142       return -1;
1143
1144     /*
1145      * Load the header.
1146      */
1147     fread((char *) &hdr, sizeof(_ucheader_t), 1, in);
1148
1149     if (hdr.bom == 0xfffe) {
1150         hdr.cnt = endian_short(hdr.cnt);
1151         hdr.size.bytes = endian_long(hdr.size.bytes);
1152     }
1153
1154     _ucnum_size = hdr.cnt;
1155     _ucnum_nodes = (ac_uint4 *) malloc(hdr.size.bytes);
1156     _ucnum_vals = (short *) (_ucnum_nodes + _ucnum_size);
1157
1158     /*
1159      * Read the combining classes in.
1160      */
1161     fread((char *) _ucnum_nodes, sizeof(unsigned char), hdr.size.bytes, in);
1162
1163     /*
1164      * Do an endian swap if necessary.
1165      */
1166     if (hdr.bom == 0xfffe) {
1167         for (i = 0; i < _ucnum_size; i++)
1168           _ucnum_nodes[i] = endian_long(_ucnum_nodes[i]);
1169
1170         /*
1171          * Determine the number of values that have to be adjusted.
1172          */
1173         size = (hdr.size.bytes -
1174                 (_ucnum_size * (sizeof(ac_uint4) << 1))) /
1175             sizeof(short);
1176
1177         for (i = 0; i < size; i++)
1178           _ucnum_vals[i] = endian_short(_ucnum_vals[i]);
1179     }
1180     fclose(in);
1181     return 0;
1182 }
1183
1184 static void
1185 _ucnumb_unload(void)
1186 {
1187     if (_ucnum_size == 0)
1188       return;
1189
1190     free((char *) _ucnum_nodes);
1191     _ucnum_size = 0;
1192 }
1193 #endif
1194
1195 int
1196 ucnumber_lookup(ac_uint4 code, struct ucnumber *num)
1197 {
1198     long l, r, m;
1199     short *vp;
1200
1201     l = 0;
1202     r = _ucnum_size - 1;
1203     while (l <= r) {
1204         /*
1205          * Determine a "mid" point and adjust to make sure the mid point is at
1206          * the beginning of a code+offset pair.
1207          */
1208         m = (l + r) >> 1;
1209         m -= (m & 1);
1210         if (code > _ucnum_nodes[m])
1211           l = m + 2;
1212         else if (code < _ucnum_nodes[m])
1213           r = m - 2;
1214         else {
1215             vp = (short *)_ucnum_vals + _ucnum_nodes[m + 1];
1216             num->numerator = (int) *vp++;
1217             num->denominator = (int) *vp;
1218             return 1;
1219         }
1220     }
1221     return 0;
1222 }
1223
1224 int
1225 ucdigit_lookup(ac_uint4 code, int *digit)
1226 {
1227     long l, r, m;
1228     short *vp;
1229
1230     l = 0;
1231     r = _ucnum_size - 1;
1232     while (l <= r) {
1233         /*
1234          * Determine a "mid" point and adjust to make sure the mid point is at
1235          * the beginning of a code+offset pair.
1236          */
1237         m = (l + r) >> 1;
1238         m -= (m & 1);
1239         if (code > _ucnum_nodes[m])
1240           l = m + 2;
1241         else if (code < _ucnum_nodes[m])
1242           r = m - 2;
1243         else {
1244             vp = (short *)_ucnum_vals + _ucnum_nodes[m + 1];
1245             if (*vp == *(vp + 1)) {
1246               *digit = *vp;
1247               return 1;
1248             }
1249             return 0;
1250         }
1251     }
1252     return 0;
1253 }
1254
1255 struct ucnumber
1256 ucgetnumber(ac_uint4 code)
1257 {
1258     struct ucnumber num;
1259
1260     /*
1261      * Initialize with some arbitrary value, because the caller simply cannot
1262      * tell for sure if the code is a number without calling the ucisnumber()
1263      * macro before calling this function.
1264      */
1265     num.numerator = num.denominator = -111;
1266
1267     (void) ucnumber_lookup(code, &num);
1268
1269     return num;
1270 }
1271
1272 int
1273 ucgetdigit(ac_uint4 code)
1274 {
1275     int dig;
1276
1277     /*
1278      * Initialize with some arbitrary value, because the caller simply cannot
1279      * tell for sure if the code is a number without calling the ucisdigit()
1280      * macro before calling this function.
1281      */
1282     dig = -111;
1283
1284     (void) ucdigit_lookup(code, &dig);
1285
1286     return dig;
1287 }
1288
1289 /**************************************************************************
1290  *
1291  * Setup and cleanup routines.
1292  *
1293  **************************************************************************/
1294
1295 #if HARDCODE_DATA
1296 int ucdata_load(char *paths, int masks) { return 0; }
1297 void ucdata_unload(int masks) { }
1298 int ucdata_reload(char *paths, int masks) { return 0; }
1299 #else
1300 /*
1301  * Return 0 if okay, negative on error
1302  */
1303 int
1304 ucdata_load(char *paths, int masks)
1305 {
1306     int error = 0;
1307
1308     if (masks & UCDATA_CTYPE)
1309       error |= _ucprop_load(paths, 0) < 0 ? UCDATA_CTYPE : 0;
1310     if (masks & UCDATA_CASE)
1311       error |= _uccase_load(paths, 0) < 0 ? UCDATA_CASE : 0;
1312     if (masks & UCDATA_DECOMP)
1313       error |= _ucdcmp_load(paths, 0) < 0 ? UCDATA_DECOMP : 0;
1314     if (masks & UCDATA_CMBCL)
1315       error |= _uccmcl_load(paths, 0) < 0 ? UCDATA_CMBCL : 0;
1316     if (masks & UCDATA_NUM)
1317       error |= _ucnumb_load(paths, 0) < 0 ? UCDATA_NUM : 0;
1318     if (masks & UCDATA_COMP)
1319       error |= _uccomp_load(paths, 0) < 0 ? UCDATA_COMP : 0;
1320     if (masks & UCDATA_KDECOMP)
1321       error |= _uckdcmp_load(paths, 0) < 0 ? UCDATA_KDECOMP : 0;
1322
1323     return -error;
1324 }
1325
1326 void
1327 ucdata_unload(int masks)
1328 {
1329     if (masks & UCDATA_CTYPE)
1330       _ucprop_unload();
1331     if (masks & UCDATA_CASE)
1332       _uccase_unload();
1333     if (masks & UCDATA_DECOMP)
1334       _ucdcmp_unload();
1335     if (masks & UCDATA_CMBCL)
1336       _uccmcl_unload();
1337     if (masks & UCDATA_NUM)
1338       _ucnumb_unload();
1339     if (masks & UCDATA_COMP)
1340       _uccomp_unload();
1341     if (masks & UCDATA_KDECOMP)
1342       _uckdcmp_unload();
1343 }
1344
1345 /*
1346  * Return 0 if okay, negative on error
1347  */
1348 int
1349 ucdata_reload(char *paths, int masks)
1350 {
1351     int error = 0;
1352
1353     if (masks & UCDATA_CTYPE)
1354         error |= _ucprop_load(paths, 1) < 0 ? UCDATA_CTYPE : 0;
1355     if (masks & UCDATA_CASE)
1356         error |= _uccase_load(paths, 1) < 0 ? UCDATA_CASE : 0;
1357     if (masks & UCDATA_DECOMP)
1358         error |= _ucdcmp_load(paths, 1) < 0 ? UCDATA_DECOMP : 0;
1359     if (masks & UCDATA_CMBCL)
1360         error |= _uccmcl_load(paths, 1) < 0 ? UCDATA_CMBCL : 0;
1361     if (masks & UCDATA_NUM)
1362         error |= _ucnumb_load(paths, 1) < 0 ? UCDATA_NUM : 0;
1363     if (masks & UCDATA_COMP)
1364         error |= _uccomp_load(paths, 1) < 0 ? UCDATA_COMP : 0;
1365     if (masks & UCDATA_KDECOMP)
1366         error |= _uckdcmp_load(paths, 1) < 0 ? UCDATA_KDECOMP : 0;
1367
1368     return -error;
1369 }
1370 #endif
1371
1372 #ifdef TEST
1373
1374 void
1375 main(void)
1376 {
1377     int dig;
1378     ac_uint4 i, lo, *dec;
1379     struct ucnumber num;
1380
1381 /*    ucdata_setup("."); */
1382
1383     if (ucisweak(0x30))
1384       printf("WEAK\n");
1385     else
1386       printf("NOT WEAK\n");
1387
1388     printf("LOWER 0x%04lX\n", uctolower(0xff3a));
1389     printf("UPPER 0x%04lX\n", uctoupper(0xff5a));
1390
1391     if (ucisalpha(0x1d5))
1392       printf("ALPHA\n");
1393     else
1394       printf("NOT ALPHA\n");
1395
1396     if (ucisupper(0x1d5)) {
1397         printf("UPPER\n");
1398         lo = uctolower(0x1d5);
1399         printf("0x%04lx\n", lo);
1400         lo = uctotitle(0x1d5);
1401         printf("0x%04lx\n", lo);
1402     } else
1403       printf("NOT UPPER\n");
1404
1405     if (ucistitle(0x1d5))
1406       printf("TITLE\n");
1407     else
1408       printf("NOT TITLE\n");
1409
1410     if (uciscomposite(0x1d5))
1411       printf("COMPOSITE\n");
1412     else
1413       printf("NOT COMPOSITE\n");
1414
1415     if (ucdecomp(0x1d5, &lo, &dec)) {
1416         for (i = 0; i < lo; i++)
1417           printf("0x%04lx ", dec[i]);
1418         putchar('\n');
1419     }
1420
1421     if ((lo = uccombining_class(0x41)) != 0)
1422       printf("0x41 CCL %ld\n", lo);
1423
1424     if (ucisxdigit(0xfeff))
1425       printf("0xFEFF HEX DIGIT\n");
1426     else
1427       printf("0xFEFF NOT HEX DIGIT\n");
1428
1429     if (ucisdefined(0x10000))
1430       printf("0x10000 DEFINED\n");
1431     else
1432       printf("0x10000 NOT DEFINED\n");
1433
1434     if (ucnumber_lookup(0x30, &num)) {
1435         if (num.denominator != 1)
1436           printf("UCNUMBER: 0x30 = %d/%d\n", num.numerator, num.denominator);
1437         else
1438           printf("UCNUMBER: 0x30 = %d\n", num.numerator);
1439     } else
1440       printf("UCNUMBER: 0x30 NOT A NUMBER\n");
1441
1442     if (ucnumber_lookup(0xbc, &num)) {
1443         if (num.denominator != 1)
1444           printf("UCNUMBER: 0xbc = %d/%d\n", num.numerator, num.denominator);
1445         else
1446           printf("UCNUMBER: 0xbc = %d\n", num.numerator);
1447     } else
1448       printf("UCNUMBER: 0xbc NOT A NUMBER\n");
1449
1450
1451     if (ucnumber_lookup(0xff19, &num)) {
1452         if (num.denominator != 1)
1453           printf("UCNUMBER: 0xff19 = %d/%d\n", num.numerator, num.denominator);
1454         else
1455           printf("UCNUMBER: 0xff19 = %d\n", num.numerator);
1456     } else
1457       printf("UCNUMBER: 0xff19 NOT A NUMBER\n");
1458
1459     if (ucnumber_lookup(0x4e00, &num)) {
1460         if (num.denominator != 1)
1461           printf("UCNUMBER: 0x4e00 = %d/%d\n", num.numerator, num.denominator);
1462         else
1463           printf("UCNUMBER: 0x4e00 = %d\n", num.numerator);
1464     } else
1465       printf("UCNUMBER: 0x4e00 NOT A NUMBER\n");
1466
1467     if (ucdigit_lookup(0x06f9, &dig))
1468       printf("UCDIGIT: 0x6f9 = %d\n", dig);
1469     else
1470       printf("UCDIGIT: 0x6f9 NOT A NUMBER\n");
1471
1472     dig = ucgetdigit(0x0969);
1473     printf("UCGETDIGIT: 0x969 = %d\n", dig);
1474
1475     num = ucgetnumber(0x30);
1476     if (num.denominator != 1)
1477       printf("UCGETNUMBER: 0x30 = %d/%d\n", num.numerator, num.denominator);
1478     else
1479       printf("UCGETNUMBER: 0x30 = %d\n", num.numerator);
1480
1481     num = ucgetnumber(0xbc);
1482     if (num.denominator != 1)
1483       printf("UCGETNUMBER: 0xbc = %d/%d\n", num.numerator, num.denominator);
1484     else
1485       printf("UCGETNUMBER: 0xbc = %d\n", num.numerator);
1486
1487     num = ucgetnumber(0xff19);
1488     if (num.denominator != 1)
1489       printf("UCGETNUMBER: 0xff19 = %d/%d\n", num.numerator, num.denominator);
1490     else
1491       printf("UCGETNUMBER: 0xff19 = %d\n", num.numerator);
1492
1493 /*    ucdata_cleanup(); */
1494     exit(0);
1495 }
1496
1497 #endif /* TEST */