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