1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /*
3  * This file is part of the libe-book project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  */
9 
10 #include <string>
11 
12 #include "libebook_utils.h"
13 #include "EBOOKCharsetConverter.h"
14 #include "EBOOKMemoryStream.h"
15 #include "EBOOKZlibStream.h"
16 #include "PDBLZ77Stream.h"
17 #include "PluckerParser.h"
18 
19 using std::unique_ptr;
20 using std::shared_ptr;
21 
22 using std::vector;
23 
24 namespace libebook
25 {
26 
27 namespace
28 {
29 
30 static const uint32_t PLUCKER_TYPE = PDB_CODE("Data");
31 static const uint32_t PLUCKER_CREATOR = PDB_CODE("Plkr");
32 
33 static const uint32_t APPINFO_SIGNATURE = 0x6c6e6368;
34 
35 enum Compression
36 {
37   COMPRESSION_UNKNOWN,
38   COMPRESSION_LZ77,
39   COMPRESSION_ZLIB
40 };
41 
42 enum DataType
43 {
44   DATA_TYPE_PHTML,
45   DATA_TYPE_PHTML_COMPRESSED,
46   DATA_TYPE_TBMP,
47   DATA_TYPE_TBMP_COMPRESSED,
48   DATA_TYPE_MAILTO,
49   DATA_TYPE_LINK_INDEX,
50   DATA_TYPE_LINKS,
51   DATA_TYPE_LINKS_COMPRESSED,
52   DATA_TYPE_BOOKMARKS,
53   DATA_TYPE_CATEGORY,
54   DATA_TYPE_METADATA,
55   DATA_TYPE_LAST = DATA_TYPE_METADATA,
56   DATA_TYPE_UNKNOWN = 0xff
57 };
58 
59 enum FunctionCode
60 {
61   LINK_END = 0x8,
62   PAGE_LINK_BEGIN = 0xa,
63   PARAGRAPH_LINK_BEGIN = 0xc,
64   SET_FONT = 0x11,
65   EMBEDDED_IMAGE = 0x1a,
66   SET_MARGIN = 0x22,
67   TEXT_ALIGNMENT = 0x29,
68   HORIZONTAL_RULE = 0x33,
69   NEW_LINE = 0x38,
70   ITALIC_BEGIN = 0x40,
71   ITALIC_END = 0x48,
72   UNKNOWN_53 = 0x53,
73   MULTIPLE_EMBEDDED_IMAGE = 0x5c,
74   UNDERLINE_BEGIN = 0x60,
75   UNDERLINE_END = 0x68,
76   STRIKETHROUGH_BEGIN = 0x70,
77   STRIKETHROUGH_END = 0x78
78 };
79 
80 enum TextAlignment
81 {
82   TEXT_ALIGNMENT_LEFT,
83   TEXT_ALIGNMENT_RIGHT,
84   TEXT_ALIGNMENT_CENTER,
85   TEXT_ALIGNMENT_LAST = TEXT_ALIGNMENT_CENTER
86 };
87 
88 enum Font
89 {
90   FONT_REGULAR,
91   FONT_H1,
92   FONT_H2,
93   FONT_H3,
94   FONT_H4,
95   FONT_H5,
96   FONT_H6,
97   FONT_BOLD,
98   FONT_FIXED_WIDTH,
99   FONT_LAST = FONT_FIXED_WIDTH
100 };
101 
102 typedef std::map<unsigned, unsigned> ExceptionalCharsetMap_t;
103 
104 // source: http://www.iana.org/assignments/character-sets/character-sets.xhtml (2013)
105 static const char *const IANA_CHARSETS[] =
106 {
107   /* 0 */
108   nullptr, nullptr, nullptr,
109   "US-ASCII",
110   "ISO_8859-1:1987",
111   "ISO_8859-2:1987",
112   "ISO_8859-3:1988",
113   "ISO_8859-4:1988",
114   "ISO_8859-5:1988",
115   "ISO_8859-6:1987",
116   /* 10 */
117   "ISO_8859-7:1987",
118   "ISO_8859-8:1988",
119   "ISO_8859-9:1989",
120   "ISO-8859-10",
121   "ISO_6937-2-add",
122   "JIS_X0201",
123   "JIS_Encoding",
124   "Shift_JIS",
125   "Extended_UNIX_Code_Packed_Format_for_Japanese",
126   "Extended_UNIX_Code_Fixed_Width_for_Japanese",
127   /* 20 */
128   "BS_4730",
129   "SEN_850200_C",
130   "IT",
131   "ES",
132   "DIN_66003",
133   "NS_4551-1",
134   "NF_Z_62-010",
135   "ISO-10646-UTF-1",
136   "ISO_646.basic:1983",
137   "INVARIANT",
138   /* 30 */
139   "ISO_646.irv:1983",
140   "NATS-SEFI",
141   "NATS-SEFI-ADD",
142   "NATS-DANO",
143   "NATS-DANO-ADD",
144   "SEN_850200_B",
145   "KS_C_5601-1987",
146   "ISO-2022-KR",
147   "EUC-KR",
148   "ISO-2022-JP",
149   /* 40 */
150   "ISO-2022-JP-2",
151   "JIS_C6220-1969-jp",
152   "JIS_C6220-1969-ro",
153   "PT",
154   "greek7-old",
155   "latin-greek",
156   "NF_Z_62-010_(1973)",
157   "Latin-greek-1",
158   "ISO_5427",
159   "JIS_C6226-1978",
160   /* 50 */
161   "BS_viewdata",
162   "INIS",
163   "INIS-8",
164   "INIS-cyrillic",
165   "ISO_5427:1981",
166   "ISO_5428:1980",
167   "GB_1988-80",
168   "GB_2312-80",
169   "NS_4551-2",
170   "videotex-suppl",
171   /* 60 */
172   "PT2",
173   "ES2",
174   "MSZ_7795.3",
175   "JIS_C6226-1983",
176   "greek7",
177   "ASMO_449",
178   "iso-ir-90",
179   "JIS_C6229-1984-a",
180   "JIS_C6229-1984-b",
181   "JIS_C6229-1984-b-add",
182   /* 70 */
183   "JIS_C6229-1984-hand",
184   "JIS_C6229-1984-hand-add",
185   "JIS_C6229-1984-kana",
186   "ISO_2033-1983",
187   "ANSI_X3.110-1983",
188   "T.61-7bit",
189   "T.61-8bit",
190   "ECMA-cyrillic",
191   "CSA_Z243.4-1985-1",
192   "CSA_Z243.4-1985-2",
193   /* 80 */
194   "CSA_Z243.4-1985-gr",
195   "ISO_8859-6-E",
196   "ISO_8859-6-I",
197   "T.101-G2",
198   "ISO_8859-8-E",
199   "ISO_8859-8-I",
200   "CSN_369103",
201   "JUS_I.B1.002",
202   "IEC_P27-1",
203   "JUS_I.B1.003-serb",
204   /* 90 */
205   "JUS_I.B1.003-mac",
206   "greek-ccitt",
207   "NC_NC00-10:81",
208   "ISO_6937-2-25",
209   "GOST_19768-74",
210   "ISO_8859-supp",
211   "ISO_10367-box",
212   "latin-lap",
213   "JIS_X0212-1990",
214   "DS_2089",
215   /* 100 */
216   "us-dk",
217   "dk-us",
218   "KSC5636",
219   "UNICODE-1-1-UTF-7",
220   "ISO-2022-CN",
221   "ISO-2022-CN-EXT",
222   "UTF-8",
223   nullptr, nullptr,
224   "ISO-8859-13",
225   /* 110 */
226   "ISO-8859-14",
227   "ISO-8859-15",
228   "ISO-8859-16",
229   "GBK",
230   "GB18030",
231   "OSD_EBCDIC_DF04_15",
232   "OSD_EBCDIC_DF03_IRV",
233   "OSD_EBCDIC_DF04_1",
234   "ISO-11548-1",
235   "KZ-1048",
236   /* 120 */
237   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
238   /* 130 */
239   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
240   /* 140 */
241   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
242   /* 150 */
243   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
244   /* 160 */
245   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
246   /* 170 */
247   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
248   /* 180 */
249   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
250   /* 190 */
251   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
252   /* 200 */
253   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
254   /* 210 */
255   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
256   /* 220 */
257   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
258   /* 230 */
259   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
260   /* 240 */
261   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
262   /* 250 */
263   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
264   /* 260 */
265   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
266   /* 270 */
267   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
268   /* 280 */
269   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
270   /* 290 */
271   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
272   /* 300 */
273   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
274   /* 310 */
275   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
276   /* 320 */
277   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
278   /* 330 */
279   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
280   /* 340 */
281   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
282   /* 350 */
283   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
284   /* 360 */
285   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
286   /* 370 */
287   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
288   /* 380 */
289   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
290   /* 390 */
291   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
292   /* 400 */
293   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
294   /* 410 */
295   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
296   /* 420 */
297   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
298   /* 430 */
299   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
300   /* 440 */
301   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
302   /* 450 */
303   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
304   /* 460 */
305   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
306   /* 470 */
307   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
308   /* 480 */
309   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
310   /* 490 */
311   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
312   /* 500 */
313   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
314   /* 510 */
315   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
316   /* 520 */
317   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
318   /* 530 */
319   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
320   /* 540 */
321   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
322   /* 550 */
323   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
324   /* 560 */
325   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
326   /* 570 */
327   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
328   /* 580 */
329   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
330   /* 590 */
331   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
332   /* 600 */
333   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
334   /* 610 */
335   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
336   /* 620 */
337   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
338   /* 630 */
339   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
340   /* 640 */
341   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
342   /* 650 */
343   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
344   /* 660 */
345   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
346   /* 670 */
347   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
348   /* 680 */
349   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
350   /* 690 */
351   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
352   /* 700 */
353   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
354   /* 710 */
355   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
356   /* 720 */
357   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
358   /* 730 */
359   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
360   /* 740 */
361   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
362   /* 750 */
363   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
364   /* 760 */
365   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
366   /* 770 */
367   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
368   /* 780 */
369   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
370   /* 790 */
371   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
372   /* 800 */
373   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
374   /* 810 */
375   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
376   /* 820 */
377   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
378   /* 830 */
379   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
380   /* 840 */
381   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
382   /* 850 */
383   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
384   /* 860 */
385   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
386   /* 870 */
387   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
388   /* 880 */
389   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
390   /* 890 */
391   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
392   /* 900 */
393   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
394   /* 910 */
395   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
396   /* 920 */
397   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
398   /* 930 */
399   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
400   /* 940 */
401   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
402   /* 950 */
403   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
404   /* 960 */
405   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
406   /* 970 */
407   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
408   /* 980 */
409   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
410   /* 990 */
411   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
412   /* 1000 */
413   "ISO-10646-UCS-2",
414   "ISO-10646-UCS-4",
415   "ISO-10646-UCS-Basic",
416   "ISO-10646-Unicode-Latin1",
417   "ISO-10646-J-1",
418   "ISO-Unicode-IBM-1261",
419   "ISO-Unicode-IBM-1268",
420   "ISO-Unicode-IBM-1276",
421   "ISO-Unicode-IBM-1264",
422   "ISO-Unicode-IBM-1265",
423   /* 1010 */
424   "UNICODE-1-1",
425   "SCSU",
426   "UTF-7",
427   "UTF-16BE",
428   "UTF-16LE",
429   "UTF-16",
430   "CESU-8",
431   "UTF-32",
432   "UTF-32BE",
433   "UTF-32LE",
434   /* 1020 */
435   "BOCU-1",
436   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
437   /* 1030 */
438   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
439   /* 1040 */
440   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
441   /* 1050 */
442   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
443   /* 1060 */
444   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
445   /* 1070 */
446   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
447   /* 1080 */
448   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
449   /* 1090 */
450   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
451   /* 1100 */
452   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
453   /* 1110 */
454   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
455   /* 1120 */
456   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
457   /* 1130 */
458   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
459   /* 1140 */
460   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
461   /* 1150 */
462   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
463   /* 1160 */
464   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
465   /* 1170 */
466   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
467   /* 1180 */
468   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
469   /* 1190 */
470   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
471   /* 1200 */
472   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
473   /* 1210 */
474   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
475   /* 1220 */
476   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
477   /* 1230 */
478   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
479   /* 1240 */
480   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
481   /* 1250 */
482   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
483   /* 1260 */
484   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
485   /* 1270 */
486   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
487   /* 1280 */
488   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
489   /* 1290 */
490   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
491   /* 1300 */
492   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
493   /* 1310 */
494   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
495   /* 1320 */
496   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
497   /* 1330 */
498   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
499   /* 1340 */
500   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
501   /* 1350 */
502   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
503   /* 1360 */
504   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
505   /* 1370 */
506   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
507   /* 1380 */
508   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
509   /* 1390 */
510   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
511   /* 1400 */
512   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
513   /* 1410 */
514   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
515   /* 1420 */
516   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
517   /* 1430 */
518   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
519   /* 1440 */
520   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
521   /* 1450 */
522   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
523   /* 1460 */
524   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
525   /* 1470 */
526   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
527   /* 1480 */
528   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
529   /* 1490 */
530   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
531   /* 1500 */
532   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
533   /* 1510 */
534   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
535   /* 1520 */
536   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
537   /* 1530 */
538   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
539   /* 1540 */
540   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
541   /* 1550 */
542   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
543   /* 1560 */
544   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
545   /* 1570 */
546   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
547   /* 1580 */
548   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
549   /* 1590 */
550   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
551   /* 1600 */
552   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
553   /* 1610 */
554   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
555   /* 1620 */
556   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
557   /* 1630 */
558   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
559   /* 1640 */
560   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
561   /* 1650 */
562   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
563   /* 1660 */
564   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
565   /* 1670 */
566   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
567   /* 1680 */
568   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
569   /* 1690 */
570   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
571   /* 1700 */
572   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
573   /* 1710 */
574   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
575   /* 1720 */
576   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
577   /* 1730 */
578   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
579   /* 1740 */
580   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
581   /* 1750 */
582   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
583   /* 1760 */
584   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
585   /* 1770 */
586   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
587   /* 1780 */
588   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
589   /* 1790 */
590   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
591   /* 1800 */
592   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
593   /* 1810 */
594   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
595   /* 1820 */
596   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
597   /* 1830 */
598   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
599   /* 1840 */
600   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
601   /* 1850 */
602   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
603   /* 1860 */
604   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
605   /* 1870 */
606   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
607   /* 1880 */
608   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
609   /* 1890 */
610   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
611   /* 1900 */
612   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
613   /* 1910 */
614   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
615   /* 1920 */
616   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
617   /* 1930 */
618   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
619   /* 1940 */
620   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
621   /* 1950 */
622   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
623   /* 1960 */
624   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
625   /* 1970 */
626   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
627   /* 1980 */
628   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
629   /* 1990 */
630   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
631   /* 2000 */
632   "ISO-8859-1-Windows-3.0-Latin-1",
633   "ISO-8859-1-Windows-3.1-Latin-1",
634   "ISO-8859-2-Windows-Latin-2",
635   "ISO-8859-9-Windows-Latin-5",
636   "hp-roman8",
637   "Adobe-Standard-Encoding",
638   "Ventura-US",
639   "Ventura-International",
640   "DEC-MCS",
641   "IBM850",
642   /* 2010 */
643   "IBM852",
644   "IBM437",
645   "PC8-Danish-Norwegian",
646   "IBM862",
647   "PC8-Turkish",
648   "IBM-Symbols",
649   "IBM-Thai",
650   "HP-Legal",
651   "HP-Pi-font",
652   "HP-Math8",
653   /* 2020 */
654   "Adobe-Symbol-Encoding",
655   "HP-DeskTop",
656   "Ventura-Math",
657   "Microsoft-Publishing",
658   "Windows-31J",
659   "GB2312",
660   "Big5",
661   "macintosh",
662   "IBM037",
663   "IBM038",
664   /* 2030 */
665   "IBM273",
666   "IBM274",
667   "IBM275",
668   "IBM277",
669   "IBM278",
670   "IBM280",
671   "IBM281",
672   "IBM284",
673   "IBM285",
674   "IBM290",
675   /* 2040 */
676   "IBM297",
677   "IBM420",
678   "IBM423",
679   "IBM424",
680   "IBM500",
681   "IBM851",
682   "IBM855",
683   "IBM857",
684   "IBM860",
685   "IBM861",
686   /* 2050 */
687   "IBM863",
688   "IBM864",
689   "IBM865",
690   "IBM868",
691   "IBM869",
692   "IBM870",
693   "IBM871",
694   "IBM880",
695   "IBM891",
696   "IBM903",
697   /* 2060 */
698   "IBM904",
699   "IBM905",
700   "IBM918",
701   "IBM1026",
702   "EBCDIC-AT-DE",
703   "EBCDIC-AT-DE-A",
704   "EBCDIC-CA-FR",
705   "EBCDIC-DK-NO",
706   "EBCDIC-DK-NO-A",
707   "EBCDIC-FI-SE",
708   /* 2070 */
709   "EBCDIC-FI-SE-A",
710   "EBCDIC-FR",
711   "EBCDIC-IT",
712   "EBCDIC-PT",
713   "EBCDIC-ES",
714   "EBCDIC-ES-A",
715   "EBCDIC-ES-S",
716   "EBCDIC-UK",
717   "EBCDIC-US",
718   "UNKNOWN-8BIT",
719   /* 2080 */
720   "MNEMONIC",
721   "MNEM",
722   "VISCII",
723   "VIQR",
724   "KOI8-R",
725   "HZ-GB-2312",
726   "IBM866",
727   "IBM775",
728   "KOI8-U",
729   "IBM00858",
730   /* 2090 */
731   "IBM00924",
732   "IBM01140",
733   "IBM01141",
734   "IBM01142",
735   "IBM01143",
736   "IBM01144",
737   "IBM01145",
738   "IBM01146",
739   "IBM01147",
740   "IBM01148",
741   /* 2100 */
742   "IBM01149",
743   "Big5-HKSCS",
744   "IBM1047",
745   "PTCP154",
746   "Amiga-1251",
747   "KOI7-switched",
748   "BRF",
749   "TSCII",
750   "CP51932",
751   "windows-874",
752   /* 2110 */
753   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
754   /* 2120 */
755   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
756   /* 2130 */
757   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
758   /* 2140 */
759   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
760   /* 2150 */
761   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
762   /* 2160 */
763   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
764   /* 2170 */
765   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
766   /* 2180 */
767   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
768   /* 2190 */
769   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
770   /* 2200 */
771   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
772   /* 2210 */
773   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
774   /* 2220 */
775   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
776   /* 2230 */
777   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
778   /* 2240 */
779   nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
780   /* 2250 */
781   "windows-1250",
782   "windows-1251",
783   "windows-1252",
784   "windows-1253",
785   "windows-1254",
786   "windows-1255",
787   "windows-1256",
788   "windows-1257",
789   "windows-1258",
790   "TIS-620",
791   /* 2260 */
792   "CP50220",
793 };
794 
795 }
796 
797 }
798 
799 namespace libebook
800 {
801 namespace
802 {
803 
804 struct PluckerAttributes
805 {
806   PluckerAttributes();
807 
808   Font font;
809   unsigned leftMargin;
810   unsigned rightMargin;
811   TextAlignment textAlignment;
812   bool italic;
813   bool underline;
814   bool strikethrough;
815 };
816 
PluckerAttributes()817 PluckerAttributes::PluckerAttributes()
818   : font(FONT_REGULAR)
819   , leftMargin(0)
820   , rightMargin(0)
821   , textAlignment(TEXT_ALIGNMENT_LEFT)
822   , italic(false)
823   , underline(false)
824   , strikethrough(false)
825 {
826 }
827 
makeParagraphProperties(const PluckerAttributes & attributes)828 librevenge::RVNGPropertyList makeParagraphProperties(const PluckerAttributes &attributes)
829 {
830   librevenge::RVNGPropertyList props;
831 
832   switch (attributes.textAlignment)
833   {
834   case TEXT_ALIGNMENT_LEFT :
835     props.insert("fo:text-align", "left");
836     break;
837   case TEXT_ALIGNMENT_RIGHT :
838     props.insert("fo:text-align", "end");
839     break;
840   case TEXT_ALIGNMENT_CENTER :
841     props.insert("fo:text-align", "center");
842     break;
843   default:
844     break;
845   }
846 
847   return props;
848 }
849 
makeCharacterProperties(const PluckerAttributes & attributes)850 librevenge::RVNGPropertyList makeCharacterProperties(const PluckerAttributes &attributes)
851 {
852   librevenge::RVNGPropertyList props;
853 
854   if (attributes.italic)
855     props.insert("fo:font-style", "italic");
856 
857   if (attributes.underline)
858     props.insert("style:text-underline-type", "single");
859 
860   if (attributes.strikethrough)
861     props.insert("style:text-line-through-type", "single");
862 
863   if (((FONT_H1 <= attributes.font) && (FONT_H6 >= attributes.font)) || (FONT_BOLD == attributes.font))
864     props.insert("fo:font-weight", "bold");
865 
866   return props;
867 }
868 
869 class MarkupParser
870 {
871   // -Weffc++
872   MarkupParser(const MarkupParser &other);
873   MarkupParser &operator=(const MarkupParser &other);
874 
875 public:
876   MarkupParser(librevenge::RVNGTextInterface *document, const PluckerImageMap_t &imageMap);
877   ~MarkupParser();
878 
879   /** Parse an input stream.
880     *
881     * The function can be called more than once. In that case, the
882     * parsing continues with the old state.
883     *
884     * @arg[in] input input stream
885     * @arg[in] paragraphLengths lengths of paragraphs in the text block
886     */
887   void parse(librevenge::RVNGInputStream *input, const vector<unsigned> &paragraphLengths);
888 
889 private:
890   void flushText(bool endOfParagraph = false);
891 
892   void closeParagraph();
893 
894   /** Insert a line break.
895     *
896     * Only line breaks in the middle of a paragraph (e.g., separators of
897     * verses in a poem) are really inserted. Line breaks at the
898     * beginning of a paragraph (before any text) and at the end of a
899     * paragraph (after all text) are ignored.
900     */
901   void insertLineBreak();
902 
903   void insertImage(unsigned id);
904 
905 private:
906   librevenge::RVNGTextInterface *m_document;
907   const PluckerImageMap_t &m_imageMap;
908 
909   librevenge::RVNGInputStream *m_input;
910 
911   PluckerAttributes m_attributes;
912 
913   std::string m_text;
914 
915   unsigned m_lineBreaks;
916 
917   bool m_paragraphOpened;
918 };
919 
MarkupParser(librevenge::RVNGTextInterface * const document,const PluckerImageMap_t & imageMap)920 MarkupParser::MarkupParser(librevenge::RVNGTextInterface *const document, const PluckerImageMap_t &imageMap)
921   : m_document(document)
922   , m_imageMap(imageMap)
923   , m_input(nullptr)
924   , m_attributes()
925   , m_text()
926   , m_lineBreaks(0)
927   , m_paragraphOpened(false)
928 {
929 }
930 
~MarkupParser()931 MarkupParser::~MarkupParser()
932 {
933   closeParagraph();
934 }
935 
parse(librevenge::RVNGInputStream * const input,const vector<unsigned> & paragraphLengths)936 void MarkupParser::parse(librevenge::RVNGInputStream *const input, const vector<unsigned> &paragraphLengths)
937 {
938   unsigned para = 0;
939   unsigned chars = 0;
940 
941   while (!input->isEnd())
942   {
943     const unsigned char c = readU8(input);
944     ++chars;
945 
946     if (0 == c)
947     {
948       const unsigned char function = readU8(input);
949       ++chars;
950 
951       switch (function)
952       {
953       case PAGE_LINK_BEGIN :
954         skip(input, 2);
955         chars += 2;
956         break;
957       case PARAGRAPH_LINK_BEGIN :
958         skip(input, 4);
959         chars += 4;
960         break;
961       case LINK_END :
962         break;
963       case SET_FONT :
964       {
965         const unsigned char font = readU8(input);
966         ++chars;
967         if (FONT_LAST >= font)
968           m_attributes.font = static_cast<Font>(font);
969         else
970         {
971           EBOOK_DEBUG_MSG(("unknown font specifier %d\n", font));
972         }
973         break;
974       }
975       case EMBEDDED_IMAGE :
976       {
977         const unsigned imageID = readU16(input, true);
978         chars += 2;
979         insertImage(imageID);
980         break;
981       }
982       case SET_MARGIN :
983         m_attributes.leftMargin = readU8(input);
984         m_attributes.rightMargin = readU8(input);
985         chars += 2;
986         break;
987       case TEXT_ALIGNMENT :
988       {
989         const unsigned alignmnent = readU8(input);
990         ++chars;
991         if (TEXT_ALIGNMENT_LAST >= alignmnent)
992           m_attributes.textAlignment = static_cast<TextAlignment>(alignmnent);
993         else
994         {
995           EBOOK_DEBUG_MSG(("unknown text alignment %d\n", (int) alignmnent));
996         }
997         break;
998       }
999       case HORIZONTAL_RULE :
1000         // ignore
1001         skip(input, 3);
1002         chars += 3;
1003         break;
1004       case NEW_LINE :
1005         flushText();
1006         insertLineBreak();
1007         break;
1008       case ITALIC_BEGIN :
1009         flushText();
1010         m_attributes.italic = true;
1011         break;
1012       case ITALIC_END :
1013         flushText();
1014         m_attributes.italic = false;
1015         break;
1016       case UNKNOWN_53 :
1017         // TODO: find what this is
1018         skip(input, 3);
1019         chars += 3;
1020         break;
1021       case MULTIPLE_EMBEDDED_IMAGE :
1022         // TODO: implement me
1023         skip(input, 4);
1024         chars += 4;
1025         break;
1026       case UNDERLINE_BEGIN :
1027         flushText();
1028         m_attributes.underline = true;
1029         break;
1030       case UNDERLINE_END :
1031         flushText();
1032         m_attributes.underline = false;
1033         break;
1034       case STRIKETHROUGH_BEGIN :
1035         flushText();
1036         m_attributes.strikethrough = true;
1037         break;
1038       case STRIKETHROUGH_END :
1039         flushText();
1040         m_attributes.strikethrough = false;
1041         break;
1042       default :
1043         EBOOK_DEBUG_MSG(("unknown function code %x\n", function));
1044         break;
1045       }
1046     }
1047     else
1048     {
1049       m_text.push_back((char) c);
1050     }
1051 
1052     if ((paragraphLengths.size() > para) && (paragraphLengths[para] <= chars))
1053     {
1054       closeParagraph();
1055       ++para;
1056       chars = 0;
1057     }
1058   }
1059 }
1060 
flushText(bool endOfParagraph)1061 void MarkupParser::flushText(bool endOfParagraph)
1062 {
1063   if (!m_paragraphOpened)
1064   {
1065     m_document->openParagraph(makeParagraphProperties(m_attributes));
1066     m_paragraphOpened = true;
1067     m_lineBreaks = 0;
1068   }
1069 
1070   // Many files I have seen have a line break followed by a space at the
1071   // end of paragraphs. IMHO that might be safely thrown away.
1072   if (!m_text.empty() && (!endOfParagraph || (std::string::npos != m_text.find_first_not_of(" "))))
1073   {
1074     // pending line break(s)
1075     if (0 != m_lineBreaks)
1076     {
1077       for (unsigned i = 0; i != m_lineBreaks; ++i)
1078         m_document->insertLineBreak();
1079       m_lineBreaks = 0;
1080     }
1081 
1082     m_document->openSpan(makeCharacterProperties(m_attributes));
1083     m_document->insertText(librevenge::RVNGString(m_text.c_str()));
1084     m_text.clear();
1085     m_document->closeSpan();
1086   }
1087 }
1088 
closeParagraph()1089 void MarkupParser::closeParagraph()
1090 {
1091   flushText(true);
1092 
1093   m_document->closeParagraph();
1094   m_paragraphOpened = false;
1095 }
1096 
insertLineBreak()1097 void MarkupParser::insertLineBreak()
1098 {
1099   ++m_lineBreaks;
1100 }
1101 
insertImage(const unsigned id)1102 void MarkupParser::insertImage(const unsigned id)
1103 {
1104   const PluckerImageMap_t::const_iterator it = m_imageMap.find(id);
1105   if (m_imageMap.end() != it)
1106   {
1107     librevenge::RVNGPropertyList props;
1108     const librevenge::RVNGBinaryData data(&(it->second)[0], it->second.size());
1109     props.insert("office:binary-data", data);
1110     m_document->insertBinaryObject(props);
1111   }
1112 }
1113 
1114 }
1115 }
1116 
1117 namespace libebook
1118 {
1119 
1120 struct PluckerHeader
1121 {
1122   PluckerHeader();
1123 
1124   bool isValid() const;
1125 
1126   Compression compression;
1127   bool valid;
1128   bool validAppInfo;
1129 };
1130 
1131 struct PluckerParserState
1132 {
1133   PluckerParserState();
1134 
1135   PluckerImageMap_t m_imageMap;
1136   shared_ptr<MarkupParser> markupParser;
1137   shared_ptr<EBOOKCharsetConverter> charsetConverter;
1138   bool knownEncoding;
1139   ExceptionalCharsetMap_t exceptionalCharsetMap;
1140 };
1141 
1142 struct PluckerRecordHeader
1143 {
1144   PluckerRecordHeader();
1145 
1146   unsigned number;
1147   unsigned uid;
1148   unsigned paragraphs;
1149   unsigned size;
1150   DataType type;
1151 };
1152 
PluckerHeader()1153 PluckerHeader::PluckerHeader()
1154   : compression(COMPRESSION_UNKNOWN)
1155   , valid(false)
1156   , validAppInfo(true)
1157 {
1158 }
1159 
isValid() const1160 bool PluckerHeader::isValid() const
1161 {
1162   return (COMPRESSION_UNKNOWN != compression) && valid && validAppInfo;
1163 }
1164 
PluckerParserState()1165 PluckerParserState::PluckerParserState()
1166   : m_imageMap()
1167   , markupParser()
1168   , charsetConverter()
1169   , knownEncoding(false)
1170   , exceptionalCharsetMap()
1171 {
1172 }
1173 
PluckerRecordHeader()1174 PluckerRecordHeader::PluckerRecordHeader()
1175   : number(0)
1176   , uid(0)
1177   , paragraphs(0)
1178   , size(0)
1179   , type(DATA_TYPE_UNKNOWN)
1180 {
1181 }
1182 
1183 }
1184 
1185 namespace libebook
1186 {
1187 
PluckerParser(librevenge::RVNGInputStream * const input,librevenge::RVNGTextInterface * const document)1188 PluckerParser::PluckerParser(librevenge::RVNGInputStream *const input, librevenge::RVNGTextInterface *const document)
1189   : PDBParser(input, document, PLUCKER_TYPE, PLUCKER_CREATOR)
1190   , m_header()
1191   , m_state(new PluckerParserState())
1192 {
1193   if (!m_header)
1194     m_header.reset(new PluckerHeader());
1195 
1196   const std::unique_ptr<librevenge::RVNGInputStream> record(getIndexRecord());
1197   readIndexRecord(record.get());
1198 
1199   if (!m_header->isValid())
1200     throw UnsupportedFormat();
1201 }
1202 
checkType(const unsigned type,const unsigned creator)1203 bool PluckerParser::checkType(const unsigned type, const unsigned creator)
1204 {
1205   return (PLUCKER_TYPE == type) && (PLUCKER_CREATOR == creator);
1206 }
1207 
readAppInfoRecord(librevenge::RVNGInputStream * const record)1208 void PluckerParser::readAppInfoRecord(librevenge::RVNGInputStream *const record)
1209 {
1210   const uint32_t signature = readU32(record, true);
1211   const unsigned version = readU16(record, true);
1212   const unsigned encoding = readU16(record, true);
1213 
1214   m_header->validAppInfo = (APPINFO_SIGNATURE == signature) && (3 == version) && (0 == encoding);
1215 }
1216 
readSortInfoRecord(librevenge::RVNGInputStream *)1217 void PluckerParser::readSortInfoRecord(librevenge::RVNGInputStream *)
1218 {
1219   // there is no sortInfo record in Plucker
1220 }
1221 
readIndexRecord(librevenge::RVNGInputStream * const record)1222 void PluckerParser::readIndexRecord(librevenge::RVNGInputStream *const record)
1223 {
1224   if (!m_header)
1225     m_header.reset(new PluckerHeader());
1226 
1227   m_header->valid = 1 == readU16(record, true);
1228 
1229   const unsigned version = readU16(record, true);
1230   switch (version)
1231   {
1232   case 1 :
1233     m_header->compression = COMPRESSION_LZ77;
1234     break;
1235   case 2 :
1236     m_header->compression = COMPRESSION_ZLIB;
1237     break;
1238   default :
1239     EBOOK_DEBUG_MSG(("unknown compression %d\n", (int) version));
1240     break;
1241   }
1242 }
1243 
readDataRecord(librevenge::RVNGInputStream * const record,bool)1244 void PluckerParser::readDataRecord(librevenge::RVNGInputStream *const record, bool)
1245 {
1246   // TODO: implement me
1247   (void) record;
1248 }
1249 
readDataRecords()1250 void PluckerParser::readDataRecords()
1251 {
1252   vector<PluckerRecordHeader> textRecords;
1253 
1254   // Process in two phases:
1255 
1256   // 1. save images, process metadata and (since we are reading the
1257   // record headers anyway) save data about text records
1258   for (unsigned i = 0; i < getDataRecordCount(); ++i)
1259   {
1260     const unique_ptr<librevenge::RVNGInputStream> record(getDataRecord(i));
1261 
1262     PluckerRecordHeader header;
1263     header.number = i;
1264     header.uid = readU16(record.get(), true);
1265     header.paragraphs = readU16(record.get(), true);
1266     header.size = readU16(record.get(), true);
1267     const unsigned typeNum = readU8(record.get(), true);
1268     header.type = DATA_TYPE_UNKNOWN;
1269 
1270     if (DATA_TYPE_LAST >= typeNum)
1271       header.type = static_cast<DataType>(typeNum);
1272 
1273     switch (header.type)
1274     {
1275     case DATA_TYPE_PHTML :
1276     case DATA_TYPE_PHTML_COMPRESSED :
1277       textRecords.push_back(header);
1278       break;
1279     case DATA_TYPE_TBMP :
1280     case DATA_TYPE_TBMP_COMPRESSED :
1281     {
1282       librevenge::RVNGInputStream *input = record.get();
1283 
1284       std::shared_ptr<librevenge::RVNGInputStream> uncompressed;
1285       if (DATA_TYPE_TBMP_COMPRESSED == header.type)
1286       {
1287         uncompressed = getUncompressedStream(input);
1288         input = uncompressed.get();
1289       }
1290 
1291       readImage(input, header);
1292 
1293       break;
1294     }
1295     case DATA_TYPE_METADATA :
1296       readMetadata(record.get(), header);
1297       break;
1298     case DATA_TYPE_MAILTO:
1299     case DATA_TYPE_LINK_INDEX:
1300     case DATA_TYPE_LINKS:
1301     case DATA_TYPE_LINKS_COMPRESSED:
1302     case DATA_TYPE_BOOKMARKS:
1303     case DATA_TYPE_CATEGORY:
1304     case DATA_TYPE_UNKNOWN:
1305     default :
1306       // not interesting
1307       break;
1308     }
1309   }
1310 
1311   // 2. process text records and generate output
1312   getDocument()->startDocument(librevenge::RVNGPropertyList());
1313   getDocument()->setDocumentMetaData(librevenge::RVNGPropertyList());
1314   getDocument()->openPageSpan(getDefaultPageSpanPropList());
1315 
1316   // create markup parser
1317   m_state->markupParser.reset(new MarkupParser(getDocument(), m_state->m_imageMap));
1318 
1319   for (vector<PluckerRecordHeader>::const_iterator it = textRecords.begin(); it != textRecords.end(); ++it)
1320   {
1321     const unique_ptr<librevenge::RVNGInputStream> record(getDataRecord(it->number));
1322 
1323     if (it->type==DATA_TYPE_PHTML || it->type==DATA_TYPE_PHTML_COMPRESSED)
1324     {
1325       librevenge::RVNGInputStream *input = record.get();
1326 
1327       skip(input, 8);
1328 
1329       vector<unsigned> paraLengths;
1330       for (unsigned i = 0; i != it->paragraphs; ++i)
1331       {
1332         paraLengths.push_back(readU16(input, true));
1333         skip(input, 2);
1334       }
1335 
1336       shared_ptr<librevenge::RVNGInputStream> uncompressed;
1337       if (DATA_TYPE_PHTML_COMPRESSED == it->type)
1338       {
1339         uncompressed = getUncompressedStream(input);
1340         input = uncompressed.get();
1341       }
1342 
1343       readText(input, *it, paraLengths);
1344 
1345       break;
1346     }
1347     else
1348     {
1349       // how comes?
1350       EBOOK_DEBUG_MSG(("unknown data type %d for text record\n", it->type));
1351     }
1352   }
1353 
1354   m_state->markupParser.reset();
1355 
1356   getDocument()->closePageSpan();
1357   getDocument()->endDocument();
1358 }
1359 
readMetadata(librevenge::RVNGInputStream * const input,const PluckerRecordHeader &)1360 void PluckerParser::readMetadata(librevenge::RVNGInputStream *const input, const PluckerRecordHeader &)
1361 {
1362   const unsigned count = readU16(input, true);
1363   for (unsigned i = 0; count != i; ++i)
1364   {
1365     const unsigned typeCode = readU16(input, true);
1366     const unsigned length = readU16(input, true);
1367 
1368     switch (typeCode)
1369     {
1370     case 1 : // charset
1371       if (1 == length)
1372       {
1373         const unsigned mib = readU16(input, true);
1374         const char *charset = nullptr;
1375         if (EBOOK_NUM_ELEMENTS(IANA_CHARSETS) > mib)
1376           charset = IANA_CHARSETS[mib];
1377         m_state->charsetConverter.reset(new EBOOKCharsetConverter(charset));
1378         m_state->knownEncoding = nullptr != charset;
1379       }
1380       else
1381       {
1382         EBOOK_DEBUG_MSG(("invalid record length %d for charset record\n", (int) length));
1383       }
1384       break;
1385     case 2 : // exceptional charsets
1386       for (unsigned j = 0; length != j; j += 2)
1387       {
1388         const unsigned id = readU16(input, true);
1389         const unsigned mib = readU16(input, true);
1390         m_state->exceptionalCharsetMap[id] = mib;
1391       }
1392       break;
1393     default :
1394       EBOOK_DEBUG_MSG(("unknown type code %d in metadata record\n", (int) typeCode));
1395     }
1396   }
1397 }
1398 
readImage(librevenge::RVNGInputStream * const input,const PluckerRecordHeader & header)1399 void PluckerParser::readImage(librevenge::RVNGInputStream *const input, const PluckerRecordHeader &header)
1400 {
1401   vector<unsigned char> data;
1402   while (!input->isEnd())
1403     data.push_back(readU8(input));
1404 
1405   m_state->m_imageMap.insert(PluckerImageMap_t::value_type(header.uid, data));
1406 }
1407 
readText(librevenge::RVNGInputStream * const input,const PluckerRecordHeader &,const std::vector<unsigned> & paragraphLengths)1408 void PluckerParser::readText(librevenge::RVNGInputStream *const input, const PluckerRecordHeader &, const std::vector<unsigned> &paragraphLengths)
1409 {
1410   m_state->markupParser->parse(input, paragraphLengths);
1411 }
1412 
getUncompressedStream(librevenge::RVNGInputStream * const input) const1413 std::shared_ptr<librevenge::RVNGInputStream> PluckerParser::getUncompressedStream(librevenge::RVNGInputStream *const input) const
1414 {
1415   const auto pos = (unsigned long) input->tell();
1416   input->seek(0, librevenge::RVNG_SEEK_END);
1417   const unsigned long length = (unsigned long) input->tell() - pos;
1418   input->seek((long) pos, librevenge::RVNG_SEEK_SET);
1419   const unsigned char *bytes = readNBytes(input, length);
1420 
1421   EBOOKMemoryStream data(bytes, static_cast<unsigned>(length));
1422 
1423   shared_ptr<librevenge::RVNGInputStream> uncompressed;
1424   switch (m_header->compression)
1425   {
1426   case COMPRESSION_LZ77 :
1427     uncompressed.reset(new PDBLZ77Stream(&data));
1428     break;
1429   case COMPRESSION_ZLIB :
1430     uncompressed.reset(new EBOOKZlibStream(&data));
1431     break;
1432   case COMPRESSION_UNKNOWN:
1433   default :
1434     // not possible
1435     break;
1436   }
1437 
1438   return uncompressed;
1439 }
1440 
1441 } // namespace libebook
1442 
1443 /* vim:set shiftwidth=2 softtabstop=2 expandtab: */
1444