最近越来越多的朋友问UMD手机电子书格式的相关源码,我觉得也没有必要遮遮捂捂的,经我那软件开发哥们的同意,把核心的源码放出来。其实这部分源码的获得很简单,现在很多UMD电子书工具,都是用.net做的,大家找一个反编译软件就可以得到源码了,比如:Reflector.exe。

UMD源代码下载

Book_Types.cs/*http://www.joymo.cn,角摩手机电子书*/

namespace JoymoEnt.JoymoParse.umd
{
    using System;

    public class Book_Types
    {
        public static byte[] BOOK_TYPE_CARTTON = new byte[] { 2, 2 };
        public static byte[] BOOK_TYPE_COMIC_BOOK = new byte[] { 3, 2 };
        public static byte[] BOOK_TYPE_TEXT = new byte[] { 1, 1 };
    }
}

CUMDBook.cs/*http://www.joymo.cn,角摩手机电子书*/

namespace JoymoEnt.JoymoParse.umd
{
    using System;
    using System.Drawing;
    using System.IO;
    using System.Text;

    public class CUMDBook
    {
        private string _Book_Author = string.Empty;
        private CChapterList _Book_Chapters = null;
        private Image _Book_Cover = null;
        private Encoding _Book_Encoding = Encoding.Unicode;
        private string _Book_Kind = string.Empty;
        private string _Book_Path = string.Empty;
        private DateTime _Book_PublishDate = DateTime.Now;
        private string _Book_Publisher = string.Empty;
        private string _Book_Title = string.Empty;
        private byte[] _Book_Type = new byte[] { 1, 1 };
        private string _Book_Vendor = string.Empty;

        public void AppendChapter(CChapter chapter)
        {
            this._Book_Chapters.Add(chapter);
        }

        public CUMDBook()
        {
            if(_Book_Chapters == null)
                _Book_Chapters = new CChapterList();
        }

        public CUMDBook(Property pro, CChapterList cList)
        {
            if (cList == null)
                _Book_Chapters = new CChapterList();
            else
                _Book_Chapters = cList;

            // 用Pro对book属性赋值
            _Book_Author = pro.Author;
            _Book_Path = pro.BookPath;
            _Book_Publisher = pro.Maker;
            _Book_Title = pro.BookName;
            _Book_Vendor = pro.Maker;
            _Book_Cover = Image.FromFile(pro.Conver);
           
        }

        public string CanSave()
        {
            if ((this.BookTitle == null) || (this.BookTitle.Length < 1))
            {
                return “标题不能为空!”;
            }
            if ((this.Author == null) || (this.Author.Length < 1))
            {
                return “作者不能为空!”;
            }
            if ((this.Chapters == null) || (this.Chapters.Count < 1))
            {
                return “内容数量不能小于0!”;
            }
            if ((this.BookPath == null) || (this.BookPath.Length < 1))
            {
                return “保存文件的路径不正确!”;
            }
            if (File.Exists(this.BookPath))
            {
                try
                {
                    File.Delete(this.BookPath);
                }
                catch (Exception exception)
                {
                    Console.WriteLine(exception.Message);
                    return “无法覆盖,文件正在被使用!”;
                }
            }
            return null;
        }

        public string Author
        {
            get
            {
                return this._Book_Author;
            }
            set
            {
                this._Book_Author = value;
            }
        }

        public Encoding BookEncoding
        {
            get
            {
                return this._Book_Encoding;
            }
        }

        public string BookKind
        {
            get
            {
                return this._Book_Kind;
            }
            set
            {
                this._Book_Kind = value;
            }
        }

        public string BookPath
        {
            get
            {
                return this._Book_Path;
            }
            set
            {
                this._Book_Path = value;
            }
        }

        public string BookTitle
        {
            get
            {
                return this._Book_Title;
            }
            set
            {
                this._Book_Title = value;
            }
        }

        public byte[] BookType
        {
            get
            {
                return this._Book_Type;
            }
            set
            {
                this._Book_Type = value;
            }
        }

        public CChapterList Chapters
        {
            get
            {
                return this._Book_Chapters;
            }
        }

        public Image Cover
        {
            get
            {
                return this._Book_Cover;
            }
            set
            {
                this._Book_Cover = value;
            }
        }

        public DateTime PublishDate
        {
            get
            {
                return this._Book_PublishDate;
            }
            set
            {
                this._Book_PublishDate = value;
            }
        }

        public string Publisher
        {
            get
            {
                return this._Book_Publisher;
            }
            set
            {
                this._Book_Publisher = value;
            }
        }

