Jo Shields a575963da9 Imported Upstream version 3.6.0
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
2014-08-13 10:39:27 +01:00

915 lines
23 KiB
C#

#define USE_MANAGED_RESOURCE
//#define USE_C_HEADER
//
// MSCompatUnicodeTable.cs : Handles Windows-like sortket tables.
//
// Author:
// Atsushi Enomoto <atsushi@ximian.com>
//
// Copyright (C) 2005 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using UUtil = Mono.Globalization.Unicode.MSCompatUnicodeTableUtil;
namespace Mono.Globalization.Unicode
{
internal class TailoringInfo
{
public readonly int LCID;
public readonly int TailoringIndex;
public readonly int TailoringCount;
public readonly bool FrenchSort;
public TailoringInfo (int lcid, int tailoringIndex, int tailoringCount, bool frenchSort)
{
LCID = lcid;
TailoringIndex = tailoringIndex;
TailoringCount = tailoringCount;
FrenchSort = frenchSort;
}
}
#region Tailoring support classes
// Possible mapping types are:
//
// - string to string (ReplacementMap)
// - string to SortKey (SortKeyMap)
// - diacritical byte to byte (DiacriticalMap)
//
// There could be mapping from string to sortkeys, but
// for now there is none as such.
//
internal class Contraction
{
public int Index;
public readonly char [] Source;
// only either of them is used.
public readonly string Replacement;
public readonly byte [] SortKey;
public Contraction (int index, char [] source,
string replacement, byte [] sortkey)
{
Index = index;
Source = source;
Replacement = replacement;
SortKey = sortkey;
}
}
internal class ContractionComparer : IComparer<Contraction>
{
public static readonly ContractionComparer Instance =
new ContractionComparer ();
public int Compare (Contraction c1, Contraction c2)
{
char [] a1 = c1.Source;
char [] a2 = c2.Source;
int min = a1.Length > a2.Length ?
a2.Length : a1.Length;
for (int i = 0; i < min; i++)
if (a1 [i] != a2 [i])
return a1 [i] - a2 [i];
if (a1.Length != a2.Length)
return a1.Length - a2.Length;
// This makes the sorting stable, since we are using Array.Sort () which is
// not stable
return c1.Index - c2.Index;
}
}
internal class Level2Map
{
public byte Source;
public byte Replace;
public Level2Map (byte source, byte replace)
{
Source = source;
Replace = replace;
}
}
#endregion
unsafe internal class MSCompatUnicodeTable
{
public static int MaxExpansionLength = 3;
static readonly byte* ignorableFlags;
static readonly byte* categories;
static readonly byte* level1;
static readonly byte* level2;
static readonly byte* level3;
// static readonly ushort* widthCompat;
#if USE_C_HEADER
static readonly char* tailoring;
#endif
static byte* cjkCHScategory;
static byte* cjkCHTcategory;
static byte* cjkJAcategory;
static byte* cjkKOcategory;
static byte* cjkCHSlv1;
static byte* cjkCHTlv1;
static byte* cjkJAlv1;
static byte* cjkKOlv1;
static byte* cjkKOlv2;
const int ResourceVersionSize = 1;
public static TailoringInfo GetTailoringInfo (int lcid)
{
for (int i = 0; i < tailoringInfos.Length; i++)
if (tailoringInfos [i].LCID == lcid)
return tailoringInfos [i];
return null;
}
unsafe public static void BuildTailoringTables (CultureInfo culture,
TailoringInfo t,
ref Contraction [] contractions,
ref Level2Map [] diacriticals)
{
// collect tailoring entries.
var cmaps = new List<Contraction> ();
var dmaps = new List<Level2Map> ();
int iindex = 0;
fixed (char* tarr = tailoringArr){
int idx = t.TailoringIndex;
int end = idx + t.TailoringCount;
while (idx < end) {
int ss = idx + 1;
char [] src = null;
switch (tarr [idx]) {
case '\x1': // SortKeyMap
idx++;
while (tarr [ss] != 0)
ss++;
src = new char [ss - idx];
// Array.Copy (tarr, idx, src, 0, ss - idx);
Marshal.Copy ((IntPtr) (tarr + idx), src, 0, ss - idx);
byte [] sortkey = new byte [4];
for (int i = 0; i < 4; i++)
sortkey [i] = (byte) tarr [ss + 1 + i];
cmaps.Add (new Contraction (iindex,
src, null, sortkey));
// it ends with 0
idx = ss + 6;
iindex ++;
break;
case '\x2': // DiacriticalMap
dmaps.Add (new Level2Map (
(byte) tarr [idx + 1],
(byte) tarr [idx + 2]));
idx += 3;
break;
case '\x3': // ReplacementMap
idx++;
while (tarr [ss] != 0)
ss++;
src = new char [ss - idx];
// Array.Copy (tarr, idx, src, 0, ss - idx);
Marshal.Copy ((IntPtr) (tarr + idx), src, 0, ss - idx);
ss++;
int l = ss;
while (tarr [l] != 0)
l++;
string r = new string (tarr, ss, l - ss);
cmaps.Add (new Contraction (iindex,
src, r, null));
idx = l + 1;
iindex ++;
break;
default:
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));
}
}
}
cmaps.Sort (ContractionComparer.Instance);
dmaps.Sort ((a, b) => a.Source - b.Source);
contractions = cmaps.ToArray ();
diacriticals = dmaps.ToArray ();
}
static void SetCJKReferences (string name,
ref CodePointIndexer cjkIndexer,
ref byte* catTable, ref byte* lv1Table,
ref CodePointIndexer lv2Indexer, ref byte* lv2Table)
{
// as a part of mscorlib.dll, this invocation is
// somewhat extraneous (pointers were already assigned).
switch (name) {
case "zh-CHS":
catTable = cjkCHScategory;
lv1Table = cjkCHSlv1;
cjkIndexer = UUtil.CjkCHS;
break;
case "zh-CHT":
catTable = cjkCHTcategory;
lv1Table = cjkCHTlv1;
cjkIndexer = UUtil.Cjk;
break;
case "ja":
catTable = cjkJAcategory;
lv1Table = cjkJAlv1;
cjkIndexer = UUtil.Cjk;
break;
case "ko":
catTable = cjkKOcategory;
lv1Table = cjkKOlv1;
lv2Table = cjkKOlv2;
cjkIndexer = UUtil.Cjk;
lv2Indexer = UUtil.Cjk;
break;
}
}
public static byte Category (int cp)
{
return categories [UUtil.Category.ToIndex (cp)];
}
public static byte Level1 (int cp)
{
return level1 [UUtil.Level1.ToIndex (cp)];
}
public static byte Level2 (int cp)
{
return level2 [UUtil.Level2.ToIndex (cp)];
}
public static byte Level3 (int cp)
{
return level3 [UUtil.Level3.ToIndex (cp)];
}
public static bool IsSortable (string s)
{
foreach (char c in s)
if (!IsSortable (c))
return false;
return true;
}
public static bool IsSortable (int cp)
{
// LAMESPEC: they should strictly match with
// IsIgnorable() result, but sometimes it does not.
if (!IsIgnorable (cp))
return true;
switch (cp) {
case 0:
case 0x0640:
case 0xFEFF:
return true;
}
return 0x180B <= cp && cp <= 0x180E ||
0x200C <= cp && cp <= 0x200F ||
0x202A <= cp && cp <= 0x202E ||
0x206A <= cp && cp <= 0x206F ||
0x200C <= cp && cp <= 0x200F ||
0xFFF9 <= cp && cp <= 0xFFFD;
}
public static bool IsIgnorable (int cp)
{
return IsIgnorable (cp, 1);
}
public static bool IsIgnorable (int cp, byte flag)
{
if (cp == 0)
return true;
if ((flag & 1) != 0) {
UnicodeCategory uc = Char.GetUnicodeCategory ((char) cp);
// This check eliminates some extraneous code areas
if (uc == UnicodeCategory.OtherNotAssigned)
return true;
// Some characters in Surrogate area are ignored.
if (0xD880 <= cp && cp < 0xDB80)
return true;
}
int i = UUtil.Ignorable.ToIndex (cp);
return i >= 0 && (ignorableFlags [i] & flag) != 0;
}
// Verifier:
// for (int i = 0; i <= char.MaxValue; i++)
// if (Char.GetUnicodeCategory ((char) i)
// == UnicodeCategory.OtherNotAssigned
// && ignorableFlags [i] != 7)
// Console.WriteLine ("{0:X04}", i);
public static bool IsIgnorableSymbol (int cp)
{
return IsIgnorable (cp, 2);
// int i = UUtil.Ignorable.ToIndex (cp);
// return i >= 0 && (ignorableFlags [i] & 0x2) != 0;
}
public static bool IsIgnorableNonSpacing (int cp)
{
return IsIgnorable (cp, 4);
// int i = UUtil.Ignorable.ToIndex (cp);
// return i >= 0 && (ignorableFlags [i] & 0x4) != 0;
// It could be implemented this way, but the above
// is faster.
// return categories [UUtil.Category.ToIndex (cp)] == 1;
}
public static int ToKanaTypeInsensitive (int i)
{
// Note that IgnoreKanaType does not treat half-width
// katakana as equivalent to full-width ones.
// Thus, it is so simple ;-)
return (0x3041 <= i && i <= 0x3094) ? i + 0x60 : i;
}
// Note that currently indexer optimizes this table a lot,
// which might have resulted in bugs.
public static int ToWidthCompat (int i)
{
if (i < 0x2190)
return i;
if (i > 0xFF00) {
if (i <= 0xFF5E)
return i - 0xFF00 + 0x20;
switch (i) {
case 0xFFE0:
return 0xA2;
case 0xFFE1:
return 0xA3;
case 0xFFE2:
return 0xAC;
case 0xFFE3:
return 0xAF;
case 0xFFE4:
return 0xA6;
case 0xFFE5:
return 0xA5;
case 0xFFE6:
return 0x20A9;
}
}
if (i > 0x32FE)
return i;
if (i <= 0x2193)
return 0xFFE9 - 0x2190 + i;
if (i < 0x2502)
return i;
if (i <= 0x25CB) {
switch (i) {
case 0x2502:
return 0xFFE8;
case 0x25A0:
return 0xFFED;
case 0x25CB:
return 0xFFEE;
default:
return i;
}
}
if (i < 0x3000)
return i;
if (i < 0x3131) {
switch (i) {
case 0x3000:
return 0x20;
case 0x3001:
return 0xFF64;
case 0x3002:
return 0xFF61;
case 0x300C:
return 0xFF62;
case 0x300D:
return 0xFF63;
case 0x30FB:
return 0xFF65;
// Other Kana compat characters' width
// compatibility is considered in special weight.
default:
return i;
}
}
if (i < 0x3164) { // Hangul compat
return i - 0x3130 + 0xFFA0;
}
if (i == 0x3164)
return 0xFFA0;
// 0x32D0-0x32FE are Kana compat characters, whose
// width compatibility is considered in special weight.
return i;
}
#region Level 4 properties (Kana)
public static bool HasSpecialWeight (char c)
{
if (c < '\u3041')
return false;
else if ('\uFF66' <= c && c < '\uFF9E')
return true;
else if ('\u3300' <= c)
return false;
else if (c < '\u309D')
return (c < '\u3099');
else if (c < '\u3100')
return c != '\u30FB';
else if (c < '\u32D0')
return false;
else if (c < '\u32FF')
return true;
return false;
}
// FIXME: it should be removed at some stage
// (will become unused).
public static byte GetJapaneseDashType (char c)
{
switch (c) {
case '\u309D':
case '\u309E':
case '\u30FD':
case '\u30FE':
case '\uFF70':
return 4;
case '\u30FC':
return 5;
}
return 3;
}
public static bool IsHalfWidthKana (char c)
{
return '\uFF66' <= c && c <= '\uFF9D';
}
public static bool IsHiragana (char c)
{
return '\u3041' <= c && c <= '\u3094';
}
public static bool IsJapaneseSmallLetter (char c)
{
if ('\uFF67' <= c && c <= '\uFF6F')
return true;
if ('\u3040' < c && c < '\u30FA') {
switch (c) {
case '\u3041':
case '\u3043':
case '\u3045':
case '\u3047':
case '\u3049':
case '\u3063':
case '\u3083':
case '\u3085':
case '\u3087':
case '\u308E':
case '\u30A1':
case '\u30A3':
case '\u30A5':
case '\u30A7':
case '\u30A9':
case '\u30C3':
case '\u30E3':
case '\u30E5':
case '\u30E7':
case '\u30EE':
case '\u30F5':
case '\u30F6':
return true;
}
}
return false;
}
#endregion
#if GENERATE_TABLE
public static readonly bool IsReady = true; // always
static MSCompatUnicodeTable ()
{
throw new Exception ("This code should not be used");
fixed (byte* tmp = ignorableFlagsArr) {
ignorableFlags = tmp;
}
fixed (byte* tmp = categoriesArr) {
categories = tmp;
}
fixed (byte* tmp = level1Arr) {
level1 = tmp;
}
fixed (byte* tmp = level2Arr) {
level2 = tmp;
}
fixed (byte* tmp = level3Arr) {
level3 = tmp;
}
// fixed (ushort* tmp = widthCompatArr) {
// widthCompat = tmp;
// }
fixed (char* tmp = tailoringArr) {
tailoring = tmp;
}
fixed (byte* tmp = cjkCHSArr) {
cjkCHScategory = tmp;
cjkCHSlv1 = tmp + cjkCHSArrLength;
}
fixed (byte* tmp = cjkCHTArr) {
cjkCHTcategory = tmp;
cjkCHTlv1 = tmp + cjkCHTArrLength;
}
fixed (byte* tmp = cjkJAArr) {
cjkJAcategory = tmp;
cjkJAlv1 = tmp + cjkJAArrLength;
}
fixed (byte* tmp = cjkKOArr) {
cjkKOcategory = tmp;
cjkKOlv1 = tmp + cjkKOArrLength;
}
fixed (byte* tmp = cjkKOlv2Arr) {
cjkKOlv2 = tmp;
}
}
public static void FillCJK (string name,
ref CodePointIndexer cjkIndexer,
ref byte* catTable, ref byte* lv1Table,
ref CodePointIndexer cjkLv2Indexer,
ref byte* lv2Table)
{
SetCJKReferences (name, ref cjkIndexer,
ref catTable, ref lv1Table,
ref cjkLv2Indexer, ref lv2Table);
}
#else
#if !USE_C_HEADER
static readonly char [] tailoringArr;
#endif
static readonly TailoringInfo [] tailoringInfos;
static object forLock = new object ();
public static readonly bool isReady;
public static bool IsReady {
get { return isReady; }
}
#if USE_MANAGED_RESOURCE
static IntPtr GetResource (string name)
{
int size;
Module module;
return Assembly.GetExecutingAssembly ().GetManifestResourceInternal (name, out size, out module);
}
#elif USE_C_HEADER
const int CollationTableIdxIgnorables = 0;
const int CollationTableIdxCategory = 1;
const int CollationTableIdxLevel1 = 2;
const int CollationTableIdxLevel2 = 3;
const int CollationTableIdxLevel3 = 4;
const int CollationTableIdxTailoringInfos = 5;
const int CollationTableIdxTailoringChars = 6;
const int CollationTableIdxCjkCHS = 7;
const int CollationTableIdxCjkCHT = 8;
const int CollationTableIdxCjkJA = 9;
const int CollationTableIdxCjkKO = 10;
const int CollationTableIdxCjkKOLv2 = 11;
[MethodImplAttribute (MethodImplOptions.InternalCall)]
static extern void load_collation_resource (int resource_index, byte** data);
#else
static readonly string corlibPath = Assembly.GetExecutingAssembly ().Location;
const int CollationResourceCore = 0;
const int CollationResourceCJKCHS = 1;
const int CollationResourceCJKCHT = 2;
const int CollationResourceCJKJA = 3;
const int CollationResourceCJKKO = 4;
const int CollationResourceCJKKOlv2 = 5;
const int CollationResourceTailoring = 6;
[MethodImplAttribute (MethodImplOptions.InternalCall)]
static extern void load_collation_resource (string path, int resource_index, byte** data, int* size);
#endif
static uint UInt32FromBytePtr (byte* raw, uint idx)
{
return (uint) (raw [idx] + (raw [idx + 1] << 8)
+ (raw [idx + 2] << 16) + (raw [idx + 3] << 24));
}
static MSCompatUnicodeTable ()
{
#if USE_C_HEADER
byte* raw;
uint* tailor;
uint size;
uint idx = 0;
lock (forLock) {
load_collation_resource (CollationTableIdxIgnorables, &raw);
ignorableFlags = raw;
load_collation_resource (CollationTableIdxCategory, &raw);
categories = raw;
load_collation_resource (CollationTableIdxLevel1, &raw);
level1 = raw;
load_collation_resource (CollationTableIdxLevel2, &raw);
level2 = raw;
load_collation_resource (CollationTableIdxLevel3, &raw);
level3 = raw;
load_collation_resource (CollationTableIdxTailoringInfos, &raw);
tailor = (uint*) raw;
load_collation_resource (CollationTableIdxTailoringChars, &raw);
tailoring = (char*) raw;
}
idx = 0;
uint count = tailor [idx++];
tailoringInfos = new TailoringInfo [count];
for (int i = 0; i < count; i++) {
int i1 = (int) tailor [idx++];
int i2 = (int) tailor [idx++];
int i3 = (int) tailor [idx++];
TailoringInfo ti = new TailoringInfo (
i1, i2, i3, tailor [idx++] != 0);
tailoringInfos [i] = ti;
}
isReady = true;
#else
byte* raw;
byte* tailor;
uint size;
uint idx = 0;
#if USE_MANAGED_RESOURCE
IntPtr ptr = GetResource ("collation.core.bin");
if (ptr == IntPtr.Zero)
return;
raw = (byte*) ((void*) ptr);
ptr = GetResource ("collation.tailoring.bin");
if (ptr == IntPtr.Zero)
return;
tailor = (byte*) ((void*) ptr);
#else
int rawsize;
int trawsize;
lock (forLock) {
load_collation_resource (corlibPath, CollationResourceCore, &raw, &rawsize);
load_collation_resource (corlibPath, CollationResourceTailoring, &tailor, &trawsize);
load_collation_resource (corlibPath, CollationResourceTailoringChars, &tailorChars, &trawsize);
}
#endif
if (raw == null || tailor == null)
return;
// check resource version
if (raw [0] != UUtil.ResourceVersion ||
tailor [0] != UUtil.ResourceVersion)
return;
idx = 1;
size = UInt32FromBytePtr (raw, idx);
idx += 4;
ignorableFlags = raw + idx;
idx += size;
size = UInt32FromBytePtr (raw, idx);
idx += 4;
categories = raw + idx;
idx += size;
size = UInt32FromBytePtr (raw, idx);
idx += 4;
level1 = raw + idx;
idx += size;
size = UInt32FromBytePtr (raw, idx);
idx += 4;
level2 = raw + idx;
idx += size;
size = UInt32FromBytePtr (raw, idx);
idx += 4;
level3 = raw + idx;
idx += size;
// size = UInt32FromBytePtr (raw, idx);
// idx += 4;
// widthCompat = (ushort*) (raw + idx);
// idx += size * 2;
// tailoring
idx = 1;
uint count = UInt32FromBytePtr (tailor, idx);
idx += 4;
tailoringInfos = new TailoringInfo [count];
for (int i = 0; i < count; i++) {
int i1 = (int) UInt32FromBytePtr (tailor, idx);
idx += 4;
int i2 = (int) UInt32FromBytePtr (tailor, idx);
idx += 4;
int i3 = (int) UInt32FromBytePtr (tailor, idx);
idx += 4;
TailoringInfo ti = new TailoringInfo (
i1, i2, i3, tailor [idx++] != 0);
tailoringInfos [i] = ti;
}
idx += 2; // dummy
// tailorings
count = UInt32FromBytePtr (tailor, idx);
idx += 4;
tailoringArr = new char [count];
for (int i = 0; i < count; i++, idx += 2)
tailoringArr [i] = (char) (tailor [idx] + (tailor [idx + 1] << 8));
isReady = true;
#endif
}
public static void FillCJK (string culture,
ref CodePointIndexer cjkIndexer,
ref byte* catTable,
ref byte* lv1Table,
ref CodePointIndexer lv2Indexer,
ref byte* lv2Table)
{
lock (forLock) {
FillCJKCore (culture, ref cjkIndexer,
ref catTable, ref lv1Table,
ref lv2Indexer, ref lv2Table);
SetCJKReferences (culture, ref cjkIndexer,
ref catTable, ref lv1Table,
ref lv2Indexer, ref lv2Table);
}
}
static void FillCJKCore (string culture,
ref CodePointIndexer cjkIndexer,
ref byte* catTable, ref byte* lv1Table,
ref CodePointIndexer cjkLv2Indexer, ref byte* lv2Table)
{
if (!IsReady)
return;
string name = null;
switch (culture) {
case "zh-CHS":
name = "cjkCHS";
catTable = cjkCHScategory;
lv1Table = cjkCHSlv1;
break;
case "zh-CHT":
name = "cjkCHT";
catTable = cjkCHTcategory;
lv1Table = cjkCHTlv1;
break;
case "ja":
name = "cjkJA";
catTable = cjkJAcategory;
lv1Table = cjkJAlv1;
break;
case "ko":
name = "cjkKO";
catTable = cjkKOcategory;
lv1Table = cjkKOlv1;
break;
}
if (name == null || lv1Table != null)
return;
byte* raw;
uint idx = 0;
#if USE_MANAGED_RESOURCE
string filename =
String.Format ("collation.{0}.bin", name);
IntPtr ptr = GetResource (filename);
if (ptr == IntPtr.Zero)
return;
raw = (byte*) ((void*) ptr);
idx += ResourceVersionSize;
#elif USE_C_HEADER
int residx = -1;
switch (culture) {
case "zh-CHS": residx = CollationTableIdxCjkCHS; break;
case "zh-CHT": residx = CollationTableIdxCjkCHT; break;
case "ja": residx = CollationTableIdxCjkJA; break;
case "ko": residx = CollationTableIdxCjkKO; break;
}
if (residx < 0)
return;
load_collation_resource (residx, &raw);
#else
int size;
int residx = -1;
switch (culture) {
case "zh-CHS": residx = CollationResourceCJKCHS; break;
case "zh-CHT": residx = CollationResourceCJKCHT; break;
case "ja": residx = CollationResourceCJKJA; break;
case "ko": residx = CollationResourceCJKKO; break;
}
if (residx < 0)
return;
load_collation_resource (corlibPath, residx, &raw, &size);
idx += ResourceVersionSize;
#endif
uint count = UInt32FromBytePtr (raw, idx);
idx += 4;
catTable = (byte*) raw + idx;
lv1Table = (byte*) raw + idx + count;
switch (culture) {
case "zh-CHS":
cjkCHScategory = catTable;
cjkCHSlv1 = lv1Table;
break;
case "zh-CHT":
cjkCHTcategory = catTable;
cjkCHTlv1 = lv1Table;
break;
case "ja":
cjkJAcategory = catTable;
cjkJAlv1 = lv1Table;
break;
case "ko":
cjkKOcategory = catTable;
cjkKOlv1 = lv1Table;
break;
}
if (name != "cjkKO")
return;
#if USE_MANAGED_RESOURCE
ptr = GetResource ("collation.cjkKOlv2.bin");
if (ptr == IntPtr.Zero)
return;
raw = (byte*) ((void*) ptr);
idx = ResourceVersionSize + 4;
#elif USE_C_HEADER
load_collation_resource (CollationTableIdxCjkKOLv2, &raw);
#else
load_collation_resource (corlibPath, CollationResourceCJKKOlv2, &raw, &size);
idx = ResourceVersionSize + 4;
#endif
cjkKOlv2 = raw + idx;
lv2Table = cjkKOlv2;
}
}
}
#endif
// For "categories", 0 means no primary weight. 6 means
// variable weight
// For expanded character the value is never filled (i.e. 0).
// Those arrays will be split into blocks (<3400 and >F800)
// level 4 is computed.
// public static bool HasSpecialWeight (char c)
// { return level1 [(int) c] == 6; }
//
// autogenerated code or icall to fill array runs here
//