Bidi stability work. I _think_ I've now removed all the failures of
[u/mdw/putty] / 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 }