]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - minibidi.c
At last! After much delay, much faffing back and forth, and much
[PuTTY.git] / minibidi.c
1 /************************************************************************
2  * $Id: minibidi.c,v 1.1 2004/05/22 10:36:50 simon Exp $
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: 2004/05/22 10:36:50 $
18  *  $Author: simon $
19  *  $Revision: 1.1 $
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(tlevel <= level[i] && i<count)
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(getType(line[j].wc) == B || 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 }