private void SerializeUCD()
        {
            COut = new StreamWriter("normalization-tables.h", true);

            // mappedChars
            COut.WriteLine("static const guint32 mappedChars [] = {");
            CSOut.WriteLine("static readonly int [] mappedCharsArr = new int [] {");
            DumpMapArray(mappedChars, mappedCharCount, false);
            COut.WriteLine("0};");
            CSOut.WriteLine("};");

            // charMapIndex
            COut.WriteLine("static const guint16 charMapIndex [] = {");
            CSOut.WriteLine("static readonly short [] charMapIndexArr = new short [] {");
            DumpMapArray(mapIndex, NUtil.MapCount, true);
            COut.WriteLine("0};");
            CSOut.WriteLine("};");

            short [] helperIndexes = new short [0x30000];

            // GetPrimaryCompositeHelperIndex ()
            int currentHead = 0;

            foreach (CharMapping m in mappings)
            {
                if (mappedChars [m.MapIndex] == currentHead)
                {
                    continue;                     // has the same head
                }
                if (!m.IsCanonical)
                {
                    continue;
                }
                currentHead = mappedChars [m.MapIndex];
                helperIndexes [currentHead] = (short)m.MapIndex;
            }

            helperIndexes = CodePointIndexer.CompressArray(
                helperIndexes, typeof(short), NUtil.Helper)
                            as short [];

            COut.WriteLine("static const guint16 helperIndex [] = {");
            CSOut.WriteLine("static short [] helperIndexArr = new short [] {");
            for (int i = 0; i < helperIndexes.Length; i++)
            {
                short value = helperIndexes [i];
                if (value < 10)
                {
                    CSOut.Write("{0},", value);
                }
                else
                {
                    CSOut.Write("0x{0:X04},", value);
                }
                COut.Write("{0},", value);
                if (i % 16 == 15)
                {
                    CSOut.WriteLine(" // {0:X04}", NUtil.Helper.ToCodePoint(i - 15));
                    COut.WriteLine();
                }
            }
            COut.WriteLine("0};");
            CSOut.WriteLine("};");

            ushort [] mapIndexes = new ushort [char.MaxValue + 1];

            // GetPrimaryCompositeFromMapIndex ()
            int currentIndex = -1;

            foreach (CharMapping m in mappings)
            {
                if (m.MapIndex == currentIndex)
                {
                    continue;
                }
                if (!m.IsCanonical)
                {
                    continue;
                }
                mapIndexes [m.MapIndex] = (ushort)m.CodePoint;
                currentIndex            = m.MapIndex;
            }

            mapIndexes = CodePointIndexer.CompressArray(mapIndexes, typeof(ushort), NUtil.Composite) as ushort [];

            COut.WriteLine("static const guint16 mapIdxToComposite [] = {");
            CSOut.WriteLine("static ushort [] mapIdxToCompositeArr = new ushort [] {");
            for (int i = 0; i < mapIndexes.Length; i++)
            {
                ushort value = (ushort)mapIndexes [i];
                if (value < 10)
                {
                    CSOut.Write("{0},", value);
                }
                else
                {
                    CSOut.Write("0x{0:X04},", value);
                }
                COut.Write("{0},", value);
                if (i % 16 == 15)
                {
                    CSOut.WriteLine(" // {0:X04}", NUtil.Composite.ToCodePoint(i - 15));
                    COut.WriteLine();
                }
            }
            COut.WriteLine("0};");
            CSOut.WriteLine("};");

            COut.Close();
        }
        private void ProcessCombiningClass()
        {
            TextReader reader = new StreamReader("downloaded/DerivedCombiningClass.txt");

            while (reader.Peek() != -1)
            {
                string line = reader.ReadLine();
                lineCount++;
                int idx = line.IndexOf('#');
                if (idx >= 0)
                {
                    line = line.Substring(0, idx).Trim();
                }
                if (line.Length == 0)
                {
                    continue;
                }
                int n = 0;
                while (Char.IsDigit(line [n]) || Char.IsLetter(line [n]))
                {
                    n++;
                }
                int cp = int.Parse(line.Substring(0, n), NumberStyles.HexNumber);
                // Windows does not handle surrogate characters.
                if (cp >= 0x10000)
                {
                    continue;
                }

                int cpEnd = -1;
                if (line [n] == '.' && line [n + 1] == '.')
                {
                    cpEnd = int.Parse(line.Substring(n + 2, n), NumberStyles.HexNumber);
                }
                int    nameStart  = line.IndexOf(';') + 1;
                int    valueStart = line.IndexOf(';', nameStart) + 1;
                string val        = valueStart == 0 ? line.Substring(nameStart) :
                                    line.Substring(nameStart, valueStart - nameStart - 1);
                SetCombiningProp(cp, cpEnd, short.Parse(val));
            }

            reader.Close();

            byte [] ret = (byte [])CodePointIndexer.CompressArray(
                combining, typeof(byte), NUtil.Combining);

            COut = new StreamWriter("normalization-tables.h", true);

            COut.WriteLine("static const guint8 combiningClass [] = {");
            CSOut.WriteLine("public static byte [] combiningClassArr = new byte [] {");
            for (int i = 0; i < ret.Length; i++)
            {
                byte value = ret [i];
                if (value < 10)
                {
                    CSOut.Write("{0},", value);
                }
                else
                {
                    CSOut.Write("0x{0:X02},", value);
                }
                COut.Write("{0},", value);
                if (i % 16 == 15)
                {
                    CSOut.WriteLine(" // {0:X04}", NUtil.Combining.ToCodePoint(i - 15));
                    COut.WriteLine();
                }
            }
            CSOut.WriteLine("};");
            COut.WriteLine("0};");

            COut.Close();
        }