2 // create-char-mapping-source.cs - creates canonical/compatibility mappings.
6 using System.Collections;
7 using System.Globalization;
10 namespace Mono.Globalization.Unicode
12 internal class CharMappingGenerator
16 public CharMapping (int cp, int mapIndex, bool isCanonical)
20 IsCanonical = isCanonical;
24 public readonly int CodePoint;
25 public readonly bool IsCanonical;
28 class CharMappingComparer : IComparer
30 CharMappingGenerator parent;
32 public CharMappingComparer (CharMappingGenerator g)
37 // Note that this never considers IsCanonical
38 public int Compare (object o1, object o2)
40 CharMapping c1 = (CharMapping) o1;
41 CharMapping c2 = (CharMapping) o2;
42 return CompareArray (c1.MapIndex, c2.MapIndex);
45 // Note that this never considers IsCanonical
46 public int CompareArray (int idx1, int idx2)
48 for (int i = 0; parent.mappedChars [idx2 + i] != 0; i++) {
49 int l = parent.mappedChars [idx1 + i];
50 int r = parent.mappedChars [idx2 + i];
58 CharMappingComparer comparer;
60 private int lineCount = 0;
61 int mappedCharCount = 1;
62 int [] mappedChars = new int [100];
63 int [] mapIndex = new int [0x5000];
65 ArrayList mappings = new ArrayList ();
67 public CharMappingGenerator ()
69 comparer = new CharMappingComparer (this);
72 public static void Main ()
74 new CharMappingGenerator ().Run ();
83 } catch (Exception ex) {
84 throw new InvalidOperationException ("Internal error at line " + lineCount + " : " + ex);
88 private void Compress ()
90 mappings.Sort (comparer);
92 // mappedChars[0] = 0. This assures that value 0 of
93 // mapIndex means there is no mapping.
95 int [] compressedMapping = new int [mappedCharCount];
97 int [] newMapIndex = new int [mappings.Count];
98 for (int mi = 0; mi < mappings.Count; mi++) {
99 CharMapping m = (CharMapping) mappings [mi];
100 if (mi > 0 && 0 == comparer.Compare (
101 mappings [mi - 1], mappings [mi])) {
102 newMapIndex [mi] = newMapIndex [mi - 1];
105 newMapIndex [mi] = count;
106 for (int i = m.MapIndex; mappedChars [i] != 0; i++)
107 compressedMapping [count++] = mappedChars [i];
108 compressedMapping [count++] = 0;
110 for (int mi = 0; mi < mappings.Count; mi++)
111 ((CharMapping) mappings [mi]).MapIndex = newMapIndex [mi];
113 int [] compressedMapIndex = new int [mapIndex.Length];
114 foreach (CharMapping m in mappings)
115 if (m.CodePoint <= char.MaxValue)
116 compressedMapIndex [MapIdx (m.CodePoint)] = m.MapIndex;
118 mappedChars = compressedMapping;
119 mapIndex = compressedMapIndex;
120 mappedCharCount = count;
123 private void Serialize ()
126 Console.WriteLine ("static readonly int [] mappedChars = new int [] {");
127 DumpArray (mappedChars, mappedCharCount, false);
128 Console.WriteLine ("};");
131 Console.WriteLine ("static readonly short [] mapIndex= new short [] {");
132 DumpArray (mapIndex, NormalizationTableUtil.MapCount, true);
133 Console.WriteLine ("};");
135 // GetPrimaryCompositeHelperIndex ()
136 Console.WriteLine ("static short GetPrimaryCompositeHelperIndex (int head)");
137 Console.WriteLine ("{");
139 Console.WriteLine (" switch (head) {");
140 foreach (CharMapping m in mappings) {
141 if (mappedChars [m.MapIndex] == currentHead)
142 continue; // has the same head
143 // FIXME: should be applied
144 // if (!m.IsCanonical)
146 currentHead = mappedChars [m.MapIndex];
147 Console.WriteLine (" case 0x{0:X}: return 0x{1:X};", currentHead, m.MapIndex);
149 Console.WriteLine (" }");
150 Console.WriteLine (" return 0;");
151 Console.WriteLine ("}");
153 // GetPrimaryCompositeFromMapIndex ()
154 Console.WriteLine ("static int GetPrimaryCompositeFromMapIndex (int idx)");
155 Console.WriteLine ("{");
156 Console.WriteLine (" switch (idx) {");
157 int currentIndex = -1;
158 foreach (CharMapping m in mappings) {
159 if (m.MapIndex == currentIndex)
163 Console.WriteLine (" case 0x{0:X}: return 0x{1:X};", m.MapIndex, m.CodePoint);
164 currentIndex = m.MapIndex;
166 Console.WriteLine (" }");
167 Console.WriteLine (" return 0;");
168 Console.WriteLine ("}");
171 private void DumpArray (int [] array, int count, bool getCP)
173 if (array.Length < count)
174 throw new ArgumentOutOfRangeException ("count");
175 for (int i = 0; i < count; i++) {
177 Console.Write ("0, ");
179 Console.Write ("0x{0:X}, ", array [i]);
181 int l = getCP ? NormalizationTableUtil.MapCP (i) : i;
182 Console.WriteLine ("// {0:X04}-{1:X04}", l - 15, l);
187 private void Parse ()
189 TextReader reader = Console.In;
190 while (reader.Peek () != -1) {
191 string line = reader.ReadLine ();
193 int idx = line.IndexOf ('#');
195 line = line.Substring (0, idx);
196 if (line.Length == 0)
199 while (Char.IsDigit (line [n]) || Char.IsLetter (line [n]))
201 int cp = int.Parse (line.Substring (0, n), NumberStyles.HexNumber);
203 string [] values = line.Substring (n + 1).Split (';');
204 string canon = values [4];
205 //if (values [2] != "0") Console.Error.WriteLine ("----- {0:X03} : {1:x}", int.Parse (values [2]), cp);
206 string combiningCategory = canon.IndexOf ('>') < 0 ? "" : canon.Substring (1, canon.IndexOf ('>') - 1);
207 string mappedCharsValue = canon;
208 if (combiningCategory.Length > 0)
209 mappedCharsValue = canon.Substring (combiningCategory.Length + 2).Trim ();
210 if (mappedCharsValue.Length > 0) {
211 mappings.Add (new CharMapping (cp,
213 combiningCategory.Length == 0));
214 SetCanonProp (cp, -1, mappedCharCount);
215 foreach (string v in mappedCharsValue.Split (' '))
217 int.Parse (v, NumberStyles.HexNumber));
218 AddMappedChars (cp, 0);
221 if (reader != Console.In)
225 private void AddMappedChars (int cp, int cv)
227 if (mappedCharCount == mappedChars.Length) {
228 int [] tmp = new int [mappedCharCount * 2];
229 Array.Copy (mappedChars, tmp, mappedCharCount);
232 mappedChars [mappedCharCount++] = cv;
235 private void SetCanonProp (int cp, int cpEnd, int flag)
237 int idx = MapIdx (cp);
239 mapIndex [idx] = flag;
241 int idxEnd = MapIdx (cpEnd);
242 for (int i = idx; i <= idxEnd; i++)
247 private int MapIdx (int cp)
249 return NormalizationTableUtil.MapIdx (cp);