        public string Vendor
        {
            get
            {
                return this._Book_Vendor;
            }
            set
            {
                this._Book_Vendor = value;
            }
        }
    }
}

CUMDFile.cs/*http://www.joymo.cn,角摩手机电子书*/

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 CUMDFile
    {
        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 uint additionalCheck;
        private string author = string.Empty;
        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 int[] chapOff;
        private CChapterList chapters = new CChapterList();
        private int cid;
        private int contentLength;
        private Image cover;
        private const byte COVER_TYPE_BMP = 0;
        private const byte COVER_TYPE_GIF = 2;
        private const byte COVER_TYPE_JPG = 1;
        private Stream coverStream;
        private const int CURR_VERSION = 1;
        private string day;
        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 Encoding encoding = Encoding.Unicode;
        private string File_Name;
        private const byte FIXED_LINE_PER_PAGE_S60 = 50;
        private const byte FIXED_LINE_PER_PAGE_SP = 0x19;
        private string gender = string.Empty;
        private const int INT_LEN = 4;
        private const string KEY_CODE_TAB = “”t”;
        private string month;
        private short pgkSeed = 0;
        private DateTime publishDate = DateTime.Now;
        private string publisher = string.Empty;
        private uint[] refContent;
        private const byte S60_FONT_SIZE_BIG = 0x10;
        private const byte S60_FONT_SIZE_SMALL = 12;
        private const byte SEREIS60_FONTS_COUNT = 2;
        private const int SHORT_LEN = 2;
        private const byte SP_FONT_SIZE_10 = 10;
        private const byte SP_FONT_SIZE_MAX = 0x10;
        private const byte SP_FONT_SIZE_MIN = 6;
        private const string SYMBIAN_RETURN = “”u2029”;
        private const string SYMBIAN_SPACE = “銆€”;
        private string text;
        private string title = string.Empty;
        private const byte UMD_DCTD_HEAD_LEN = 9;
        private const byte UMD_DCTS_HEAD_LEN = 5;
        private const int UMD_FREE_CID_MIN = 0x5f5e100;
        private const int UMD_FREE_PGK_SEED_MIN = 0x400;
        private const int UMD_LICENSEKEY_LEN = 0x10;
        private const int UMD_MAX_BOOKMARK_STR_LEN = 40;
        private const byte UMD_PLATFORM_ID_NONE = 0;
        private const byte UMD_PLATFORM_ID_S60 = 1;
        private const byte UMD_PLATFORM_ID_SP = 5;
        private const int UMD_SEGMENT_LENGTH = 0x8000;
        private string vendor = string.Empty;
        private const byte VER_PKG_LEN = 3;
        private static ArrayList widthData_S60 = new ArrayList();
        private static ArrayList widthData_SP = new ArrayList();
        private const string WINDOWS_RETURN = “”r”n”;
        private string year;
        private const int ZIP_LEVEL = 9;
        private ArrayList zippedSeg = new ArrayList();

        public void AppendChapter()
        {
            CChapter chapter = new CChapter(“第 ” + (this.chapters.Count + 1) + “章”, “”);
            this.Chapters.Add(chapter);
        }

        public bool CanSave()
        {
            return ((this.File_Name != null) && (this.File_Name.Length > 0));
        }

        private byte CharWidth_S60(string @char, byte fontSize)/*http://www.joymo.cn,角摩手机电子书*/
        {
            ushort num = @char[0];
            foreach (SWidthData data in 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 byte CharWidth_SP(string @char, byte fontSize)
        {
            ushort num = @char[0];
            foreach (SWidthData data in widthData_SP)
            {
                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;
        }

        public void Close()
        {
            this.File_Name = “”;
            this.chapters.Clear();
        }

        public void Extract(string path)
        {
            string str = path.EndsWith(@”””) ? path : (path + ‘””‘);
            if (!Directory.Exists(str))
            {
                Directory.CreateDirectory(str);
            }
            this.SaveCover(str);
            for (int i = 0; i < this.chapOff.Length; i++)
            {
                StreamWriter writer = new StreamWriter(str + this.chapters[i].Title + “.txt”, false, Encoding.Unicode);
                writer.Write(this.chapters[i].Content);
                writer.Close();
            }
        }

        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.text.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.text.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()
        {
            if (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);
                            widthData_S60.Add(data);
                        }
                        reader.Close();
                        input.Close();
                    }
                }
            }
        }

        private void GetWidthData_SP()
        {
            if (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);
                            widthData_SP.Add(data);
                        }
                        reader.Close();
                        input.Close();
                    }
                }
            }
        }

        private void Initialize()
        {
            if (this.title.Length == 0)
            {
                throw new ArgumentException(“title”);
            }
            if (this.author.Length == 0)
            {
                throw new ArgumentException(“author”);
            }
            if (this.chapters.Count == 0)
            {
                throw new ApplicationException(“no chapter”);
            }
            foreach (CChapter chapter in this.chapters)
            {
                if (!chapter.Content.EndsWith(“”u2029”))
                {
                    chapter.Content = chapter.Content + “”u2029”;
                }
            }
            this.chapOff = new int[this.chapters.Count];
        }

        public void Make(string path)
        {
            this.Make(path, false);
        }

        public void Make(string path, bool overwrite)
        {
            uint[] numArray;
            if (File.Exists(path))
            {
                File.Delete(path);
            }
            this.Initialize();
            string str = path;
            this.Prepare();
            FileStream output = new FileStream(str, FileMode.OpenOrCreate, FileAccess.Write);
            BinaryWriter writer = new BinaryWriter(output);
            writer.Write((uint) 0xde9a9b89);
            this.WriteSection(1, 0, 3, writer);
            this.WriteSection(2, 0, (byte) (this.title.Length * 2), writer);
            this.WriteSection(3, 0, (byte) (this.author.Length * 2), writer);
            this.WriteSection(4, 0, (byte) (this.year.Length * 2), writer);
            this.WriteSection(5, 0, (byte) (this.month.Length * 2), writer);
            this.WriteSection(6, 0, (byte) (this.day.Length * 2), writer);
            if (this.gender.Length != 0)
            {
                this.WriteSection(7, 0, (byte) (this.gender.Length * 2), writer);
            }
            if (this.publisher.Length != 0)
            {
                this.WriteSection(8, 0, (byte) (this.publisher.Length * 2), writer);
            }
            if (this.vendor.Length != 0)
            {
                this.WriteSection(9, 0, (byte) (this.vendor.Length * 2), writer);
            }
            this.WriteSection(11, 0, 4, writer);
            Random random = new Random();
            this.additionalCheck = (uint) (0x3000 + random.Next(0xfff));
            this.WriteSection(0x83, 0, 4, writer);
            this.WriteAdditional(0x83, this.additionalCheck, (uint) (this.chapOff.Length * 4), writer);
            int num = 0;
            foreach (CChapter chapter in this.chapters)
            {
                num += (chapter.Title.Length * 2) + 1;
            }
            this.additionalCheck = (uint) (0x4000 + random.Next(0xfff));
            this.WriteSection(0x84, 1, 4, writer);
            this.WriteAdditional(0x84, this.additionalCheck, (uint) num, writer);
            int num2 = 0;
            int num3 = 0;
            if (this.zippedSeg.Count > 1)
            {
                num2 = random.Next(0, this.zippedSeg.Count – 1);
                num3 = random.Next(0, this.zippedSeg.Count – 1);
            }
            this.refContent = new uint[this.zippedSeg.Count];
            for (int i = 0; i < this.zippedSeg.Count; i++)
            {
                byte[] buffer = (byte[]) this.zippedSeg[i];
                this.refContent[i] = (uint) (random.Next(1, 0xfffffff) * -1);
                this.WriteAdditional(0x84, this.refContent[i], (uint) buffer.Length, writer);
                if (i == num2)
                {
                    this.WriteSection(0xf1, 0, 0x10, writer);
                }
                if (i == num3)
                {
                    this.WriteSection(10, 0, 4, writer);
                }
            }
            this.additionalCheck = (uint) (0x2000 + random.Next(0xfff));
            this.WriteSection(0x81, 1, 4, writer);
            this.WriteAdditional(0x81, this.additionalCheck, (uint) (this.refContent.Length * 4), writer);
            if (this.cover != null)
            {
                this.coverStream = new MemoryStream();
                this.cover.Save(this.coverStream, ImageFormat.Gif);
                this.additionalCheck = (uint) (0x1000 + random.Next(0xfff));
                this.WriteSection(130, 1, 5, writer);
                this.WriteAdditional(130, this.additionalCheck, (uint) this.coverStream.Length, writer);
                this.coverStream.Close();
                this.coverStream = null;
            }
            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);
            this.WriteSection(12, 1, 4, writer);
            writer.Close();
        }

        public void Open(string strFileName)
        {
            this.Read(strFileName);
            this.File_Name = strFileName;
        }

        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.text.Length)
                    {
                        str2 = this.text.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.text.Length) && (num > ((uint) pagesOff[pagesOff.Count – 1])))
                        {
                            pagesOff.Add(((uint) num2) + ((uint) pagesOff[pagesOff.Count – 1]));
                        }
                        if (num >= this.text.Length)
                        {
                            pagesOff.Add((uint) this.text.Length);
                        }
                    }
                }
            }
        }

        private void Prepare()
        {
            this.year = this.publishDate.Year.ToString();
            this.month = this.publishDate.Month.ToString();
            this.day = this.publishDate.Day.ToString();
            Random random = new Random();
            this.pgkSeed = (short) (random.Next(0x401, 0x7fff) % 0xffff);
            this.cid = random.Next(0x5f5e101, 0x3b9aca00);
            int byteIndex = 0;
            StringBuilder builder = new StringBuilder();
            for (int i = 0; i < this.chapters.Count; i++)
            {
                CChapter chapter = this.chapters[i];
                chapter.Content = chapter.Content.Replace(“”r”n”, “”u2029”);
                builder.Append(chapter.Content);
                this.chapOff[i] = byteIndex;
                byteIndex += chapter.Content.Length * 2;
            }
            this.contentLength = byteIndex;
            this.text = builder.ToString();
            byte[] bytes = new byte[this.contentLength];
            byteIndex = 0;
            for (int j = 0; j < this.chapters.Count; j++)
            {
                CChapter chapter2 = this.chapters[j];
                this.encoding.GetBytes(chapter2.Content, 0, chapter2.Content.Length, bytes, byteIndex);
                byteIndex += chapter2.Content.Length * 2;
            }
            int num4 = 0;
            if ((bytes.Length % 0x8000) == 0)
            {
                num4 = bytes.Length / 0x8000;
            }
            else
            {
                num4 = (bytes.Length / 0x8000) + 1;
            }
            byteIndex = 0;
            byte[] output = new byte[0x8000];
            for (int k = 0; k < num4; k++)
            {
                Deflater deflater = new Deflater(Deflater.BEST_COMPRESSION, false);
                deflater.SetInput(bytes, byteIndex, Math.Min(0x8000, bytes.Length – byteIndex));
                deflater.Finish();
                deflater.Deflate(output);
                byte[] destinationArray = new byte[deflater.TotalOut];
                Array.Copy(output, 0, destinationArray, 0, destinationArray.Length);
                this.zippedSeg.Add(destinationArray);
                byteIndex += output.Length;
            }
        }

        private void Read(BinaryReader reader)
        {
            this.chapters.Clear();
            if (reader.ReadUInt32() != 0xde9a9b89)
            {
                throw new ApplicationException(“Wrong header”);
            }
            char ch = (char) reader.PeekChar();
            while (ch == ‘#’)
            {
                reader.ReadChar();
                short id = reader.ReadInt16();
                byte b = reader.ReadByte();
                byte length = (byte) (reader.ReadByte() – 5);
                this.ReadSection(id, b, length, reader);
                ch = (char) reader.PeekChar();
                switch (id)
                {
                    case 10:
                    case 0xf1:
                        id = 0x84;
                        break;
                }
                while (ch == ‘$’)
                {
                    reader.ReadChar();
                    uint check = reader.ReadUInt32();
                    uint num6 = reader.ReadUInt32() – 9;
                    this.ReadAdditional(id, check, num6, reader);
                    ch = (char) reader.PeekChar();
                }
            }
            reader.Close();
            int destinationIndex = 0;
            byte[] destinationArray = new byte[this.contentLength];
            byte[] buf = new byte[0x8000];
            foreach (byte[] buffer3 in this.zippedSeg)
            {
                Inflater inflater = new Inflater();
                inflater.SetInput(buffer3);
                inflater.Inflate(buf);
                if (destinationIndex < destinationArray.Length)
                {
                    Array.Copy(buf, 0, destinationArray, destinationIndex, Math.Min(destinationArray.Length – destinationIndex, inflater.TotalOut));
                    destinationIndex += inflater.TotalOut;
                }
            }
            for (int i = 0; i < this.chapOff.Length; i++)
            {
                this.chapters[i].Content = this.encoding.GetString(destinationArray, this.chapOff[i], ((i < (this.chapOff.Length – 1)) ? this.chapOff[i + 1] : destinationArray.Length) – this.chapOff[i]).Replace(“”u2029”, “”r”n”);
            }
            this.zippedSeg.Clear();
            this.publishDate = new DateTime(int.Parse(this.year), int.Parse(this.month), int.Parse(this.day));
        }

        private void Read(string file)
        {
            BinaryReader reader = new BinaryReader(new FileStream(file, FileMode.Open));
            this.Read(reader);
        }

        protected virtual void ReadAdditional(short id, uint check, uint length, BinaryReader reader)
        {
            switch (id)
            {
                case 0x81:
                    reader.ReadBytes((int) length);
                    return;

                case 130:
                    this.cover = Image.FromStream(new MemoryStream(reader.ReadBytes((int) length)));
                    return;

                case 0x83:
                    this.chapOff = new int[length / 4];
                    for (int i = 0; i < this.chapOff.Length; i++)
                    {
                        this.chapOff[i] = reader.ReadInt32();
                    }
                    return;

                case 0x84:
                    if (this.additionalCheck == check)
                    {
                        int index = 0;
                        byte[] bytes = reader.ReadBytes((int) length);
                        while (index < bytes.Length)
                        {
                            byte count = bytes[index];
                            this.chapters.Add(new CChapter(this.encoding.GetString(bytes, ++index, count), string.Empty));
                            index += count;
                        }
                        return;
                    }
                    this.zippedSeg.Add(reader.ReadBytes((int) length));
                    return;
            }
            reader.ReadBytes((int) length);
        }

        protected virtual void ReadSection(short id, byte b, byte length, BinaryReader reader)
        {
            switch (id)
            {
                case 1:
                    reader.ReadByte();
                    this.pgkSeed = reader.ReadInt16();
                    return;

                case 2:
                    this.title = this.encoding.GetString(reader.ReadBytes(length));
                    return;

                case 3:
                    this.author = this.encoding.GetString(reader.ReadBytes(length));
                    return;

                case 4:
                    this.year = this.encoding.GetString(reader.ReadBytes(length));
                    return;

                case 5:
                    this.month = this.encoding.GetString(reader.ReadBytes(length));
                    return;

                case 6:
                    this.day = this.encoding.GetString(reader.ReadBytes(length));
                    return;

                case 7:
                    this.gender = this.encoding.GetString(reader.ReadBytes(length));
                    return;

                case 8:
                    this.publisher = this.encoding.GetString(reader.ReadBytes(length));
                    return;

                case 9:
                    this.vendor = this.encoding.GetString(reader.ReadBytes(length));
                    return;

                case 10:
                    this.cid = reader.ReadInt32();
                    return;

                case 11:
                    this.contentLength = reader.ReadInt32();
                    return;

                case 12:
                    reader.ReadUInt32();
                    return;

                case 0x81:
                case 0x83:
                case 0x84:
                    this.additionalCheck = reader.ReadUInt32();
                    return;

                case 130:
                    reader.ReadByte();
                    this.additionalCheck = reader.ReadUInt32();
                    return;
            }
            reader.ReadBytes(length);
        }

        public void Save()
        {
            this.Save(this.File_Name);
        }

        public void Save(string strFileName)
        {
            widthData_S60.Clear();
            widthData_SP.Clear();
            this.pgkSeed = 0;
            this.zippedSeg.Clear();
            this.chapOff = null;
            this.Make(strFileName, true);
            this.File_Name = strFileName;
        }

        public void SaveAs(string strFileName)
        {
            this.Save(strFileName);
        }

        protected virtual void SaveCover(string path)
        {
            Guid guid = this.cover.RawFormat.Guid;
            string str = “.tmp”;
            if (guid == ImageFormat.Bmp.Guid)
            {
                str = “.bmp”;
            }
            else if (guid == ImageFormat.Gif.Guid)
            {
                str = “.gif”;
            }
            else if (guid == ImageFormat.Jpeg.Guid)
            {
                str = “.jpg”;
            }
            this.cover.Save(path + “cover” + str);
        }

        protected virtual void WriteAdditional(short id, uint check, uint length, BinaryWriter writer)
        {
            writer.Write(‘$’);
            writer.Write(check);
            writer.Write((uint) (length + 9));
            switch (id)
            {
                case 0x81:
                    foreach (uint num in this.refContent)
                    {
                        writer.Write(num);
                    }
                    return;

                case 130:
                {
                    this.coverStream.Seek(0L, SeekOrigin.Begin);
                    byte[] buffer = new byte[this.coverStream.Length];
                    this.coverStream.Read(buffer, 0, buffer.Length);
                    writer.Write(buffer);
                    this.coverStream.Close();
                    return;
                }
                case 0x83:
                    foreach (int num2 in this.chapOff)
                    {
                        writer.Write(num2);
                    }
                    return;

                case 0x84:
                    if (this.additionalCheck != check)
                    {
                        int index = Array.IndexOf(this.refContent, check);
                        if (index != -1)
                        {
                            writer.Write((byte[]) this.zippedSeg[index]);
                        }
                        return;
                    }
                    foreach (CChapter chapter in this.chapters)
                    {
                        writer.Write((byte) (chapter.Title.Length * 2));
                        writer.Write(this.encoding.GetBytes(chapter.Title));
                    }
                    return;
            }
        }

        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);
            }
        }

        protected virtual void WriteSection(short id, byte b, byte length, BinaryWriter writer)
        {
            writer.Write(‘#’);
            writer.Write(id);
            writer.Write(b);
            writer.Write((byte) (length + 5));
            switch (id)
            {
                case 1:
                    writer.Write((byte) 1);
                    writer.Write(this.pgkSeed);
                    return;

                case 2:
                    writer.Write(this.encoding.GetBytes(this.title));
                    return;

                case 3:
                    writer.Write(this.encoding.GetBytes(this.author));
                    return;

                case 4:
                    writer.Write(this.encoding.GetBytes(this.year));
                    return;

                case 5:
                    writer.Write(this.encoding.GetBytes(this.month));
                    return;

                case 6:
                    writer.Write(this.encoding.GetBytes(this.day));
                    return;

                case 7:
                    writer.Write(this.encoding.GetBytes(this.gender));
                    return;

                case 8:
                    writer.Write(this.encoding.GetBytes(this.publisher));
                    return;

                case 9:
                    writer.Write(this.encoding.GetBytes(this.vendor));
                    return;

                case 10:
                    writer.Write(this.cid);
                    return;

                case 11:
                    writer.Write(this.contentLength);
                    return;

                case 12:
                    writer.Write((uint) (((uint) writer.BaseStream.Position) + 4));
                    return;

                case 0x81:
                case 0x83:
                case 0x84:
                    writer.Write(this.additionalCheck);
                    return;

                case 130:
                    writer.Write((byte) 1);
                    writer.Write(this.additionalCheck);
                    return;

                case 0xf1:
                    writer.Write(Encoding.ASCII.GetBytes(“”0″0″0″0″0″0″0″0″0″0″0″0″0″0″0″0”));
                    return;
            }
        }

        public string Author
        {
            get
            {
                return this.author;
            }
            set
            {
                this.author = value;
            }
        }

        public CChapterList Chapters
        {
            get
            {
                return this.chapters;
            }
        }

        public Image Cover
        {
            get
            {
                return this.cover;
            }
            set
            {
                this.cover = value;
            }
        }

        public string Gender
        {
            get
            {
                return this.gender;
            }
            set
            {
                this.gender = value;
            }
        }

        public DateTime PublishDate
        {
            get
            {
                return this.publishDate;
            }
            set
            {
                this.publishDate = value;
            }
        }

        public string Publisher
        {
            get
            {
                return this.publisher;
            }
            set
            {
                this.publisher = value;
            }
        }

        public string Title
        {
            get
            {
                return this.title;
            }
            set
            {
                this.title = value;
            }
        }

        public string Vendor
        {
            get
            {
                return this.vendor;
            }
            set
            {
                this.vendor = value;
            }
        }

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

UMDBookReader.cs

namespace JoymoEnt.JoymoParse.umd
{
    using ICSharpCode.SharpZipLib.Zip.Compression;
    using System;
    using System.Collections;
    using System.Drawing;
    using System.IO;

    public class UMDBookReader
    {
        private uint _AdditionalCheckNumber;
        private CUMDBook _Book = null;
        private int[] _ChaptersOff = null;
        private string _Publish_Day = string.Empty;
        private string _Publish_Month = string.Empty;
        private string _Publish_Year = string.Empty;
        private int _TotalContentLen = 0;
        private ArrayList _TotalImageList = new ArrayList();
        private ArrayList _ZippedContentList = new ArrayList();

        private CChapter GetChapter(int index)
        {
            if (index != this._Book.Chapters.Count)
            {
                throw new Exception(“堆栈溢出!”);
            }
            this._Book.Chapters.Add(new CChapter());
            return this._Book.Chapters[index];
        }

        private void ParseChapterImages()
        {
            int count = 0;
            for (int i = 0; i < this._Book.Chapters.Count; i++)
            {
                if (i < (this._Book.Chapters.Count – 1))
                {
                    count = this._ChaptersOff[i + 1];
                }
                else
                {
                    count = this._TotalImageList.Count;
                }
                int num1 = this._ChaptersOff[i];
                for (int j = this._ChaptersOff[i]; j < count; j++)/*http://www.joymo.cn,角摩手机电子书*/
                {
                    this._Book.Chapters[i].AppendImage((Image) this._TotalImageList[j]);
                }
            }
            if (count < this._TotalImageList.Count)
            {
                CChapter chapter = new CChapter(“未知”, string.Empty);
                for (int k = count; k < this._TotalImageList.Count; k++)
                {
                    chapter.AppendImage((Image) this._TotalImageList[k]);
                }
                this._Book.AppendChapter(chapter);
            }
            this._TotalImageList.Clear();
        }

        private void ParseChapterTxtContents()
        {
            int destinationIndex = 0;
            byte[] destinationArray = new byte[this._TotalContentLen];
            byte[] buf = new byte[0x8000];
            foreach (byte[] buffer3 in this._ZippedContentList)
            {
                Inflater inflater = new Inflater();
                inflater.SetInput(buffer3);
                inflater.Inflate(buf);
                if (destinationIndex < destinationArray.Length)
                {
                    Array.Copy(buf, 0, destinationArray, destinationIndex, Math.Min(destinationArray.Length – destinationIndex, inflater.TotalOut));
                    destinationIndex += inflater.TotalOut;
                }
            }
            for (int i = 0; i < this._ChaptersOff.Length; i++)
            {
                int index = this._ChaptersOff[i];
                int count = 0;
                if (i < (this._ChaptersOff.Length – 1))
                {
                    count = this._ChaptersOff[i + 1] – index;
                }
                else
                {
                    count = destinationArray.Length – index;
                }
                this._Book.Chapters[i].Content = this._Book.BookEncoding.GetString(destinationArray, index, count).Replace(“”u2029”, “”r”n”);
            }
            this._ZippedContentList.Clear();
        }

        private void Read(BinaryReader reader)
        {
            if (reader.ReadUInt32() != 0xde9a9b89)
            {
                throw new ApplicationException(“Wrong header”);
            }
            short num2 = -1;
            char ch = (char) reader.PeekChar();
            while (ch == ‘#’)
            {
                reader.ReadChar();
                short segType = reader.ReadInt16();
                byte segFlag = reader.ReadByte();
                byte length = (byte) (reader.ReadByte() – 5);
                this.ReadSection(segType, segFlag, length, reader);
                switch (segType)
                {
                    case 0xf1:
                    case 10:
                        segType = num2;
                        break;
                }
                num2 = segType;
                ch = (char) reader.PeekChar();
                while (ch == ‘$’)
                {
                    reader.ReadChar();
                    uint additionalCheckNumber = reader.ReadUInt32();
                    uint num7 = reader.ReadUInt32() – 9;
                    this.ReadAdditionalSection(segType, additionalCheckNumber, num7, reader);
                    ch = (char) reader.PeekChar();
                }
                Console.WriteLine(“BEGIN”);
                Console.WriteLine((int) segType);
                Console.WriteLine(ch);
                Console.WriteLine(“END”);
            }
        }

        public CUMDBook Read(string filepath)
        {
            if (!File.Exists(filepath))
            {
                throw new Exception(“找不到” + filepath);
            }
            this._Book = new CUMDBook();
            FileStream input = new FileStream(filepath, FileMode.Open, FileAccess.Read);
            if (input.CanRead)
            {
                BinaryReader reader = new BinaryReader(input);
                try
                {
                    this.Read(reader);
                    input.Close();
                    input = null;
                    try
                    {
                        this._Book.PublishDate = new DateTime(int.Parse(this._Publish_Year), int.Parse(this._Publish_Month), int.Parse(this._Publish_Day));
                    }
                    catch (Exception)
                    {
                        this._Book.PublishDate = DateTime.Now;
                    }
                    if (this._Book.BookType[1] == 1)
                    {
                        this.ParseChapterTxtContents();
                    }
                    else if (this._Book.BookType[1] == 2)
                    {
                        this.ParseChapterImages();
                    }
                    this._Book.BookPath = filepath;
                    return this._Book;
                }
                catch (Exception exception)
                {
                    Console.WriteLine(exception.Message);
                    Console.WriteLine(exception.StackTrace);
                    this._Book = null;
                    throw exception;
                }
                finally
                {
                    reader.Close();
                    reader = null;
                }
            }
            throw new Exception(“文件正在被使用,无法读取!”);
        }

        protected virtual void ReadAdditionalSection(short segType, uint additionalCheckNumber, uint length, BinaryReader reader)
        {
            switch (segType)
            {
                case 14:
                {
                    Image image = Image.FromStream(new MemoryStream(reader.ReadBytes((int) length)));
                    this._TotalImageList.Add(image);
                    return;
                }
                case 15:
                {
                    Image image2 = Image.FromStream(new MemoryStream(reader.ReadBytes((int) length)));
                    this._TotalImageList.Add(image2);
                    return;
                }
                case 0x81:
                    reader.ReadBytes((int) length);
                    return;

                case 130:
                    this._Book.Cover = Image.FromStream(new MemoryStream(reader.ReadBytes((int) length)));
                    return;

                case 0x83:
                    this._ChaptersOff = null;
                    this._ChaptersOff = new int[length / 4];
                    for (int i = 0; i < this._ChaptersOff.Length; i++)
                    {
                        this._ChaptersOff[i] = reader.ReadInt32();
                    }
                    return;

                case 0x84:
                    if (this._AdditionalCheckNumber == additionalCheckNumber)
                    {
                        int index = 0;
                        byte[] bytes = reader.ReadBytes((int) length);
                        while (index < bytes.Length)
                        {
                            byte count = bytes[index];
                            index++;
                            this._Book.Chapters.Add(new CChapter(this._Book.BookEncoding.GetString(bytes, index, count), string.Empty));
                            index += count;
                        }
                        return;
                    }
                    this._ZippedContentList.Add(reader.ReadBytes((int) length));
                    return;
            }
            Console.WriteLine(“未知内容”);
            Console.WriteLine(“Seg Type = ” + segType);
            Console.WriteLine(“Seg Len = ” + length);
            Console.WriteLine(“content = ” + reader.ReadBytes((int) length));
        }

        protected void ReadSection(short segType, byte segFlag, byte length, BinaryReader reader)
        {
            switch (segType)
            {
                case 1:
                    this._Book.BookType[0] = reader.ReadByte();
                    this._Book.BookType[1] = this._Book.BookType[0];
                    reader.ReadInt16();
                    return;

                case 2:
                    this._Book.BookTitle = this._Book.BookEncoding.GetString(reader.ReadBytes(length));
                    return;

                case 3:
                    this._Book.Author = this._Book.BookEncoding.GetString(reader.ReadBytes(length));
                    return;

                case 4:
                    this._Publish_Year = this._Book.BookEncoding.GetString(reader.ReadBytes(length));
                    return;

                case 5:
                    this._Publish_Month = this._Book.BookEncoding.GetString(reader.ReadBytes(length));
                    return;

                case 6:
                    this._Publish_Day = this._Book.BookEncoding.GetString(reader.ReadBytes(length));
                    return;

                case 7:
                    this._Book.BookKind = this._Book.BookEncoding.GetString(reader.ReadBytes(length));
                    return;

                case 8:
                    this._Book.Publisher = this._Book.BookEncoding.GetString(reader.ReadBytes(length));
                    return;

                case 9:
                    this._Book.Vendor = this._Book.BookEncoding.GetString(reader.ReadBytes(length));
                    return;

                case 10:
                    reader.ReadInt32();
                    return;

                case 11:
                    this._TotalContentLen = reader.ReadInt32();
                    return;

                case 12:
                    reader.ReadUInt32();
                    return;

                case 13:
                    Console.WriteLine(“Seq type = ” + 13);
                    Console.WriteLine(reader.ReadUInt32());
                    return;

                case 14:
                    reader.ReadByte();
                    return;

                case 15:
                    reader.ReadBytes(length);
                    this._Book.BookType[0] = 3;
                    return;

                case 0x81:
                case 0x83:
                case 0x84:
                    this._AdditionalCheckNumber = reader.ReadUInt32();
                    return;

                case 130:
                    reader.ReadByte();
                    this._AdditionalCheckNumber = reader.ReadUInt32();
                    return;
            }
            byte[] buffer = reader.ReadBytes(length);
            Console.WriteLine(“未知编码”);
            Console.WriteLine(“Seg Type = ” + segType);
            Console.WriteLine(“Seg Flag = ” + segFlag);
            Console.WriteLine(“Seg Len = ” + length);
            Console.WriteLine(“Seg content = ” + buffer.ToString());
        }
    }
}

UMD手机电子书的读取和制作源码(一)-风君雪科技博客