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