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