无线我的无限

让无线技术给生活带来无限快乐
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

UMD手机电子书的读取和制作源码(二)

Posted on 2009-03-15 11:01  freemobile  阅读(1429)  评论(0编辑  收藏  举报

转载本文章,请注明“来自角摩手机乐园(http://www.joymo.cn)”,其它相关开发,请见角摩手机乐园个人空间中,站长的博客:http://www.joymo.cn/space/space.asp?username=admin

UMDBookWriter.cs

namespace JoymoEnt.JoymoParse.umd
{
    using ICSharpCode.SharpZipLib.Zip.Compression;
    using System;
    using System.Collections;
    using System.Drawing;
    using System.Drawing.Imaging;
    using System.IO;
    using System.Reflection;
    using System.Runtime.InteropServices;
    using System.Text;

    public class UMDBookWriter/*http://www.joymo.cn,角摩手机电子书*/
    {
        private CUMDBook _Book = null;
        private int[] _ChaptersOff = null;
        private Random _Random = new Random();
        private string _TotalContent = string.Empty;
        private int _TotalContentLen = 0;
        private ArrayList _TotalImageList = new ArrayList();
        private const int A_32K_BYTE = 0x8000;
        private const byte ACTUAL_WIDTH_S60_HORI = 0xcc;
        private const byte ACTUAL_WIDTH_S60_VERT = 0xac;
        private const byte ACTUAL_WIDTH_SP = 0xa6;
        private const uint BASE_REFN_CHAP_OFF = 0x3000;
        private const uint BASE_REFN_CHAP_STR = 0x4000;
        private const uint BASE_REFN_CONTENT = 0x2000;
        private const uint BASE_REFN_COVER = 0x1000;
        private const uint BASE_REFN_PAGE_OFFSET = 0x7000;
        private const string BEYOND_END_FLAG = ""0";
        private const int BYTE_LEN = 1;
        private const byte COVER_TYPE_BMP = 0;
        private const byte COVER_TYPE_GIF = 2;
        private const byte COVER_TYPE_JPG = 1;
        private const int CURR_VERSION = 1;
        private const short DCTS_CMD_ID_AUTHOR = 3;
        private const short DCTS_CMD_ID_CDS_KEY = 240;
        private const short DCTS_CMD_ID_CHAP_OFF = 0x83;
        private const short DCTS_CMD_ID_CHAP_STR = 0x84;
        private const short DCTS_CMD_ID_CONTENT_ID = 10;
        private const short DCTS_CMD_ID_COVER_PAGE = 130;
        private const short DCTS_CMD_ID_DAY = 6;
        private const short DCTS_CMD_ID_FILE_LENGTH = 11;
        private const short DCTS_CMD_ID_FIXED_LEN = 12;
        private const short DCTS_CMD_ID_GENDER = 7;
        private const short DCTS_CMD_ID_LICENSE_KEY = 0xf1;
        private const short DCTS_CMD_ID_MONTH = 5;
        private const short DCTS_CMD_ID_PAGE_OFFSET = 0x87;
        private const short DCTS_CMD_ID_PUBLISHER = 8;
        private const short DCTS_CMD_ID_REF_CONTENT = 0x81;
        private const short DCTS_CMD_ID_TITLE = 2;
        private const short DCTS_CMD_ID_VENDOR = 9;
        private const short DCTS_CMD_ID_VERSION = 1;
        private const short DCTS_CMD_ID_YEAR = 4;
        private const byte FIXED_LINE_PER_PAGE_S60 = 50;
        private const byte FIXED_LINE_PER_PAGE_SP = 0x19;
        private ArrayList widthData_S60 = new ArrayList();
        private ArrayList widthData_SP = new ArrayList();

        public UMDBookWriter(CUMDBook book)
        {
            this._Book = book;
        }

        private byte CharWidth_S60(string @char, byte fontSize)
        {
            ushort num = @char[0];
            foreach (SWidthData data in this.widthData_S60)
            {
                if (((data.FontSize == fontSize) && (num >= data.rngFrom)) && (num <= data.rngTo))
                {
                    if (data.vCount == 1)
                    {
                        return data.Value[0];
                    }
                    return data.Value[num - data.rngFrom];
                }
            }
            return fontSize;
        }

        private void ClearTempVariables()
        {
            this._TotalContent = string.Empty;
            this._TotalContentLen = 0;
            this._ChaptersOff = null;
            if (this.widthData_S60 == null)
            {
                this.widthData_S60 = new ArrayList();
            }
            else
            {
                this.widthData_S60.Clear();
            }
            if (this.widthData_SP == null)
            {
                this.widthData_SP = new ArrayList();
            }
            else
            {
                this.widthData_SP.Clear();
            }
        }

        private byte[][] CompressTxtContent(Encoding encoding, CChapterList chapters)
        {
            string s = string.Empty;
            int num = 0;
            ArrayList list = new ArrayList(chapters.Count);
            int[] numArray = new int[chapters.Count];
            for (int i = 0; i < chapters.Count; i++)
            {
                string str2 = chapters[i].Content.Replace(""r"n", ""u2029") + ""u2029";
                list.Add(str2);
                s = s + str2;
                numArray[i] = num;
                num += str2.Length * 2;
            }
            byte[] bytes = new byte[num];
            bytes = Encoding.Unicode.GetBytes(s);
            int num3 = 0;
            if ((num % 0x8000) == 0)
            {
                num3 = num / 0x8000;
            }
            else
            {
                num3 = (num / 0x8000) + 1;
            }
            byte[][] bufferArray = new byte[num3][];
            int index = 0;
            byte[] input = new byte[0x8000];
            int num5 = 0;
            for (int j = 0; j < bytes.Length; j++)
            {
                input[num5] = bytes[j];
                num5++;
                if ((num5 == 0x8000) || (j == (bytes.Length - 1)))
                {
                    byte[] output = new byte[0x8000];
                    Deflater deflater = new Deflater(Deflater.BEST_COMPRESSION, false);
                    if (deflater.IsNeedingInput)
                    {
                        deflater.SetInput(input, 0, input.Length);
                    }
                    deflater.Finish();
                    deflater.Deflate(output);
                    bufferArray[index] = new byte[deflater.TotalOut];
                    Deflater deflater2 = new Deflater(Deflater.BEST_COMPRESSION, false);
                    if (deflater2.IsNeedingInput)
                    {
                        deflater2.SetInput(input, 0, input.Length);
                    }
                    deflater2.Finish();
                    deflater2.Deflate(bufferArray[index]);
                    index++;
                    input = null;
                    input = new byte[0x8000];
                    num5 = 0;
                }
            }
            return bufferArray;
        }

        private bool GetPageOffsetS60(byte size, uint actualWidth, out uint[] result)
        {
            if ((size != 0x10) && (size != 12))
            {
                result = new uint[0];
                return false;
            }
            this.GetWidthData_S60();
            ArrayList pagesOff = new ArrayList();
            pagesOff.Add(0);
            while (((uint) pagesOff[pagesOff.Count - 1]) < this._TotalContent.Length)
            {
                this.ParseOnePage((uint) (pagesOff.Count - 1), size, actualWidth, ref pagesOff, 1);
            }
            result = new uint[pagesOff.Count];
            for (int i = 0; i < pagesOff.Count; i++)
            {
                result[i] = ((uint) pagesOff[i]) * 2;
            }
            return true;
        }

        private bool GetPageOffsetSP(byte size, uint actualWidth, out uint[] result)
        {
            if ((size < 6) || (size > 0x10))
            {
                result = new uint[0];
                return false;
            }
            ArrayList pagesOff = new ArrayList();
            pagesOff.Add(0);
            while (((uint) pagesOff[pagesOff.Count - 1]) < this._TotalContent.Length)
            {
                this.ParseOnePage((uint) (pagesOff.Count - 1), size, actualWidth, ref pagesOff, 5);
            }
            result = new uint[pagesOff.Count];
            for (int i = 0; i < pagesOff.Count; i++)
            {
                result[i] = ((uint) pagesOff[i]) * 2;
            }
            return true;
        }

        private void GetWidthData_S60()/*http://www.joymo.cn,角摩手机电子书*/
        {
            if (this.widthData_S60.Count == 0)
            {
                for (int i = 0; i < 2; i++)
                {
                    string path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + @""FontWidthData"S60CHS." + ((i == 0) ? "S16" : "S12") + ".wdt";
                    if (File.Exists(path))
                    {
                        FileStream input = new FileStream(path, FileMode.Open, FileAccess.Read);
                        BinaryReader reader = new BinaryReader(input);
                        while (reader.BaseStream.Position < reader.BaseStream.Length)
                        {
                            SWidthData data = new SWidthData();
                            data.FontSize = (i == 0) ? ((byte) 0x10) : ((byte) 12);
                            data.rngFrom = reader.ReadUInt16();
                            data.rngTo = reader.ReadUInt16();
                            data.vCount = reader.ReadUInt16();
                            data.Value = reader.ReadBytes((int) data.vCount);
                            this.widthData_S60.Add(data);
                        }
                        reader.Close();
                        input.Close();
                    }
                }
            }
        }

        private void GetWidthData_SP()
        {
            if (this.widthData_SP.Count == 0)
            {
                for (int i = 6; i < 0x10; i++)
                {
                    string path = string.Concat(new object[] { Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), @""FontWidthData"sunfon.s", i, ".wdt" });
                    if (File.Exists(path))
                    {
                        FileStream input = new FileStream(path, FileMode.Open, FileAccess.Read);
                        BinaryReader reader = new BinaryReader(input);
                        while (reader.BaseStream.Position < reader.BaseStream.Length)
                        {
                            SWidthData data = new SWidthData();
                            data.FontSize = (byte) i;
                            data.rngFrom = reader.ReadUInt16();
                            data.rngTo = reader.ReadUInt16();
                            data.vCount = reader.ReadUInt16();
                            data.Value = reader.ReadBytes((int) data.vCount);
                            this.widthData_SP.Add(data);
                        }
                        reader.Close();
                        input.Close();
                    }
                }
            }
        }

        public string MakeImageBook(BinaryWriter writer)/*http://www.joymo.cn,角摩手机电子书*/
        {
            this.WriteChaptersOff(writer);
            this.WriteChapterTitles(writer);
            if (this._Book.BookType[1] == 2)
            {
                this.WriteChapterImageContent(writer, 14);
            }
            else if (this._Book.BookType[1] == 3)
            {
                this.WriteChapterImageContent(writer, 15);
            }
            if (this._Book.Cover != null)
            {
                this.WriteBookCover(writer);
            }
            writer.Write('#');
            writer.Write((short) 0xf1);
            writer.Write((byte) 0);
            writer.Write((byte) 0x15);
            writer.Write(Encoding.ASCII.GetBytes(""0"0"0"0"0"0"0"0"0"0"0"0"0"0"0"0"));
            return null;
        }

        public string MakeTxtBook(BinaryWriter writer)
        {
            uint[] numArray;
            Encoding bookEncoding = this._Book.BookEncoding;
            writer.Write('#');
            writer.Write((short) 11);
            writer.Write((byte) 0);
            writer.Write((byte) 9);
            writer.Write(this._TotalContentLen);
            this.WriteChaptersOff(writer);
            this.WriteChapterTitles(writer);
            if (this._Book.BookType[0] == 1)
            {
                this.WriteChapterTxtContents(writer);
            }
            if (this._Book.Cover != null)
            {
                this.WriteBookCover(writer);
            }
            this.GetPageOffsetS60(0x10, 0xcc, out numArray);
            this.WritePageOffset(0x10, 0xd0, ref numArray, writer, 1);
            this.GetPageOffsetS60(0x10, 0xac, out numArray);
            this.WritePageOffset(0x10, 0xb0, ref numArray, writer, 1);
            this.GetPageOffsetS60(12, 0xcc, out numArray);
            this.WritePageOffset(12, 0xd0, ref numArray, writer, 1);
            this.GetPageOffsetS60(12, 0xac, out numArray);
            this.WritePageOffset(12, 0xb0, ref numArray, writer, 1);
            this.GetPageOffsetSP(10, 0xa6, out numArray);
            this.WritePageOffset(10, 0xa6, ref numArray, writer, 5);
            return null;
        }

        private void ParseOnePage(uint pageNumber, byte fontSize, uint screenWidth, ref ArrayList pagesOff, int PID)
        {
            if (pageNumber < pagesOff.Count)
            {
                uint num = (uint) pagesOff[(int) pageNumber];
                int num2 = 0;
                string str = string.Empty;
                ArrayList list = new ArrayList();
                byte num3 = (PID == 1) ? ((byte) 50) : ((byte) 0x19);
                for (byte i = 0; i < num3; i = (byte) (i + 1))
                {
                    str = string.Empty;
                    string str2 = string.Empty;
                    byte num5 = 0;
                Label_0053:
                    if (num < this._TotalContent.Length)
                    {
                        str2 = this._TotalContent.Substring((int) num, 1);
                    }
                    else
                    {
                        str2 = ""0";
                    }
                    switch (str2)
                    {
                        case ""t":
                        case ""0":
                            str2 = "銆€";
                            break;
                    }
                    byte num6 = this.CharWidth_S60(str2, fontSize);
                    if (str2 == ""u2029")
                    {
                        num6 = 0;
                    }
                    if ((num6 + num5) <= screenWidth)
                    {
                        num5 = (byte) (num5 + num6);
                        num++;
                        if (str2 != ""u2029")
                        {
                            str = str + str2;
                            goto Label_0053;
                        }
                    }
                    if (str2 != ""u2029")
                    {
                        list.Add(str.Length);
                    }
                    else
                    {
                        list.Add(str.Length + 1);
                    }
                    num2 += (int) list[i];
                    if (i == ((byte) (num3 - 1)))
                    {
                        if ((num < this._TotalContent.Length) && (num > ((uint) pagesOff[pagesOff.Count - 1])))
                        {
                            pagesOff.Add(((uint) num2) + ((uint) pagesOff[pagesOff.Count - 1]));
                        }
                        if (num >= this._TotalContent.Length)
                        {
                            pagesOff.Add((uint) this._TotalContent.Length);
                        }
                    }
                }
            }
        }

        private string Precheck()
        {
            if ((this._Book.BookTitle == null) || (this._Book.BookTitle.Length < 1))
            {
                return "标题不能为空!";
            }
            if ((this._Book.Author == null) || (this._Book.Author.Length < 1))
            {
                return "作者不能为空!";
            }
            if ((this._Book.Chapters == null) || (this._Book.Chapters.Count < 1))
            {
                return "内容数量不能小于0!";
            }
            if ((this._Book.BookPath == null) || (this._Book.BookPath.Length < 1))
            {
                return "保存文件的路径不不正确!";
            }
            if (File.Exists(this._Book.BookPath))
            {
                File.Delete(this._Book.BookPath);
            }
            return null;
        }

        private string Prepare()/*http://www.joymo.cn,角摩手机电子书*/
        {
            string str = string.Empty;
            int[] numArray = new int[this._Book.Chapters.Count];
            int num = 0;
            CChapter chapter = null;
            string str2 = null;
            for (int i = 0; i < this._Book.Chapters.Count; i++)
            {
                chapter = this._Book.Chapters[i];
                numArray[i] = num;
                if (this._Book.BookType[1] == 2)
                {
                    this._TotalImageList.AddRange(chapter.ImageList);
                    num += chapter.ImageList.Count;
                }
                else if (this._Book.BookType[1] == 1)
                {
                    str2 = chapter.Content.Replace(""r"n", ""u2029") + ""u2029";
                    str = str + str2;
                    num += str2.Length * 2;
                }
            }
            this._TotalContent = str;
            this._TotalContentLen = num;
            this._ChaptersOff = numArray;
            return null;
        }

        public string Write()
        {
            string message = this.Precheck();
            if (message == null)
            {
                this.ClearTempVariables();
                message = this.Prepare();
                if (message != null)
                {
                    return message;
                }
                BinaryWriter writer = null;
                FileStream output = new FileStream(this._Book.BookPath, FileMode.OpenOrCreate, FileAccess.Write);
                try
                {
                    writer = new BinaryWriter(output);
                    short num = (short) (this._Random.Next(0x401, 0x7fff) % 0xffff);
                    writer.Write((uint) 0xde9a9b89);
                    writer.Write('#');
                    writer.Write((short) 1);
                    writer.Write((byte) 0);
                    writer.Write((byte) 8);
                    writer.Write(this._Book.BookType[1]);
                    writer.Write(num);
                    this.WriteBookProperties(writer);
                    if (this._Book.BookType[1] == 1)
                    {
                        this.MakeTxtBook(writer);
                    }
                    else if (this._Book.BookType[1] == 2)
                    {
                        this.MakeImageBook(writer);
                    }
                    writer.Write('#');
                    writer.Write((short) 12);
                    writer.Write((byte) 1);
                    writer.Write((byte) 9);
                    writer.Write((uint) (((uint) writer.BaseStream.Position) + 4));
                }
                catch (Exception exception)
                {
                    message = exception.Message;
                }
                finally
                {
                    if (writer != null)
                    {
                        writer.Close();
                        writer = null;
                    }
                    output.Close();
                    output = null;
                }
            }
            return message;
        }

        private void WriteBookCover(BinaryWriter Writer)
        {
            uint num = (uint) (0x1000 + this._Random.Next(0xfff));
            byte[] buffer = null;
            MemoryStream stream = new MemoryStream();
            this._Book.Cover.Save(stream, ImageFormat.Gif);
            stream.Seek(0L, SeekOrigin.Begin);
            buffer = new byte[stream.Length];
            stream.Read(buffer, 0, buffer.Length);
            stream.Close();
            stream = null;
            Writer.Write('#');
            Writer.Write((short) 130);
            Writer.Write((byte) 1);
            Writer.Write((byte) 10);
            Writer.Write((byte) 1);
            Writer.Write(num);
            Writer.Write('$');
            Writer.Write(num);
            Writer.Write((uint) (9 + buffer.Length));
            Writer.Write(buffer);
            buffer = null;
        }

        private void WriteBookProperties(BinaryWriter Writer)
        {
            Encoding bookEncoding = this._Book.BookEncoding;
            string propertyValue = this._Book.PublishDate.Year.ToString();
            string str2 = this._Book.PublishDate.Month.ToString();
            string str3 = this._Book.PublishDate.Day.ToString();
            this.WriteBookProperty(Writer, this._Book.BookTitle, 2);
            this.WriteBookProperty(Writer, this._Book.Author, 3);
            this.WriteBookProperty(Writer, propertyValue, 4);
            this.WriteBookProperty(Writer, str2, 5);
            this.WriteBookProperty(Writer, str3, 6);
            if ((this._Book.BookKind != null) && (this._Book.BookKind.Length > 0))
            {
                this.WriteBookProperty(Writer, this._Book.BookKind, 7);
            }
            if ((this._Book.Publisher != null) && (this._Book.Publisher.Length > 0))
            {
                this.WriteBookProperty(Writer, this._Book.Publisher, 8);
            }
            if ((this._Book.Vendor != null) && (this._Book.Vendor.Length > 0))
            {
                this.WriteBookProperty(Writer, this._Book.Vendor, 9);
            }
        }

        private void WriteBookProperty(BinaryWriter Writer, string PropertyValue, int Type)
        {
            Writer.Write('#');
            Writer.Write((short) Type);
            Writer.Write((byte) 0);
            Writer.Write((byte) (5 + (PropertyValue.Length * 2)));
            Writer.Write(this._Book.BookEncoding.GetBytes(PropertyValue));
        }

        private void WriteChapterImageContent(BinaryWriter writer, int SegType)
        {
            int num = this._Random.Next(0x5f5e101, 0x3b9aca00);
            uint[] numArray = new uint[this._TotalImageList.Count];
            uint num2 = 0;
            if (this._TotalImageList.Count > 1)
            {
                num2 = (uint) this._Random.Next(0, this._TotalImageList.Count - 1);
            }
            writer.Write('#');
            writer.Write((short) SegType);
            writer.Write((byte) 0);
            writer.Write((byte) 6);
            writer.Write((byte) 1);
            byte[] buffer = null;
            for (int i = 0; i < this._TotalImageList.Count; i++)
            {
                Image image = (Image) this._TotalImageList[i];
                MemoryStream stream = new MemoryStream();
                image.Save(stream, ImageFormat.Jpeg);
                stream.Seek(0L, SeekOrigin.Begin);
                buffer = new byte[stream.Length];
                stream.Read(buffer, 0, buffer.Length);
                stream.Close();
                stream = null;
                numArray[i] = (uint) (this._Random.Next(1, 0xfffffff) * -1);
                writer.Write('$');
                writer.Write(numArray[i]);
                writer.Write((uint) (9 + buffer.Length));
                writer.Write(buffer);
                if (num2 == i)
                {
                    writer.Write('#');
                    writer.Write((short) 10);
                    writer.Write((byte) 0);
                    writer.Write((byte) 9);
                    writer.Write(num);
                }
            }
            num2 = (uint) (0x2000 + this._Random.Next(0xfff));
            writer.Write('#');
            writer.Write((short) 0x81);
            writer.Write((byte) 1);
            writer.Write((byte) 9);
            writer.Write(num2);
            writer.Write('$');
            writer.Write(num2);
            writer.Write((uint) (9 + (numArray.Length * 4)));
            for (int j = 0; j < numArray.Length; j++)
            {
                writer.Write(numArray[j]);
            }
        }

        private void WriteChaptersOff(BinaryWriter writer)/*http://www.joymo.cn,角摩手机电子书*/
        {
            uint num = (uint) (0x3000 + this._Random.Next(0xfff));
            writer.Write('#');
            writer.Write((short) 0x83);
            writer.Write((byte) 1);
            writer.Write((byte) 9);
            writer.Write(num);
            writer.Write('$');
            writer.Write(num);
            writer.Write((uint) (9 + (this._ChaptersOff.Length * 4)));
            for (int i = 0; i < this._ChaptersOff.Length; i++)
            {
                writer.Write(this._ChaptersOff[i]);
            }
        }

        private void WriteChapterTitles(BinaryWriter Writer)
        {
            uint num = (uint) (0x4000 + this._Random.Next(0xfff));
            int num2 = 0;
            foreach (CChapter chapter in this._Book.Chapters)
            {
                num2 += (chapter.Title.Length * 2) + 1;
            }
            Writer.Write('#');
            Writer.Write((short) 0x84);
            Writer.Write((byte) 1);
            Writer.Write((byte) 9);
            Writer.Write(num);
            Writer.Write('$');
            Writer.Write(num);
            Writer.Write((uint) (9 + num2));
            foreach (CChapter chapter2 in this._Book.Chapters)
            {
                Writer.Write((byte) (chapter2.Title.Length * 2));
                Writer.Write(this._Book.BookEncoding.GetBytes(chapter2.Title));
            }
        }

        private void WriteChapterTxtContents(BinaryWriter Writer)
        {
            Random random = new Random();
            int num2 = random.Next(0x5f5e101, 0x3b9aca00);
            byte[][] bufferArray = this.CompressTxtContent(this._Book.BookEncoding, this._Book.Chapters);
            int num3 = 0;
            int num4 = 0;
            if (bufferArray.Length > 1)
            {
                num3 = random.Next(0, bufferArray.Length - 1);
                num4 = random.Next(0, bufferArray.Length - 1);
            }
            uint[] numArray = new uint[bufferArray.Length];
            for (int i = 0; i < bufferArray.Length; i++)
            {
                numArray[i] = (uint) (random.Next(1, 0xfffffff) * -1);
                Writer.Write('$');
                Writer.Write(numArray[i]);
                Writer.Write((uint) (9 + bufferArray[i].Length));
                Writer.Write(bufferArray[i]);
                if (i == num3)
                {
                    Writer.Write('#');
                    Writer.Write((short) 0xf1);
                    Writer.Write((byte) 0);
                    Writer.Write((byte) 0x15);
                    Writer.Write(Encoding.ASCII.GetBytes(""0"0"0"0"0"0"0"0"0"0"0"0"0"0"0"0"));
                }
                if (i == num4)
                {
                    Writer.Write('#');
                    Writer.Write((short) 10);
                    Writer.Write((byte) 0);
                    Writer.Write((byte) 9);
                    Writer.Write(num2);
                }
            }
            uint num = (uint) (0x2000 + random.Next(0xfff));/*手机电子书*/
            Writer.Write('#');
            Writer.Write((short) 0x81);
            Writer.Write((byte) 1);
            Writer.Write((byte) 9);
            Writer.Write(num);
            Writer.Write('$');
            Writer.Write(num);
            Writer.Write((uint) (9 + (numArray.Length * 4)));
            for (int j = 0; j < numArray.Length; j++)
            {
                Writer.Write(numArray[j]);
            }
        }

        private void WritePageOffset(byte fontSize, byte screenWidth, ref uint[] data, BinaryWriter writer, byte PID)
        {
            Random random = new Random();
            uint num = (uint) (0x7000 + random.Next(0xfff));
            writer.Write('#');
            writer.Write((short) 0x87);
            writer.Write(PID);
            writer.Write((byte) 11);
            writer.Write(fontSize);
            writer.Write(screenWidth);
            writer.Write(num);
            writer.Write('$');
            writer.Write(num);
            writer.Write((uint) (9 + (data.Length * 4)));
            foreach (uint num2 in data)
            {
                writer.Write(num2);
            }
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct SWidthData
        {
            public byte FontSize;
            public ushort rngFrom;
            public ushort rngTo;
            public uint vCount;
            public byte[] Value;
        }
    }
}

UMDFactory.cs

namespace JoymoEnt.JoymoParse.umd
{
    using System;

    public class UMDFactory
    {
        private UMDFactory()
        {
        }

        public static CUMDBook CreateNewUMDBook()
        {
            return new CUMDBook();
        }

        public static CUMDBook ReadUMDBook(string filepath)
        {
            UMDBookReader reader = new UMDBookReader();
            return reader.Read(filepath);
        }

        public static string WriteUMDBook(CUMDBook book)
        {
            UMDBookWriter writer = new UMDBookWriter(book);
            return writer.Write();
        }
    }
}