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