1 /* This file is part of the KDE project
2    Copyright (C) 2012 Mojtaba Shahi Senobari <mojtaba.shahi3000@gmail.com>
3 
4    This library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Library General Public
6    License as published by the Free Software Foundation; either
7    version 2 of the License, or (at your option) any later version.
8 
9    This library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Library General Public License for more details.
13 
14    You should have received a copy of the GNU Library General Public License
15    along with this library; see the file COPYING.LIB.  If not, write to
16    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18 */
19 
20 #ifndef MOBIHEADERGENERATOR_H
21 #define MOBIHEADERGENERATOR_H
22 
23 #include <QObject>
24 #include <QHash>
25 #include <QChar>
26 
27 // I follow the file structure that mobi packet creator  create.
28 struct palmDBHeader {
29     palmDBHeader();
30 
31     /// database name. This name is 0 terminated in the field and will be used as the file name on a computer.
32     /// For eBooks this usually contains the title and may have the author depending on the length available.
33     QByteArray title;
34 
35     /** bit field.
36         0x0002 Read-Only
37         0x0004 Dirty AppInfoArea
38         0x0008 Backup this database (i.e. no conduit exists)
39         0x0010 (16 decimal) Okay to install newer over existing copy, if present on PalmPilot
40         0x0020 (32 decimal) Force the PalmPilot to reset after this database is installed
41         0x0040 (64 decimal) Don't allow copy of file to be beamed to other Pilot.
42         */
43     qint16 attributes;
44 
45     qint16 version; /// file version
46     qint32 creationDate; /// No. of seconds since start of January 1, 1904.
47     qint32 modificationDate; /// No. of seconds since start of January 1, 1904.
48     qint32 lastBackupDate; /// 	No. of seconds since start of January 1, 1904.
49     qint32 modificationNumber;
50     qint32 appInfoId; /// offset to start of Application Info (if present) or null
51     qint32 sortInfoId; /// offset to start of Sort Info (if present) or null
52     QByteArray type;
53     QByteArray creator;
54     qint32 uniqueIdSeed; /// used internally to identify record
55     qint32 nextRecordIdList; /// Only used when in-memory on Palm OS. Always set to zero in stored files.
56     qint16 numberOfRecords; /// number of records in the file - N
57 
58     // This will repeate of record numbers.
59     qint32 recordOffset; /// the offset of record n from the start of the PDB of this record
60     int recordUniqueId; /// The unique ID for this record. Often just a sequential count from 0
61     // Format: QHash<recordOffset, recorUniqueId>
62     QHash<int, int> recordsInfo;
63     //
64 
65     // There should two bytes zero
66 
67     int headerLength; // This is not in header just to have header length for myself
68     //qint32 grapToData; /// traditionally 2 zero bytes to Info or raw data
69 };
70 
71 /// PalmDocHeadr length = 16
72 struct palmDocHeader
73 {
74     palmDocHeader();
75 
76     qint16 compression;  /// 1 == no compression, 2 = PalmDOC compression, 17480 = HUFF/CDIC compression
77     qint16 unused; /// Always zero
78     qint32 textLength;
79     qint16 pdbrecordCount;
80     qint16 maxRecordSize;/// Maximum size of each record containing text, always 4096
81 
82     /// 0 == no encryption, 1 = Old Mobipocket
83     /// Encryption, 2 = Mobipocket Encryption
84     qint16 encryptionType;
85 
86     qint16 unknown;/// Usually zero
87     qint32 headerLength; // This is not in header just to have header length for myself
88 };
89 
90 /// mobi header length 232
91 struct mobiHeader
92 {
93     mobiHeader();
94 
95     QByteArray identifier; /// 	the characters M O B I
96     int mobiHeaderLength;// = 232;
97     qint32 mobiType;// = 2;
98     /**  The kind of Mobipocket file this is
99         2 Mobipocket Book
100         3 PalmDoc Book
101         4 Audio
102         232 mobipocket? generated by kindlegen1.2
103         248 KF8: generated by kindlegen2
104         257 News
105         258 News_Feed
106         259 News_Magazine
107         513 PICS
108         514 WORD
109         515 XLS
110         516 PPT
111         517 TEXT
112         518 HTML
113     */
114     qint32 textEncoding; /// 1252 = CP1252 (WinLatin1); 65001 = UTF-8
115     qint32 uniqueId; /// Some kind of unique ID number
116 
117     // FIXME: Really i do not know what should i set for this parameter.
118     qint32 fileVersion; /// Version of the Mobipocket format used in this file.
119 
120     qint32 ortographicIndex;/// Section number of orthographic meta index. 0xFFFFFFFF if index is not available.
121     qint32 inflectionIndex;/// Section number of inflection meta index. 0xFFFFFFFF if index is not available.
122     qint32 indexNames;/// 0xFFFFFFFF if index is not available.
123     qint32 indexkeys;/// 0xFFFFFFFF if index is not available.
124     qint32 extraIndex0;/// Section number of extra 0 meta index. 0xFFFFFFFF if index is not available.
125     qint32 extraIndex1;/// Section number of extra 0 meta index. 0xFFFFFFFF if index is not available.
126     qint32 extraIndex2;/// Section number of extra 0 meta index. 0xFFFFFFFF if index is not available.
127     qint32 extraIndex3;/// Section number of extra 0 meta index. 0xFFFFFFFF if index is not available.
128     qint32 extraIndex4;/// Section number of extra 0 meta index. 0xFFFFFFFF if index is not available.
129     qint32 extraIndex5;/// Section number of extra 0 meta index. 0xFFFFFFFF if index is not available.
130 
131     qint32 firstNonBookIndex; /// First record number (starting with 0) that's not the book's text
132 
133     qint32 fullNameOffset; /// Offset in record 0 (not from start of file) of the full name of the book
134     qint32 fullNameLength; /// Length in bytes of the full name of the book
135 
136     /// Book locale code. Low byte is main language 09= English,
137     /// next byte is dialect, 08 = British, 04 = US.
138     /// Thus US English is 1033, UK English is 2057.
139     qint32 local;
140     qint32 inputLanguage;/// Input language for a dictionary
141     qint32 outputLanguage;/// Output language for a dictionary
142     qint32 minversion;/// Minimum mobipocket version support needed to read this file.
143 
144     /// First record number (starting with 0) that contains an image.
145     /// Image records should be sequential.
146     qint32 firstImageIndex;
147     qint32 huffmanRecordOffset;/// The record number of the first huffman compression record.
148     qint32 huffmanRecordCount;/// The number of huffman compression records.
149     qint32 huffmanTableOffset;// = 0;
150     qint32 huffmanTableLength;// = 0;
151 
152     qint32 EXTH_Flags;/// bitfield. if bit 6 (0x40) is set, then there's an EXTH record
153 
154     // Here there is 32 byte
155     qint64 unknown1;// = 0;
156     qint64 unknown1_1;// = 0;
157     qint64 unknown1_2;// = 0;
158     qint64 unknown1_3;// = 0;
159 
160     qint32 drmOffset;/// Offset to DRM key info in DRMed files. 0xFFFFFFFF if no DRM
161     qint32 drmCount;/// Number of entries in DRM info. 0xFFFFFFFF if no DRM
162     qint32 drmSize;/// Number of bytes in DRM info.
163     qint32 drmFlags;/// Some flags concerning the DRM info.
164 
165     // Here there is 12 byte unknown
166     qint64 unknown2;// = 0;
167     qint32 unknown2_1;// = 0;
168 
169     qint16 firstContentRecordNumber;/// Number of first text record. Normally 1.
170     qint16 lastContentRecordNumber; /// Last content record number
171 
172     qint32 unknown3;/// Use 0x00000001.
173 
174     qint32 FCIS_recordNumber;
175     qint32 unknown4;/// Use 0x00000001.
176 
177     qint32 FLIS_recordNumber;
178     qint32 unknown5;/// Use 0x00000001.
179 
180     qint64 unknown6;/// Use 0x0000000000000000.
181     qint32 unknown7;/// Use 0xFFFFFFFF.
182     qint32 unknown8;/// Use 0x00000000.
183     qint32 unknown9;/// Use 0xFFFFFFFF.
184     qint32 unknown10;/// Use 0xFFFFFFFF.
185     qint32 extraRecordDataFlags;// = 0;
186 
187     /// (If not 0xFFFFFFFF)The record number of the
188     /// first INDX record created from an ncx file.
189     qint32 INDX_recordOffset;
190 };
191 struct exthHeader {
192     exthHeader();
193 
194     QByteArray identifier; /// the characters E X T H.
195 
196     /// the length of the EXTH header, including
197     /// the previous 4 bytes - but not including the final padding.
198     int headerLength;
199 
200     /// The number of records in the EXTH header. the rest of the EXTH header
201     /// consists of repeated EXTH records to the end of the EXTH length.
202     qint32 exthRecordCount;
203 
204     // EXTH record start
205     qint32 recordType; /// 	Exth Record type. Just a number identifying what's stored in the record
206 
207     /// length of EXTH record = L , including the 8 bytes in
208     /// the type and length fields
209 
210     int pad;
211     QHash<qint32, QByteArray> exthRecord;
212 };
213 
214 class MobiHeaderGenerator
215 {
216 public:
217     MobiHeaderGenerator();
218     ~MobiHeaderGenerator();
219 
220     void generateMobiHeaders(QHash<QString, QString> metaData
221                              ,int compressedTextSize, int uncompressedTextSize,
222                              QList<int> imagesSize, QList<qint32> textRecordsOffset);
223 
224 public:
225     palmDBHeader *m_dbHeader;
226     palmDocHeader *m_docHeader;
227     mobiHeader *m_mobiHeader;
228     exthHeader *m_exthHeader;
229 
230     QByteArray m_title;
231 
232 private:
233     void generatePalmDataBase();
234     void generatePalmDocHeader();
235     void generateMobiHeader();
236     void generateEXTH();
237     int calculateRecordsCount();
238 
239 private:
240 
241     QByteArray m_author;
242     int m_rawTextSize;
243     int m_uncompressedTextSize;
244     QList<int> m_imgListSize;
245     QList<qint32> m_textRecordsOffset;
246 };
247 
248 #endif // MOBIHEADERGENERATOR_H
249