Пример #1
0
        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());
        }
Пример #2
0
        /// <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);
            }
        }
Пример #3
0
        /// <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);
            }
        }