private MobipocketDocument(PalmDatabaseFormat pdb) { if (pdb == null) { throw new ArgumentNullException("pdb"); } if (pdb.Records.Count < 1) { throw new Exception("palm database must contain at least one record"); } //set pdb this._pdb = pdb; //parse header this.Header = MobipocketHeader.FromPalmDatabase(_pdb); //parse records _records.AddRange(ParseMobipocketRecords()); }
/// <summary> /// Creates new instance of mobipocket header from provided bytes /// </summary> /// <param name="bytes"></param> /// <returns></returns> public static MobipocketHeader FromBinary(ArraySegment<byte> bytes) { if (bytes.Array == null) throw new ArgumentException("bytes array cannot be null"); var header = new MobipocketHeader(); try { using (var stream = new MemoryStream(bytes.Array, bytes.Offset, bytes.Count)) using (var reader = new BinaryReader(stream)) { if (bytes.Count < 0x80) throw new Exception("header is to small"); //palmdoc header start //Get compression header.Compression = (MobipocketCompression)Enum.ToObject(typeof(MobipocketCompression), reader.ReadUInt16(Endian.BigEndian)); //usnused zeroes reader.BaseStream.Seek(2, SeekOrigin.Current); //length of text header.TotalTextLength = reader.ReadUInt32(Endian.BigEndian); //count of dpb records that contain text header.TextRecordCount = reader.ReadUInt16(Endian.BigEndian); //maximum record size, always 4096 header.MaxRecordSize = reader.ReadUInt16(Endian.BigEndian); //read mobipocket encryption header.Encryption = (MobipocketEncryption)Enum.ToObject(typeof(MobipocketEncryption), reader.ReadUInt16(Endian.BigEndian)); //skip two zeroes reader.BaseStream.Seek(2, SeekOrigin.Current); //palmdoc header end //mobi header start //read identifier "MOBI" var identifier = reader.ReadUInt32(Endian.BigEndian); if (MobiIdentifier != identifier) throw new Exception("unsupported identifier: " + identifier); //read byte length of header var length = reader.ReadUInt32(Endian.BigEndian); //read the type of document header.Type = (MobipocketType)Enum.ToObject(typeof(MobipocketType), reader.ReadUInt32(Endian.BigEndian)); //read encoding of document header.Encoding = (MobipocketEncoding)Enum.ToObject(typeof(MobipocketEncoding), reader.ReadUInt32(Endian.BigEndian)); //read uid header.UniqueId = reader.ReadUInt32(Endian.BigEndian); //read version header.Version = reader.ReadUInt32(Endian.BigEndian); //40 0xff bytes reader.BaseStream.Seek(40, SeekOrigin.Current); //first no book record header.FirstNonTextRecord = reader.ReadUInt32(Endian.BigEndian); //offset in header of full name data header._fullNameOffset = reader.ReadUInt32(Endian.BigEndian); //length of full name data header._fullNameLength = reader.ReadUInt32(Endian.BigEndian); //locale of mobipocket file header.Locale = reader.ReadUInt32(Endian.BigEndian); //dictionary input language header.DictionaryInfo.InputLanguage = reader.ReadUInt32(Endian.BigEndian); //dictionary output language header.DictionaryInfo.OutputLanguage = reader.ReadUInt32(Endian.BigEndian); //minimal mobi pocket reader version header.MinReaderVersion = reader.ReadUInt32(Endian.BigEndian); //index of first image in pdb database header.FirtImageRecord = reader.ReadUInt32(Endian.BigEndian); //offset of huffman data header.HuffmanInfo.RecordOffset = reader.ReadUInt32(Endian.BigEndian); //count of huffman data header.HuffmanInfo.RecordCount = reader.ReadUInt32(Endian.BigEndian); //Skip 8 bytes, often zeroes reader.BaseStream.Seek(8, SeekOrigin.Current); //Check if we have exth record var exthBitField = reader.ReadUInt32(Endian.BigEndian); header._exthEnabled = ((exthBitField & 0x40) == 0x40); if (length > 0x80) { byte[] data = new byte[32]; reader.Read(data, 0, 32); // DRM Offset var drmOffset = reader.ReadUInt32(Endian.BigEndian); // DRM Count var drmCount = reader.ReadUInt32(Endian.BigEndian); // DRM Size var drmSize = reader.ReadUInt32(Endian.BigEndian); // DRM Flags var drmFlags = reader.ReadUInt32(Endian.BigEndian); header.Drm = new MobipocketDrm(drmOffset, drmCount, drmSize, drmFlags); header.Drm.Parse(bytes); } //read trailing byte flags if present if (length > 228) { reader.BaseStream.Seek(0xf2, SeekOrigin.Begin); header.TrailingEntries = reader.ReadUInt16(Endian.BigEndian); } //read full name reader.BaseStream.Seek(header._fullNameOffset, SeekOrigin.Begin); var nameBuffer = new byte[header._fullNameLength]; checked { reader.Read(nameBuffer, 0, (int)header._fullNameLength); } header.FullName = header.GetString(nameBuffer); //mobi header end if (header._exthEnabled) { //exth header start //header.Data, length + 16 checked { Exth = ExthHeader.FromBinary(new ArraySegment<byte>(bytes.Array, bytes.Offset + (int)length + 16, bytes.Count - (int)length - 16)); } //exth headet end } } return header; } catch (Exception e) { throw new Exception("cannot parse mobipocket header from binary", e); } }
/// <summary> /// Creates new instance of mobipocket header from provided bytes /// </summary> /// <param name="bytes"></param> /// <returns></returns> public static MobipocketHeader FromBinary(ArraySegment <byte> bytes) { if (bytes.Array == null) { throw new ArgumentException("bytes array cannot be null"); } var header = new MobipocketHeader(); try { using (var stream = new MemoryStream(bytes.Array, bytes.Offset, bytes.Count)) using (var reader = new BinaryReader(stream)) { if (bytes.Count < 0x80) { throw new Exception("header is to small"); } //palmdoc header start //Get compression header.Compression = (MobipocketCompression)Enum.ToObject(typeof(MobipocketCompression), reader.ReadUInt16(Endian.BigEndian)); //usnused zeroes reader.BaseStream.Seek(2, SeekOrigin.Current); //length of text header.TotalTextLength = reader.ReadUInt32(Endian.BigEndian); //count of dpb records that contain text header.TextRecordCount = reader.ReadUInt16(Endian.BigEndian); //maximum record size, always 4096 header.MaxRecordSize = reader.ReadUInt16(Endian.BigEndian); //read mobipocket encryption header.Encryption = (MobipocketEncryption)Enum.ToObject(typeof(MobipocketEncryption), reader.ReadUInt16(Endian.BigEndian)); //skip two zeroes reader.BaseStream.Seek(2, SeekOrigin.Current); //palmdoc header end //mobi header start //read identifier "MOBI" var identifier = reader.ReadUInt32(Endian.BigEndian); if (MobiIdentifier != identifier) { throw new Exception("unsupported identifier: " + identifier); } //read byte length of header var length = reader.ReadUInt32(Endian.BigEndian); //read the type of document header.Type = (MobipocketType)Enum.ToObject(typeof(MobipocketType), reader.ReadUInt32(Endian.BigEndian)); //read encoding of document header.Encoding = (MobipocketEncoding)Enum.ToObject(typeof(MobipocketEncoding), reader.ReadUInt32(Endian.BigEndian)); //read uid header.UniqueId = reader.ReadUInt32(Endian.BigEndian); //read version header.Version = reader.ReadUInt32(Endian.BigEndian); //40 0xff bytes reader.BaseStream.Seek(40, SeekOrigin.Current); //first no book record header.FirstNonTextRecord = reader.ReadUInt32(Endian.BigEndian); //offset in header of full name data header._fullNameOffset = reader.ReadUInt32(Endian.BigEndian); //length of full name data header._fullNameLength = reader.ReadUInt32(Endian.BigEndian); //locale of mobipocket file header.Locale = reader.ReadUInt32(Endian.BigEndian); //dictionary input language header.DictionaryInfo.InputLanguage = reader.ReadUInt32(Endian.BigEndian); //dictionary output language header.DictionaryInfo.OutputLanguage = reader.ReadUInt32(Endian.BigEndian); //minimal mobi pocket reader version header.MinReaderVersion = reader.ReadUInt32(Endian.BigEndian); //index of first image in pdb database header.FirtImageRecord = reader.ReadUInt32(Endian.BigEndian); //offset of huffman data header.HuffmanInfo.RecordOffset = reader.ReadUInt32(Endian.BigEndian); //count of huffman data header.HuffmanInfo.RecordCount = reader.ReadUInt32(Endian.BigEndian); //Skip 8 bytes, often zeroes reader.BaseStream.Seek(8, SeekOrigin.Current); //Check if we have exth record var exthBitField = reader.ReadUInt32(Endian.BigEndian); header._exthEnabled = ((exthBitField & 0x40) == 0x40); if (length > 0x80) { byte[] data = new byte[32]; reader.Read(data, 0, 32); // DRM Offset var drmOffset = reader.ReadUInt32(Endian.BigEndian); // DRM Count var drmCount = reader.ReadUInt32(Endian.BigEndian); // DRM Size var drmSize = reader.ReadUInt32(Endian.BigEndian); // DRM Flags var drmFlags = reader.ReadUInt32(Endian.BigEndian); header.Drm = new MobipocketDrm(drmOffset, drmCount, drmSize, drmFlags); header.Drm.Parse(bytes); } //read trailing byte flags if present if (length > 228) { reader.BaseStream.Seek(0xf2, SeekOrigin.Begin); header.TrailingEntries = reader.ReadUInt16(Endian.BigEndian); } //read full name reader.BaseStream.Seek(header._fullNameOffset, SeekOrigin.Begin); var nameBuffer = new byte[header._fullNameLength]; checked { reader.Read(nameBuffer, 0, (int)header._fullNameLength); } header.FullName = header.GetString(nameBuffer); //mobi header end if (header._exthEnabled) { //exth header start //header.Data, length + 16 checked { Exth = ExthHeader.FromBinary(new ArraySegment <byte>(bytes.Array, bytes.Offset + (int)length + 16, bytes.Count - (int)length - 16)); } //exth headet end } } return(header); } catch (Exception e) { throw new Exception("cannot parse mobipocket header from binary", e); } }