2005-07-27 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mcs / class / corlib / Mono.Globalization.Unicode / MSCompatUnicodeTable.cs
1 #define USE_MANAGED_RESOURCE
2 using System;
3 using System.Collections;
4 using System.Globalization;
5 using System.Reflection;
6 using System.Runtime.CompilerServices;
7
8 using UUtil = Mono.Globalization.Unicode.MSCompatUnicodeTableUtil;
9
10 namespace Mono.Globalization.Unicode
11 {
12         internal class TailoringInfo
13         {
14                 public readonly int LCID;
15                 public readonly int TailoringIndex;
16                 public readonly int TailoringCount;
17                 public readonly bool FrenchSort;
18
19                 public TailoringInfo (int lcid, int tailoringIndex, int tailoringCount, bool frenchSort)
20                 {
21                         LCID = lcid;
22                         TailoringIndex = tailoringIndex;
23                         TailoringCount = tailoringCount;
24                         FrenchSort = frenchSort;
25                 }
26         }
27
28         #region Tailoring support classes
29         // Possible mapping types are:
30         //
31         //      - string to string (ReplacementMap)
32         //      - string to SortKey (SortKeyMap)
33         //      - diacritical byte to byte (DiacriticalMap)
34         //
35         // There could be mapping from string to sortkeys, but
36         // for now there is none as such.
37         //
38         internal class Contraction
39         {
40                 public readonly char [] Source;
41                 // only either of them is used.
42                 public readonly string Replacement;
43                 public readonly byte [] SortKey;
44
45                 public Contraction (char [] source,
46                         string replacement, byte [] sortkey)
47                 {
48                         Source = source;
49                         Replacement = replacement;
50                         SortKey = sortkey;
51                 }
52         }
53
54         internal class ContractionComparer : IComparer
55         {
56                 public static readonly ContractionComparer Instance =
57                         new ContractionComparer ();
58
59                 public int Compare (object o1, object o2)
60                 {
61                         Contraction c1 = (Contraction) o1;
62                         Contraction c2 = (Contraction) o2;
63                         char [] a1 = c1.Source;
64                         char [] a2 = c2.Source;
65                         int min = a1.Length > a2.Length ?
66                                 a2.Length : a1.Length;
67                         for (int i = 0; i < min; i++)
68                                 if (a1 [i] != a2 [i])
69                                         return a1 [i] - a2 [i];
70                         return a1.Length - a2.Length;
71                 }
72         }
73
74         internal class Level2Map
75         {
76                 public byte Source;
77                 public byte Replace;
78
79                 public Level2Map (byte source, byte replace)
80                 {
81                         Source = source;
82                         Replace = replace;
83                 }
84         }
85
86         internal class Level2MapComparer : IComparer
87         {
88                 public static readonly Level2MapComparer Instance =
89                         new Level2MapComparer ();
90
91                 public int Compare (object o1, object o2)
92                 {
93                         Level2Map m1 = (Level2Map) o1;
94                         Level2Map m2 = (Level2Map) o2;
95                         return (m1.Source - m2.Source);
96                 }
97         }
98
99         #endregion
100
101         unsafe internal class MSCompatUnicodeTable
102         {
103                 public static int MaxExpansionLength = 3;
104
105                 static readonly byte* ignorableFlags;
106                 static readonly byte* categories;
107                 static readonly byte* level1;
108                 static readonly byte* level2;
109                 static readonly byte* level3;
110 //              static readonly ushort* widthCompat;
111                 static byte* cjkCHScategory;
112                 static byte* cjkCHTcategory;
113                 static byte* cjkJAcategory;
114                 static byte* cjkKOcategory;
115                 static byte* cjkCHSlv1;
116                 static byte* cjkCHTlv1;
117                 static byte* cjkJAlv1;
118                 static byte* cjkKOlv1;
119                 static byte* cjkKOlv2;
120
121                 const int ResourceVersionSize = 1;
122
123                 public static TailoringInfo GetTailoringInfo (int lcid)
124                 {
125                         for (int i = 0; i < tailoringInfos.Length; i++)
126                                 if (tailoringInfos [i].LCID == lcid)
127                                         return tailoringInfos [i];
128                         return null;
129                 }
130
131                 public static void BuildTailoringTables (CultureInfo culture,
132                         TailoringInfo t,
133                         ref Contraction [] contractions,
134                         ref Level2Map [] diacriticals)
135                 {
136                         // collect tailoring entries.
137                         ArrayList cmaps = new ArrayList ();
138                         ArrayList dmaps = new ArrayList ();
139                         char [] tarr = tailorings;
140                         int idx = t.TailoringIndex;
141                         int end = idx + t.TailoringCount;
142                         while (idx < end) {
143                                 int ss = idx + 1;
144                                 char [] src = null;
145                                 switch (tarr [idx]) {
146                                 case '\x1': // SortKeyMap
147                                         idx++;
148                                         while (tarr [ss] != 0)
149                                                 ss++;
150                                         src = new char [ss - idx];
151                                         Array.Copy (tarr, idx, src, 0, ss - idx);
152                                         byte [] sortkey = new byte [4];
153                                         for (int i = 0; i < 4; i++)
154                                                 sortkey [i] = (byte) tarr [ss + 1 + i];
155                                         cmaps.Add (new Contraction (
156                                                 src, null, sortkey));
157                                         // it ends with 0
158                                         idx = ss + 6;
159                                         break;
160                                 case '\x2': // DiacriticalMap
161                                         dmaps.Add (new Level2Map (
162                                                 (byte) tarr [idx + 1],
163                                                 (byte) tarr [idx + 2]));
164                                         idx += 3;
165                                         break;
166                                 case '\x3': // ReplacementMap
167                                         idx++;
168                                         while (tarr [ss] != 0)
169                                                 ss++;
170                                         src = new char [ss - idx];
171                                         Array.Copy (tarr, idx, src, 0, ss - idx);
172                                         ss++;
173                                         int l = ss;
174                                         while (tarr [l] != 0)
175                                                 l++;
176                                         string r = new string (tarr, ss, l - ss);
177                                         cmaps.Add (new Contraction (
178                                                 src, r, null));
179                                         idx = l + 1;
180                                         break;
181                                 default:
182                                         throw new NotImplementedException (String.Format ("Mono INTERNAL ERROR (Should not happen): Collation tailoring table is broken for culture {0} ({1}) at 0x{2:X}", culture.LCID, culture.Name, idx));
183                                 }
184                         }
185                         cmaps.Sort (ContractionComparer.Instance);
186                         dmaps.Sort (Level2MapComparer.Instance);
187                         contractions = cmaps.ToArray (typeof (Contraction))
188                                 as Contraction [];
189                         diacriticals = dmaps.ToArray (typeof (Level2Map))
190                                 as Level2Map [];
191                 }
192
193                 static void SetCJKReferences (string name,
194                         ref CodePointIndexer cjkIndexer,
195                         ref byte* catTable, ref byte* lv1Table,
196                         ref CodePointIndexer lv2Indexer, ref byte* lv2Table)
197                 {
198                         // as a part of mscorlib.dll, this invocation is
199                         // somewhat extraneous (pointers were already assigned).
200
201                         switch (name) {
202                         case "zh-CHS":
203                                 catTable = cjkCHScategory;
204                                 lv1Table = cjkCHSlv1;
205                                 cjkIndexer = UUtil.CjkCHS;
206                                 break;
207                         case "zh-CHT":
208                                 catTable = cjkCHTcategory;
209                                 lv1Table = cjkCHTlv1;
210                                 cjkIndexer = UUtil.Cjk;
211                                 break;
212                         case "ja":
213                                 catTable = cjkJAcategory;
214                                 lv1Table = cjkJAlv1;
215                                 cjkIndexer = UUtil.Cjk;
216                                 break;
217                         case "ko":
218                                 catTable = cjkKOcategory;
219                                 lv1Table = cjkKOlv1;
220                                 lv2Table = cjkKOlv2;
221                                 cjkIndexer = UUtil.Cjk;
222                                 lv2Indexer = UUtil.Cjk;
223                                 break;
224                         }
225                 }
226
227                 public static byte Category (int cp)
228                 {
229                         return categories [UUtil.Category.ToIndex (cp)];
230                 }
231
232                 public static byte Level1 (int cp)
233                 {
234                         return level1 [UUtil.Level1.ToIndex (cp)];
235                 }
236
237                 public static byte Level2 (int cp)
238                 {
239                         return level2 [UUtil.Level2.ToIndex (cp)];
240                 }
241
242                 public static byte Level3 (int cp)
243                 {
244                         return level3 [UUtil.Level3.ToIndex (cp)];
245                 }
246
247                 public static bool IsIgnorable (int cp)
248                 {
249                         UnicodeCategory uc = Char.GetUnicodeCategory ((char) cp);
250                         // This check eliminates some extraneous code areas
251                         if (uc == UnicodeCategory.OtherNotAssigned)
252                                 return true;
253                         // Some characters in Surrogate area are ignored.
254                         if (0xD880 <= cp && cp < 0xDB80)
255                                 return true;
256                         int i = UUtil.Ignorable.ToIndex (cp);
257                         return i >= 0 && ignorableFlags [i] == 7;
258                 }
259                 // Verifier:
260                 // for (int i = 0; i <= char.MaxValue; i++)
261                 //      if (Char.GetUnicodeCategory ((char) i)
262                 //              == UnicodeCategory.OtherNotAssigned 
263                 //              && ignorableFlags [i] != 7)
264                 //              Console.WriteLine ("{0:X04}", i);
265
266                 public static bool IsIgnorableSymbol (int cp)
267                 {
268                         int i = UUtil.Ignorable.ToIndex (cp);
269                         return i >= 0 && (ignorableFlags [i] & 0x2) != 0;
270                 }
271
272                 public static bool IsIgnorableNonSpacing (int cp)
273                 {
274                         int i = UUtil.Ignorable.ToIndex (cp);
275                         return i >= 0 && (ignorableFlags [i] & 0x4) != 0;
276                         // It could be implemented this way, but the above
277                         // is faster.
278 //                      return categories [UUtil.Category.ToIndex (cp)] == 1;
279                 }
280
281                 public static int ToKanaTypeInsensitive (int i)
282                 {
283                         // Note that IgnoreKanaType does not treat half-width
284                         // katakana as equivalent to full-width ones.
285
286                         // Thus, it is so simple ;-)
287                         return (0x3041 <= i && i <= 0x3094) ? i + 0x60 : i;
288                 }
289
290                 // Note that currently indexer optimizes this table a lot,
291                 // which might have resulted in bugs.
292                 public static int ToWidthCompat (int i)
293                 {
294                         if (i < 0x2190)
295                                 return i;
296                         if (i > 0xFF00) {
297                                 if (i <= 0xFF5E)
298                                         return i - 0xFF00 + 0x20;
299                                 switch (i) {
300                                 case 0xFFE0:
301                                         return 0xA2;
302                                 case 0xFFE1:
303                                         return 0xA3;
304                                 case 0xFFE2:
305                                         return 0xAC;
306                                 case 0xFFE3:
307                                         return 0xAF;
308                                 case 0xFFE4:
309                                         return 0xA6;
310                                 case 0xFFE5:
311                                         return 0xA5;
312                                 case 0xFFE6:
313                                         return 0x20A9;
314                                 }
315                         }
316                         if (i > 0x32FE)
317                                 return i;
318
319                         if (i <= 0x2193)
320                                 return 0xFFE9 - 0x2190 + i;
321                         if (i < 0x2502)
322                                 return i;
323                         if (i <= 0x25CB) {
324                                 switch (i) {
325                                 case 0x2502:
326                                         return 0xFFE8;
327                                 case 0x25A0:
328                                         return 0xFFED;
329                                 case 0x25CB:
330                                         return 0xFFEE;
331                                 default:
332                                         return i;
333                                 }
334                         }
335                         if (i < 0x3000)
336                                 return i;
337                         if (i < 0x3131) {
338                                 switch (i) {
339                                 case 0x3000:
340                                         return 0x20;
341                                 case 0x3001:
342                                         return 0xFF64;
343                                 case 0x3002:
344                                         return 0xFF61;
345                                 case 0x300C:
346                                         return 0xFF62;
347                                 case 0x300D:
348                                         return 0xFF63;
349                                 case 0x30FB:
350                                         return 0xFF65;
351                                 // Other Kana compat characters' width
352                                 // compatibility is considered in special weight.
353                                 default:
354                                         return i;
355                                 }
356                         }
357                         if (i < 0x3164) { // Hangul compat
358                                 return i - 0x3130 + 0xFFA0;
359                         }
360                         if (i == 0x3164)
361                                 return 0xFFA0;
362                         // 0x32D0-0x32FE are Kana compat characters, whose
363                         // width compatibility is considered in special weight.
364                         return i;
365                 }
366
367                 #region Level 4 properties (Kana)
368
369                 public static bool HasSpecialWeight (char c)
370                 {
371                         if (c < '\u3041')
372                                 return false;
373                         else if ('\uFF66' <= c && c < '\uFF9E')
374                                 return true;
375                         else if ('\u3300' <= c)
376                                 return false;
377                         else if (c < '\u309D')
378                                 return (c < '\u3099');
379                         else if (c < '\u3100')
380                                 return c != '\u30FB';
381                         else if (c < '\u32D0')
382                                 return false;
383                         else if (c < '\u32FF')
384                                 return true;
385                         return false;
386                 }
387
388                 // FIXME: it should be removed at some stage
389                 // (will become unused).
390                 public static byte GetJapaneseDashType (char c)
391                 {
392                         switch (c) {
393                         case '\u309D':
394                         case '\u309E':
395                         case '\u30FD':
396                         case '\u30FE':
397                         case '\uFF70':
398                                 return 4;
399                         case '\u30FC':
400                                 return 5;
401                         }
402                         return 3;
403                 }
404
405                 public static bool IsHalfWidthKana (char c)
406                 {
407                         return '\uFF66' <= c && c <= '\uFF9D';
408                 }
409
410                 public static bool IsHiragana (char c)
411                 {
412                         return '\u3041' <= c && c <= '\u3094';
413                 }
414
415                 public static bool IsJapaneseSmallLetter (char c)
416                 {
417                         if ('\uFF67' <= c && c <= '\uFF6F')
418                                 return true;
419                         if ('\u3040' < c && c < '\u30FA') {
420                                 switch (c) {
421                                 case '\u3041':
422                                 case '\u3043':
423                                 case '\u3045':
424                                 case '\u3047':
425                                 case '\u3049':
426                                 case '\u3063':
427                                 case '\u3083':
428                                 case '\u3085':
429                                 case '\u3087':
430                                 case '\u308E':
431                                 case '\u30A1':
432                                 case '\u30A3':
433                                 case '\u30A5':
434                                 case '\u30A7':
435                                 case '\u30A9':
436                                 case '\u30C3':
437                                 case '\u30E3':
438                                 case '\u30E5':
439                                 case '\u30E7':
440                                 case '\u30EE':
441                                 case '\u30F5':
442                                 case '\u30F6':
443                                         return true;
444                                 }
445                         }
446                         return false;
447                 }
448
449                 #endregion
450
451 #if GENERATE_TABLE
452
453                 public static readonly bool IsReady = true; // always
454
455                 static MSCompatUnicodeTable ()
456                 {
457                         fixed (byte* tmp = ignorableFlagsArr) {
458                                 ignorableFlags = tmp;
459                         }
460                         fixed (byte* tmp = categoriesArr) {
461                                 categories = tmp;
462                         }
463                         fixed (byte* tmp = level1Arr) {
464                                 level1 = tmp;
465                         }
466                         fixed (byte* tmp = level2Arr) {
467                                 level2 = tmp;
468                         }
469                         fixed (byte* tmp = level3Arr) {
470                                 level3 = tmp;
471                         }
472 //                      fixed (ushort* tmp = widthCompatArr) {
473 //                              widthCompat = tmp;
474 //                      }
475                         fixed (byte* tmp = cjkCHSArr) {
476                                 cjkCHScategory = tmp;
477                                 cjkCHSlv1 = tmp + cjkCHSArrLength;
478                         }
479                         fixed (byte* tmp = cjkCHTArr) {
480                                 cjkCHTcategory = tmp;
481                                 cjkCHTlv1 = tmp + cjkCHTArrLength;
482                         }
483                         fixed (byte* tmp = cjkJAArr) {
484                                 cjkJAcategory = tmp;
485                                 cjkJAlv1 = tmp + cjkJAArrLength;
486                         }
487                         fixed (byte* tmp = cjkKOArr) {
488                                 cjkKOcategory = tmp;
489                                 cjkKOlv1 = tmp + cjkKOArrLength;
490                         }
491                         fixed (byte* tmp = cjkKOlv2Arr) {
492                                 cjkKOlv2 = tmp;
493                         }
494                 }
495
496                 public static void FillCJK (string name,
497                         ref CodePointIndexer cjkIndexer,
498                         ref byte* catTable, ref byte* lv1Table,
499                         ref CodePointIndexer cjkLv2Indexer,
500                         ref byte* lv2Table)
501                 {
502                         SetCJKReferences (name, ref cjkIndexer,
503                                 ref catTable, ref lv1Table,
504                                 ref cjkLv2Indexer, ref lv2Table);
505                 }
506 #else
507
508                 static readonly char [] tailorings;
509                 static readonly TailoringInfo [] tailoringInfos;
510                 static object forLock = new object ();
511                 public static readonly bool isReady;
512
513                 public static bool IsReady {
514                         get { return isReady; }
515                 }
516
517 #if USE_MANAGED_RESOURCE
518                 static IntPtr GetResource (string name)
519                 {
520                         int size;
521                         Module module;
522                         return Assembly.GetExecutingAssembly ().GetManifestResourceInternal (name, out size, out module);
523                 }
524 #else
525                 static readonly string corlibPath = Assembly.GetExecutingAssembly ().Location;
526
527                 const int CollationResourceCore = 0;
528                 const int CollationResourceCJKCHS = 1;
529                 const int CollationResourceCJKCHT = 2;
530                 const int CollationResourceCJKJA = 3;
531                 const int CollationResourceCJKKO = 4;
532                 const int CollationResourceCJKKOlv2 = 5;
533                 const int CollationResourceTailoring = 6;
534
535                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
536                 static extern void load_collation_resource (string path, int resource_index, byte** data, int* size);
537 #endif
538
539                 static uint UInt32FromBytePtr (byte* raw, uint idx)
540                 {
541                         return (uint) (raw [idx] + (raw [idx + 1] << 8)
542                                 + (raw [idx + 2] << 16) + (raw [idx + 3] << 24));
543                 }
544
545                 static MSCompatUnicodeTable ()
546                 {
547                         byte* raw;
548                         byte* tailor;
549                         uint size;
550                         uint idx = 0;
551
552 #if USE_MANAGED_RESOURCE
553                         IntPtr ptr = GetResource ("collation.core.bin");
554                         if (ptr == IntPtr.Zero)
555                                 return;
556                         raw = (byte*) ((void*) ptr);
557                         ptr = GetResource ("collation.tailoring.bin");
558                         if (ptr == IntPtr.Zero)
559                                 return;
560                         tailor = (byte*) ((void*) ptr);
561 #else
562                         int rawsize;
563                         int trawsize;
564
565                         lock (forLock) {
566                                 load_collation_resource (corlibPath, CollationResourceCore, &raw, &rawsize);
567                                 load_collation_resource (corlibPath, CollationResourceTailoring, &tailor, &trawsize);
568                         }
569 #endif
570
571                         if (raw == null || tailor == null)
572                                 return;
573                         // check resource version
574                         if (raw [0] != UUtil.ResourceVersion ||
575                                 tailor [0] != UUtil.ResourceVersion)
576                                 return;
577
578                         idx = 1;
579                         size = UInt32FromBytePtr (raw, idx);
580                         idx += 4;
581                         ignorableFlags = raw + idx;
582                         idx += size;
583
584                         size = UInt32FromBytePtr (raw, idx);
585                         idx += 4;
586                         categories = raw + idx;
587                         idx += size;
588
589                         size = UInt32FromBytePtr (raw, idx);
590                         idx += 4;
591                         level1 = raw + idx;
592                         idx += size;
593
594                         size = UInt32FromBytePtr (raw, idx);
595                         idx += 4;
596                         level2 = raw + idx;
597                         idx += size;
598
599                         size = UInt32FromBytePtr (raw, idx);
600                         idx += 4;
601                         level3 = raw + idx;
602                         idx += size;
603
604 //                      size = UInt32FromBytePtr (raw, idx);
605 //                      idx += 4;
606 //                      widthCompat = (ushort*) (raw + idx);
607 //                      idx += size * 2;
608
609                         idx = 1;
610                         uint count = UInt32FromBytePtr (tailor, idx);
611                         idx += 4;
612                         tailoringInfos = new TailoringInfo [count];
613                         for (int i = 0; i < count; i++) {
614                                 int i1 = (int) UInt32FromBytePtr (tailor, idx);
615                                 idx += 4;
616                                 int i2 = (int) UInt32FromBytePtr (tailor, idx);
617                                 idx += 4;
618                                 int i3 = (int) UInt32FromBytePtr (tailor, idx);
619                                 idx += 4;
620                                 TailoringInfo ti = new TailoringInfo (
621                                         i1, i2, i3, tailor [idx++] != 0);
622                                 tailoringInfos [i] = ti;
623                         }
624                         idx += 2; // dummy
625                         // tailorings
626                         count = UInt32FromBytePtr (tailor, idx);
627                         idx += 4;
628                         tailorings = new char [count];
629                         for (int i = 0; i < count; i++, idx += 2)
630                                 tailorings [i] = (char) (tailor [idx] + (tailor [idx + 1] << 8));
631                         isReady = true;
632                 }
633
634                 public static void FillCJK (string culture,
635                         ref CodePointIndexer cjkIndexer,
636                         ref byte* catTable,
637                         ref byte* lv1Table,
638                         ref CodePointIndexer lv2Indexer,
639                         ref byte* lv2Table)
640                 {
641                         lock (forLock) {
642                                 FillCJKCore (culture, ref cjkIndexer,
643                                         ref catTable, ref lv1Table,
644                                         ref lv2Indexer, ref lv2Table);
645                                 SetCJKReferences (culture, ref cjkIndexer,
646                                         ref catTable, ref lv1Table,
647                                         ref lv2Indexer, ref lv2Table);
648                         }
649                 }
650
651                 static void FillCJKCore (string culture,
652                         ref CodePointIndexer cjkIndexer,
653                         ref byte* catTable, ref byte* lv1Table,
654                         ref CodePointIndexer cjkLv2Indexer, ref byte* lv2Table)
655                 {
656                         if (!IsReady)
657                                 return;
658
659                         string name = null;
660                         switch (culture) {
661                         case "zh-CHS":
662                                 name = "cjkCHS";
663                                 catTable = cjkCHScategory;
664                                 lv1Table = cjkCHSlv1;
665                                 break;
666                         case "zh-CHT":
667                                 name = "cjkCHT";
668                                 catTable = cjkCHTcategory;
669                                 lv1Table = cjkCHTlv1;
670                                 break;
671                         case "ja":
672                                 name = "cjkJA";
673                                 catTable = cjkJAcategory;
674                                 lv1Table = cjkJAlv1;
675                                 break;
676                         case "ko":
677                                 name = "cjkKO";
678                                 catTable = cjkKOcategory;
679                                 lv1Table = cjkKOlv1;
680                                 break;
681                         }
682
683                         if (name == null || lv1Table != null)
684                                 return;
685
686                         byte* raw;
687 #if USE_MANAGED_RESOURCE
688                         string filename =
689                                 String.Format ("collation.{0}.bin", name);
690                         IntPtr ptr = GetResource (filename);
691                         if (ptr == IntPtr.Zero)
692                                 return;
693                         raw = (byte*) ((void*) ptr);
694 #else
695                         int size;
696                         int residx = -1;
697                         switch (culture) {
698                         case "zh-CHS": residx = CollationResourceCJKCHS; break;
699                         case "zh-CHT": residx = CollationResourceCJKCHT; break;
700                         case "ja": residx = CollationResourceCJKJA; break;
701                         case "ko": residx = CollationResourceCJKKO; break;
702                         }
703                         if (residx < 0)
704                                 return;
705                         load_collation_resource (corlibPath, residx, &raw, &size);
706 #endif
707                         uint count = UInt32FromBytePtr (raw, ResourceVersionSize);
708                         catTable = (byte*) raw + ResourceVersionSize + 4;
709                         lv1Table = (byte*) raw + ResourceVersionSize + 4 + count;
710
711                         switch (culture) {
712                         case "zh-CHS":
713                                 cjkCHScategory = catTable;
714                                 cjkCHSlv1 = lv1Table;
715                                 break;
716                         case "zh-CHT":
717                                 cjkCHTcategory = catTable;
718                                 cjkCHTlv1 = lv1Table;
719                                 break;
720                         case "ja":
721                                 cjkJAcategory = catTable;
722                                 cjkJAlv1 = lv1Table;
723                                 break;
724                         case "ko":
725                                 cjkKOcategory = catTable;
726                                 cjkKOlv1 = lv1Table;
727                                 break;
728                         }
729
730                         if (name != "cjkKO")
731                                 return;
732 #if USE_MANAGED_RESOURCE
733                         ptr = GetResource ("collation.cjkKOlv2.bin");
734                         if (ptr == IntPtr.Zero)
735                                 return;
736                         raw = (byte*) ((void*) ptr);
737 #else
738                         load_collation_resource (corlibPath, CollationResourceCJKKOlv2, &raw, &size);
739 #endif
740                         cjkKOlv2 = raw + ResourceVersionSize + 4;
741                         lv2Table = cjkKOlv2;
742                 }
743         }
744 }
745 #endif
746
747
748                 // For "categories", 0 means no primary weight. 6 means 
749                 // variable weight
750                 // For expanded character the value is never filled (i.e. 0).
751                 // Those arrays will be split into blocks (<3400 and >F800)
752                 // level 4 is computed.
753
754                 // public static bool HasSpecialWeight (char c)
755                 // { return level1 [(int) c] == 6; }
756
757                 //
758                 // autogenerated code or icall to fill array runs here
759                 //
760