Developer Area

root/apps/outlook/branches/1.5/DotTelSystem/Punycode/generate/GenerateNFKC.cs @ 580

Revision 580, 27.7 kB (checked in by jonmaycock, 10 months ago)
Line 
1/// <summary> Copyright (C) 2004, 2007  Free Software Foundation, Inc.
2/// *
3/// Author: Alexander Gnauck AG-Software
4/// *
5/// This file is part of GNU Libidn.
6/// *
7/// This library is free software; you can redistribute it and/or
8/// modify it under the terms of the GNU Lesser General Public License
9/// as published by the Free Software Foundation; either version 2.1 of
10/// the License, or (at your option) any later version.
11/// *
12/// This library is distributed in the hope that it will be useful, but
13/// WITHOUT ANY WARRANTY; without even the implied warranty of
14/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15/// Lesser General Public License for more details.
16/// *
17/// You should have received a copy of the GNU Lesser General Public
18/// License along with this library; if not, write to the Free Software
19/// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
20/// USA
21/// </summary>
22using System;
23using System.IO;
24using System.Collections;
25using System.Text;
26
27namespace gnu.inet.encoding.misc
28{
29    public class GenerateNFKC
30    {
31        internal static string stripComment(string sIn)
32        {
33            int c = sIn.IndexOf('#');
34            if (c == -1)
35            {
36                return sIn;
37            }
38            else
39            {
40                return sIn.Substring(0, (c) - (0));
41            }
42        }
43
44        internal static string[] split(string sIn, char sep)
45        {
46            StringBuilder sb = new StringBuilder(sIn);
47            int c = 0;
48            for (int i = 0; i < sb.Length; i++)
49            {
50                if (sb[i] == sep)
51                {
52                    c++;
53                }
54            }
55
56            string[] sOut = new string[c + 1];
57            c = 0;
58            int l = 0;
59            for (int i = 0; i < sb.Length; i++)
60            {
61                if (sb[i] == sep)
62                {
63                    if (l >= i)
64                    {
65                        sOut[c] = "";
66                    }
67                    else
68                    {
69                        // TODO, check this
70                        sOut[c] = sb.ToString(l, i-l);
71                    }
72                    l = i + 1;
73                    c++;
74                }
75            }
76            if (l < sb.Length)
77            {
78                sOut[c] = sb.ToString(l, sb.Length - l);
79            }
80            return sOut;
81        }
82
83        internal static bool isCompatibilityMapping(string sIn)
84        {
85            return sIn.Length > 0 && sIn[0] == '<';
86        }
87
88        internal static string stripCompatibilityTag(string sIn)
89        {
90            return sIn.Substring(sIn.IndexOf('>') + 2);
91        }
92
93        internal static string toString(string sIn)
94        {
95            StringBuilder sOut = new StringBuilder();
96            string[] chars = split(sIn, ' ');
97            for (int i = 0; i < chars.Length; i++)
98            {
99                if (chars[i].Equals("005C"))
100                {
101                    sOut.Append("\\\\");
102                }
103                else if (chars[i].Equals("0022"))
104                {
105                    sOut.Append("\\\"");
106                }
107                else
108                {
109                    sOut.Append("\\u");
110                    sOut.Append(chars[i]);
111                }
112            }
113            return sOut.ToString();
114        }
115           
116        internal static string decompose(string sIn, SortedList mappings)
117        {
118            StringBuilder sOut = new StringBuilder();
119            string[] c = split(sIn, ' ');
120
121            for (int i = 0; i < c.Length; i++)
122            {
123                if (mappings.ContainsKey(c[i]))
124                {
125                    if (sOut.Length > 0)
126                    {
127                        sOut.Append(" ");
128                    }
129                    sOut.Append(decompose((string)mappings[c[i]], mappings));
130                }
131                else
132                {
133                    if (sOut.Length > 0)
134                    {
135                        sOut.Append(" ");
136                    }
137                    sOut.Append(c[i]);
138                }
139            }
140
141            return sOut.ToString();
142        }
143           
144        public static void Generate()
145        {
146            // Check if the unicode files exist
147            {
148                FileInfo f1 = new FileInfo("CompositionExclusions.txt");
149                FileInfo f2 = new FileInfo("UnicodeData.txt");
150                bool tmpBool;
151                if (File.Exists(f1.FullName))
152                    tmpBool = true;
153                else
154                    tmpBool = Directory.Exists(f1.FullName);
155                bool tmpBool2;
156                if (File.Exists(f2.FullName))
157                    tmpBool2 = true;
158                else
159                    tmpBool2 = Directory.Exists(f2.FullName);
160                if (!tmpBool || !tmpBool2)
161                {
162                    Console.WriteLine("Unable to find UnicodeData.txt or CompositionExclusions.txt.");
163                    Console.WriteLine("Please download the latest version of these file from:");
164                    Console.WriteLine("http://www.unicode.org/Public/UNIDATA/");
165                    System.Environment.Exit(1);
166                }
167            }
168                   
169            ArrayList exclusions = new ArrayList();
170            {           
171                StreamReader r = new StreamReader("CompositionExclusions.txt", System.Text.Encoding.Default);
172                string line;
173                while (null != (line = r.ReadLine()))
174                {
175                    line = stripComment(line);
176                    line = line.Trim();
177                    if (line.Length == 0)
178                    {
179                        // Empty line
180                    }
181                    else if (line.Length == 4)
182                    {
183                        exclusions.Add(line);
184                    }
185                    else
186                    {
187                        // Skip code points > 0xffff
188                    }
189                }
190                r.Close();
191            }
192
193            // Read UnicodeData
194           
195            SortedList canonical = new SortedList();       
196            SortedList compatibility = new SortedList();       
197            SortedList combiningClasses = new SortedList();
198            {       
199                StreamReader r = new StreamReader("UnicodeData.txt", Encoding.Default);
200                string line;
201                while (null != (line = r.ReadLine()))
202                {
203                    line = stripComment(line);
204                    line = line.Trim();
205
206                    if (line.Length == 0)
207                    {
208                        // Empty line
209                    }
210                    else
211                    {
212                        string[] f = split(line, ';');
213
214                        if (f[0].Length == 4)
215                        {
216                            if (!f[5].Equals(""))
217                            {
218                                if (isCompatibilityMapping(f[5]))
219                                {
220                                    compatibility[f[0]] = stripCompatibilityTag(f[5]);
221                                }
222                                else
223                                {
224                                    compatibility[f[0]] = f[5];
225                                    if (!exclusions.Contains(f[0]))
226                                    {
227                                        canonical[f[0]] = f[5];
228                                    }
229                                }
230                            }
231                            if (!f[3].Equals("0"))
232                            {
233                                //UPGRADE_TODO: Method 'java.lang.Integer.parseInt' was converted to 'System.Convert.ToInt32' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073'"
234                                combiningClasses[(int)System.Convert.ToInt32(f[0], 16)] = f[3];
235                            }
236                        }
237                        else
238                        {
239                            // Skip code points > 0xffff
240                        }
241                    }
242                }
243                r.Close();
244            }
245
246            // Recursively apply compatibility mappings
247            while (true)
248            {
249                bool replaced = false;
250                           
251                IEnumerator i = new HashSet(compatibility.Keys).GetEnumerator();           
252                while (i.MoveNext())
253                {               
254                    string k = (string)i.Current;
255                    string v = (string)compatibility[k];
256
257                    string d = decompose(v, compatibility);
258                    if (!d.Equals(v))
259                    {
260                        replaced = true;
261                        compatibility[k] = d;
262                    }
263                }
264
265                if (!replaced)
266                {
267                    break;
268                }
269            }
270
271            // Eliminate duplicate mappings       
272            SortedList compatibilityKeys = new SortedList();
273            ArrayList compatibilityMappings = new ArrayList();
274            {           
275                IEnumerator i = new HashSet(compatibility.Keys).GetEnumerator();           
276                while (i.MoveNext())
277                {               
278                    string k = (string)i.Current;
279                    string v = (string)compatibility[k];
280
281                    int index = compatibilityMappings.IndexOf(v);
282                    if (index == -1)
283                    {
284                        index = compatibilityMappings.Count;
285                        compatibilityMappings.Add(v);
286                    }
287                    compatibilityKeys[k] = (int)index;
288                }
289            }
290
291            // Create composition tables       
292            SortedList firstMap = new SortedList();       
293            SortedList secondMap = new SortedList();
294            {           
295                IEnumerator i = new HashSet(canonical.Keys).GetEnumerator();           
296                while (i.MoveNext())
297                {               
298                    string k = (string)i.Current;
299                    string v = (string)canonical[k];
300
301                    string[] s = split(v, ' ');
302
303                    if (s.Length == 2)
304                    {
305                        // If both characters have the same combining class, they
306                        // won't be combined (in the sequence AB, B is blocked from
307                        // A if both have the same combining class)                   
308                        string cc1 = (string)combiningClasses[(int)System.Convert.ToInt32(s[0], 16)];                   
309                        string cc2 = (string)combiningClasses[(int)System.Convert.ToInt32(s[1], 16)];
310                        if (cc1 != null || (cc1 != null && cc1.Equals(cc2)))
311                        {
312                            // Ignore this composition                       
313                            // TODO check this
314                            //i.remove();                       
315                            canonical.Remove(k);
316                            continue;
317                        }
318
319                        if (firstMap.ContainsKey(s[0]))
320                        {
321                            int c = (int)firstMap[s[0]];
322                            firstMap[s[0]] = (int)(c + 1);
323                        }
324                        else
325                        {
326                            firstMap[s[0]] = 1;
327                        }
328
329                        if (secondMap.ContainsKey(s[1]))
330                        {
331                            int c = (int)secondMap[s[1]];
332                            secondMap[s[1]] = (int)(c + 1);
333                        }
334                        else
335                        {
336                            secondMap[s[1]] = 1;
337                        }
338                    }
339                    else if (s.Length > 2)
340                    {
341                        Console.WriteLine("? wrong canonical mapping for " + k);
342                        System.Environment.Exit(1);
343                    }
344                }
345            }
346                   
347            SortedList singleFirstComposition = new SortedList();       
348            SortedList singleSecondComposition = new SortedList();       
349            SortedList complexComposition = new SortedList();
350
351            int composeLookupMax = 0;
352            {           
353                IEnumerator i = new HashSet(canonical.Keys).GetEnumerator();         
354                while (i.MoveNext())
355                {               
356                    string k = (string) i.Current;
357                    string v = (string) canonical[k];
358
359                    string[] s = split(v, ' ');
360
361                    if (s.Length == 2)
362                    {
363                        // TODO, check this
364                        int first = 0;
365                        if(firstMap.Contains(s[0]))
366                            first = (int) firstMap[s[0]];
367                       
368                        int second = 0;
369                        if (secondMap.Contains(s[1]))
370                            second = (int) secondMap[s[1]];
371                        // TODO, check this
372
373                        if (first == 1)
374                        {
375                            singleFirstComposition[s[0]] = new string[] { s[1], k };                       
376                            composeLookupMax = System.Math.Max(composeLookupMax, System.Convert.ToInt32(s[0], 16));
377                        }
378                        else if (second == 1)
379                        {
380                            singleSecondComposition[s[1]] = new string[] { s[0], k };                       
381                            composeLookupMax = System.Math.Max(composeLookupMax, System.Convert.ToInt32(s[1], 16));
382                        }
383                        else
384                        {
385                            if (complexComposition.ContainsKey(s[0]))
386                            {                           
387                                SortedList m = (SortedList)complexComposition[s[0]];
388                                if (m.ContainsKey(s[1]))
389                                {
390                                    Console.WriteLine("? ambiguous canonical mapping for " + s[0]);
391                                    System.Environment.Exit(1);
392                                }
393                                m[s[1]] = k;
394                            }
395                            else
396                            {                           
397                                SortedList m = new SortedList();
398                                m[s[1]] = k;
399                                complexComposition[s[0]] = m;
400                            }                       
401                            composeLookupMax = System.Math.Max(composeLookupMax, System.Convert.ToInt32(s[0], 16));                       
402                            composeLookupMax = System.Math.Max(composeLookupMax, System.Convert.ToInt32(s[1], 16));
403                        }
404                    }
405                }
406            }
407
408            Console.WriteLine("Generating CombiningClass.cs file...");
409
410            // Dump combining classes
411            {
412                StreamWriter w = new StreamWriter("CombiningClass.cs", false, Encoding.Default);
413                w.WriteLine("// Do not edit !!!");
414                w.WriteLine("// this file is generated automatically");
415                w.WriteLine();           
416                w.WriteLine("public class CombiningClass");           
417                w.WriteLine("{");           
418                w.WriteLine("\tpublic static readonly int[,] c = new int[,] {");
419                System.Text.StringBuilder index = new System.Text.StringBuilder();
420
421                int count = 0;
422
423                for (int i = 0; i < 256; i++)
424                {
425                    bool empty = true;
426
427                    StringBuilder page = new StringBuilder();
428                    page.Append("    { /* Page " + i + " */");
429
430                    for (int j = 0; j < 256; j++)
431                    {
432                        int c = (int)((i << 8) + j);
433                        string cc = (string)combiningClasses[c];
434
435                        if (0 == (j & 31))
436                        {
437                            page.Append("\r\n      ");
438                        }
439                        if (cc == null)
440                        {
441                            page.Append("0, ");
442                        }
443                        else
444                        {
445                            page.Append(cc + ", ");
446                            empty = false;
447                        }
448                    }
449                    page.Append("\r\n    },");
450
451                    index.Append("    ");
452
453                    if (!empty)
454                    {                   
455                        w.WriteLine(page.ToString());
456                        index.Append(count++);
457                        index.Append(",\r\n");
458                    }
459                    else
460                    {
461                        index.Append("-1,\r\n");
462                    }
463                }           
464                w.WriteLine("  };\r\n");
465                           
466                w.WriteLine("\tpublic static readonly int[] i = new int[] {");
467                w.Write(index.ToString());           
468                w.WriteLine("  };");           
469                w.WriteLine("}");           
470                w.Close();
471            }
472
473            //Console.WriteLine(" Ok.");
474            Console.WriteLine("Generating DecompositionKeys.cs file...");
475
476            // Dump compatibility decomposition
477            {
478                StreamWriter w = new StreamWriter("DecompositionKeys.cs", false, Encoding.Default);
479                w.WriteLine("// Do not edit !!!");
480                w.WriteLine("// this file is generated automatically");         
481                w.WriteLine();           
482                w.WriteLine("public class DecompositionKeys");           
483                w.WriteLine("{");
484
485                w.WriteLine("\tpublic static readonly int[] k = new int[] {");           
486                IEnumerator i = new HashSet(compatibilityKeys.Keys).GetEnumerator();           
487                while (i.MoveNext())
488                {           
489                    string k = (string)i.Current;
490                    int index = ((int)compatibilityKeys[k]);             
491                    w.WriteLine("    '\\u" + k + "', " + index + ",");
492                }           
493                w.WriteLine("  };");           
494                w.WriteLine("}");           
495                w.Close();
496            }
497
498            //Console.WriteLine(" Ok.");
499            Console.WriteLine("Generating DecompositionMappings.cs file...");
500
501            {
502                StreamWriter w = new StreamWriter("DecompositionMappings.cs", false, Encoding.Default);
503                w.WriteLine("// Do not edit !!!");
504                w.WriteLine("// this file is generated automatically");
505                w.WriteLine();           
506                w.WriteLine("public class DecompositionMappings");           
507                w.WriteLine("{");           
508                w.WriteLine("\tpublic static readonly string[] m = new string[] {");
509                IEnumerator i = compatibilityMappings.GetEnumerator();
510                while (i.MoveNext())
511                {               
512                    string m = (string)i.Current;             
513                    w.WriteLine("    \"" + toString(m) + "\",");
514                }           
515                w.WriteLine("  };");           
516                w.WriteLine("}");           
517                w.Close();
518            }
519
520            //Console.WriteLine(" Ok.");
521            Console.WriteLine("Generating Composition.cs file...");
522
523            // Dump canonical composition
524            {
525                StreamWriter w = new StreamWriter("Composition.cs", false, Encoding.Default);
526                w.WriteLine("// Do not edit !!!");
527                w.WriteLine("// this file is generated automatically");
528                w.WriteLine();           
529                w.WriteLine("public class Composition");           
530                w.WriteLine("{");
531
532                IEnumerator i;
533                int index = 0;
534                           
535                SortedList indices = new SortedList();
536                           
537                i = new HashSet(complexComposition.Keys).GetEnumerator();           
538                while (i.MoveNext())
539                {               
540                    string s0 = (string)i.Current;             
541                    indices[(int)System.Convert.ToInt32(s0, 16)] = (int)index;
542                    index++;
543                }
544
545                int multiSecondStart = index;
546                w.WriteLine("\t/* jagged Array */");
547                w.WriteLine("\tpublic static readonly char[][] multiFirst = new char[][] {");
548                //w.WriteLine("  public final static char[][] multiFirst = new char[][] {");
549                i = new HashSet(complexComposition.Keys).GetEnumerator();           
550                while (i.MoveNext())
551                {               
552                    string s0 = (string)i.Current;             
553                    SortedList m = (SortedList)complexComposition[s0];
554                                   
555                    SortedList line = new SortedList();
556                    int maxIndex = 1;
557                                   
558                    System.Collections.IEnumerator i2 = new HashSet(m.Keys).GetEnumerator();               
559                    while (i2.MoveNext())
560                    {                   
561                        string s1 = (string)i2.Current;
562                        string k = (string)m[s1];
563                                         
564                        int s1i = (int)System.Convert.ToInt32(s1, 16);
565
566                        if (!indices.ContainsKey(s1i))
567                        {
568                            indices[s1i] = (int)index;
569                            index++;
570                        }
571                        line[indices[s1i]] = k;
572                        maxIndex = System.Math.Max(maxIndex, ((int)indices[s1i]));
573                    }
574
575                    w.Write("\tnew char[] { ");
576                    for (int j = multiSecondStart; j <= maxIndex; j++)
577                    {
578                        if (line.ContainsKey((int)j))
579                        {
580                            string s = (string)line[(int)j];
581                            w.Write("'" + toString(s) + "', ");
582                        }
583                        else
584                        {
585                            //w.Write("       0, ");
586                            w.Write("'" + toString("0000") + "', ");
587                        }
588                    }               
589                    w.WriteLine("},");
590                }           
591                w.WriteLine("  };");
592
593                int singleFirstStart = index;
594
595                w.WriteLine("\tpublic static readonly char[,] singleFirst = new char[,] {");
596                i = new HashSet(singleFirstComposition.Keys).GetEnumerator();           
597                while (i.MoveNext())
598                {           
599                    string k = (string)i.Current;
600                    string[] v = ((string[])singleFirstComposition[k]);             
601                    w.WriteLine("    { '" + toString(v[0]) + "', '" + toString(v[1]) + "' },");
602                                   
603                    if (indices.ContainsKey((int)System.Convert.ToInt32(k, 16)))
604                    {
605                        Console.WriteLine(k + " already indexed!");
606                    }
607                                   
608                    indices[(int)System.Convert.ToInt32(k, 16)] = (int)index;
609                    index++;
610                }           
611                w.WriteLine("  };");
612
613                int singleSecondStart = index;
614                           
615                w.WriteLine("\tpublic static readonly char[,] singleSecond = new char[,] {");
616                i = new HashSet(singleSecondComposition.Keys).GetEnumerator();           
617                while (i.MoveNext())
618                {               
619                    string k = (string)i.Current;
620                    string[] v = ((string[])singleSecondComposition[k]);             
621                    w.WriteLine("    { '" + toString(v[0]) + "', '" + toString(v[1]) + "' },");
622                                   
623                    indices[(int)System.Convert.ToInt32(k, 16)] = (int)index;
624                    index++;
625                }           
626                w.WriteLine("  };");
627                           
628                w.WriteLine("\tpublic static readonly int multiSecondStart = " + multiSecondStart + ";");           
629                w.WriteLine("\tpublic static readonly int singleFirstStart = " + singleFirstStart + ";");           
630                w.WriteLine("\tpublic static readonly int singleSecondStart = " + singleSecondStart + ";");
631
632                System.Text.StringBuilder compositionPages = new System.Text.StringBuilder();
633                           
634                w.WriteLine("\tpublic static readonly int[] composePage = new int[] {");
635                int pageCount = 0;
636                for (int j = 0; j * 256 < composeLookupMax + 255; j++)
637                {
638                    bool empty = true;
639                    StringBuilder page = new StringBuilder();
640                    for (int k = 0; k < 256; k++)
641                    {
642                        if (k % 16 == 0)
643                        {
644                            page.Append("\r\n      ");
645                        }
646                        if (indices.ContainsKey((int)(j * 256 + k)))
647                        {
648                            page.Append(indices[(int)(j * 256 + k)]);
649                            page.Append(", ");
650                            empty = false;
651                        }
652                        else
653                        {
654                            page.Append("-1, ");
655                        }
656                    }
657
658                    if (empty)
659                    {                   
660                        w.WriteLine("    -1,");
661                    }
662                    else
663                    {                 
664                        w.WriteLine("    " + pageCount + ",");
665                        compositionPages.Append("\t{");
666                        compositionPages.Append(page);
667                        compositionPages.Append("\r\n    },\r\n");
668                        pageCount++;
669                    }
670                }           
671                w.WriteLine("  };");
672                //w.WriteLine("\t/* jagged Array */");                       
673                w.WriteLine("\tpublic static readonly int[,] composeData = new int[,] {");
674                w.Write(compositionPages);           
675                w.WriteLine("  };");                       
676                w.WriteLine("}");           
677                w.Close();
678            }
679
680            //Console.WriteLine(" Ok.");             
681            Console.WriteLine("Finished!");
682        }
683    }
684}
Note: See TracBrowser for help on using the browser.
Telnic
Search This Site
Partners
Neustar
ICANN
Main site | WHOIS | Sell .tel | FAQ | Archived Site | About Telnic | Contact Us