]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - minibidi.c
Stability fixes (thanks valgrind).
[PuTTY.git] / minibidi.c
1 /************************************************************************
2  * $Id$
3  *
4  * ------------
5  * Description:
6  * ------------
7  * This is an implemention of Unicode's Bidirectional Algorithm
8  * (known as UAX #9).
9  *
10  *   http://www.unicode.org/reports/tr9/
11  * 
12  * Author: Ahmad Khalifa
13  *
14  * -----------------
15  * Revision Details:    (Updated by Revision Control System)
16  * -----------------
17  *  $Date$
18  *  $Author$
19  *  $Revision$
20  *  $Source: /u1/simon/svn-migration/cvs/putty/minibidi.c,v $
21  *
22  * (www.arabeyes.org - under MIT license)
23  *
24  ************************************************************************/
25
26 /*
27  * TODO:
28  * =====
29  * - Explicit marks need to be handled (they are not 100% now)
30  * - Ligatures
31  */
32
33 #include "minibidi.h"
34
35 /*
36  * Flips the text buffer, according to max level, and
37  * all higher levels
38  * 
39  * Input:
40  * from: text buffer, on which to apply flipping
41  * level: resolved levels buffer
42  * max: the maximum level found in this line (should be unsigned char)
43  * count: line size in bidi_char
44  */
45 void flipThisRun(bidi_char *from, unsigned char *level, int max, int count)
46 {
47     int i, j, rcount, tlevel;
48     bidi_char temp;
49
50     j = i = 0;
51     while(i<count && j<count)
52     {
53
54         /* find the start of the run of level=max */
55         tlevel = max;
56         i = j = findIndexOfRun(level, i, count, max);
57         /* find the end of the run */
58         while(i<count && tlevel <= level[i])
59         {
60             i++;
61         }
62         rcount = i-j;
63         for(; rcount>((i-j)/2); rcount--)
64         {
65             temp = from[j+rcount-1];
66             from[j+rcount-1] = from[i-rcount];
67             from[i-rcount] = temp;
68         }
69     }
70 }
71
72 /*
73  * Finds the index of a run with level equals tlevel
74  */
75 int findIndexOfRun(unsigned char* level , int start, int count, int tlevel)
76 {
77     int i;
78     for(i=start; i<count; i++)
79     {
80         if(tlevel == level[i])
81         {
82             return i;
83         }
84     }
85     return count;
86 }
87
88 /*
89  * Returns character type of ch, by calling RLE table lookup
90  * function
91  */
92 unsigned char getType(wchar_t ch)
93 {
94     return getRLE(ch);
95 }
96
97 /*
98  * The most significant 2 bits of each level are used to store
99  * Override status of each character
100  * This function sets the override bits of level according
101  * to the value in override, and reurns the new byte.
102  */
103 unsigned char setOverrideBits(unsigned char level, unsigned char override)
104 {
105     if(override == ON)
106         return level;
107     else if(override == R)
108         return level | OISR;
109     else if(override == L)
110         return level | OISL;
111     return level;
112 }
113
114 /* Dont remember what this was used for :-) */
115 unsigned char getPreviousLevel(unsigned char* level, int from)
116 {
117     unsigned char current;
118     from--;
119     current = level[from];
120     while(from>0 && level[from] == current)
121     {
122         from--;
123     }
124     return level[++from];
125 }
126
127 /*
128  * Returns the first odd value greater than x
129  */
130 unsigned char leastGreaterOdd(unsigned char x)
131 {
132     if((x % 2) == 0)
133         return x+1;
134     else
135         return x+2;
136 }
137
138 /*
139  * Returns the first even value greater than x
140  */
141 unsigned char leastGreaterEven(unsigned char x)
142 {
143     if((x % 2) == 0)
144         return x+2;
145     else
146         return x+1;
147 }
148
149 /*
150  * Loops over the RLE_table array looking for the
151  * type of ch
152  */
153 unsigned char getRLE(wchar_t ch)
154 {
155     int offset, i, freq;
156
157     freq = offset = 0;
158     for(i=0; i<0xFFFF; i++)
159     {
160         freq = ((RLENode*)RLE_table)[i].f;
161         offset += freq;
162         if(offset == ch)
163             return ((RLENode*)RLE_table)[i].d;
164         else if(offset > ch)
165             return ((RLENode*)RLE_table)[i-1].d;
166     }
167     /* this is here to stop compiler nagging */
168     return ON;
169 }
170
171 /* The Main shaping function, and the only one to be used
172  * by the outside world.
173  *
174  * line: buffer to apply shaping to. this must be passed by doBidi() first
175  * to: output buffer for the shaped data
176  * count: number of characters in line
177  */
178 int do_shape(bidi_char *line, bidi_char *to, int count)
179 {
180     int i, tempShape, ligFlag;
181
182     for(ligFlag=i=0; i<count; i++)
183     {
184         to[i] = line[i];
185         tempShape = STYPE(line[i].wc);
186         switch(tempShape )
187         {
188           case SC:
189             break;
190
191           case SU:
192             break;
193
194           case SR:
195             tempShape = STYPE(line[i+1].wc);
196             if((tempShape == SL) || (tempShape == SD) || (tempShape == SC))
197                 to[i].wc = SFINAL((SISOLATED(line[i].wc)));
198             else
199                 to[i].wc = SISOLATED(line[i].wc);
200             break;
201
202
203           case SD:
204             /* Make Ligatures */
205             tempShape = STYPE(line[i+1].wc);
206             if(line[i].wc == 0x644)
207             {
208                 switch(line[i-1].wc)
209                 {
210                   case 0x622:
211                     ligFlag = 1;
212                     if((tempShape == SL) || (tempShape == SD) || (tempShape == SC))
213                         to[i].wc = 0xFEF6;
214                     else
215                         to[i].wc = 0xFEF5;
216                     break;
217                   case 0x623:
218                     ligFlag = 1;
219                     if((tempShape == SL) || (tempShape == SD) || (tempShape == SC))
220                         to[i].wc = 0xFEF8;
221                     else
222                         to[i].wc = 0xFEF7;
223                     break;
224                   case 0x625:
225                     ligFlag = 1;
226                     if((tempShape == SL) || (tempShape == SD) || (tempShape == SC))
227                         to[i].wc = 0xFEFA;
228                     else
229                         to[i].wc = 0xFEF9;
230                     break;
231                   case 0x627:
232                     ligFlag = 1;
233                     if((tempShape == SL) || (tempShape == SD) || (tempShape == SC))
234                         to[i].wc = 0xFEFC;
235                     else
236                         to[i].wc = 0xFEFB;
237                     break;
238                 }
239                 if(ligFlag)
240                 {
241                     to[i-1].wc = 0x20;
242                     ligFlag = 0;
243                     break;
244                 }
245             }
246
247             if((tempShape == SL) || (tempShape == SD) || (tempShape == SC))
248             {
249                 tempShape = STYPE(line[i-1].wc);
250                 if((tempShape == SR) || (tempShape == SD) || (tempShape == SC))
251                     to[i].wc = SMEDIAL( (SISOLATED(line[i].wc)) );
252                 else
253                     to[i].wc = SFINAL((SISOLATED(line[i].wc)));
254                 break;
255             }
256
257             tempShape = STYPE(line[i-1].wc);
258             if((tempShape == SR) || (tempShape == SD) || (tempShape == SC))
259                 to[i].wc = SINITIAL((SISOLATED(line[i].wc)));
260             else
261                 to[i].wc = SISOLATED(line[i].wc);
262             break;
263
264
265         }
266     }
267     return 1;
268 }
269
270 /*
271  * The Main Bidi Function, and the only function that should
272  * be used by the outside world.
273  *
274  * line: a buffer of size count containing text to apply
275  * the Bidirectional algorithm to.
276  */
277
278 int do_bidi(bidi_char *line, int count)
279 {
280     unsigned char* types;
281     unsigned char* levels;
282     unsigned char paragraphLevel;
283     unsigned char currentEmbedding;
284     unsigned char currentOverride;
285     unsigned char tempType;
286     int i, j, imax, yes, bover;
287
288     /* Check the presence of R or AL types as optimization */
289     yes = 0;
290     for(i=0; i<count; i++)
291     {
292         if(getType(line[i].wc) == R || getType(line[i].wc) == AL)
293         {
294             yes = 1;
295             break;
296         }
297     }
298     if(yes == 0)
299         return L;
300
301     /* Initialize types, levels */
302     types = malloc(sizeof(unsigned char) * count);
303     levels = malloc(sizeof(unsigned char) * count);
304
305     /* Rule (P1)  NOT IMPLEMENTED
306      * P1. Split the text into separate paragraphs. A paragraph separator is
307      * kept with the previous paragraph. Within each paragraph, apply all the
308      * other rules of this algorithm.
309      */
310
311     /* Rule (P2), (P3)
312      * P2. In each paragraph, find the first character of type L, AL, or R.
313      * P3. If a character is found in P2 and it is of type AL or R, then set
314      * the paragraph embedding level to one; otherwise, set it to zero.
315      */
316     paragraphLevel = 0;
317     for( i=0; i<count ; i++)
318     {
319         if(getType(line[i].wc) == R || getType(line[i].wc) == AL)
320         {
321             paragraphLevel = 1;
322             break;
323         }
324         else if(getType(line[i].wc) == L)
325             break;
326     }
327
328     /* Rule (X1)
329      * X1. Begin by setting the current embedding level to the paragraph
330      * embedding level. Set the directional override status to neutral.
331      */
332     currentEmbedding = paragraphLevel;
333     currentOverride = ON;
334
335     /* Rule (X2), (X3), (X4), (X5), (X6), (X7), (X8)
336      * X2. With each RLE, compute the least greater odd embedding level.
337      * X3. With each LRE, compute the least greater even embedding level.
338      * X4. With each RLO, compute the least greater odd embedding level.
339      * X5. With each LRO, compute the least greater even embedding level.
340      * X6. For all types besides RLE, LRE, RLO, LRO, and PDF:
341      *          a. Set the level of the current character to the current
342      *              embedding level.
343      *          b.  Whenever the directional override status is not neutral,
344      *               reset the current character type to the directional
345      *               override status.
346      * X7. With each PDF, determine the matching embedding or override code.
347      * If there was a valid matching code, restore (pop) the last
348      * remembered (pushed) embedding level and directional override.
349      * X8. All explicit directional embeddings and overrides are completely
350      * terminated at the end of each paragraph. Paragraph separators are not
351      * included in the embedding. (Useless here) NOT IMPLEMENTED
352      */
353     bover = 0;
354     for( i=0; i<count; i++)
355     {
356         tempType = getType(line[i].wc);
357         switch(tempType)
358         {
359           case RLE:
360             currentEmbedding = levels[i] = leastGreaterOdd(currentEmbedding);
361             levels[i] = setOverrideBits(levels[i], currentOverride);
362             currentOverride = ON;
363             break;
364
365           case LRE:
366             currentEmbedding = levels[i] = leastGreaterEven(currentEmbedding);
367             levels[i] = setOverrideBits(levels[i], currentOverride);
368             currentOverride = ON;
369             break;
370
371           case RLO:
372             currentEmbedding = levels[i] = leastGreaterOdd(currentEmbedding);
373             tempType = currentOverride = R;
374             bover = 1;
375             break;
376
377           case LRO:
378             currentEmbedding = levels[i] = leastGreaterEven(currentEmbedding);
379             tempType = currentOverride = L;
380             bover = 1;
381             break;
382
383           case PDF:
384             currentEmbedding = getPreviousLevel(levels, i);
385             currentOverride = currentEmbedding & OMASK;
386             currentEmbedding = currentEmbedding & ~OMASK;
387             levels[i] = currentEmbedding;
388             break;
389
390             /* Whitespace is treated as neutral for now */
391           case WS:
392           case S:
393             levels[i] = currentEmbedding;
394             tempType = ON;
395             if(currentOverride != ON)
396                 tempType = currentOverride;
397             break;
398
399           default:
400             levels[i] = currentEmbedding;
401             if(currentOverride != ON)
402                 tempType = currentOverride;
403             break;
404
405         }
406         types[i] = tempType;
407     }
408     /* this clears out all overrides, so we can use levels safely... */
409     /* checks bover first */
410     if(bover)
411         for( i=0; i<count; i++)
412             levels[i] = levels[i] & LMASK;
413
414     /* Rule (X9)
415      * X9. Remove all RLE, LRE, RLO, LRO, PDF, and BN codes.
416      * Here, they're converted to BN.
417      */
418     for(i=0; i<count; i++)
419     {
420         switch(types[i])
421         {
422           case RLE:
423           case LRE:
424           case RLO:
425           case LRO:
426           case PDF:
427             types[i] = BN;
428             break;
429         }
430     }
431
432     /* Rule (W1)
433      * W1. Examine each non-spacing mark (NSM) in the level run, and change
434      * the type of the NSM to the type of the previous character. If the NSM
435      * is at the start of the level run, it will get the type of sor.
436      */
437     if(types[0] == NSM)
438         types[0] = paragraphLevel;
439
440     for(i=1; i<count; i++)
441     {
442         if(types[i] == NSM)
443             types[i] = types[i-1];
444         /* Is this a safe assumption?
445          * I assumed the previous, IS a character.
446          */
447     }
448
449     /* Rule (W2)
450      * W2. Search backwards from each instance of a European number until the
451      * first strong type (R, L, AL, or sor) is found.  If an AL is found,
452      * change the type of the European number to Arabic number.
453      */
454     for(i=0; i<count; i++)
455     {
456         if(types[i] == EN)
457         {
458             j=i;
459             while(j >= 0)
460             {
461                 if(types[j] == AL)
462                 {
463                     types[i] = AN;
464                     break;
465                 }else if(types[j] == R || types[j] == L)
466                     {
467                         break;
468                     }
469                 j--;
470             }
471         }
472     }
473
474     /* Rule (W3)
475      * W3. Change all ALs to R.
476      *
477      * Optimization: on Rule Xn, we might set a flag on AL type
478      * to prevent this loop in L R lines only...
479      */
480     for(i=0; i<count; i++)
481     {
482         if(types[i] == AL)
483             types[i] = R;
484     }
485
486     /* Rule (W4)
487      * W4. A single European separator between two European numbers changes
488      * to a European number. A single common separator between two numbers
489      * of the same type changes to that type.
490      */
491     for( i=0; i<(count-1); i++)
492     {
493         if(types[i] == ES)
494         {
495             if(types[i-1] == EN && types[i+1] == EN)
496                 types[i] = EN;
497         }else if(types[i] == CS)
498             {
499                 if(types[i-1] == EN && types[i+1] == EN)
500                     types[i] = EN;
501                 else if(types[i-1] == AN && types[i+1] == AN)
502                     types[i] = AN;
503             }
504     }
505
506     /* Rule (W5)
507      * W5. A sequence of European terminators adjacent to European numbers
508      * changes to all European numbers.
509      *
510      * Optimization: lots here... else ifs need rearrangement
511      */
512     for(i=0; i<count; i++)
513     {
514         if(types[i] == ET)
515         {
516             if(types[i-1] == EN)
517             {
518                 types[i] = EN;
519                 continue;
520             }else if(types[i+1] == EN)
521                 {
522                     types[i] = EN;
523                     continue;
524                 }else if(types[i+1] == ET)
525                     {
526                         j=i;
527                         while(j <count && types[j] == ET)
528                         {
529                             j++;
530                         }
531                         if(types[j] == EN)
532                             types[i] = EN;
533                     }
534         }
535     }
536
537     /* Rule (W6)
538      * W6. Otherwise, separators and terminators change to Other Neutral:
539      */
540     for(i=0; i<count; i++)
541     {
542         switch(types[i])
543         {
544           case ES:
545           case ET:
546           case CS:
547             types[i] = ON;
548             break;
549         }
550     }
551
552     /* Rule (W7)
553      * W7. Search backwards from each instance of a European number until
554      * the first strong type (R, L, or sor) is found. If an L is found,
555      * then change the type of the European number to L.
556      */
557     for(i=0; i<count; i++)
558     {
559         if(types[i] == EN)
560         {
561             j=i;
562             while(j >= 0)
563             {
564                 if(types[j] == L)
565                 {
566                     types[i] = L;
567                     break;
568                 }
569                 else if(types[j] == R || types[j] == AL)
570                 {
571                     break;
572                 }
573                 j--;
574             }
575         }
576     }
577
578     /* Rule (N1)
579      * N1. A sequence of neutrals takes the direction of the surrounding
580      * strong text if the text on both sides has the same direction. European
581      * and Arabic numbers are treated as though they were R.
582      */
583     if(types[0] == ON)
584     {
585         if((types[1] == R) || (types[1] == EN) || (types[1] == AN))
586             types[0] = R;
587         else if(types[1] == L)
588             types[0] = L;
589     }
590     for(i=1; i<(count-1); i++)
591     {
592         if(types[i] == ON)
593         {
594             if(types[i-1] == L)
595             {
596                 j=i;
597                 while(j<(count-1) && types[j] == ON)
598                 {
599                     j++;
600                 }
601                 if(types[j] == L)
602                 {
603                     while(i<j)
604                     {
605                         types[i] = L;
606                         i++;
607                     }
608                 }
609
610             }else if((types[i-1] == R)  ||
611                      (types[i-1] == EN) ||
612                      (types[i-1] == AN))
613                 {
614                     j=i;
615                     while(j<(count-1) && types[j] == ON)
616                     {
617                         j++;
618                     }
619                     if((types[j] == R)  ||
620                        (types[j] == EN) ||
621                        (types[j] == AN))
622                     {
623                         while(i<j)
624                         {
625                             types[i] = R;
626                             i++;
627                         }
628                     }
629                 }
630         }
631     }
632     if(types[count-1] == ON)
633     {
634         if(types[count-2] == R || types[count-2] == EN || types[count-2] == AN)
635             types[count-1] = R;
636         else if(types[count-2] == L)
637             types[count-1] = L;
638     }
639
640     /* Rule (N2)
641      * N2. Any remaining neutrals take the embedding direction.
642      */
643     for(i=0; i<count; i++)
644     {
645         if(types[i] == ON)
646         {
647             if((levels[i] % 2) == 0)
648                 types[i] = L;
649             else
650                 types[i] = R;
651         }
652     }
653
654     /* Rule (I1)
655      * I1. For all characters with an even (left-to-right) embedding
656      * direction, those of type R go up one level and those of type AN or
657      * EN go up two levels.
658      */
659     for(i=0; i<count; i++)
660     {
661         if((levels[i] % 2) == 0)
662         {
663             if(types[i] == R)
664                 levels[i] += 1;
665             else if(types[i] == AN || types[i] == EN)
666                 levels[i] += 2;
667         }
668     }
669
670     /* Rule (I2)
671      * I2. For all characters with an odd (right-to-left) embedding direction,
672      * those of type L, EN or AN go up one level.
673      */
674     for(i=0; i<count; i++)
675     {
676         if((levels[i] % 2) == 1)
677         {
678             if(types[i] == L || types[i] == EN || types[i] == AN)
679                 levels[i] += 1;
680         }
681     }
682
683     /* Rule (L1)
684      * L1. On each line, reset the embedding level of the following characters
685      * to the paragraph embedding level:
686      *          (1)segment separators, (2)paragraph separators,
687      *           (3)any sequence of whitespace characters preceding
688      *           a segment separator or paragraph separator,
689      *           (4)and any sequence of white space characters
690      *           at the end of the line.
691      * The types of characters used here are the original types, not those
692      * modified by the previous phase.
693      */
694     j=count-1;
695     while(j>0 && (getType(line[j].wc) == WS))
696     {
697         j--;
698     }
699     if(j < (count-1))
700     {
701         for(j++; j<count; j++)
702             levels[j] = paragraphLevel;
703     }
704     for(i=0; i<count; i++)
705     {
706         tempType = getType(line[i].wc);
707         if(tempType == WS)
708         {
709             j=i;
710             while(j<count && (getType(line[j].wc) == WS))
711             {
712                 j++;
713             }
714             if(j==count || getType(line[j].wc) == B ||
715                getType(line[j].wc) == S)
716             {
717                 for(j--; j>=i ; j--)
718                 {
719                     levels[j] = paragraphLevel;
720                 }
721             }
722         }else if(tempType == B || tempType == S)
723                 levels[i] = paragraphLevel;
724     }
725
726     /* Rule (L4) NOT IMPLEMENTED
727      * L4. A character that possesses the mirrored property as specified by
728      * Section 4.7, Mirrored, must be depicted by a mirrored glyph if the
729      * resolved directionality of that character is R.
730      */
731     /* Note: this is implemented before L2 for efficiency */
732     for(i=0; i<count; i++)
733         if((levels[i] % 2) == 1)
734             doMirror(&line[i].wc);
735
736     /* Rule (L2)
737      * L2. From the highest level found in the text to the lowest odd level on
738      * each line, including intermediate levels not actually present in the
739      * text, reverse any contiguous sequence of characters that are at that
740      * level or higher
741      */
742     /* we flip the character string and leave the level array */
743     imax = 0;
744     i=0;
745     tempType = levels[0];
746     while(i < count)
747     {
748         if(levels[i] > tempType)
749         {
750             tempType = levels[i];
751             imax=i;
752         }
753         i++;
754     }
755     /* maximum level in tempType, its index in imax. */
756     while(tempType > 0)         /* loop from highest level to the least odd, */
757     {                           /* which i assume is 1 */
758         flipThisRun(line, levels, tempType, count);
759         tempType--;
760     }
761
762     /* Rule (L3) NOT IMPLEMENTED
763      * L3. Combining marks applied to a right-to-left base character will at
764      * this point precede their base character. If the rendering engine
765      * expects them to follow the base characters in the final display
766      * process, then the ordering of the marks and the base character must
767      * be reversed.
768      */
769     free(types);
770     free(levels);
771     return R;
772 }
773
774
775 /*
776  * Bad, Horrible funtion
777  * takes a pointer to a character that is checked for
778  * having a mirror glyph.
779  */
780 void doMirror(wchar_t* ch)
781 {
782     if((*ch & 0xFF00) == 0)
783     {
784         switch(*ch)
785         {
786           case 0x0028:
787             *ch = 0x0029;
788             break;
789           case 0x0029:
790             *ch = 0x0028;
791             break;
792           case 0x003C:
793             *ch = 0x003E;
794             break;
795           case 0x003E:
796             *ch = 0x003C;
797             break;
798           case 0x005B:
799             *ch = 0x005D;
800             break;
801           case 0x005D:
802             *ch = 0x005B;
803             break;
804           case 0x007B:
805             *ch = 0x007D;
806             break;
807           case 0x007D:
808             *ch = 0x007B;
809             break;
810           case 0x00AB:
811             *ch = 0x00BB;
812             break;
813           case 0x00BB:
814             *ch = 0x00AB;
815             break;
816         }
817     }
818     else if((*ch & 0xFF00) == 0x2000)
819     {
820         switch(*ch)
821         {
822           case 0x2039:
823             *ch = 0x203A;
824             break;
825           case 0x203A:
826             *ch = 0x2039;
827             break;
828           case 0x2045:
829             *ch = 0x2046;
830             break;
831           case 0x2046:
832             *ch = 0x2045;
833             break;
834           case 0x207D:
835             *ch = 0x207E;
836             break;
837           case 0x207E:
838             *ch = 0x207D;
839             break;
840           case 0x208D:
841             *ch = 0x208E;
842             break;
843           case 0x208E:
844             *ch = 0x208D;
845             break;
846         }
847     }
848     else if((*ch & 0xFF00) == 0x2200)
849     {
850         switch(*ch)
851         {
852           case 0x2208:
853             *ch = 0x220B;
854             break;
855           case 0x2209:
856             *ch = 0x220C;
857             break;
858           case 0x220A:
859             *ch = 0x220D;
860             break;
861           case 0x220B:
862             *ch = 0x2208;
863             break;
864           case 0x220C:
865             *ch = 0x2209;
866             break;
867           case 0x220D:
868             *ch = 0x220A;
869             break;
870           case 0x2215:
871             *ch = 0x29F5;
872             break;
873           case 0x223C:
874             *ch = 0x223D;
875             break;
876           case 0x223D:
877             *ch = 0x223C;
878             break;
879           case 0x2243:
880             *ch = 0x22CD;
881             break;
882           case 0x2252:
883             *ch = 0x2253;
884             break;
885           case 0x2253:
886             *ch = 0x2252;
887             break;
888           case 0x2254:
889             *ch = 0x2255;
890             break;
891           case 0x2255:
892             *ch = 0x2254;
893             break;
894           case 0x2264:
895             *ch = 0x2265;
896             break;
897           case 0x2265:
898             *ch = 0x2264;
899             break;
900           case 0x2266:
901             *ch = 0x2267;
902             break;
903           case 0x2267:
904             *ch = 0x2266;
905             break;
906           case 0x2268:
907             *ch = 0x2269;
908             break;
909           case 0x2269:
910             *ch = 0x2268;
911             break;
912           case 0x226A:
913             *ch = 0x226B;
914             break;
915           case 0x226B:
916             *ch = 0x226A;
917             break;
918           case 0x226E:
919             *ch = 0x226F;
920             break;
921           case 0x226F:
922             *ch = 0x226E;
923             break;
924           case 0x2270:
925             *ch = 0x2271;
926             break;
927           case 0x2271:
928             *ch = 0x2270;
929             break;
930           case 0x2272:
931             *ch = 0x2273;
932             break;
933           case 0x2273:
934             *ch = 0x2272;
935             break;
936           case 0x2274:
937             *ch = 0x2275;
938             break;
939           case 0x2275:
940             *ch = 0x2274;
941             break;
942           case 0x2276:
943             *ch = 0x2277;
944             break;
945           case 0x2277:
946             *ch = 0x2276;
947             break;
948           case 0x2278:
949             *ch = 0x2279;
950             break;
951           case 0x2279:
952             *ch = 0x2278;
953             break;
954           case 0x227A:
955             *ch = 0x227B;
956             break;
957           case 0x227B:
958             *ch = 0x227A;
959             break;
960           case 0x227C:
961             *ch = 0x227D;
962             break;
963           case 0x227D:
964             *ch = 0x227C;
965             break;
966           case 0x227E:
967             *ch = 0x227F;
968             break;
969           case 0x227F:
970             *ch = 0x227E;
971             break;
972           case 0x2280:
973             *ch = 0x2281;
974             break;
975           case 0x2281:
976             *ch = 0x2280;
977             break;
978           case 0x2282:
979             *ch = 0x2283;
980             break;
981           case 0x2283:
982             *ch = 0x2282;
983             break;
984           case 0x2284:
985             *ch = 0x2285;
986             break;
987           case 0x2285:
988             *ch = 0x2284;
989             break;
990           case 0x2286:
991             *ch = 0x2287;
992             break;
993           case 0x2287:
994             *ch = 0x2286;
995             break;
996           case 0x2288:
997             *ch = 0x2289;
998             break;
999           case 0x2289:
1000             *ch = 0x2288;
1001             break;
1002           case 0x228A:
1003             *ch = 0x228B;
1004             break;
1005           case 0x228B:
1006             *ch = 0x228A;
1007             break;
1008           case 0x228F:
1009             *ch = 0x2290;
1010             break;
1011           case 0x2290:
1012             *ch = 0x228F;
1013             break;
1014           case 0x2291:
1015             *ch = 0x2292;
1016             break;
1017           case 0x2292:
1018             *ch = 0x2291;
1019             break;
1020           case 0x2298:
1021             *ch = 0x29B8;
1022             break;
1023           case 0x22A2:
1024             *ch = 0x22A3;
1025             break;
1026           case 0x22A3:
1027             *ch = 0x22A2;
1028             break;
1029           case 0x22A6:
1030             *ch = 0x2ADE;
1031             break;
1032           case 0x22A8:
1033             *ch = 0x2AE4;
1034             break;
1035           case 0x22A9:
1036             *ch = 0x2AE3;
1037             break;
1038           case 0x22AB:
1039             *ch = 0x2AE5;
1040             break;
1041           case 0x22B0:
1042             *ch = 0x22B1;
1043             break;
1044           case 0x22B1:
1045             *ch = 0x22B0;
1046             break;
1047           case 0x22B2:
1048             *ch = 0x22B3;
1049             break;
1050           case 0x22B3:
1051             *ch = 0x22B2;
1052             break;
1053           case 0x22B4:
1054             *ch = 0x22B5;
1055             break;
1056           case 0x22B5:
1057             *ch = 0x22B4;
1058             break;
1059           case 0x22B6:
1060             *ch = 0x22B7;
1061             break;
1062           case 0x22B7:
1063             *ch = 0x22B6;
1064             break;
1065           case 0x22C9:
1066             *ch = 0x22CA;
1067             break;
1068           case 0x22CA:
1069             *ch = 0x22C9;
1070             break;
1071           case 0x22CB:
1072             *ch = 0x22CC;
1073             break;
1074           case 0x22CC:
1075             *ch = 0x22CB;
1076             break;
1077           case 0x22CD:
1078             *ch = 0x2243;
1079             break;
1080           case 0x22D0:
1081             *ch = 0x22D1;
1082             break;
1083           case 0x22D1:
1084             *ch = 0x22D0;
1085             break;
1086           case 0x22D6:
1087             *ch = 0x22D7;
1088             break;
1089           case 0x22D7:
1090             *ch = 0x22D6;
1091             break;
1092           case 0x22D8:
1093             *ch = 0x22D9;
1094             break;
1095           case 0x22D9:
1096             *ch = 0x22D8;
1097             break;
1098           case 0x22DA:
1099             *ch = 0x22DB;
1100             break;
1101           case 0x22DB:
1102             *ch = 0x22DA;
1103             break;
1104           case 0x22DC:
1105             *ch = 0x22DD;
1106             break;
1107           case 0x22DD:
1108             *ch = 0x22DC;
1109             break;
1110           case 0x22DE:
1111             *ch = 0x22DF;
1112             break;
1113           case 0x22DF:
1114             *ch = 0x22DE;
1115             break;
1116           case 0x22E0:
1117             *ch = 0x22E1;
1118             break;
1119           case 0x22E1:
1120             *ch = 0x22E0;
1121             break;
1122           case 0x22E2:
1123             *ch = 0x22E3;
1124             break;
1125           case 0x22E3:
1126             *ch = 0x22E2;
1127             break;
1128           case 0x22E4:
1129             *ch = 0x22E5;
1130             break;
1131           case 0x22E5:
1132             *ch = 0x22E4;
1133             break;
1134           case 0x22E6:
1135             *ch = 0x22E7;
1136             break;
1137           case 0x22E7:
1138             *ch = 0x22E6;
1139             break;
1140           case 0x22E8:
1141             *ch = 0x22E9;
1142             break;
1143           case 0x22E9:
1144             *ch = 0x22E8;
1145             break;
1146           case 0x22EA:
1147             *ch = 0x22EB;
1148             break;
1149           case 0x22EB:
1150             *ch = 0x22EA;
1151             break;
1152           case 0x22EC:
1153             *ch = 0x22ED;
1154             break;
1155           case 0x22ED:
1156             *ch = 0x22EC;
1157             break;
1158           case 0x22F0:
1159             *ch = 0x22F1;
1160             break;
1161           case 0x22F1:
1162             *ch = 0x22F0;
1163             break;
1164           case 0x22F2:
1165             *ch = 0x22FA;
1166             break;
1167           case 0x22F3:
1168             *ch = 0x22FB;
1169             break;
1170           case 0x22F4:
1171             *ch = 0x22FC;
1172             break;
1173           case 0x22F6:
1174             *ch = 0x22FD;
1175             break;
1176           case 0x22F7:
1177             *ch = 0x22FE;
1178             break;
1179           case 0x22FA:
1180             *ch = 0x22F2;
1181             break;
1182           case 0x22FB:
1183             *ch = 0x22F3;
1184             break;
1185           case 0x22FC:
1186             *ch = 0x22F4;
1187             break;
1188           case 0x22FD:
1189             *ch = 0x22F6;
1190             break;
1191           case 0x22FE:
1192             *ch = 0x22F7;
1193             break;
1194         }
1195     }else if((*ch & 0xFF00) == 0x2300)
1196         {
1197             switch(*ch)
1198             {
1199               case 0x2308:
1200                 *ch = 0x2309;
1201                 break;
1202               case 0x2309:
1203                 *ch = 0x2308;
1204                 break;
1205               case 0x230A:
1206                 *ch = 0x230B;
1207                 break;
1208               case 0x230B:
1209                 *ch = 0x230A;
1210                 break;
1211               case 0x2329:
1212                 *ch = 0x232A;
1213                 break;
1214               case 0x232A:
1215                 *ch = 0x2329;
1216                 break;
1217             }
1218         }
1219     else if((*ch & 0xFF00) == 0x2700)
1220     {
1221         switch(*ch)
1222         {
1223           case 0x2768:
1224             *ch = 0x2769;
1225             break;
1226           case 0x2769:
1227             *ch = 0x2768;
1228             break;
1229           case 0x276A:
1230             *ch = 0x276B;
1231             break;
1232           case 0x276B:
1233             *ch = 0x276A;
1234             break;
1235           case 0x276C:
1236             *ch = 0x276D;
1237             break;
1238           case 0x276D:
1239             *ch = 0x276C;
1240             break;
1241           case 0x276E:
1242             *ch = 0x276F;
1243             break;
1244           case 0x276F:
1245             *ch = 0x276E;
1246             break;
1247           case 0x2770:
1248             *ch = 0x2771;
1249             break;
1250           case 0x2771:
1251             *ch = 0x2770;
1252             break;
1253           case 0x2772:
1254             *ch = 0x2773;
1255             break;
1256           case 0x2773:
1257             *ch = 0x2772;
1258             break;
1259           case 0x2774:
1260             *ch = 0x2775;
1261             break;
1262           case 0x2775:
1263             *ch = 0x2774;
1264             break;
1265           case 0x27D5:
1266             *ch = 0x27D6;
1267             break;
1268           case 0x27D6:
1269             *ch = 0x27D5;
1270             break;
1271           case 0x27DD:
1272             *ch = 0x27DE;
1273             break;
1274           case 0x27DE:
1275             *ch = 0x27DD;
1276             break;
1277           case 0x27E2:
1278             *ch = 0x27E3;
1279             break;
1280           case 0x27E3:
1281             *ch = 0x27E2;
1282             break;
1283           case 0x27E4:
1284             *ch = 0x27E5;
1285             break;
1286           case 0x27E5:
1287             *ch = 0x27E4;
1288             break;
1289           case 0x27E6:
1290             *ch = 0x27E7;
1291             break;
1292           case 0x27E7:
1293             *ch = 0x27E6;
1294             break;
1295           case 0x27E8:
1296             *ch = 0x27E9;
1297             break;
1298           case 0x27E9:
1299             *ch = 0x27E8;
1300             break;
1301           case 0x27EA:
1302             *ch = 0x27EB;
1303             break;
1304           case 0x27EB:
1305             *ch = 0x27EA;
1306             break;
1307         }
1308     }
1309     else if((*ch & 0xFF00) == 0x2900)
1310     {
1311         switch(*ch)
1312         {
1313           case 0x2983:
1314             *ch = 0x2984;
1315             break;
1316           case 0x2984:
1317             *ch = 0x2983;
1318             break;
1319           case 0x2985:
1320             *ch = 0x2986;
1321             break;
1322           case 0x2986:
1323             *ch = 0x2985;
1324             break;
1325           case 0x2987:
1326             *ch = 0x2988;
1327             break;
1328           case 0x2988:
1329             *ch = 0x2987;
1330             break;
1331           case 0x2989:
1332             *ch = 0x298A;
1333             break;
1334           case 0x298A:
1335             *ch = 0x2989;
1336             break;
1337           case 0x298B:
1338             *ch = 0x298C;
1339             break;
1340           case 0x298C:
1341             *ch = 0x298B;
1342             break;
1343           case 0x298D:
1344             *ch = 0x2990;
1345             break;
1346           case 0x298E:
1347             *ch = 0x298F;
1348             break;
1349           case 0x298F:
1350             *ch = 0x298E;
1351             break;
1352           case 0x2990:
1353             *ch = 0x298D;
1354             break;
1355           case 0x2991:
1356             *ch = 0x2992;
1357             break;
1358           case 0x2992:
1359             *ch = 0x2991;
1360             break;
1361           case 0x2993:
1362             *ch = 0x2994;
1363             break;
1364           case 0x2994:
1365             *ch = 0x2993;
1366             break;
1367           case 0x2995:
1368             *ch = 0x2996;
1369             break;
1370           case 0x2996:
1371             *ch = 0x2995;
1372             break;
1373           case 0x2997:
1374             *ch = 0x2998;
1375             break;
1376           case 0x2998:
1377             *ch = 0x2997;
1378             break;
1379           case 0x29B8:
1380             *ch = 0x2298;
1381             break;
1382           case 0x29C0:
1383             *ch = 0x29C1;
1384             break;
1385           case 0x29C1:
1386             *ch = 0x29C0;
1387             break;
1388           case 0x29C4:
1389             *ch = 0x29C5;
1390             break;
1391           case 0x29C5:
1392             *ch = 0x29C4;
1393             break;
1394           case 0x29CF:
1395             *ch = 0x29D0;
1396             break;
1397           case 0x29D0:
1398             *ch = 0x29CF;
1399             break;
1400           case 0x29D1:
1401             *ch = 0x29D2;
1402             break;
1403           case 0x29D2:
1404             *ch = 0x29D1;
1405             break;
1406           case 0x29D4:
1407             *ch = 0x29D5;
1408             break;
1409           case 0x29D5:
1410             *ch = 0x29D4;
1411             break;
1412           case 0x29D8:
1413             *ch = 0x29D9;
1414             break;
1415           case 0x29D9:
1416             *ch = 0x29D8;
1417             break;
1418           case 0x29DA:
1419             *ch = 0x29DB;
1420             break;
1421           case 0x29DB:
1422             *ch = 0x29DA;
1423             break;
1424           case 0x29F5:
1425             *ch = 0x2215;
1426             break;
1427           case 0x29F8:
1428             *ch = 0x29F9;
1429             break;
1430           case 0x29F9:
1431             *ch = 0x29F8;
1432             break;
1433           case 0x29FC:
1434             *ch = 0x29FD;
1435             break;
1436           case 0x29FD:
1437             *ch = 0x29FC;
1438             break;
1439         }
1440     }
1441     else if((*ch & 0xFF00) == 0x2A00)
1442     {
1443         switch(*ch)
1444         {
1445           case 0x2A2B:
1446             *ch = 0x2A2C;
1447             break;
1448           case 0x2A2C:
1449             *ch = 0x2A2B;
1450             break;
1451           case 0x2A2D:
1452             *ch = 0x2A2C;
1453             break;
1454           case 0x2A2E:
1455             *ch = 0x2A2D;
1456             break;
1457           case 0x2A34:
1458             *ch = 0x2A35;
1459             break;
1460           case 0x2A35:
1461             *ch = 0x2A34;
1462             break;
1463           case 0x2A3C:
1464             *ch = 0x2A3D;
1465             break;
1466           case 0x2A3D:
1467             *ch = 0x2A3C;
1468             break;
1469           case 0x2A64:
1470             *ch = 0x2A65;
1471             break;
1472           case 0x2A65:
1473             *ch = 0x2A64;
1474             break;
1475           case 0x2A79:
1476             *ch = 0x2A7A;
1477             break;
1478           case 0x2A7A:
1479             *ch = 0x2A79;
1480             break;
1481           case 0x2A7D:
1482             *ch = 0x2A7E;
1483             break;
1484           case 0x2A7E:
1485             *ch = 0x2A7D;
1486             break;
1487           case 0x2A7F:
1488             *ch = 0x2A80;
1489             break;
1490           case 0x2A80:
1491             *ch = 0x2A7F;
1492             break;
1493           case 0x2A81:
1494             *ch = 0x2A82;
1495             break;
1496           case 0x2A82:
1497             *ch = 0x2A81;
1498             break;
1499           case 0x2A83:
1500             *ch = 0x2A84;
1501             break;
1502           case 0x2A84:
1503             *ch = 0x2A83;
1504             break;
1505           case 0x2A8B:
1506             *ch = 0x2A8C;
1507             break;
1508           case 0x2A8C:
1509             *ch = 0x2A8B;
1510             break;
1511           case 0x2A91:
1512             *ch = 0x2A92;
1513             break;
1514           case 0x2A92:
1515             *ch = 0x2A91;
1516             break;
1517           case 0x2A93:
1518             *ch = 0x2A94;
1519             break;
1520           case 0x2A94:
1521             *ch = 0x2A93;
1522             break;
1523           case 0x2A95:
1524             *ch = 0x2A96;
1525             break;
1526           case 0x2A96:
1527             *ch = 0x2A95;
1528             break;
1529           case 0x2A97:
1530             *ch = 0x2A98;
1531             break;
1532           case 0x2A98:
1533             *ch = 0x2A97;
1534             break;
1535           case 0x2A99:
1536             *ch = 0x2A9A;
1537             break;
1538           case 0x2A9A:
1539             *ch = 0x2A99;
1540             break;
1541           case 0x2A9B:
1542             *ch = 0x2A9C;
1543             break;
1544           case 0x2A9C:
1545             *ch = 0x2A9B;
1546             break;
1547           case 0x2AA1:
1548             *ch = 0x2AA2;
1549             break;
1550           case 0x2AA2:
1551             *ch = 0x2AA1;
1552             break;
1553           case 0x2AA6:
1554             *ch = 0x2AA7;
1555             break;
1556           case 0x2AA7:
1557             *ch = 0x2AA6;
1558             break;
1559           case 0x2AA8:
1560             *ch = 0x2AA9;
1561             break;
1562           case 0x2AA9:
1563             *ch = 0x2AA8;
1564             break;
1565           case 0x2AAA:
1566             *ch = 0x2AAB;
1567             break;
1568           case 0x2AAB:
1569             *ch = 0x2AAA;
1570             break;
1571           case 0x2AAC:
1572             *ch = 0x2AAD;
1573             break;
1574           case 0x2AAD:
1575             *ch = 0x2AAC;
1576             break;
1577           case 0x2AAF:
1578             *ch = 0x2AB0;
1579             break;
1580           case 0x2AB0:
1581             *ch = 0x2AAF;
1582             break;
1583           case 0x2AB3:
1584             *ch = 0x2AB4;
1585             break;
1586           case 0x2AB4:
1587             *ch = 0x2AB3;
1588             break;
1589           case 0x2ABB:
1590             *ch = 0x2ABC;
1591             break;
1592           case 0x2ABC:
1593             *ch = 0x2ABB;
1594             break;
1595           case 0x2ABD:
1596             *ch = 0x2ABE;
1597             break;
1598           case 0x2ABE:
1599             *ch = 0x2ABD;
1600             break;
1601           case 0x2ABF:
1602             *ch = 0x2AC0;
1603             break;
1604           case 0x2AC0:
1605             *ch = 0x2ABF;
1606             break;
1607           case 0x2AC1:
1608             *ch = 0x2AC2;
1609             break;
1610           case 0x2AC2:
1611             *ch = 0x2AC1;
1612             break;
1613           case 0x2AC3:
1614             *ch = 0x2AC4;
1615             break;
1616           case 0x2AC4:
1617             *ch = 0x2AC3;
1618             break;
1619           case 0x2AC5:
1620             *ch = 0x2AC6;
1621             break;
1622           case 0x2AC6:
1623             *ch = 0x2AC5;
1624             break;
1625           case 0x2ACD:
1626             *ch = 0x2ACE;
1627             break;
1628           case 0x2ACE:
1629             *ch = 0x2ACD;
1630             break;
1631           case 0x2ACF:
1632             *ch = 0x2AD0;
1633             break;
1634           case 0x2AD0:
1635             *ch = 0x2ACF;
1636             break;
1637           case 0x2AD1:
1638             *ch = 0x2AD2;
1639             break;
1640           case 0x2AD2:
1641             *ch = 0x2AD1;
1642             break;
1643           case 0x2AD3:
1644             *ch = 0x2AD4;
1645             break;
1646           case 0x2AD4:
1647             *ch = 0x2AD3;
1648             break;
1649           case 0x2AD5:
1650             *ch = 0x2AD6;
1651             break;
1652           case 0x2AD6:
1653             *ch = 0x2AD5;
1654             break;
1655           case 0x2ADE:
1656             *ch = 0x22A6;
1657             break;
1658           case 0x2AE3:
1659             *ch = 0x22A9;
1660             break;
1661           case 0x2AE4:
1662             *ch = 0x22A8;
1663             break;
1664           case 0x2AE5:
1665             *ch = 0x22AB;
1666             break;
1667           case 0x2AEC:
1668             *ch = 0x2AED;
1669             break;
1670           case 0x2AED:
1671             *ch = 0x2AEC;
1672             break;
1673           case 0x2AF7:
1674             *ch = 0x2AF8;
1675             break;
1676           case 0x2AF8:
1677             *ch = 0x2AF7;
1678             break;
1679           case 0x2AF9:
1680             *ch = 0x2AFA;
1681             break;
1682           case 0x2AFA:
1683             *ch = 0x2AF9;
1684             break;
1685         }
1686     }
1687     else if((*ch & 0xFF00) == 0x3000)
1688     {
1689         switch(*ch)
1690         {
1691           case 0x3008:
1692             *ch = 0x3009;
1693             break;
1694           case 0x3009:
1695             *ch = 0x3008;
1696             break;
1697           case 0x300A:
1698             *ch = 0x300B;
1699             break;
1700           case 0x300B:
1701             *ch = 0x300A;
1702             break;
1703           case 0x300C:
1704             *ch = 0x300D;
1705             break;
1706           case 0x300D:
1707             *ch = 0x300C;
1708             break;
1709           case 0x300E:
1710             *ch = 0x300F;
1711             break;
1712           case 0x300F:
1713             *ch = 0x300E;
1714             break;
1715           case 0x3010:
1716             *ch = 0x3011;
1717             break;
1718           case 0x3011:
1719             *ch = 0x3010;
1720             break;
1721           case 0x3014:
1722             *ch = 0x3015;
1723             break;
1724           case 0x3015:
1725             *ch = 0x3014;
1726             break;
1727           case 0x3016:
1728             *ch = 0x3017;
1729             break;
1730           case 0x3017:
1731             *ch = 0x3016;
1732             break;
1733           case 0x3018:
1734             *ch = 0x3019;
1735             break;
1736           case 0x3019:
1737             *ch = 0x3018;
1738             break;
1739           case 0x301A:
1740             *ch = 0x301B;
1741             break;
1742           case 0x301B:
1743             *ch = 0x301A;
1744             break;
1745         }
1746     }
1747     else if((*ch & 0xFF00) == 0xFF00)
1748     {
1749         switch(*ch)
1750         {
1751           case 0xFF08:
1752             *ch = 0xFF09;
1753             break;
1754           case 0xFF09:
1755             *ch = 0xFF08;
1756             break;
1757           case 0xFF1C:
1758             *ch = 0xFF1E;
1759             break;
1760           case 0xFF1E:
1761             *ch = 0xFF1C;
1762             break;
1763           case 0xFF3B:
1764             *ch = 0xFF3D;
1765             break;
1766           case 0xFF3D:
1767             *ch = 0xFF3B;
1768             break;
1769           case 0xFF5B:
1770             *ch = 0xFF5D;
1771             break;
1772           case 0xFF5D:
1773             *ch = 0xFF5B;
1774             break;
1775           case 0xFF5F:
1776             *ch = 0xFF60;
1777             break;
1778           case 0xFF60:
1779             *ch = 0xFF5F;
1780             break;
1781           case 0xFF62:
1782             *ch = 0xFF63;
1783             break;
1784           case 0xFF63:
1785             *ch = 0xFF62;
1786             break;
1787         }
1788     }
1789 }