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