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