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