/src/libwps/src/lib/WPS4Text.cpp
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ |
2 | | /* libwps |
3 | | * Version: MPL 2.0 / LGPLv2.1+ |
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 | | * Major Contributor(s): |
10 | | * Copyright (C) 2009, 2011 Alonso Laurent (alonso@loria.fr) |
11 | | * Copyright (C) 2006, 2007 Andrew Ziem |
12 | | * Copyright (C) 2004-2006 Fridrich Strba (fridrich.strba@bluewin.ch) |
13 | | * Copyright (C) 2004 Marc Maurer (uwog@uwog.net) |
14 | | * Copyright (C) 2003-2005 William Lachance (william.lachance@sympatico.ca) |
15 | | * |
16 | | * For minor contributions see the git repository. |
17 | | * |
18 | | * Alternatively, the contents of this file may be used under the terms |
19 | | * of the GNU Lesser General Public License Version 2.1 or later |
20 | | * (LGPLv2.1+), in which case the provisions of the LGPLv2.1+ are |
21 | | * applicable instead of those above. |
22 | | * |
23 | | * For further information visit http://libwps.sourceforge.net |
24 | | */ |
25 | | |
26 | | #ifdef DEBUG_WITH_FILES |
27 | | // set to 1 to debug the font property |
28 | | # define DEBUG_FP 1 |
29 | | // set to 1 to debug the paragraph property |
30 | | # define DEBUG_PP 1 |
31 | | // set to 1 to print the plc position |
32 | | # define DEBUG_PLC_POS 1 |
33 | | #else |
34 | | # define DEBUG_FP 0 |
35 | | # define DEBUG_PP 0 |
36 | | # define DEBUG_PLC_POS 0 |
37 | | #endif |
38 | | |
39 | | #include <iomanip> |
40 | | #include <iostream> |
41 | | |
42 | | #include <map> |
43 | | #include <vector> |
44 | | |
45 | | #include <librevenge/librevenge.h> |
46 | | |
47 | | #include "libwps_internal.h" |
48 | | #include "libwps_tools_win.h" |
49 | | |
50 | | #include "WPSContentListener.h" |
51 | | #include "WPSFont.h" |
52 | | #include "WPSPosition.h" |
53 | | #include "WPSParagraph.h" |
54 | | |
55 | | #include "WPS4.h" |
56 | | |
57 | | #include "WPS4Text.h" |
58 | | |
59 | | /** Internal and low level: the structures of a WPS4Text used to parse PLC*/ |
60 | | namespace WPS4PLCInternal |
61 | | { |
62 | | /** Internal and low level: the PLC different types and their structures */ |
63 | | struct PLC; |
64 | | |
65 | | //! a map of known plc |
66 | | struct KnownPLC |
67 | | { |
68 | | public: |
69 | | //! constructor |
70 | | KnownPLC(); |
71 | | //! destructor |
72 | | ~KnownPLC(); |
73 | | //! returns the PLC corresponding to a name |
74 | | PLC get(std::string const &name); |
75 | | protected: |
76 | | //! creates the map of known PLC |
77 | | void createMapping(); |
78 | | //! map name -> known PLC |
79 | | std::map<std::string, PLC> m_knowns; |
80 | | }; |
81 | | } |
82 | | |
83 | | ////////////////////////////////////////////////////////////////////////////// |
84 | | // general enum |
85 | | ////////////////////////////////////////////////////////////////////////////// |
86 | | namespace WPS4TextInternal |
87 | | { |
88 | | /** a enum used to type a zone */ |
89 | | enum ZoneType { Z_String=-1, Z_Header=0, Z_Footer=1, Z_Main=2, Z_Note, Z_Bookmark, Z_DLink, Z_Unknown}; |
90 | | /** Internal: class to store a font name: name with encoding type */ |
91 | | struct FontName |
92 | | { |
93 | | //! constructor with file's version to define the default encoding */ |
94 | | explicit FontName(libwps_tools_win::Font::Type type) |
95 | 1.87k | : m_name("") |
96 | 1.87k | , m_type(type) |
97 | 1.87k | { |
98 | 1.87k | } |
99 | | //! operator<< |
100 | | friend std::ostream &operator<<(std::ostream &o, FontName const &ft); |
101 | | /** returns the default dos name corresponding to \a id th font */ |
102 | | static librevenge::RVNGString getDosName(int id); |
103 | | |
104 | | //! font name |
105 | | librevenge::RVNGString m_name; |
106 | | //! font encoding type |
107 | | libwps_tools_win::Font::Type m_type; |
108 | | }; |
109 | | //! operator<< for a font name |
110 | | std::ostream &operator<<(std::ostream &o, FontName const &ft) |
111 | 0 | { |
112 | 0 | if (!ft.m_name.empty()) o << "name='" << ft.m_name.cstr() << "'"; |
113 | 0 | else o << "name='Unknown'"; |
114 | 0 | if (ft.m_type!=libwps_tools_win::Font::WIN3_WEUROPE && |
115 | 0 | ft.m_type!=libwps_tools_win::Font::DOS_850) |
116 | 0 | o << ",type=" << libwps_tools_win::Font::getTypeName(ft.m_type).cstr() << ","; |
117 | 0 | return o; |
118 | 0 | } |
119 | | |
120 | | librevenge::RVNGString FontName::getDosName(int id) |
121 | 9.42k | { |
122 | 9.42k | switch (id) |
123 | 9.42k | { |
124 | 984 | case 0: |
125 | 984 | return "Courier"; |
126 | 514 | case 1: |
127 | 514 | return "Courier PC"; |
128 | 222 | case 3: |
129 | 222 | return "Univers_Scale"; |
130 | 584 | case 4: |
131 | 584 | return "Universe"; |
132 | 1.91k | case 6: |
133 | 1.91k | return "LinePrinterPC"; |
134 | 607 | case 7: |
135 | 607 | return "LinePrinter"; |
136 | 686 | case 16: |
137 | 686 | return "CGTimes_Scale"; |
138 | 201 | case 24: |
139 | 201 | return "CGTimes"; |
140 | 3.70k | default: |
141 | 3.70k | break; |
142 | 9.42k | } |
143 | | |
144 | 3.70k | WPS_DEBUG_MSG(("WPS4TextInternal::FontName::getDosName: encountered unknown font %i\n", id)); |
145 | 3.70k | return "Courier"; |
146 | 9.42k | } |
147 | | /** Internal: class to store font properties */ |
148 | | struct Font final : public WPSFont |
149 | | { |
150 | | //! constructor with file's version to define the default encoding */ |
151 | | explicit Font(libwps_tools_win::Font::Type type) |
152 | 78.9k | : WPSFont() |
153 | 78.9k | , m_type(type) |
154 | 78.9k | , m_backColor(WPSColor::white()) |
155 | 78.9k | , m_special(false) |
156 | 78.9k | , m_dlinkId(-1) |
157 | 78.9k | { |
158 | 78.9k | } |
159 | 99.5k | Font(Font const &)=default; |
160 | 57.8k | Font &operator=(Font const &)=default; |
161 | | //! destructor |
162 | | ~Font() final; |
163 | | //! returns a default font (Courier12) with file's version to define the default encoding */ |
164 | | static Font getDefault(libwps_tools_win::Font::Type type, int version) |
165 | 78.9k | { |
166 | 78.9k | Font res(type); |
167 | 78.9k | if (version <= 2) |
168 | 35.8k | res.m_name="Courier"; |
169 | 43.1k | else |
170 | 43.1k | res.m_name="Times New Roman"; |
171 | 78.9k | res.m_size=12; |
172 | 78.9k | return res; |
173 | 78.9k | } |
174 | | |
175 | | //! operator<< |
176 | | friend std::ostream &operator<<(std::ostream &o, Font const &ft); |
177 | | |
178 | | //! the font encoding type |
179 | | libwps_tools_win::Font::Type m_type; |
180 | | //! background color index |
181 | | WPSColor m_backColor; |
182 | | //! a flag to know if we have a special field (a note), ... |
183 | | bool m_special; |
184 | | //! a id to retrieve a file name ( dos ) |
185 | | int m_dlinkId; |
186 | | }; |
187 | | |
188 | | Font::~Font() |
189 | 178k | { |
190 | 178k | } |
191 | | |
192 | | //! operator<< for font properties |
193 | | std::ostream &operator<<(std::ostream &o, Font const &ft) |
194 | 0 | { |
195 | 0 | o << static_cast<WPSFont const &>(ft) << ","; |
196 | |
|
197 | 0 | if (ft.m_special) |
198 | 0 | { |
199 | 0 | if (ft.m_dlinkId >= 0) |
200 | 0 | o << "spec[" << ft.m_dlinkId << "],"; |
201 | 0 | else |
202 | 0 | o << "spec,"; |
203 | 0 | } |
204 | |
|
205 | 0 | if (!ft.m_backColor.isWhite()) |
206 | 0 | o << "bgCol=" << ft.m_backColor << ","; |
207 | 0 | return o; |
208 | 0 | } |
209 | | |
210 | | /** Internal: class to store an note type */ |
211 | | struct Note final : public WPSEntry |
212 | | { |
213 | | //! constructor |
214 | | Note() |
215 | 2.99k | : WPSEntry() |
216 | 2.99k | , m_label("") |
217 | 2.99k | , m_error("") {} |
218 | 2.57k | Note(Note const &)=default; |
219 | 1.21k | Note &operator=(Note const &)=default; |
220 | | //! destructor |
221 | | ~Note() final; |
222 | | bool isNumeric() const |
223 | 0 | { |
224 | 0 | return m_label.len()==0; |
225 | 0 | } |
226 | | //! operator << |
227 | | friend std::ostream &operator<<(std::ostream &o, Note const ¬e) |
228 | 0 | { |
229 | 0 | if (note.m_label.len()) |
230 | 0 | o << "lab=" << note.m_label.cstr() << ","; |
231 | 0 | else |
232 | 0 | o << "numeric,"; |
233 | 0 | if (!note.m_error.empty()) o << note.m_error << ","; |
234 | 0 | return o; |
235 | 0 | } |
236 | | //! the label if not numeric |
237 | | librevenge::RVNGString m_label; |
238 | | //! a string used to store the parsing errors |
239 | | std::string m_error; |
240 | | }; |
241 | | |
242 | | Note::~Note() |
243 | 5.57k | { |
244 | 5.57k | } |
245 | | /** Internal: class to store an object definition */ |
246 | | struct Object |
247 | | { |
248 | | //! constructor |
249 | | Object() |
250 | 2.37k | : m_id(-1) |
251 | 2.37k | , m_page(0) |
252 | 2.37k | , m_origin() |
253 | 2.37k | , m_size() |
254 | 2.37k | , m_pos() |
255 | 2.37k | , m_unknown(0) |
256 | 2.37k | , m_extra("") {} |
257 | | //! operator << |
258 | | friend std::ostream &operator<<(std::ostream &o, Object const &obj); |
259 | | |
260 | | //! the object identificator |
261 | | int m_id; |
262 | | //! the page |
263 | | int m_page; |
264 | | //! the origin |
265 | | Vec2f m_origin; |
266 | | //! the object size in the document |
267 | | Vec2f m_size; |
268 | | //! an entry which indicates where the object is defined in the file |
269 | | WPSEntry m_pos; |
270 | | //! unknown data |
271 | | long m_unknown; |
272 | | //! a string used to store the parsing errors |
273 | | std::string m_extra; |
274 | | }; |
275 | | //! operator<< for an object |
276 | | std::ostream &operator<<(std::ostream &o, Object const &obj) |
277 | 0 | { |
278 | 0 | if (obj.m_id > -1) o << "ole" << obj.m_id << ","; |
279 | 0 | if (obj.m_page) o << "page=" << obj.m_page << ","; |
280 | 0 | if (obj.m_origin!=Vec2f(0,0)) o << "orig=" << obj.m_origin << ","; |
281 | 0 | o <<"size=" << obj.m_size << ","; |
282 | 0 | if (obj.m_pos.valid()) o << std::hex << "def=(0x" << obj.m_pos.begin() << "->" << obj.m_pos.end() << ")," << std::dec; |
283 | 0 | if (obj.m_unknown) o << std::hex << "unkn=" << obj.m_unknown << std::dec << ","; |
284 | 0 | if (!obj.m_extra.empty()) o << obj.m_extra; |
285 | 0 | return o; |
286 | 0 | } |
287 | | |
288 | | /** Internal: class to store an object definition */ |
289 | | struct DosLink |
290 | | { |
291 | | //! constructor |
292 | | DosLink() |
293 | 7.75k | : m_type(-1) |
294 | 7.75k | , m_width(-1) |
295 | 7.75k | , m_size() |
296 | 7.75k | , m_name("") |
297 | 7.75k | , m_pos() |
298 | 7.75k | , m_extra("") {} |
299 | | //! operator << |
300 | | friend std::ostream &operator<<(std::ostream &o, DosLink const &dlink); |
301 | | |
302 | | //! the type |
303 | | int m_type; |
304 | | //! the width |
305 | | float m_width; |
306 | | //! the object size in the document |
307 | | Vec2f m_size; |
308 | | //! the file name |
309 | | std::string m_name; |
310 | | //! an entry which indicates where the object is defined in the file |
311 | | WPSEntry m_pos; |
312 | | //! a string used to store the parsing errors |
313 | | std::string m_extra; |
314 | | }; |
315 | | //! operator<< for an object |
316 | | std::ostream &operator<<(std::ostream &o, DosLink const &dlink) |
317 | 0 | { |
318 | 0 | switch (dlink.m_type) |
319 | 0 | { |
320 | 0 | case -1: |
321 | 0 | break; |
322 | 0 | case 1: |
323 | 0 | o << "chart,"; |
324 | 0 | break; |
325 | 0 | case 0x81: |
326 | 0 | o << "pict,"; |
327 | 0 | break; |
328 | 0 | case 0x40: |
329 | 0 | o << "spreadsheet,"; |
330 | 0 | break; |
331 | 0 | default: |
332 | 0 | o << "#type=" << dlink.m_type << ","; |
333 | 0 | break; |
334 | 0 | } |
335 | 0 | if (dlink.m_width >= 0) o << "width?=" << dlink.m_width << ","; |
336 | 0 | if (dlink.m_size.x() >= 0 && (dlink.m_size.y()<0 || dlink.m_size.y()>0)) |
337 | 0 | o <<"size=" << dlink.m_size << ","; |
338 | 0 | if (dlink.m_name.length()) o << "name='" << dlink.m_name << "',"; |
339 | 0 | if (!dlink.m_extra.empty()) o << ", err=" << dlink.m_extra; |
340 | 0 | return o; |
341 | 0 | } |
342 | | |
343 | | /** Internal: class to store a date/time format */ |
344 | | struct DateTime |
345 | | { |
346 | | //! constructor |
347 | | DateTime() |
348 | 690 | : m_type(-1) |
349 | 690 | , m_extra("") {} |
350 | | //! returns a format to used with strftime |
351 | | std::string format() const; |
352 | | //! operator << |
353 | | friend std::ostream &operator<<(std::ostream &o, DateTime const &dtime); |
354 | | |
355 | | //! the type |
356 | | int m_type; |
357 | | //! a string used to store the parsing errors |
358 | | std::string m_extra; |
359 | | }; |
360 | | |
361 | | std::string DateTime::format() const |
362 | 4.85k | { |
363 | 4.85k | switch (m_type) |
364 | 4.85k | { |
365 | 573 | case 0: |
366 | 573 | return "%m/%d/%Y"; |
367 | 224 | case 1: |
368 | 224 | return "%m/%Y"; |
369 | 261 | case 2: |
370 | 261 | return "%d %B %Y"; |
371 | 498 | case 3: |
372 | 498 | return "%A %d %B %Y"; |
373 | 84 | case 4: |
374 | 84 | return "%B %Y"; |
375 | 212 | case 5: |
376 | 212 | return "%m/%d/%Y %I:%M"; |
377 | 249 | case 6: |
378 | 249 | return "%m/%d/%Y %I:%M:%S"; |
379 | 355 | case 7: |
380 | 355 | return "%I:%M:%S"; |
381 | 308 | case 8: |
382 | 308 | return "%I:%M"; |
383 | 355 | case 9: |
384 | 355 | return "%H:%M:%S"; |
385 | 871 | case 10: |
386 | 871 | return "%H:%M"; |
387 | 864 | default: |
388 | 864 | break; |
389 | 4.85k | } |
390 | 864 | return ""; |
391 | 4.85k | } |
392 | | |
393 | | //! operator<< for an object |
394 | | std::ostream &operator<<(std::ostream &o, DateTime const &dtime) |
395 | 0 | { |
396 | 0 | switch (dtime.m_type) |
397 | 0 | { |
398 | 0 | case -1: |
399 | 0 | break; |
400 | 0 | case 0: |
401 | 0 | case 1: |
402 | 0 | case 2: |
403 | 0 | case 3: |
404 | 0 | case 4: |
405 | 0 | o << "date[F"<<dtime.m_type<<"],"; |
406 | 0 | break; |
407 | 0 | case 5: |
408 | 0 | case 6: |
409 | 0 | o << "date&time[F"<<dtime.m_type-5<<"],"; |
410 | 0 | break; |
411 | 0 | case 7: |
412 | 0 | case 8: |
413 | 0 | case 9: |
414 | 0 | case 10: |
415 | 0 | o << "time[F"<<dtime.m_type-7<<"],"; |
416 | 0 | break; |
417 | 0 | default: |
418 | 0 | o << "#type=" << dtime.m_type << ","; |
419 | 0 | break; |
420 | 0 | } |
421 | 0 | if (!dtime.m_extra.empty()) o << ", err=" << dtime.m_extra; |
422 | 0 | return o; |
423 | 0 | } |
424 | | |
425 | | /** different types |
426 | | * |
427 | | * - BTE: font/paragraph properties |
428 | | * - OBJECT: object properties |
429 | | * - FTNp, FTNd: footnote position in text and footnote content |
430 | | * - BKMK: comment field |
431 | | * - DTTM: field type: date/time/.. |
432 | | */ |
433 | | enum PLCType { BTE=0, OBJECT, FTNp, FTNd, BKMK, DTTM, Unknown}; |
434 | | |
435 | | /** Internal: class to store the PLC: Pointer List Content ? */ |
436 | | struct DataPLC |
437 | | { |
438 | | //! constructor |
439 | | DataPLC() |
440 | 50.6k | : m_name("") |
441 | 50.6k | , m_type(Unknown) |
442 | 50.6k | , m_value(-1) |
443 | 50.6k | , m_extra() {} |
444 | | //! operator<< |
445 | | friend std::ostream &operator<<(std::ostream &o, DataPLC const &plc); |
446 | | //! the entry field name |
447 | | std::string m_name; |
448 | | //! the plc type |
449 | | PLCType m_type; |
450 | | //! a potential value |
451 | | long m_value; |
452 | | //! a string used to store the parsing errors |
453 | | std::string m_extra; |
454 | | }; |
455 | | //! operator<< for a dataPLC |
456 | | std::ostream &operator<<(std::ostream &o, DataPLC const &plc) |
457 | 0 | { |
458 | 0 | o << "type=" << plc.m_name << ","; |
459 | 0 | if (plc.m_value != -1) o << "val=" << std::hex << plc.m_value << std::dec << ", "; |
460 | 0 | if (!plc.m_extra.empty()) o << "errors=(" << plc.m_extra << ")"; |
461 | 0 | return o; |
462 | 0 | } |
463 | | |
464 | | /** Internal: the state of a WPS4Text */ |
465 | | struct State |
466 | | { |
467 | | //! constructor |
468 | | State() |
469 | 5.20k | : m_fontNames() |
470 | 5.20k | , m_fontList() |
471 | 5.20k | , m_paragraphList() |
472 | 5.20k | , m_FDPCs() |
473 | 5.20k | , m_FDPPs() |
474 | 5.20k | , m_footnoteList() |
475 | 5.20k | , m_footnoteMap() |
476 | 5.20k | , m_bookmarkMap() |
477 | 5.20k | , m_dosLinkList() |
478 | 5.20k | , m_main() |
479 | 5.20k | , m_header() |
480 | 5.20k | , m_footer() |
481 | 5.20k | , m_otherZones() |
482 | 5.20k | , m_objectMap() |
483 | 5.20k | , m_dateTimeMap() |
484 | 5.20k | , m_plcList() |
485 | 5.20k | , m_knownPLC() |
486 | 5.20k | {} |
487 | | |
488 | | //! the list of fonts names |
489 | | std::map<int,FontName> m_fontNames; |
490 | | //! the list of all font properties |
491 | | std::vector<Font> m_fontList; |
492 | | //! the list of all paragraph properties |
493 | | std::vector<WPSParagraph> m_paragraphList; |
494 | | |
495 | | //! the list of FDPC entries (ie list to find the font properties lists ) |
496 | | std::vector<WPSEntry> m_FDPCs; |
497 | | //! the list of FDPP entries (ie list to find the paragraph properties lists ) |
498 | | std::vector<WPSEntry> m_FDPPs; |
499 | | |
500 | | //! the footnote entries |
501 | | std::vector<Note> m_footnoteList; |
502 | | //! map: footnote in text -> footnote entry |
503 | | std::map<long,Note const *> m_footnoteMap; |
504 | | //! map: bookmark in text -> bookmark |
505 | | std::map<long, WPSEntry> m_bookmarkMap; |
506 | | //! the dos file links |
507 | | std::vector<DosLink> m_dosLinkList; |
508 | | |
509 | | WPSEntry m_main /** the main text zone entry*/, |
510 | | m_header /** the header text entry*/, m_footer /** the footer text entry*/; |
511 | | |
512 | | //! the entries which are not in main/header/footer text and in the footnotes |
513 | | std::vector<WPSEntry> m_otherZones; |
514 | | //! map: object in text -> object |
515 | | std::map<long, Object> m_objectMap; |
516 | | //! map: date field in text -> date time format |
517 | | std::map<long, DateTime> m_dateTimeMap; |
518 | | //! a list of all PLCs |
519 | | std::vector<DataPLC> m_plcList; |
520 | | //! the known plc |
521 | | WPS4PLCInternal::KnownPLC m_knownPLC; |
522 | | }; |
523 | | } |
524 | | |
525 | | ////////////////////////////////////////////////////////////////////////////// |
526 | | // |
527 | | // MAIN CODE |
528 | | // |
529 | | ////////////////////////////////////////////////////////////////////////////// |
530 | | |
531 | | // constructor/destructor |
532 | | WPS4Text::WPS4Text(WPS4Parser &parser, RVNGInputStreamPtr &input) |
533 | 5.20k | : WPSTextParser(parser, input) |
534 | 5.20k | , m_listener() |
535 | 5.20k | , m_state() |
536 | 5.20k | { |
537 | 5.20k | m_state.reset(new WPS4TextInternal::State); |
538 | 5.20k | } |
539 | | |
540 | | WPS4Text::~WPS4Text() |
541 | 5.20k | { |
542 | 5.20k | } |
543 | | |
544 | | // number of page |
545 | | int WPS4Text::numPages() const |
546 | 3.09k | { |
547 | 3.09k | int numPage = 1; |
548 | 3.09k | m_input->seek(m_textPositions.begin(), librevenge::RVNG_SEEK_SET); |
549 | 5.42M | while (!m_input->isEnd() && m_input->tell() != m_textPositions.end()) |
550 | 5.42M | { |
551 | 5.42M | if (libwps::readU8(m_input.get()) == 0x0C) numPage++; |
552 | 5.42M | } |
553 | 3.09k | for (auto const &it : m_state->m_objectMap) |
554 | 525 | { |
555 | 525 | if (it.second.m_page<=numPage) continue; |
556 | 188 | if (it.second.m_page<=numPage+10) |
557 | 9 | numPage=it.second.m_page; |
558 | 179 | else |
559 | 179 | { |
560 | 179 | WPS_DEBUG_MSG(("WPS4Text::numPages: the number of pages seems bad\n")); |
561 | 179 | } |
562 | 188 | } |
563 | 3.09k | return numPage; |
564 | 3.09k | } |
565 | | |
566 | | // page object |
567 | | void WPS4Text::sendObjects(int page) |
568 | 3.09k | { |
569 | 3.09k | for (auto const &it : m_state->m_objectMap) |
570 | 525 | { |
571 | 525 | auto const &obj=it.second; |
572 | 525 | if (obj.m_page<=0 || obj.m_id<0) continue; |
573 | 188 | if (page>=0 && obj.m_page!=page+1) continue; |
574 | 188 | WPSPosition position(obj.m_origin, obj.m_size); |
575 | 188 | if (page<0) position.setPage(obj.m_page); |
576 | 188 | position.setRelativePosition(WPSPosition::Page); |
577 | 188 | position.m_wrapping = WPSPosition::WDynamic; |
578 | 188 | mainParser().sendObject(position, obj.m_id); |
579 | 188 | } |
580 | 3.09k | } |
581 | | |
582 | | // return main/header/footer/all entry |
583 | | WPSEntry WPS4Text::getHeaderEntry() const |
584 | 3.09k | { |
585 | 3.09k | if (m_state->m_header.valid()) return m_state->m_header; |
586 | 2.52k | auto const &nameMultiMap = getNameEntryMap(); |
587 | 2.52k | auto pos = nameMultiMap.find("SHdr"); |
588 | 2.52k | if (pos == nameMultiMap.end()) return WPSEntry(); |
589 | 383 | WPSEntry res = pos->second; |
590 | 383 | res.setType("TEXT"); |
591 | 383 | res.setId(WPS4TextInternal::Z_String); |
592 | 383 | return res; |
593 | 2.52k | } |
594 | | |
595 | | WPSEntry WPS4Text::getFooterEntry() const |
596 | 3.09k | { |
597 | 3.09k | if (m_state->m_footer.valid()) return m_state->m_footer; |
598 | 2.86k | auto const &nameMultiMap = getNameEntryMap(); |
599 | 2.86k | auto pos = nameMultiMap.find("SFtr"); |
600 | 2.86k | if (pos == nameMultiMap.end()) return WPSEntry(); |
601 | 484 | WPSEntry res = pos->second; |
602 | 484 | res.setType("TEXT"); |
603 | 484 | res.setId(WPS4TextInternal::Z_String); |
604 | 484 | return res; |
605 | 2.86k | } |
606 | | |
607 | | WPSEntry WPS4Text::getMainTextEntry() const |
608 | 3.09k | { |
609 | 3.09k | return m_state->m_main; |
610 | 3.09k | } |
611 | | |
612 | | WPS4TextInternal::Font WPS4Text::getDefaultFont() const |
613 | 78.9k | { |
614 | 78.9k | return WPS4TextInternal::Font::getDefault(mainParser().getDefaultFontType(), version()); |
615 | 78.9k | } |
616 | | |
617 | | //////////////////////////////////////////////////////////// |
618 | | // send the data |
619 | | //////////////////////////////////////////////////////////// |
620 | | void WPS4Text::flushExtra() |
621 | 0 | { |
622 | 0 | if (!m_listener) |
623 | 0 | { |
624 | 0 | WPS_DEBUG_MSG(("WPS4Text::flushExtra can not find the listener\n")); |
625 | 0 | return; |
626 | 0 | } |
627 | 0 | size_t numExtra = m_state->m_otherZones.size(); |
628 | 0 | if (numExtra == 0) return; |
629 | | |
630 | 0 | m_listener->setFont(getDefaultFont()); |
631 | 0 | m_listener->setParagraph(WPSParagraph()); |
632 | 0 | m_listener->insertEOL(); |
633 | | #ifdef DEBUG |
634 | | librevenge::RVNGString message = "--------- extra text zone -------- "; |
635 | | m_listener->insertUnicodeString(message); |
636 | | #endif |
637 | 0 | for (size_t i = 0; i < numExtra; ++i) |
638 | 0 | readText(m_state->m_otherZones[i]); |
639 | 0 | } |
640 | | |
641 | | bool WPS4Text::readText(WPSEntry const &zone) |
642 | 63.7k | { |
643 | 63.7k | bool bookmark = zone.id() == WPS4TextInternal::Z_Bookmark; |
644 | 63.7k | bool dlink = zone.id() == WPS4TextInternal::Z_DLink; |
645 | 63.7k | bool simpleString = zone.id() == WPS4TextInternal::Z_String || bookmark || dlink; |
646 | 63.7k | bool mainZone = zone.id() == WPS4TextInternal::Z_Main; |
647 | | |
648 | 63.7k | if (m_listener.get() == nullptr) |
649 | 0 | { |
650 | 0 | WPS_DEBUG_MSG(("WPS4Text::readText can not find the listener\n")); |
651 | 0 | return false; |
652 | 0 | } |
653 | 63.7k | if (!zone.valid()) |
654 | 0 | { |
655 | 0 | WPS_DEBUG_MSG(("WPS4Text::readText invalid zone, must not happen\n")); |
656 | 0 | m_listener->insertCharacter(' '); |
657 | 0 | return false; |
658 | 0 | } |
659 | 63.7k | if (mainZone) |
660 | 2.97k | { |
661 | 2.97k | int numCols = mainParser().numColumns(); |
662 | 2.97k | if (numCols > 1) |
663 | 139 | { |
664 | 139 | if (m_listener->isSectionOpened()) |
665 | 0 | { |
666 | 0 | WPS_DEBUG_MSG(("WPS4Text::readText the section is already open\n")); |
667 | 0 | } |
668 | 139 | else |
669 | 139 | { |
670 | 139 | int w = int(72*mainParser().pageWidth())/numCols; |
671 | 139 | std::vector<int> width; |
672 | 139 | width.resize(size_t(numCols), w); |
673 | 139 | m_listener->openSection(width,librevenge::RVNG_POINT); |
674 | 139 | } |
675 | 139 | } |
676 | 2.97k | } |
677 | 63.7k | auto FODs_iter = m_FODList.begin(); |
678 | | |
679 | | // update the property to correspond to the text |
680 | 63.7k | int prevFId = -1, prevPId = -1; |
681 | 63.7k | if (simpleString) FODs_iter = m_FODList.end(); |
682 | 41.4k | else if (FODs_iter == m_FODList.end() && mainZone) |
683 | 1.34k | { |
684 | 1.34k | WPS_DEBUG_MSG(("WPS4Text::readText: CAN NOT FIND any FODs for main zone, REVERT to basic string!!!!!!!!!\n")); |
685 | 1.34k | simpleString = true; |
686 | 1.34k | } |
687 | | |
688 | 92.7k | for (; FODs_iter!= m_FODList.end(); ++FODs_iter) |
689 | 35.2k | { |
690 | 35.2k | auto const &fod = *(FODs_iter); |
691 | 35.2k | if (fod.m_pos >= zone.begin()) break; |
692 | | |
693 | 28.9k | int id = (*FODs_iter).m_id; |
694 | 28.9k | if (fod.m_type == DataFOD::ATTR_TEXT) prevFId = id; |
695 | 22.0k | else if (fod.m_type == DataFOD::ATTR_PARAG) prevPId = id; |
696 | 28.9k | } |
697 | | |
698 | 63.7k | WPS4TextInternal::Font defaultFont(getDefaultFont()); |
699 | 63.7k | WPS4TextInternal::Font actFont(defaultFont); |
700 | 63.7k | if (prevFId != -1) |
701 | 384 | actFont = m_state->m_fontList[size_t(prevFId)]; |
702 | 63.7k | m_listener->setFont(actFont); |
703 | | |
704 | 63.7k | if (prevPId != -1) |
705 | 234 | m_listener->setParagraph(m_state->m_paragraphList[size_t(prevPId)]); |
706 | 63.5k | else |
707 | 63.5k | m_listener->setParagraph(WPSParagraph()); |
708 | | |
709 | 63.7k | if (dlink) |
710 | 4.61k | { |
711 | 4.61k | m_listener->insertUnicodeString("include "); |
712 | 4.61k | m_listener->insertUnicode(0x226a); |
713 | 4.61k | } |
714 | 63.7k | bool first = true; |
715 | 63.7k | int actPage = 1; |
716 | 265k | for (; simpleString || FODs_iter!= m_FODList.end(); ++FODs_iter) |
717 | 228k | { |
718 | 228k | long actPos; |
719 | 228k | long lastPos; |
720 | | |
721 | | |
722 | 228k | libwps::DebugStream f; |
723 | 228k | f << "Text"; |
724 | | |
725 | 228k | if (simpleString) |
726 | 23.6k | { |
727 | 23.6k | actPos = zone.begin(); |
728 | 23.6k | lastPos = zone.end(); |
729 | 23.6k | } |
730 | 205k | else |
731 | 205k | { |
732 | 205k | auto fod = *(FODs_iter); |
733 | 205k | actPos = first ? zone.begin() : fod.m_pos; |
734 | 205k | if (long(actPos) >= zone.end()) break; |
735 | 202k | first = false; |
736 | | |
737 | 202k | if (++FODs_iter!= m_FODList.end()) |
738 | 198k | { |
739 | 198k | lastPos = (*FODs_iter).m_pos; |
740 | 198k | if (long(lastPos) >= zone.end()) lastPos = zone.end(); |
741 | 198k | } |
742 | 3.24k | else |
743 | 3.24k | lastPos = zone.end(); |
744 | 202k | --FODs_iter; |
745 | 202k | int fId = fod.m_id; |
746 | 202k | switch (fod.m_type) |
747 | 202k | { |
748 | 57.4k | case DataFOD::ATTR_TEXT: |
749 | 57.4k | if (fId >= 0) |
750 | 21.2k | actFont = m_state->m_fontList[size_t(fId)]; |
751 | 36.2k | else |
752 | 36.2k | actFont = defaultFont; |
753 | 57.4k | m_listener->setFont(actFont); |
754 | | #if DEBUG_FP |
755 | | f << "["; |
756 | | if (fId >= 0) f << "C" << fId << ":" << actFont << "]"; |
757 | | else f << "_]"; |
758 | | #endif |
759 | 57.4k | break; |
760 | 133k | case DataFOD::ATTR_PARAG: |
761 | 133k | if (fId >= 0) |
762 | 78.1k | m_listener->setParagraph(m_state->m_paragraphList[size_t(fId)]); |
763 | 55.2k | else |
764 | 55.2k | m_listener->setParagraph(WPSParagraph()); |
765 | | #if DEBUG_PP |
766 | | f << "["; |
767 | | if (fId >= 0) f << "P" << fId << ":" << m_state->m_paragraphList[size_t(fId)] << "]"; |
768 | | else f << "_]"; |
769 | | #endif |
770 | 133k | break; |
771 | 11.2k | case DataFOD::ATTR_PLC: |
772 | 11.2k | if (fId >= 0 && m_state->m_plcList[size_t(fId)].m_type == WPS4TextInternal::BKMK) |
773 | 2.90k | { |
774 | 2.90k | WPSEntry bkmk; |
775 | 2.90k | if (m_state->m_bookmarkMap.find(actPos) == m_state->m_bookmarkMap.end()) |
776 | 1.39k | { |
777 | 1.39k | WPS_DEBUG_MSG(("WPS4Text::readText: can not find the bookmark entry\n")); |
778 | 1.39k | } |
779 | 1.50k | else |
780 | 1.50k | bkmk = m_state->m_bookmarkMap.find(actPos)->second; |
781 | 2.90k | bkmk.setType("TEXT"); |
782 | 2.90k | bkmk.setId(WPS4TextInternal::Z_Bookmark); |
783 | 2.90k | mainParser().createDocument(bkmk, libwps::DOC_COMMENT_ANNOTATION); |
784 | 2.90k | } |
785 | | #if DEBUG_PLC_POS |
786 | | f << "[PLC"; |
787 | | if (fId>= 0) f << m_state->m_plcList[size_t(fId)] << "]"; |
788 | | else f << "_]"; |
789 | | #endif |
790 | 11.2k | break; |
791 | 0 | case DataFOD::ATTR_UNKN: |
792 | 0 | default: |
793 | 0 | WPS_DEBUG_MSG(("WPS4Text::readText: find unknown plc\n")); |
794 | | #if DEBUG_PLC_POS |
795 | | f << "[DataFOD(###Unknown)]"; |
796 | | #endif |
797 | 0 | break; |
798 | 202k | } |
799 | 202k | } |
800 | 225k | m_input->seek(actPos, librevenge::RVNG_SEEK_SET); |
801 | 225k | std::string chaine(""); |
802 | 225k | long len = lastPos-actPos; |
803 | 225k | std::string text; |
804 | 27.0M | for (long i = len; i>=0; i--) |
805 | 26.8M | { |
806 | 26.8M | long pos = m_input->tell(); |
807 | 26.8M | uint8_t readVal = i==0 ? uint8_t('\0') : libwps::readU8(m_input); |
808 | 26.8M | bool isSimpleField=false; |
809 | 26.8M | if (readVal=='&' && simpleString && pos+2 <= lastPos) |
810 | 61.4k | { |
811 | 61.4k | int nextVal = libwps::readU8(m_input); |
812 | 61.4k | m_input->seek(-1, librevenge::RVNG_SEEK_CUR); |
813 | 61.4k | switch (nextVal) // check me |
814 | 61.4k | { |
815 | 3.12k | case 'p': |
816 | 3.70k | case 'P': |
817 | 3.98k | case 'd': |
818 | 4.30k | case 'D': |
819 | 5.24k | case 't': |
820 | 6.55k | case 'T': |
821 | 7.33k | case 'f': |
822 | 8.57k | case 'F': |
823 | 8.57k | isSimpleField=true; |
824 | 8.57k | break; |
825 | 52.9k | default: |
826 | 52.9k | break; |
827 | 61.4k | } |
828 | 61.4k | } |
829 | 26.8M | if ((readVal<0x10 || readVal==0x11 || readVal==0x12 || readVal==0x1f || (version()<=2 && readVal==0xca) || isSimpleField) && !text.empty()) |
830 | 2.54M | { |
831 | 2.54M | m_listener->insertUnicodeString(libwps_tools_win::Font::unicodeString(text, actFont.m_type)); |
832 | 2.54M | text.clear(); |
833 | 2.54M | } |
834 | 26.8M | if (0x00 == readVal) |
835 | 14.6M | { |
836 | 14.6M | if (i > 1) |
837 | 14.3M | { |
838 | 14.3M | WPS_DEBUG_MSG(("WPS4Text::readText: find some unexpected 0 character\n")); |
839 | | // probably an error, but we can ignore id |
840 | 14.3M | chaine += '#'; |
841 | 14.3M | } |
842 | 14.6M | continue; |
843 | 14.6M | } |
844 | 12.2M | chaine += char(readVal); |
845 | 12.2M | switch (readVal) |
846 | 12.2M | { |
847 | 341k | case 0x01: // chart ? |
848 | 401k | case 0x08: // spreadsheet range |
849 | 434k | case 0x0e: // picture |
850 | 434k | { |
851 | 434k | if (!actFont.m_special || m_state->m_dosLinkList.empty() || actFont.m_dlinkId >= int(m_state->m_dosLinkList.size())) |
852 | 428k | { |
853 | 428k | WPS_DEBUG_MSG(("WPS4Text::readText: send DLINK can not find id\n")); |
854 | 428k | break; |
855 | 428k | } |
856 | 5.28k | int id = actFont.m_dlinkId >= 0 ? actFont.m_dlinkId : 0; |
857 | 5.28k | WPSEntry ent = m_state->m_dosLinkList[size_t(id)].m_pos; |
858 | 5.28k | ent.setType("TEXT"); |
859 | 5.28k | ent.setId(WPS4TextInternal::Z_DLink); |
860 | 5.28k | WPSPosition pos_(Vec2f(),Vec2f(3.0f,0.2f)); |
861 | 5.28k | pos_.setRelativePosition(WPSPosition::Paragraph, WPSPosition::XCenter); |
862 | 5.28k | pos_.m_wrapping = WPSPosition::WNone; |
863 | 5.28k | librevenge::RVNGPropertyList extras; |
864 | 5.28k | mainParser().createTextBox(ent, pos_, extras); |
865 | 5.28k | m_listener->insertEOL(); |
866 | 5.28k | break; |
867 | 434k | } |
868 | 146k | case 0x02: |
869 | 146k | m_listener->insertField(WPSField(WPSField::PageNumber)); |
870 | 146k | break; |
871 | 54.5k | case 0x03: |
872 | 54.5k | m_listener->insertField(WPSField(WPSField::Date)); |
873 | 54.5k | break; |
874 | 164k | case 0x04: |
875 | 164k | m_listener->insertField(WPSField(WPSField::Time)); |
876 | 164k | break; |
877 | 66.0k | case 0x05: |
878 | 66.0k | m_listener->insertField(WPSField(WPSField::Title)); |
879 | 66.0k | break; |
880 | 60.4k | case 0x07: |
881 | 60.4k | { |
882 | 60.4k | if (m_state->m_objectMap.find(actPos) == m_state->m_objectMap.end()) |
883 | 58.1k | { |
884 | 58.1k | WPS_DEBUG_MSG(("WPS4Text::readText: can not find object for position : %lX\n", static_cast<unsigned long>(actPos))); |
885 | 58.1k | } |
886 | 2.24k | else |
887 | 2.24k | { |
888 | 2.24k | WPS4TextInternal::Object const &obj = m_state->m_objectMap[actPos]; |
889 | 2.24k | if (obj.m_id < 0 || obj.m_page > 0) break; |
890 | 1.84k | WPSPosition position(Vec2f(0,0), obj.m_size); |
891 | 1.84k | position.setRelativePosition(WPSPosition::CharBaseLine); |
892 | 1.84k | position.m_wrapping = WPSPosition::WDynamic; |
893 | 1.84k | mainParser().sendObject(position, obj.m_id); |
894 | 1.84k | } |
895 | 60.0k | break; |
896 | 60.4k | } |
897 | 60.0k | case 0x0f: |
898 | 41.3k | { |
899 | 41.3k | if (m_state->m_dateTimeMap.find(actPos) == m_state->m_dateTimeMap.end()) |
900 | 36.4k | { |
901 | 36.4k | WPS_DEBUG_MSG(("WPS4Text::readText: can not find date/time for position : %lX\n", static_cast<unsigned long>(actPos))); |
902 | 36.4k | } |
903 | 4.85k | else |
904 | 4.85k | { |
905 | 4.85k | auto const &form = m_state->m_dateTimeMap[actPos]; |
906 | 4.85k | std::string format = form.format(); |
907 | 4.85k | if (format.length()) |
908 | 3.99k | { |
909 | 3.99k | WPSField field(WPSField::Date); |
910 | 3.99k | field.m_DTFormat=format; |
911 | 3.99k | m_listener->insertField(field); |
912 | 3.99k | } |
913 | 864 | else |
914 | 864 | { |
915 | 864 | WPS_DEBUG_MSG(("WPS4Text::readText: unknown date/time format for position : %lX\n", static_cast<unsigned long>(actPos))); |
916 | 864 | } |
917 | 4.85k | } |
918 | 41.3k | break; |
919 | 60.4k | } |
920 | 70.3k | case 0x06: // footnote |
921 | 70.3k | { |
922 | | // ok if this is the first character of the footnote definition |
923 | 70.3k | if (zone.id() == WPS4TextInternal::Z_Note) break; |
924 | 66.7k | if (m_state->m_footnoteMap.find(pos) == m_state->m_footnoteMap.end() || |
925 | 1.56k | m_state->m_footnoteMap[pos] == nullptr) |
926 | 65.1k | { |
927 | 65.1k | WPS_DEBUG_MSG(("WPS4Text::readText:do not find the footnote zone\n")); |
928 | 65.1k | break; |
929 | 65.1k | } |
930 | 1.56k | auto const ¬e = *m_state->m_footnoteMap[pos]; |
931 | 1.56k | mainParser().createNote(note, note.m_label); |
932 | 1.56k | break; |
933 | 66.7k | } |
934 | 81.3k | case 0x09: |
935 | 81.3k | m_listener->insertTab(); |
936 | 81.3k | break; |
937 | 903k | case 0x0C: |
938 | 903k | if (mainZone) mainParser().newPage(++actPage); |
939 | 903k | break; |
940 | 84.6k | case 0x0d: |
941 | 84.6k | break; // 0d0a = end of line |
942 | 204k | case 0x0a: |
943 | 204k | m_listener->insertEOL(); |
944 | 204k | break; |
945 | 40.4k | case 0x0b: // check me |
946 | 40.4k | m_listener->insertEOL(true); |
947 | 40.4k | break; |
948 | 21.9k | case 0x11: // insecable hyphen |
949 | 21.9k | m_listener->insertUnicode(0x2011); |
950 | 21.9k | break; |
951 | 87.7k | case 0x12: // insecable space |
952 | 87.7k | m_listener->insertUnicode(0xA0); |
953 | 87.7k | break; |
954 | 16.0k | case 0x1F: // optional hyphen |
955 | 16.0k | break; |
956 | 64.1k | case '&': |
957 | 64.1k | if (isSimpleField) |
958 | 8.57k | { |
959 | 8.57k | int nextVal = libwps::readU8(m_input); |
960 | 8.57k | bool done = true; |
961 | 8.57k | switch (nextVal) // check me |
962 | 8.57k | { |
963 | 3.12k | case 'p': |
964 | 3.70k | case 'P': |
965 | 3.70k | m_listener->insertField(WPSField(WPSField::PageNumber)); |
966 | 3.70k | break; |
967 | 280 | case 'd': |
968 | 599 | case 'D': |
969 | 599 | m_listener->insertField(WPSField(WPSField::Date)); |
970 | 599 | break; |
971 | 939 | case 't': |
972 | 2.24k | case 'T': |
973 | 2.24k | m_listener->insertField(WPSField(WPSField::Time)); |
974 | 2.24k | break; |
975 | 785 | case 'f': |
976 | 2.02k | case 'F': |
977 | 2.02k | m_listener->insertField(WPSField(WPSField::Title)); |
978 | 2.02k | break; |
979 | | // case '&': check me does '&&'->'&' ? |
980 | 0 | default: |
981 | 0 | done = false; |
982 | 0 | break; |
983 | 8.57k | } |
984 | 8.57k | if (done) |
985 | 8.57k | { |
986 | 8.57k | i--; |
987 | 8.57k | break; |
988 | 8.57k | } |
989 | 0 | m_input->seek(-1, librevenge::RVNG_SEEK_CUR); |
990 | 0 | } |
991 | 55.6k | WPS_FALLTHROUGH; |
992 | 9.74M | default: |
993 | 9.74M | if (version()<=2) |
994 | 7.19M | { |
995 | | // special caracter |
996 | 7.19M | if (readVal==0xca) // not breaking space |
997 | 5.06k | { |
998 | 5.06k | m_listener->insertCharacter(0xA0); |
999 | 5.06k | break; |
1000 | 5.06k | } |
1001 | 7.19M | } |
1002 | 9.74M | if (readVal) |
1003 | 9.74M | text.push_back(char(readVal)); |
1004 | 9.74M | break; |
1005 | 12.2M | } |
1006 | 12.2M | } |
1007 | | |
1008 | 225k | if (simpleString) break; |
1009 | | |
1010 | 202k | f << "='"<<chaine<<"'"; |
1011 | 202k | ascii().addPos(actPos); |
1012 | 202k | ascii().addNote(f.str().c_str()); |
1013 | 202k | } |
1014 | | |
1015 | 63.7k | if (dlink) |
1016 | 4.61k | m_listener->insertUnicode(0x226b); |
1017 | | |
1018 | 63.7k | return true; |
1019 | 63.7k | } |
1020 | | |
1021 | | //////////////////////////////////////////////////////////// |
1022 | | // find all the text entries |
1023 | | //////////////////////////////////////////////////////////// |
1024 | | bool WPS4Text::readEntries() |
1025 | 4.63k | { |
1026 | 4.63k | auto &nameMultiMap = getNameEntryMap(); |
1027 | | |
1028 | 4.63k | libwps::DebugStream f; |
1029 | 4.63k | long actPos = m_input->tell(); |
1030 | 4.63k | f << "ZZHeader-Text:Limit("; |
1031 | | |
1032 | 4.63k | int textLimits[4]; |
1033 | | // look like begin of text : end of header/end of footer/end text |
1034 | | // but sometimes the zones overlaps !!! |
1035 | 18.5k | for (int &textLimit : textLimits) textLimit = libwps::read32(m_input); |
1036 | | |
1037 | 4.63k | bool first = true, ok = true; |
1038 | 4.63k | long lastPos = textLimits[0] < 0x100 ? 0x100 : textLimits[0]; |
1039 | 18.5k | for (int i = 0; i < 3; ++i) |
1040 | 13.9k | { |
1041 | 13.9k | long newPos = textLimits[i+1]; |
1042 | 13.9k | WPSEntry zone; |
1043 | 13.9k | zone.setBegin(lastPos); |
1044 | 13.9k | zone.setEnd(newPos); |
1045 | 13.9k | zone.setType("TEXT"); |
1046 | 13.9k | zone.setId(i); |
1047 | | |
1048 | 13.9k | if (newPos >= lastPos) |
1049 | 7.43k | lastPos = newPos; |
1050 | 13.9k | if (!zone.valid() || zone.begin() < 0x100) |
1051 | 9.22k | { |
1052 | 9.22k | if (newPos != 0x100 && newPos != -1) |
1053 | 7.44k | { |
1054 | 7.44k | WPS_DEBUG_MSG(("WPS4Text::readEntries: find odd text limit\n")); |
1055 | 7.44k | ok = false; |
1056 | 7.44k | } |
1057 | 9.22k | f << "_, "; |
1058 | 9.22k | continue; |
1059 | 9.22k | } |
1060 | | |
1061 | 4.68k | if (first) |
1062 | 3.53k | { |
1063 | 3.53k | m_textPositions.setBegin(zone.begin()); |
1064 | 3.53k | first = false; |
1065 | 3.53k | } |
1066 | | |
1067 | 4.68k | m_textPositions.setEnd(zone.end()); |
1068 | 4.68k | nameMultiMap.insert(WPS4Parser::NameMultiMap::value_type(zone.type(), zone)); |
1069 | | |
1070 | 4.68k | switch (i) |
1071 | 4.68k | { |
1072 | 1.13k | case 0: |
1073 | 1.13k | m_state->m_header = zone; |
1074 | 1.13k | break; |
1075 | 1.58k | case 1: |
1076 | 1.58k | m_state->m_footer = zone; |
1077 | 1.58k | break; |
1078 | 1.96k | case 2: |
1079 | 1.96k | m_state->m_main = zone; |
1080 | 1.96k | break; |
1081 | 0 | default: |
1082 | 0 | break; |
1083 | 4.68k | } |
1084 | | |
1085 | 4.68k | f << "Text"<<i << "=" << std::hex << zone.begin() << "x" << zone.end() << ","; |
1086 | 4.68k | ascii().addPos(zone.begin()); |
1087 | 4.68k | std::string name = "ZZ"; |
1088 | 4.68k | name+= zone.type(); |
1089 | 4.68k | name+=char('0'+i); |
1090 | 4.68k | ascii().addNote(name.c_str()); |
1091 | 4.68k | ascii().addPos(zone.end()); |
1092 | 4.68k | ascii().addNote("_"); |
1093 | 4.68k | } |
1094 | 4.63k | f << ")"; |
1095 | 4.63k | if (!ok) |
1096 | 3.54k | { |
1097 | 3.54k | m_state->m_header = m_state->m_footer = WPSEntry(); |
1098 | 3.54k | m_state->m_main = m_textPositions; |
1099 | 3.54k | } |
1100 | 4.63k | if (!m_textPositions.valid()) |
1101 | 1.10k | { |
1102 | 1.10k | WPS_DEBUG_MSG(("WPS4Text::readEntries: textPosition is not valid")); |
1103 | 1.10k | return false; |
1104 | 1.10k | } |
1105 | | |
1106 | | /* stream offset to end of file */ |
1107 | 3.53k | auto eof = long(libwps::readU32(m_input)); |
1108 | | |
1109 | 3.53k | if (m_textPositions.end() > eof) |
1110 | 117 | { |
1111 | 117 | WPS_DEBUG_MSG(("WPS4Text:readEntries: can not find text positions\n")); |
1112 | 117 | return false; |
1113 | 117 | } |
1114 | | |
1115 | | // check if fPositions.offset_eos |
1116 | 3.41k | long newPos = m_input->tell(); |
1117 | 3.41k | if (m_input->seek(eof-1, librevenge::RVNG_SEEK_SET) != 0 || m_input->tell() != eof-1) |
1118 | 2.93k | { |
1119 | 2.93k | eof = m_input->tell(); |
1120 | 2.93k | WPS_DEBUG_MSG(("WPS4Text:readEntries: incomplete file\n")); |
1121 | 2.93k | if (eof < m_textPositions.end()) return false; |
1122 | 2.93k | } |
1123 | 3.22k | mainParser().setSizeFile(eof); |
1124 | | |
1125 | 3.22k | f << ", endFile=" << eof; |
1126 | 3.22k | ascii().addPos(actPos); |
1127 | 3.22k | ascii().addNote(f.str().c_str()); |
1128 | | |
1129 | 3.22k | m_input->seek(newPos, librevenge::RVNG_SEEK_SET); |
1130 | | |
1131 | 3.22k | static char const *zName[] = |
1132 | 3.22k | { "BTEC", "BTEP", "SHdr", "SFtr", "DLINK", "FTNp", "FTNd", "BKMK", "FONT" }; |
1133 | | |
1134 | 3.22k | for (auto &i : zName) |
1135 | 29.0k | mainParser().parseEntry(i); |
1136 | | |
1137 | 3.22k | return true; |
1138 | 3.41k | } |
1139 | | |
1140 | | //////////////////////////////////////////////////////////// |
1141 | | // find all the text structures |
1142 | | //////////////////////////////////////////////////////////// |
1143 | | bool WPS4Text::readStructures() |
1144 | 3.22k | { |
1145 | 3.22k | auto &nameMultiMap = getNameEntryMap(); |
1146 | | |
1147 | | // first find the font name |
1148 | 3.22k | auto pos = nameMultiMap.find("FONT"); |
1149 | 3.22k | if (pos != nameMultiMap.end()) readFontNames(pos->second); |
1150 | | |
1151 | | // now find the character and paragraph properties |
1152 | 9.41k | for (int i = 0; i < 2; ++i) |
1153 | 6.19k | { |
1154 | | // we begin by i = 1 to create firsts the fdpc structure |
1155 | 6.19k | if (findFDPStructures(1-i)) continue; |
1156 | 4.97k | findFDPStructuresByHand(1-i); |
1157 | 4.97k | } |
1158 | | |
1159 | | /* read character FODs (FOrmatting Descriptors) */ |
1160 | 3.22k | std::vector<DataFOD> fdps; |
1161 | 3.22k | for (auto const &fdp : m_state->m_FDPCs) |
1162 | 14.7k | readFDP(fdp, fdps, static_cast<FDPParser>(&WPS4Text::readFont)); |
1163 | 3.22k | m_FODList = mergeSortedFODLists(fdps, m_FODList); |
1164 | | |
1165 | | |
1166 | | /* read paragraphs FODs (FOrmatting Descriptors) */ |
1167 | 3.22k | fdps.resize(0); |
1168 | 3.22k | for (auto const &fdp : m_state->m_FDPPs) |
1169 | 30.4k | readFDP(fdp, fdps, static_cast<FDPParser>(&WPS4Text::readParagraph)); |
1170 | 3.22k | m_FODList = mergeSortedFODLists(fdps, m_FODList); |
1171 | | |
1172 | | /* read the object structures */ |
1173 | 3.22k | pos = nameMultiMap.find("EOBJ"); |
1174 | 3.22k | if (pos != nameMultiMap.end()) |
1175 | 782 | { |
1176 | 782 | std::vector<long> textPtrs, listValues; |
1177 | 782 | readPLC(pos->second, textPtrs, listValues, &WPS4Text::objectDataParser); |
1178 | 782 | } |
1179 | | |
1180 | | // update the footnote |
1181 | 3.22k | WPSEntry ftnD, ftnP; |
1182 | 3.22k | pos = nameMultiMap.find("FTNd"); |
1183 | 3.22k | if (pos != nameMultiMap.end()) ftnD = pos->second; |
1184 | 3.22k | pos = nameMultiMap.find("FTNp"); |
1185 | 3.22k | if (pos != nameMultiMap.end()) ftnP = pos->second; |
1186 | 3.22k | readFootNotes(ftnD, ftnP); |
1187 | | |
1188 | | // bookmark |
1189 | 3.22k | pos = nameMultiMap.find("BKMK"); |
1190 | 3.22k | if (pos != nameMultiMap.end()) |
1191 | 420 | { |
1192 | 420 | std::vector<long> textPtrs, listValues; |
1193 | 420 | readPLC(pos->second, textPtrs, listValues, &WPS4Text::bkmkDataParser); |
1194 | 420 | } |
1195 | | |
1196 | | // the list of file |
1197 | 3.22k | pos = nameMultiMap.find("DLINK"); |
1198 | 3.22k | if (pos != nameMultiMap.end()) |
1199 | 299 | readDosLink(pos->second); |
1200 | | |
1201 | | // date/time format |
1202 | 3.22k | pos = nameMultiMap.find("DTTM"); |
1203 | 3.22k | if (pos != nameMultiMap.end()) |
1204 | 340 | { |
1205 | 340 | WPSEntry const &zone = pos->second; |
1206 | 340 | std::vector<long> textPtrs, listValues; |
1207 | 340 | readPLC(zone, textPtrs, listValues, &WPS4Text::dttmDataParser); |
1208 | 340 | } |
1209 | | |
1210 | | // finally, we must remove the footnote of textposition... |
1211 | 3.22k | long bot = m_state->m_main.begin(); |
1212 | 3.22k | long endPos = m_state->m_main.end(); |
1213 | 3.22k | size_t numFootNotes = m_state->m_footnoteList.size(), actNote = 0; |
1214 | 3.22k | bool textPosUpdated = false; |
1215 | 8.75k | while (bot < endPos) |
1216 | 5.52k | { |
1217 | 5.52k | if (actNote < numFootNotes && |
1218 | 2.56k | m_state->m_footnoteList[actNote].begin()==bot) |
1219 | 1.53k | { |
1220 | 1.53k | bot = m_state->m_footnoteList[actNote].end(); |
1221 | 1.53k | actNote++; |
1222 | 1.53k | continue; |
1223 | 1.53k | } |
1224 | 3.99k | long lastPos = actNote < numFootNotes ? |
1225 | 2.96k | m_state->m_footnoteList[actNote].begin() : endPos; |
1226 | 3.99k | if (lastPos > endPos) lastPos = endPos; |
1227 | 3.99k | WPSEntry mZone; |
1228 | 3.99k | mZone.setBegin(bot); |
1229 | 3.99k | mZone.setEnd(lastPos); |
1230 | 3.99k | mZone.setType("TEXT"); |
1231 | 3.99k | if (!textPosUpdated) |
1232 | 3.01k | { |
1233 | 3.01k | mZone.setId(WPS4TextInternal::Z_Main); |
1234 | 3.01k | m_state->m_main = mZone; |
1235 | 3.01k | textPosUpdated = true; |
1236 | 3.01k | } |
1237 | 982 | else |
1238 | 982 | { |
1239 | 982 | if (m_state->m_otherZones.size() == 0) |
1240 | 41 | { |
1241 | 41 | WPS_DEBUG_MSG(("WPS4Text::readStructures: find unknown text zone\n")); |
1242 | 41 | } |
1243 | 982 | mZone.setId(WPS4TextInternal::Z_Unknown); |
1244 | 982 | m_state->m_otherZones.push_back(mZone); |
1245 | 982 | } |
1246 | 3.99k | bot = lastPos; |
1247 | 3.99k | } |
1248 | | |
1249 | | |
1250 | 3.22k | return true; |
1251 | 3.22k | } |
1252 | | |
1253 | | //////////////////////////////////////////////////////////// |
1254 | | // find FDP zones ( normal method followed by another method |
1255 | | // which may works for some bad files ) |
1256 | | //////////////////////////////////////////////////////////// |
1257 | | bool WPS4Text::findFDPStructures(int which) |
1258 | 6.19k | { |
1259 | 6.19k | std::vector<WPSEntry> &zones = which ? m_state->m_FDPCs : m_state->m_FDPPs; |
1260 | 6.19k | zones.resize(0); |
1261 | | |
1262 | 6.19k | char const *indexName = which ? "BTEC" : "BTEP"; |
1263 | 6.19k | char const *sIndexName = which ? "FDPC" : "FDPP"; |
1264 | | |
1265 | 6.19k | auto const &nameMultiMap =getNameEntryMap(); |
1266 | 6.19k | auto pos = nameMultiMap.find(indexName); |
1267 | 6.19k | if (pos == nameMultiMap.end()) return false; |
1268 | | |
1269 | 2.82k | std::vector<long> textPtrs; |
1270 | 2.82k | std::vector<long> listValues; |
1271 | | |
1272 | 2.82k | if (!readPLC(pos->second, textPtrs, listValues)) return false; |
1273 | | |
1274 | 1.46k | size_t numV = listValues.size(); |
1275 | 1.46k | if (textPtrs.size() != numV+1) return false; |
1276 | | |
1277 | 1.35k | WPSEntry zone; |
1278 | 1.35k | zone.setType(sIndexName); |
1279 | | |
1280 | 46.0k | for (size_t i = 0; i < numV; ++i) |
1281 | 44.8k | { |
1282 | 44.8k | long bPos = listValues[i]; |
1283 | 44.8k | if (bPos <= 0) return false; |
1284 | 44.7k | zone.setBegin(bPos); |
1285 | 44.7k | zone.setLength(0x80); |
1286 | | |
1287 | 44.7k | zones.push_back(zone); |
1288 | 44.7k | } |
1289 | | |
1290 | 1.22k | return true; |
1291 | 1.35k | } |
1292 | | |
1293 | | bool WPS4Text::findFDPStructuresByHand(int which) |
1294 | 4.97k | { |
1295 | 4.97k | char const *indexName = which ? "FDPC" : "FDPP"; |
1296 | 4.97k | WPS_DEBUG_MSG(("WPS4Text::findFDPStructuresByHand: need to create %s list by hand \n", indexName)); |
1297 | | |
1298 | 4.97k | auto &zones = which ? m_state->m_FDPCs : m_state->m_FDPPs; |
1299 | 4.97k | zones.resize(0); |
1300 | | |
1301 | 4.97k | long debPos; |
1302 | 4.97k | if (which == 1) |
1303 | 2.65k | { |
1304 | | // hack: each fdp block is aligned with 0x80, |
1305 | | // and appears consecutively just after the text |
1306 | 2.65k | auto pnChar = uint32_t((m_textPositions.end()+127)>>7); |
1307 | | /* sanity check */ |
1308 | 2.65k | if (0 == pnChar) |
1309 | 0 | { |
1310 | 0 | WPS_DEBUG_MSG(("WPS4Text::findFDPStructuresByHand: pnChar is 0, so file may be corrupt\n")); |
1311 | 0 | throw libwps::ParseException(); |
1312 | 0 | } |
1313 | 2.65k | debPos = 0x80 * long(pnChar); |
1314 | 2.65k | } |
1315 | 2.31k | else |
1316 | 2.31k | { |
1317 | 2.31k | size_t nFDPC = m_state->m_FDPCs.size(); |
1318 | 2.31k | if (!nFDPC) |
1319 | 1.84k | { |
1320 | 1.84k | WPS_DEBUG_MSG(("WPS4Text::findFDPStructuresByHand: can not find last fdpc pos\n")); |
1321 | 1.84k | return false; |
1322 | 1.84k | } |
1323 | 470 | debPos = m_state->m_FDPCs[nFDPC-1].end(); |
1324 | 470 | } |
1325 | | |
1326 | 3.12k | WPSEntry fdp; |
1327 | 3.12k | fdp.setType(indexName); |
1328 | | |
1329 | 3.12k | long lastPos = m_textPositions.begin(); |
1330 | 4.51k | while (1) |
1331 | 4.51k | { |
1332 | 4.51k | m_input->seek(debPos+0x7f, librevenge::RVNG_SEEK_SET); |
1333 | 4.51k | if (m_input->tell() != debPos+0x7f) |
1334 | 1.43k | { |
1335 | 1.43k | WPS_DEBUG_MSG(("WPS4Text: find EOF while parsing the %s\n", indexName)); |
1336 | 1.43k | return false; |
1337 | 1.43k | } |
1338 | 3.07k | int nbElt = libwps::readU8(m_input); |
1339 | 3.07k | if (5*nbElt+4 > 0x80) |
1340 | 584 | { |
1341 | 584 | WPS_DEBUG_MSG(("WPS4Text: find too big number of data while parsing the %s\n", indexName)); |
1342 | 584 | return false; |
1343 | 584 | } |
1344 | 2.49k | m_input->seek(debPos, librevenge::RVNG_SEEK_SET); |
1345 | 2.49k | if (long(libwps::readU32(m_input)) != lastPos) |
1346 | 991 | { |
1347 | 991 | WPS_DEBUG_MSG(("WPS4Text: find incorrect linking while parsing the %s\n", indexName)); |
1348 | 991 | return false; |
1349 | 991 | } |
1350 | 1.50k | if (nbElt != 1) |
1351 | 1.40k | m_input->seek(4*nbElt-4, librevenge::RVNG_SEEK_CUR); |
1352 | | |
1353 | 1.50k | auto newPos = long(libwps::readU32(m_input)); |
1354 | 1.50k | if (newPos < lastPos || newPos > m_textPositions.end()) |
1355 | 67 | { |
1356 | 67 | WPS_DEBUG_MSG(("WPS4Text: find incorrect linking while parsing the %s\n", indexName)); |
1357 | 67 | return false; |
1358 | 67 | } |
1359 | 1.43k | fdp.setBegin(debPos); |
1360 | 1.43k | fdp.setLength(0x80); |
1361 | 1.43k | zones.push_back(fdp); |
1362 | | |
1363 | 1.43k | if (newPos == m_textPositions.end()) break; |
1364 | | |
1365 | 1.39k | lastPos = newPos; |
1366 | 1.39k | debPos = fdp.end(); |
1367 | 1.39k | } |
1368 | | |
1369 | 46 | return true; |
1370 | 3.12k | } |
1371 | | |
1372 | | // PLC Data: default parser |
1373 | | bool WPS4Text::defDataParser(long, long, int, long endPos, std::string &mess) |
1374 | 785 | { |
1375 | 785 | mess = ""; |
1376 | 785 | libwps::DebugStream f; |
1377 | | |
1378 | 785 | long actPos = m_input->tell(); |
1379 | 785 | long length = endPos+1-actPos; |
1380 | 785 | int sz = (length%4)==0 ? 4 : (length%2)==0 ? 2 : 1; |
1381 | 785 | f << "unk["<< sz << "]="; |
1382 | 7.88k | while (m_input->tell() <= endPos+1-sz) |
1383 | 7.10k | { |
1384 | 7.10k | long val = 0; |
1385 | 7.10k | switch (sz) |
1386 | 7.10k | { |
1387 | 2.92k | case 1: |
1388 | 2.92k | val = libwps::readU8(m_input); |
1389 | 2.92k | break; |
1390 | 982 | case 2: |
1391 | 982 | val = libwps::readU16(m_input); |
1392 | 982 | break; |
1393 | 3.20k | case 4: |
1394 | 3.20k | val = long(libwps::readU32(m_input)); |
1395 | 3.20k | break; |
1396 | 0 | default: |
1397 | 0 | break; |
1398 | 7.10k | } |
1399 | 7.10k | f << std::hex << val << std::dec << ","; |
1400 | 7.10k | } |
1401 | 785 | mess = f.str(); |
1402 | 785 | return true; |
1403 | 785 | } |
1404 | | |
1405 | | //////////////////////////////////////////////////////////// |
1406 | | // the fonts name zone (zone8) |
1407 | | //////////////////////////////////////////////////////////// |
1408 | | bool WPS4Text::readFontNames(WPSEntry const &entry) |
1409 | 502 | { |
1410 | 502 | if (!entry.valid()) return false; |
1411 | | |
1412 | 502 | m_input->seek(entry.begin(), librevenge::RVNG_SEEK_SET); |
1413 | | |
1414 | 502 | long endPos = entry.end(); |
1415 | 502 | int nFonts = 0; |
1416 | 502 | auto docType=mainParser().getDefaultFontType(); |
1417 | 2.38k | while (m_input->tell() < endPos) |
1418 | 2.00k | { |
1419 | 2.00k | long actPos; |
1420 | 2.00k | actPos = m_input->tell(); |
1421 | 2.00k | libwps::DebugStream f; |
1422 | | |
1423 | | /* Sometimes the font numbers start at 0 and increment nicely. |
1424 | | However, other times the font numbers jump around. */ |
1425 | 2.00k | uint8_t font_number = libwps::readU8(m_input); |
1426 | 2.00k | if (m_state->m_fontNames.find(font_number) != m_state->m_fontNames.end()) |
1427 | 105 | { |
1428 | 105 | WPS_DEBUG_MSG(("WPS4Text::readFontNames: at position 0x%lx: font number %i duplicated\n", |
1429 | 105 | static_cast<unsigned long>(m_input->tell()-2), font_number)); |
1430 | 105 | throw libwps::ParseException(); |
1431 | 105 | } |
1432 | | |
1433 | 1.90k | f << "Font" << nFonts++ << ": id=" << int(font_number) << ", "; |
1434 | | //fixme: what is this byte? maybe a font class |
1435 | 1.90k | uint8_t unknown_byte = libwps::readU8(m_input); |
1436 | 1.90k | f << "unk=" << int(unknown_byte) << ", "; |
1437 | | |
1438 | 1.90k | librevenge::RVNGString s; |
1439 | 1.90k | uint8_t nChar = libwps::readU8(m_input); |
1440 | 144k | for (uint8_t i = nChar; i>0; i--) |
1441 | 142k | { |
1442 | 142k | if (m_input->isEnd()) |
1443 | 23 | { |
1444 | 23 | WPS_DEBUG_MSG(("WPS4Text::readFontNames: can not read the font number %i (end of file)\n", |
1445 | 23 | font_number)); |
1446 | 23 | throw libwps::ParseException(); |
1447 | 23 | } |
1448 | 142k | unsigned char val = libwps::readU8(m_input); |
1449 | | // sanity check (because sometimes contains char > 0x80 .. ) |
1450 | 142k | if (val >= ' ' && val <= 'z') s.append(char(val)); |
1451 | 92.9k | else |
1452 | 92.9k | { |
1453 | 92.9k | static bool first = true; |
1454 | 92.9k | if (first) |
1455 | 3 | { |
1456 | 3 | first = false; |
1457 | 3 | WPS_DEBUG_MSG(("WPS4Text:readFontNames find odd caracters in font name : %d\n", int(val))); |
1458 | 3 | } |
1459 | 92.9k | f << "##oddC=" << int(val) << ", "; |
1460 | 92.9k | } |
1461 | 142k | } |
1462 | 1.87k | auto fType=libwps_tools_win::Font::getFontType(s); |
1463 | 1.87k | if (fType==libwps_tools_win::Font::UNKNOWN) |
1464 | 1.82k | fType=docType; |
1465 | 1.87k | WPS4TextInternal::FontName font(fType); |
1466 | 1.87k | font.m_name = s; |
1467 | 1.87k | f << font; |
1468 | | |
1469 | 1.87k | m_state->m_fontNames.insert(std::pair<int,WPS4TextInternal::FontName>(font_number,font)); |
1470 | | |
1471 | 1.87k | ascii().addPos(actPos); |
1472 | 1.87k | ascii().addNote(f.str().c_str()); |
1473 | 1.87k | ascii().addPos(m_input->tell()); |
1474 | 1.87k | } |
1475 | | |
1476 | 374 | return true; |
1477 | 502 | } |
1478 | | |
1479 | | //////////////////////////////////////////////////////////// |
1480 | | // the font: |
1481 | | //////////////////////////////////////////////////////////// |
1482 | | bool WPS4Text::readFont(long endPos, int &id, std::string &mess) |
1483 | 15.1k | { |
1484 | 15.1k | WPS4TextInternal::Font font(getDefaultFont()); |
1485 | 15.1k | font.m_size = 12; |
1486 | | |
1487 | 15.1k | libwps::DebugStream f; |
1488 | | |
1489 | 15.1k | int fl[4] = { 0, 0, 0, 0}; |
1490 | 15.1k | if (m_input->tell() < endPos) fl[0] = libwps::readU8(m_input); |
1491 | | |
1492 | | /* set difference from default properties */ |
1493 | 15.1k | uint32_t attributes = 0; |
1494 | 15.1k | if (fl[0] & 0x01) attributes |= WPS_BOLD_BIT; |
1495 | 15.1k | if (fl[0] & 0x02) attributes |= WPS_ITALICS_BIT; |
1496 | 15.1k | if (fl[0] & 0x04) attributes |= WPS_STRIKEOUT_BIT; |
1497 | 15.1k | fl[0] &= 0xf8; |
1498 | | |
1499 | | // what & 0x01 -> ??? |
1500 | | // what & 0x02 -> note |
1501 | | // what & 0x04 -> ??? |
1502 | | // what & 0x08 -> fName |
1503 | | // what & 0x10 -> size |
1504 | | // what & 0x20 -> underline (fl[2]) |
1505 | | // what & 0x40 -> decalage |
1506 | | // what & 0x80 -> color |
1507 | 15.1k | int what = 0; |
1508 | 15.1k | if (m_input->tell() < endPos) what = libwps::readU8(m_input); |
1509 | | |
1510 | 15.1k | font.m_special = ((what & 2) != 0); |
1511 | 15.1k | what &= 0xfd; |
1512 | | |
1513 | 15.1k | if (m_input->tell() < endPos) |
1514 | 10.9k | { |
1515 | | // the fonts |
1516 | | // FIXME: find some properties with size=3, |
1517 | | // for which this character seems |
1518 | | // related to size, not font |
1519 | 10.9k | uint8_t font_n = libwps::readU8(m_input); |
1520 | | |
1521 | 10.9k | if (m_state->m_fontNames.find(font_n) != m_state->m_fontNames.end()) |
1522 | 766 | { |
1523 | 766 | auto const &fontName=m_state->m_fontNames.find(font_n)->second; |
1524 | 766 | font.m_name=fontName.m_name; |
1525 | 766 | font.m_type=fontName.m_type; |
1526 | 766 | } |
1527 | 10.1k | else if (version() <= 2) |
1528 | 9.42k | { |
1529 | 9.42k | font.m_name=WPS4TextInternal::FontName::getDosName(font_n); |
1530 | 9.42k | font.m_type=mainParser().getDefaultFontType(); |
1531 | 9.42k | } |
1532 | 748 | else |
1533 | 748 | { |
1534 | 748 | WPS_DEBUG_MSG(("WPS4Text: error: encountered font %i which is not indexed\n", |
1535 | 748 | font_n)); |
1536 | 748 | } |
1537 | | |
1538 | 10.9k | if (font.m_name.empty()) f << "###nameId=" << int(font_n) << ","; |
1539 | 10.9k | } |
1540 | | |
1541 | 15.1k | if (m_input->tell() < endPos) |
1542 | 10.1k | { |
1543 | | // underline, ... |
1544 | 10.1k | int underlinePos = libwps::readU8(m_input); |
1545 | 10.1k | if (underlinePos) |
1546 | 7.82k | { |
1547 | 7.82k | if (!(what & 0x20)) f << "undFl,"; |
1548 | 1.74k | else what &= 0xdf; |
1549 | 7.82k | attributes |= WPS_UNDERLINE_BIT; |
1550 | 7.82k | } |
1551 | 10.1k | } |
1552 | | |
1553 | 15.1k | if (m_input->tell() < endPos) // font size * 2 |
1554 | 9.82k | { |
1555 | 9.82k | int fSize = libwps::readU8(m_input); |
1556 | 9.82k | if (fSize) |
1557 | 7.85k | { |
1558 | 7.85k | if (!(what & 0x10)) f << "szFl,"; |
1559 | 2.99k | else what &= 0xef; |
1560 | 7.85k | font.m_size = (fSize/2); |
1561 | 7.85k | } |
1562 | 9.82k | } |
1563 | | |
1564 | 15.1k | if (m_input->tell() < endPos) // height decalage -> sub/superscript |
1565 | 9.41k | { |
1566 | 9.41k | int fDec = libwps::read8(m_input); |
1567 | 9.41k | if (fDec) |
1568 | 7.08k | { |
1569 | 7.08k | if (!(what & 0x40)) f << "sub/supFl(val=" << fDec<<"),"; |
1570 | 1.09k | else what &= 0xbf; |
1571 | | |
1572 | 7.08k | if (fDec > 0) attributes |= WPS_SUPERSCRIPT_BIT; |
1573 | 1.65k | else attributes |= WPS_SUBSCRIPT_BIT; |
1574 | 7.08k | } |
1575 | 9.41k | } |
1576 | 15.1k | if (m_input->tell()+2 <= endPos) // color field |
1577 | 7.06k | { |
1578 | 7.06k | int bkColor = libwps::readU8(m_input); |
1579 | 7.06k | int ftColor = libwps::readU8(m_input); |
1580 | 7.06k | bool setColor = !!(what & 0x80); |
1581 | 7.06k | what &= 0x7F; |
1582 | | |
1583 | 7.06k | if ((bkColor || ftColor) && !setColor) |
1584 | 4.71k | { |
1585 | 4.71k | setColor = true; |
1586 | 4.71k | f << "colorFl,"; |
1587 | 4.71k | } |
1588 | 7.06k | if (setColor) |
1589 | 5.78k | { |
1590 | 5.78k | WPSColor color; |
1591 | 5.78k | if (mainParser().getColor(bkColor, color)) |
1592 | 2.89k | font.m_backColor = color; |
1593 | 5.78k | if (mainParser().getColor(ftColor, color)) |
1594 | 3.06k | font.m_color = color; |
1595 | 5.78k | } |
1596 | 7.06k | } |
1597 | 15.1k | if (m_input->tell() < endPos) |
1598 | 7.48k | font.m_dlinkId = libwps::readU8(m_input); |
1599 | 15.1k | if (what) f << "#what=" << std::hex << what << std::dec << ","; |
1600 | 15.1k | if (fl[0]) f << "unkn0=" << std::hex << fl[0] << std::dec << ","; |
1601 | | |
1602 | 15.1k | if (m_input->tell() != endPos) |
1603 | 6.32k | { |
1604 | 6.32k | f << "#unknEnd=("; |
1605 | 104k | while (m_input->tell() < endPos) f << std::hex << libwps::readU8(m_input) <<","; |
1606 | 6.32k | f << ")"; |
1607 | 6.32k | } |
1608 | | |
1609 | 15.1k | font.m_attributes = attributes; |
1610 | 15.1k | font.m_extra = f.str(); |
1611 | | |
1612 | 15.1k | id = int(m_state->m_fontList.size()); |
1613 | 15.1k | m_state->m_fontList.push_back(font); |
1614 | 15.1k | f.str(""); |
1615 | 15.1k | f << font; |
1616 | 15.1k | mess = f.str(); |
1617 | | |
1618 | 15.1k | return true; |
1619 | 15.1k | } |
1620 | | |
1621 | | //////////////////////////////////////////////////////////// |
1622 | | // the file list: only in dos3 ? |
1623 | | //////////////////////////////////////////////////////////// |
1624 | | bool WPS4Text::readDosLink(WPSEntry const &entry) |
1625 | 299 | { |
1626 | 299 | if (!entry.valid()) return false; |
1627 | | |
1628 | 299 | long length = entry.length(); |
1629 | 299 | if (length%44) |
1630 | 123 | { |
1631 | 123 | WPS_DEBUG_MSG(("WPS4Text::readDosLink: length::=%ld seem odd\n", length)); |
1632 | 123 | return false; |
1633 | 123 | } |
1634 | | |
1635 | 176 | m_input->seek(entry.begin(), librevenge::RVNG_SEEK_SET); |
1636 | 176 | libwps::DebugStream f; |
1637 | 176 | long numElt = length/44; |
1638 | 176 | long val; |
1639 | 7.93k | for (long n = 0; n < numElt; ++n) |
1640 | 7.75k | { |
1641 | 7.75k | WPS4TextInternal::DosLink link; |
1642 | 7.75k | long pos = m_input->tell(); |
1643 | 7.75k | long endPos = pos+44; |
1644 | 7.75k | f.str(""); |
1645 | 23.2k | for (int i = 0; i < 2; ++i) // always 0, 0 |
1646 | 15.5k | { |
1647 | 15.5k | val = libwps::readU16(m_input); |
1648 | 15.5k | if (val) f << "unkn" << i << "=" << std::hex << val << std::dec << ","; |
1649 | 15.5k | } |
1650 | 7.75k | link.m_width = float(libwps::readU16(m_input)/1440.); |
1651 | 23.2k | for (int i = 2; i < 4; ++i) // always f0, f0 |
1652 | 15.5k | { |
1653 | 15.5k | val = libwps::readU16(m_input); |
1654 | 15.5k | if (val != 0xf0) f << "unkn" << i << "=" << std::hex << val << std::dec << ","; |
1655 | 15.5k | } |
1656 | 7.75k | link.m_type = libwps::readU8(m_input); |
1657 | 7.75k | val = libwps::readU8(m_input); |
1658 | 7.75k | if (val) // find 0x18 for a spreadsheet |
1659 | 5.58k | f << "unk4=" << std::hex << val << std::dec << ","; |
1660 | 7.75k | switch (link.m_type) |
1661 | 7.75k | { |
1662 | 299 | case 0x81: // picture ? |
1663 | 299 | { |
1664 | 299 | long dim[2]; |
1665 | 598 | for (long &i : dim) i = libwps::readU16(m_input); |
1666 | 299 | link.m_size = Vec2f(float(dim[0])/1440.f, float(dim[1])/1440.f); |
1667 | 299 | val = libwps::readU16(m_input); // always 0 |
1668 | 299 | if (val) f << "g0=" << val << ","; |
1669 | 299 | val = libwps::readU16(m_input); // always 4 |
1670 | 299 | if (val != 4) f << "g1=" << val << ","; |
1671 | 299 | } |
1672 | 299 | WPS_FALLTHROUGH; |
1673 | 799 | case 0x40: // spreadsheet range |
1674 | 2.19k | case 0x01: // char ? |
1675 | 2.19k | { |
1676 | 2.19k | std::string name(""); |
1677 | 2.19k | link.m_pos.setBegin(m_input->tell()); |
1678 | 52.0k | while (!m_input->isEnd() && long(m_input->tell()) < endPos) |
1679 | 50.5k | { |
1680 | 50.5k | auto c = char(libwps::readU8(m_input)); |
1681 | 50.5k | if (!c) |
1682 | 685 | { |
1683 | 685 | m_input->seek(-1, librevenge::RVNG_SEEK_CUR); |
1684 | 685 | break; |
1685 | 685 | } |
1686 | 49.8k | name += c; |
1687 | 49.8k | } |
1688 | 2.19k | link.m_pos.setEnd(m_input->tell()); |
1689 | 2.19k | link.m_pos.setId(WPS4TextInternal::Z_DLink); |
1690 | 2.19k | link.m_name = name; |
1691 | 2.19k | break; |
1692 | 799 | } |
1693 | 5.56k | default: |
1694 | 5.56k | break; |
1695 | 7.75k | } |
1696 | 7.75k | link.m_extra = f.str(); |
1697 | 7.75k | m_state->m_dosLinkList.push_back(link); |
1698 | 7.75k | f.str(""); |
1699 | 7.75k | f << "ZZDLINK-" << n << ":" << link; |
1700 | 7.75k | if (long(m_input->tell()) != endPos) |
1701 | 6.24k | ascii().addDelimiter(m_input->tell(),'|'); |
1702 | 7.75k | ascii().addPos(pos); |
1703 | 7.75k | ascii().addNote(f.str().c_str()); |
1704 | 7.75k | m_input->seek(endPos, librevenge::RVNG_SEEK_SET); |
1705 | 7.75k | } |
1706 | 176 | return true; |
1707 | 176 | } |
1708 | | |
1709 | | //////////////////////////////////////////////////////////// |
1710 | | // the paragraph properties: |
1711 | | //////////////////////////////////////////////////////////// |
1712 | | bool WPS4Text::readParagraph(long endPos, int &id, std::string &mess) |
1713 | 73.8k | { |
1714 | 73.8k | long actPos = m_input->tell(); |
1715 | 73.8k | long size = endPos - actPos; |
1716 | | |
1717 | 73.8k | WPSParagraph pp; |
1718 | 73.8k | if (size && size < 3) |
1719 | 4.58k | { |
1720 | 4.58k | WPS_DEBUG_MSG(("WPS4Text:readParagraph:(sz=%ld)\n", size)); |
1721 | 4.58k | return false; |
1722 | 4.58k | } |
1723 | | |
1724 | 69.2k | libwps::DebugStream f; |
1725 | 277k | for (int i = 0; i < 3; ++i) |
1726 | 207k | { |
1727 | 207k | int v = libwps::readU8(m_input); |
1728 | 207k | if (v != 0) f << "unkn"<<i<< "=" << v; |
1729 | 207k | } |
1730 | | |
1731 | 217k | while (m_input->tell() < endPos) |
1732 | 193k | { |
1733 | 193k | int v = libwps::readU8(m_input); |
1734 | 193k | long pos = m_input->tell(); |
1735 | 193k | bool ok = true, done = true; |
1736 | 193k | int arg = -1; |
1737 | 193k | switch (v) |
1738 | 193k | { |
1739 | 3.34k | case 0x2: |
1740 | 3.34k | { |
1741 | 3.34k | if (pos+1 > endPos) |
1742 | 220 | { |
1743 | 220 | ok = false; |
1744 | 220 | break; |
1745 | 220 | } |
1746 | 3.12k | arg = libwps::readU8(m_input); |
1747 | 3.12k | f << "f2=" << arg << ","; |
1748 | 3.12k | break; |
1749 | 3.34k | } |
1750 | 9.26k | case 0x5: |
1751 | 9.26k | { |
1752 | 9.26k | if (pos+1 > endPos) |
1753 | 670 | { |
1754 | 670 | ok = false; |
1755 | 670 | break; |
1756 | 670 | } |
1757 | 8.59k | arg = libwps::readU8(m_input); |
1758 | 8.59k | switch (arg) |
1759 | 8.59k | { |
1760 | 1.44k | case 0: |
1761 | 1.44k | pp.m_justify = libwps::JustificationLeft; |
1762 | 1.44k | break; |
1763 | 438 | case 1: |
1764 | 438 | pp.m_justify = libwps::JustificationCenter; |
1765 | 438 | break; |
1766 | 280 | case 2: |
1767 | 280 | pp.m_justify = libwps::JustificationRight; |
1768 | 280 | break; |
1769 | 417 | case 3: |
1770 | 417 | pp.m_justify = libwps::JustificationFull; |
1771 | 417 | break; |
1772 | 6.02k | default: |
1773 | 6.02k | f << "#just=" << arg << ","; |
1774 | 6.02k | pp.m_justify = libwps::JustificationLeft; |
1775 | 8.59k | } |
1776 | 8.59k | break; |
1777 | 8.59k | } |
1778 | 8.59k | case 0x7: // 1: marked don't break paragraph |
1779 | 14.3k | case 0x8: // 1: marked keep paragraph with next |
1780 | 14.3k | { |
1781 | 14.3k | if (pos+1 > endPos) |
1782 | 917 | { |
1783 | 917 | ok = false; |
1784 | 917 | break; |
1785 | 917 | } |
1786 | 13.4k | arg = libwps::readU8(m_input); |
1787 | 13.4k | if (arg == 0) break; |
1788 | 12.6k | if (arg == 1) pp.m_breakStatus |= ((v == 7) ? libwps::NoBreakBit : libwps::NoBreakWithNextBit); |
1789 | 11.7k | else f << "#status=" << arg << ","; |
1790 | 12.6k | break; |
1791 | 13.4k | } |
1792 | | |
1793 | | // BORDER |
1794 | 14.1k | case 0x9: |
1795 | 14.1k | { |
1796 | 14.1k | if (pos+1 > endPos) |
1797 | 446 | { |
1798 | 446 | ok = false; |
1799 | 446 | break; |
1800 | 446 | } |
1801 | 13.7k | arg = libwps::readU8(m_input); |
1802 | 13.7k | pp.m_borderStyle.m_style = WPSBorder::Simple; |
1803 | 13.7k | pp.m_borderStyle.m_type = WPSBorder::Single; |
1804 | 13.7k | pp.m_borderStyle.m_width = 1; |
1805 | 13.7k | int style = (arg&0xf); |
1806 | 13.7k | switch (style) |
1807 | 13.7k | { |
1808 | 681 | case 0: |
1809 | 681 | break; |
1810 | 1.07k | case 1: |
1811 | 1.07k | pp.m_borderStyle.m_width = 2; |
1812 | 1.07k | break; |
1813 | 1.95k | case 2: |
1814 | 1.95k | pp.m_borderStyle.m_type = WPSBorder::Double; |
1815 | 1.95k | break; |
1816 | 790 | case 3: |
1817 | 790 | pp.m_borderStyle.m_style = WPSBorder::Dot; |
1818 | 790 | break; |
1819 | 585 | case 4: |
1820 | 585 | pp.m_borderStyle.m_style = WPSBorder::LargeDot; |
1821 | 585 | break; |
1822 | 577 | case 5: |
1823 | 577 | pp.m_borderStyle.m_style = WPSBorder::Dash; |
1824 | 577 | break; |
1825 | 920 | case 6: |
1826 | 1.58k | case 7: |
1827 | 2.30k | case 8: |
1828 | 2.30k | pp.m_borderStyle.m_width = style-3; |
1829 | 2.30k | break; |
1830 | 4.54k | case 9: |
1831 | 4.92k | case 10: |
1832 | 4.92k | pp.m_borderStyle.m_width = style-7; |
1833 | 4.92k | pp.m_borderStyle.m_type = WPSBorder::Double; |
1834 | 4.92k | break; |
1835 | 832 | default: |
1836 | 832 | f << "#borderStyle=" << style << ","; |
1837 | 832 | WPS_DEBUG_MSG(("WPS4Text:readParagraph: unknown border style\n")); |
1838 | 832 | break; |
1839 | 13.7k | } |
1840 | 13.7k | int high = (arg>>4); |
1841 | 13.7k | if (version() < 3) |
1842 | 4.39k | { |
1843 | 4.39k | WPSColor color; |
1844 | 4.39k | if (high && mainParser().getColor(high, color)) |
1845 | 2.43k | pp.m_borderStyle.m_color = color; |
1846 | 1.95k | else if (high) |
1847 | 72 | f << "#borderColor=" << high << ","; |
1848 | 4.39k | } |
1849 | 9.32k | else |
1850 | 9.32k | { |
1851 | 9.32k | switch (high) |
1852 | 9.32k | { |
1853 | 4.65k | case 0: |
1854 | 4.65k | break; |
1855 | 729 | case 4: |
1856 | 729 | pp.m_border = 0xf; |
1857 | 729 | break; |
1858 | 201 | case 8: |
1859 | 201 | pp.m_border = 0xf; |
1860 | 201 | f << "borderShaded,"; |
1861 | 201 | break; |
1862 | 3.74k | default: |
1863 | 3.74k | f << "#borderStyle[high]=" << high << ","; |
1864 | 3.74k | break; |
1865 | 9.32k | } |
1866 | 9.32k | } |
1867 | 13.7k | break; |
1868 | 13.7k | } |
1869 | 13.7k | case 0xa: // 1: top border |
1870 | 2.44k | case 0xb: // : bottom border |
1871 | 31.0k | case 0xc: // : left border |
1872 | 37.9k | case 0xd: // : right border |
1873 | 37.9k | { |
1874 | 37.9k | if (pos+1 > endPos) |
1875 | 1.22k | { |
1876 | 1.22k | ok = false; |
1877 | 1.22k | break; |
1878 | 1.22k | } |
1879 | 36.6k | arg = libwps::readU8(m_input); |
1880 | 36.6k | if (arg == 0) break; |
1881 | 34.2k | if (arg == 1) |
1882 | 9.38k | { |
1883 | 9.38k | switch (v) |
1884 | 9.38k | { |
1885 | 492 | case 0xa: |
1886 | 492 | pp.m_border |= WPSBorder::TopBit; |
1887 | 492 | break; |
1888 | 262 | case 0xb: |
1889 | 262 | pp.m_border |= WPSBorder::BottomBit; |
1890 | 262 | break; |
1891 | 3.23k | case 0xc: |
1892 | 3.23k | pp.m_border |= WPSBorder::LeftBit; |
1893 | 3.23k | break; |
1894 | 5.40k | case 0xd: |
1895 | 5.40k | pp.m_border |= WPSBorder::RightBit; |
1896 | 5.40k | break; |
1897 | 0 | default: |
1898 | 0 | break; |
1899 | 9.38k | } |
1900 | 9.38k | } |
1901 | 24.8k | else f << "#border=" << arg << ","; |
1902 | 34.2k | break; |
1903 | 34.2k | } |
1904 | 34.2k | case 0x18: // border color |
1905 | 5.45k | { |
1906 | 5.45k | if (long(pos)==endPos) |
1907 | 453 | { |
1908 | 453 | ok = false; |
1909 | 453 | break; |
1910 | 453 | } |
1911 | 5.00k | int colorId = libwps::readU8(m_input); |
1912 | 5.00k | WPSColor color; |
1913 | 5.00k | if (mainParser().getColor(colorId, color)) |
1914 | 1.13k | pp.m_borderStyle.m_color = color; |
1915 | 3.87k | else |
1916 | 3.87k | f << "#colorId=" << colorId << ","; |
1917 | 5.00k | break; |
1918 | 5.45k | } |
1919 | 17.1k | case 0xe: // 1: bullet |
1920 | 17.1k | { |
1921 | 17.1k | if (pos+1 > endPos) |
1922 | 804 | { |
1923 | 804 | ok = false; |
1924 | 804 | break; |
1925 | 804 | } |
1926 | 16.3k | arg = libwps::readU8(m_input); |
1927 | 16.3k | if (arg == 0) break; |
1928 | | |
1929 | 13.3k | pp.m_listLevelIndex = 1; |
1930 | 13.3k | pp.m_listLevel.m_type = libwps::BULLET; |
1931 | 13.3k | static const uint32_t bulletList[]= |
1932 | 13.3k | { |
1933 | 13.3k | 0x2022, 0x3e, 0x25c6, 0x21d2, 0x25c7, 0x2605, /* 1-6 */ |
1934 | 13.3k | 0, 0, 0, 0, 0, 0, /* 7-12 unknown */ |
1935 | 13.3k | 0, 0, 0, 0, 0, 0x2750, /* 13-17 unknown and document... */ |
1936 | 13.3k | 0x2713, 0x261e, 0x2704, 0x2611, 0x2612, 0x270e /* 18-24 */ |
1937 | 13.3k | }; |
1938 | 13.3k | if (arg <= 24 && bulletList[arg-1]) |
1939 | 4.63k | libwps::appendUnicode(bulletList[arg-1], pp.m_listLevel.m_bullet); |
1940 | 8.73k | else |
1941 | 8.73k | libwps::appendUnicode(0x2022, pp.m_listLevel.m_bullet); |
1942 | 13.3k | break; |
1943 | 16.3k | } |
1944 | 1.55k | case 0x1b: |
1945 | 20.9k | case 0x1a: |
1946 | 23.3k | case 0x10: // the bullet char : 0x18 |
1947 | 23.3k | { |
1948 | 23.3k | if (pos+1 > endPos) |
1949 | 1.04k | { |
1950 | 1.04k | ok = false; |
1951 | 1.04k | break; |
1952 | 1.04k | } |
1953 | 22.3k | arg = libwps::readU8(m_input); |
1954 | 22.3k | done = true; |
1955 | 22.3k | switch (v) |
1956 | 22.3k | { |
1957 | 18.7k | case 0x1a: |
1958 | 18.7k | if (arg) f << "backPattern=" << arg << ","; |
1959 | 18.7k | break; |
1960 | 1.40k | case 0x1b: |
1961 | 1.40k | { |
1962 | 1.40k | if (arg==0) break; |
1963 | 710 | WPSColor color; |
1964 | 710 | if (mainParser().getColor(arg>>4, color)) |
1965 | 706 | f << "backPatternBackColor=" << color << ";"; |
1966 | 4 | else |
1967 | 4 | f << "#backPatternBackColor=" << (arg>>4) << ","; |
1968 | 710 | if (mainParser().getColor(arg&0xf, color)) |
1969 | 610 | f << "backPatternFrontColor=" << color << ";"; |
1970 | 100 | else |
1971 | 100 | f << "#backPatternFrontColor=" << (arg&0xf) << ","; |
1972 | 710 | break; |
1973 | 1.40k | } |
1974 | 2.24k | case 0x10: |
1975 | 2.24k | if (arg!=0x18) f << "bullet?=" << arg << ","; |
1976 | 2.24k | break; |
1977 | 0 | default: |
1978 | 0 | done = false; |
1979 | 0 | break; |
1980 | 22.3k | } |
1981 | 22.3k | break; |
1982 | 22.3k | } |
1983 | 22.3k | case 0xf: // tabs: |
1984 | 4.94k | { |
1985 | 4.94k | if (pos+1 > endPos) |
1986 | 112 | { |
1987 | 112 | ok = false; |
1988 | 112 | break; |
1989 | 112 | } |
1990 | 4.83k | int nVal = libwps::read8(m_input); |
1991 | 4.83k | if (nVal < 2 || pos + 1 + nVal > endPos) |
1992 | 1.74k | { |
1993 | 1.74k | ok = false; |
1994 | 1.74k | break; |
1995 | 1.74k | } |
1996 | 3.08k | int flag = libwps::readU8(m_input); |
1997 | 3.08k | if (flag) f << "#tabsFl=" << flag << ","; |
1998 | 3.08k | size_t nItem = libwps::readU8(m_input); |
1999 | 3.08k | if (size_t(nVal) != 2 + 3*nItem) |
2000 | 1.21k | { |
2001 | 1.21k | ok = false; |
2002 | 1.21k | break; |
2003 | 1.21k | } |
2004 | 1.87k | pp.m_tabs.resize(nItem); |
2005 | 7.28k | for (size_t i = 0; i < nItem; ++i) |
2006 | 5.40k | pp.m_tabs[i].m_position = libwps::read16(m_input)/1440.; |
2007 | 7.28k | for (size_t i = 0; i < nItem; ++i) |
2008 | 5.40k | { |
2009 | 5.40k | enum WPSTabStop::Alignment align = WPSTabStop::LEFT; |
2010 | 5.40k | int val = libwps::readU8(m_input); |
2011 | 5.40k | switch ((val & 0x3)) |
2012 | 5.40k | { |
2013 | 1.90k | case 0: |
2014 | 1.90k | align = WPSTabStop::LEFT; |
2015 | 1.90k | break; |
2016 | 2.06k | case 1: |
2017 | 2.06k | align = WPSTabStop::CENTER; |
2018 | 2.06k | break; |
2019 | 500 | case 2: |
2020 | 500 | align = WPSTabStop::RIGHT; |
2021 | 500 | break; |
2022 | 947 | case 3: |
2023 | 947 | align = WPSTabStop::DECIMAL; |
2024 | 947 | break; |
2025 | 0 | default: |
2026 | 0 | break; |
2027 | 5.40k | } |
2028 | 5.40k | pp.m_tabs[i].m_alignment = align; |
2029 | | |
2030 | 5.40k | if (val&4) f << "#Tabbits3"; |
2031 | 5.40k | val = (val>>3); |
2032 | | |
2033 | 5.40k | switch (val) |
2034 | 5.40k | { |
2035 | 1.28k | case 0: |
2036 | 1.28k | break; |
2037 | 828 | case 1: |
2038 | 828 | pp.m_tabs[i].m_leaderCharacter = '.'; |
2039 | 828 | break; |
2040 | 1.84k | case 2: |
2041 | 1.84k | pp.m_tabs[i].m_leaderCharacter = '-'; |
2042 | 1.84k | break; |
2043 | 87 | case 3: |
2044 | 87 | pp.m_tabs[i].m_leaderCharacter = '_'; |
2045 | 87 | break; |
2046 | 579 | case 4: |
2047 | 579 | pp.m_tabs[i].m_leaderCharacter = '='; |
2048 | 579 | break; |
2049 | 780 | default: |
2050 | 780 | f << "#TabSep=" << val; |
2051 | 5.40k | } |
2052 | 5.40k | } |
2053 | | |
2054 | 1.87k | break; |
2055 | 1.87k | } |
2056 | 2.50k | case 0x11: // right margin : 1440*inches |
2057 | 10.1k | case 0x12: // left margin |
2058 | 11.6k | case 0x13: // another margin ( check me ) |
2059 | 15.0k | case 0x14: // left text indent (relative to left margin) |
2060 | 17.5k | case 0x15: // line spacing (inter line) 240 |
2061 | 23.9k | case 0x16: // line spacing before 240 = 1 line spacing |
2062 | 27.8k | case 0x17: // line spacing after |
2063 | 27.8k | { |
2064 | 27.8k | if (pos+2 > endPos) |
2065 | 1.09k | { |
2066 | 1.09k | ok = false; |
2067 | 1.09k | break; |
2068 | 1.09k | } |
2069 | | |
2070 | 26.7k | arg = libwps::read16(m_input); |
2071 | 26.7k | switch (v) |
2072 | 26.7k | { |
2073 | 2.41k | case 0x11: |
2074 | 2.41k | pp.m_margins[2] = arg/1440.; |
2075 | 2.41k | break; |
2076 | 1.40k | case 0x13: // seems another way to define the left margin |
2077 | 1.40k | f << "#left,"; |
2078 | 1.40k | WPS_FALLTHROUGH; |
2079 | 9.05k | case 0x12: |
2080 | 9.05k | pp.m_margins[1] = arg/1440.; |
2081 | 9.05k | break; |
2082 | 3.26k | case 0x14: |
2083 | 3.26k | pp.m_margins[0] = arg/1440.; |
2084 | 3.26k | break; |
2085 | 2.42k | case 0x15: |
2086 | 2.42k | { |
2087 | 2.42k | double lines = arg ? arg/240. : 1.0; |
2088 | 2.42k | if (lines < 1.0 || lines > 2.0) |
2089 | 1.18k | { |
2090 | 1.18k | f << "##interLineSpacing=" << lines << ","; |
2091 | 1.18k | lines = (lines < 1.0) ? 1.0 : 2.0; |
2092 | 1.18k | } |
2093 | 2.42k | pp.setInterline(lines, librevenge::RVNG_PERCENT); |
2094 | 2.42k | break; |
2095 | 1.40k | } |
2096 | 5.81k | case 0x16: |
2097 | 5.81k | pp.m_spacings[1] = arg/240.; |
2098 | 5.81k | break; |
2099 | 3.78k | case 0x17: |
2100 | 3.78k | pp.m_spacings[2] = arg/240.; |
2101 | 3.78k | break; |
2102 | 0 | default: |
2103 | 0 | done = false; |
2104 | 26.7k | } |
2105 | 26.7k | break; |
2106 | 26.7k | } |
2107 | 36.0k | default: |
2108 | 36.0k | ok = false; |
2109 | 193k | } |
2110 | 193k | if (!ok) |
2111 | 46.0k | { |
2112 | 46.0k | m_input->seek(pos, librevenge::RVNG_SEEK_SET); |
2113 | 46.0k | f << "###v" << v<<"=" <<std::hex; |
2114 | 494k | while (m_input->tell() < endPos) |
2115 | 448k | f << int(libwps::readU8(m_input)) << ","; |
2116 | 46.0k | break; |
2117 | 46.0k | } |
2118 | | |
2119 | 147k | if (done) continue; |
2120 | | |
2121 | 0 | f << "f" << v << "=" << std::hex << arg << std::dec << ","; |
2122 | 0 | } |
2123 | 69.2k | if (pp.m_listLevelIndex >= 1) |
2124 | 6.12k | pp.m_listLevel.m_labelIndent = pp.m_margins[1]; |
2125 | 63.1k | else if (pp.m_margins[0] + pp.m_margins[1] < 0.0) |
2126 | 3.82k | { |
2127 | | // sanity check |
2128 | 3.82k | if (pp.m_margins[1] < 0.0) pp.m_margins[1] = 0.0; |
2129 | 3.82k | pp.m_margins[0] = -pp.m_margins[1]; |
2130 | 3.82k | } |
2131 | 69.2k | pp.m_extra = f.str(); |
2132 | | |
2133 | 69.2k | id = int(m_state->m_paragraphList.size()); |
2134 | 69.2k | m_state->m_paragraphList.push_back(pp); |
2135 | | |
2136 | 69.2k | f.str(""); |
2137 | 69.2k | f << pp; |
2138 | 69.2k | mess = f.str(); |
2139 | 69.2k | return true; |
2140 | 69.2k | } |
2141 | | |
2142 | | //////////////////////////////////////////////////////////// |
2143 | | // the foot note properties: |
2144 | | //////////////////////////////////////////////////////////// |
2145 | | bool WPS4Text::readFootNotes(WPSEntry const &ftnD, WPSEntry const &ftnP) |
2146 | 3.09k | { |
2147 | 3.09k | if (!ftnD.valid() && !ftnP.valid()) return true; |
2148 | 803 | if (!ftnD.valid() || !ftnP.valid()) |
2149 | 395 | { |
2150 | 395 | WPS_DEBUG_MSG(("WPS4Text::readFootNotes: one of the two entry is not valid, footnote will be ignored\n")); |
2151 | 395 | return false; |
2152 | 395 | } |
2153 | | |
2154 | 408 | std::vector<long> footNotePos,footNoteDef, listValues; |
2155 | 408 | if (!readPLC(ftnP, footNotePos, listValues, &WPS4Text::footNotesDataParser)) |
2156 | 172 | { |
2157 | 172 | WPS_DEBUG_MSG(("WPS4Text::readFootNotes: can not read positions\n")); |
2158 | 172 | return false; |
2159 | 172 | } |
2160 | | |
2161 | 236 | if (!readPLC(ftnD, footNoteDef, listValues)) |
2162 | 37 | { |
2163 | 37 | WPS_DEBUG_MSG(("WPS4Text::readFootNotes: can not read definitions\n")); |
2164 | 37 | return false; |
2165 | 37 | } |
2166 | | |
2167 | 199 | int numFootNotes = int(footNotePos.size())-1; |
2168 | 199 | if (numFootNotes <= 0 || int(footNoteDef.size())-1 != numFootNotes) |
2169 | 10 | { |
2170 | 10 | WPS_DEBUG_MSG(("WPS4Text::readFootNotes: no footnotes\n")); |
2171 | 10 | return false; |
2172 | 10 | } |
2173 | | |
2174 | | // save the actual type and create a list of footnote entries |
2175 | 189 | std::vector<WPS4TextInternal::Note> noteTypes=m_state->m_footnoteList; |
2176 | 189 | m_state->m_footnoteList.resize(0); |
2177 | | |
2178 | 189 | std::vector<int> corresp; |
2179 | 745 | for (size_t i = 0; i < size_t(numFootNotes); ++i) |
2180 | 556 | { |
2181 | 556 | WPS4TextInternal::Note fZone; |
2182 | 556 | fZone.setBegin(footNoteDef[i]); |
2183 | 556 | fZone.setEnd(footNoteDef[i+1]); |
2184 | 556 | fZone.setType("TEXT"); |
2185 | 556 | fZone.setId(WPS4TextInternal::Z_Note); |
2186 | 556 | m_state->m_footnoteList.push_back(fZone); |
2187 | 556 | corresp.push_back(int(i)); |
2188 | | |
2189 | | // sort the footnote |
2190 | 556 | for (size_t j = i; j > 0; j--) |
2191 | 367 | { |
2192 | 367 | if (m_state->m_footnoteList[j].begin() >= |
2193 | 367 | m_state->m_footnoteList[j-1].end()) break; |
2194 | | |
2195 | 0 | if (m_state->m_footnoteList[j].end() > |
2196 | 0 | m_state->m_footnoteList[j-1].begin()) |
2197 | 0 | { |
2198 | 0 | WPS_DEBUG_MSG |
2199 | 0 | (("WPS4Text: error: can not create footnotes zone, found %lx and %lx\n", |
2200 | 0 | static_cast<unsigned long>(m_state->m_footnoteList[j].end()), |
2201 | 0 | static_cast<unsigned long>(m_state->m_footnoteList[j-1].begin()))); |
2202 | |
|
2203 | 0 | m_state->m_footnoteList.resize(0); |
2204 | 0 | return false; |
2205 | 0 | } |
2206 | | |
2207 | 0 | std::swap(m_state->m_footnoteList[j], m_state->m_footnoteList[j-1]); |
2208 | |
|
2209 | 0 | int pos = corresp[j]; |
2210 | 0 | corresp[j] = corresp[j-1]; |
2211 | 0 | corresp[j-1] = pos; |
2212 | 0 | } |
2213 | 556 | } |
2214 | | // ok, we can create the map, ... |
2215 | 745 | for (size_t i = 0; i < size_t(numFootNotes); ++i) |
2216 | 556 | { |
2217 | 556 | auto id = size_t(corresp[i]); |
2218 | 556 | WPS4TextInternal::Note &z = m_state->m_footnoteList[id]; |
2219 | 556 | if (id < noteTypes.size()) |
2220 | 240 | { |
2221 | 240 | z.m_label = noteTypes[id].m_label; |
2222 | 240 | z.m_error = noteTypes[id].m_error; |
2223 | 240 | } |
2224 | 556 | m_state->m_footnoteMap[footNotePos[id]] = &z; |
2225 | 556 | } |
2226 | 189 | return true; |
2227 | 189 | } |
2228 | | |
2229 | | bool WPS4Text::footNotesDataParser(long /*bot*/, long /*eot*/, int id, |
2230 | | long endPos, std::string &mess) |
2231 | 1.32k | { |
2232 | 1.32k | mess = ""; |
2233 | | |
2234 | 1.32k | long actPos = m_input->tell(); |
2235 | 1.32k | long length = endPos+1-actPos; |
2236 | 1.32k | if (length != 12) |
2237 | 107 | { |
2238 | 107 | WPS_DEBUG_MSG(("WPS4Text::footNotesDataParser: unknown size %ld for footdata data\n", length)); |
2239 | 107 | return false; |
2240 | 107 | } |
2241 | 1.21k | libwps::DebugStream f; |
2242 | 1.21k | WPS4TextInternal::Note note; |
2243 | 1.21k | auto type = libwps::readU16(m_input); |
2244 | 1.21k | if (type & 1) |
2245 | 493 | { |
2246 | 493 | if (type != 1) |
2247 | 427 | f << "###numeric=" << std::hex << type << std::dec << ","; |
2248 | 493 | } |
2249 | 725 | else if (type == 0 || type > 20) |
2250 | 668 | f << "###char,"; |
2251 | 57 | else |
2252 | 57 | note.m_label=libwps_tools_win::Font::unicodeString(m_input.get(), type/2, mainParser().getDefaultFontType()); |
2253 | 1.21k | note.m_error=f.str(); |
2254 | 1.21k | if (id >= int(m_state->m_footnoteList.size())) |
2255 | 1.21k | m_state->m_footnoteList.resize(size_t(id+1)); |
2256 | 1.21k | m_state->m_footnoteList[size_t(id)]=note; |
2257 | 1.21k | f.str(""); |
2258 | 1.21k | f << note; |
2259 | 1.21k | mess = f.str(); |
2260 | 1.21k | m_input->seek(endPos+1, librevenge::RVNG_SEEK_SET); |
2261 | 1.21k | return true; |
2262 | 1.32k | } |
2263 | | |
2264 | | //////////////////////////////////////////////////////////// |
2265 | | // the bookmark properties: |
2266 | | //////////////////////////////////////////////////////////// |
2267 | | bool WPS4Text::bkmkDataParser(long bot, long /*eot*/, int /*id*/, |
2268 | | long endPos, std::string &mess) |
2269 | 155 | { |
2270 | 155 | mess = ""; |
2271 | 155 | if (m_state->m_bookmarkMap.find(bot) != m_state->m_bookmarkMap.end()) |
2272 | 18 | { |
2273 | 18 | WPS_DEBUG_MSG(("WPS4Text:bkmkDataParser: bookmark already exists in this position\n")); |
2274 | 18 | return true; |
2275 | 18 | } |
2276 | | |
2277 | 137 | long actPos = m_input->tell(); |
2278 | 137 | long length = endPos+1-actPos; |
2279 | 137 | if (length != 16) |
2280 | 14 | { |
2281 | 14 | WPS_DEBUG_MSG(("WPS4Text::bkmkDataParser: unknown size %ld for bkmkdata data\n", length)); |
2282 | 14 | return false; |
2283 | 14 | } |
2284 | | |
2285 | 977 | for (int i = 0; i < 16; ++i) |
2286 | 948 | { |
2287 | 948 | auto c = char(libwps::readU8(m_input)); |
2288 | 948 | if (c == '\0') break; |
2289 | 854 | mess += c; |
2290 | 854 | } |
2291 | 123 | WPSEntry ent; |
2292 | 123 | ent.setBegin(actPos); |
2293 | 123 | ent.setEnd(m_input->tell()); |
2294 | 123 | ent.setId(WPS4TextInternal::Z_String); |
2295 | 123 | m_state->m_bookmarkMap[bot] = ent; |
2296 | 123 | m_input->seek(endPos+1, librevenge::RVNG_SEEK_SET); |
2297 | 123 | return true; |
2298 | 137 | } |
2299 | | |
2300 | | //////////////////////////////////////////////////////////// |
2301 | | // the object properties: |
2302 | | //////////////////////////////////////////////////////////// |
2303 | | bool WPS4Text::objectDataParser(long bot, long /*eot*/, int id, |
2304 | | long endPos, std::string &mess) |
2305 | 2.01k | { |
2306 | 2.01k | mess = ""; |
2307 | 2.01k | if (m_state->m_objectMap.find(bot) != m_state->m_objectMap.end()) |
2308 | 150 | { |
2309 | 150 | WPS_DEBUG_MSG(("WPS4Text:objectDataParser: object already exists in this position\n")); |
2310 | 150 | return true; |
2311 | 150 | } |
2312 | | |
2313 | 1.86k | libwps::DebugStream f; |
2314 | | |
2315 | 1.86k | long actPos = m_input->tell(); |
2316 | 1.86k | long length = endPos+1-actPos; |
2317 | 1.86k | if (length != 36) |
2318 | 15 | { |
2319 | 15 | WPS_DEBUG_MSG(("WPS4Text:objectDataParser unknown size %ld for object data\n", length)); |
2320 | 15 | return false; |
2321 | 15 | } |
2322 | | // 3->08 4->4f4d or 68->list? |
2323 | 1.85k | f << "type?=" << int(libwps::read16(m_input)) << ","; |
2324 | 5.55k | for (int i = 0; i < 2; ++i) |
2325 | 3.70k | { |
2326 | 3.70k | int v =libwps::read16(m_input); |
2327 | 3.70k | if (v) f << "unkn1:" << i << "=" << v << ","; |
2328 | 3.70k | } |
2329 | 1.85k | float dim[4]; |
2330 | 1.85k | for (float &i : dim) |
2331 | 7.41k | i =float(libwps::read16(m_input)/1440.); |
2332 | | |
2333 | | // CHECKME: the next two sizes are often simillar, |
2334 | | // maybe the first one is the original size and the second |
2335 | | // size in the document... |
2336 | 1.85k | f << "origSz?=[" << dim[0] << "," << dim[1] << "],"; |
2337 | | |
2338 | 1.85k | WPS4TextInternal::Object obj; |
2339 | 1.85k | obj.m_size = Vec2f(dim[2], dim[3]); // CHECKME: unit |
2340 | | |
2341 | 1.85k | auto size = long(libwps::readU32(m_input)); |
2342 | 1.85k | auto pos = long(libwps::readU32(m_input)); |
2343 | | |
2344 | 1.85k | actPos = m_input->tell(); |
2345 | 1.85k | if (pos >= 0 && size > 0 && (long)((unsigned long) pos+(unsigned long) size)>pos && mainParser().checkFilePosition(pos+size)) |
2346 | 826 | { |
2347 | 826 | obj.m_pos.setBegin(pos); |
2348 | 826 | obj.m_pos.setLength(size); |
2349 | 826 | obj.m_pos.setId(id); |
2350 | | |
2351 | 826 | int objectId = mainParser().readObject(m_input, obj.m_pos); |
2352 | 826 | if (objectId == -1) |
2353 | 301 | { |
2354 | 301 | WPS_DEBUG_MSG(("WPS4Text::objectDataParser: can not find the object %d\n", id)); |
2355 | 301 | } |
2356 | 826 | obj.m_id = objectId; |
2357 | 826 | } |
2358 | 1.02k | else |
2359 | 1.02k | { |
2360 | 1.02k | WPS_DEBUG_MSG(("WPS4Text::objectDataParser: bad object position\n")); |
2361 | 1.02k | } |
2362 | | |
2363 | 1.85k | m_input->seek(actPos, librevenge::RVNG_SEEK_SET); |
2364 | 1.85k | auto val =int(libwps::read16(m_input)); // small number, probably an id |
2365 | 1.85k | if (val) f << "id=" << val << ","; |
2366 | 5.55k | for (int i = 0; i < 2; ++i) |
2367 | 3.70k | { |
2368 | 3.70k | val =int(libwps::read16(m_input)); |
2369 | 3.70k | if (val) f << "f" << i << "=" << val << ","; |
2370 | 3.70k | } |
2371 | 1.85k | obj.m_page =int(libwps::read16(m_input)); |
2372 | 1.85k | int origin[2]; |
2373 | 3.70k | for (int &i : origin) i =int(libwps::read16(m_input)); |
2374 | 1.85k | obj.m_origin=Vec2f(float(origin[0]/1440.),float(origin[1]/1440.)); |
2375 | 1.85k | val =int(libwps::read16(m_input)); // can be big |
2376 | 1.85k | if (val) f << "f2=" << val << ","; |
2377 | 1.85k | obj.m_extra = f.str(); |
2378 | 1.85k | if (obj.m_id>=0) |
2379 | 525 | m_state->m_objectMap[bot] = obj; |
2380 | 1.85k | f.str(""); |
2381 | 1.85k | f << obj; |
2382 | | |
2383 | 1.85k | mess = f.str(); |
2384 | 1.85k | return true; |
2385 | 1.86k | } |
2386 | | |
2387 | | //////////////////////////////////////////////////////////// |
2388 | | // the dttm properties: |
2389 | | //////////////////////////////////////////////////////////// |
2390 | | bool WPS4Text::dttmDataParser(long bot, long /*eot*/, int /*id*/, |
2391 | | long endPos, std::string &mess) |
2392 | 680 | { |
2393 | 680 | mess = ""; |
2394 | 680 | if (m_state->m_dateTimeMap.find(bot) != m_state->m_dateTimeMap.end()) |
2395 | 328 | { |
2396 | 328 | WPS_DEBUG_MSG(("WPS4Text:dttmDataParser: dttm already exists in this position\n")); |
2397 | 328 | return true; |
2398 | 328 | } |
2399 | | |
2400 | 352 | libwps::DebugStream f; |
2401 | | |
2402 | 352 | long actPos = m_input->tell(); |
2403 | 352 | long length = endPos+1-actPos; |
2404 | 352 | if (length != 42) |
2405 | 7 | { |
2406 | 7 | WPS_DEBUG_MSG(("WPS4Text:dttmDataParser unknown size %ld for dttm data\n", length)); |
2407 | 7 | return false; |
2408 | 7 | } |
2409 | | |
2410 | 345 | WPS4TextInternal::DateTime form; |
2411 | 345 | int val; |
2412 | 1.38k | for (int i = 0; i < 3; ++i) // always 0, 0, 0 ? |
2413 | 1.03k | { |
2414 | 1.03k | val =libwps::read16(m_input); |
2415 | 1.03k | if (val) f << "f" << i << "=" << val << ","; |
2416 | 1.03k | } |
2417 | 345 | form.m_type=libwps::read16(m_input); |
2418 | 345 | val =libwps::read16(m_input); // alway 0 ? |
2419 | 345 | if (val) f << "f3=" << val << ","; |
2420 | | // end unknown |
2421 | 5.86k | for (int i = 0; i < 16; ++i) |
2422 | 5.52k | { |
2423 | 5.52k | val =libwps::readU16(m_input); |
2424 | 5.52k | if (val) f << "g" << i << "=" << std::hex << val << std::dec << ","; |
2425 | 5.52k | } |
2426 | 345 | form.m_extra = f.str(); |
2427 | 345 | m_state->m_dateTimeMap[bot] = form; |
2428 | 345 | f.str(""); |
2429 | 345 | f << form; |
2430 | 345 | mess = f.str(); |
2431 | 345 | return true; |
2432 | 352 | } |
2433 | | |
2434 | | //////////////////////////////////////// |
2435 | | // VERY LOW LEVEL ( plc ) |
2436 | | //////////////////////////////////////// |
2437 | | /** Internal and low level: the structures of a WPS4Text used to parse PLC*/ |
2438 | | namespace WPS4PLCInternal |
2439 | | { |
2440 | | /** Internal and low level: the PLC different types and their structures */ |
2441 | | struct PLC |
2442 | | { |
2443 | | /** the PLC types */ |
2444 | | typedef enum WPS4TextInternal::PLCType PLCType; |
2445 | | /** the way to define the text positions |
2446 | | * |
2447 | | * - P_ABS: absolute position, |
2448 | | * - P_REL: position are relative to the beginning text offset */ |
2449 | | typedef enum { P_ABS=0, P_REL, P_UNKNOWN} Position; |
2450 | | /** the type of the content |
2451 | | * |
2452 | | * - T_CST: size is constant |
2453 | | * - T_STRUCT: a structured type ( which unknown size) */ |
2454 | | typedef enum { T_CST=0, T_COMPLEX, T_UNKNOWN} Type; |
2455 | | |
2456 | | //! constructor |
2457 | | explicit PLC(PLCType w= WPS4TextInternal::Unknown, Position p=P_UNKNOWN, Type t=T_UNKNOWN, unsigned char tChar='\0', int f=1) : |
2458 | 72.8k | m_type(w), m_pos(p), m_contentType(t), m_textChar(tChar), m_cstFactor(f) {} |
2459 | | PLC(PLC const &orig)=default; |
2460 | | PLC(PLC &&orig)=default; |
2461 | | PLC &operator=(PLC const &orig)=default; |
2462 | | PLC &operator=(PLC &&orig)=default; |
2463 | | //! PLC type |
2464 | | PLCType m_type; |
2465 | | //! the way to define the text positions |
2466 | | Position m_pos; |
2467 | | //! the type of the content |
2468 | | Type m_contentType; |
2469 | | /** the character which appears in the text when this PLC is found |
2470 | | * |
2471 | | * '\\0' means that there is not default character */ |
2472 | | unsigned char m_textChar; |
2473 | | //! some data are stored divided by some unit |
2474 | | int m_cstFactor; |
2475 | | }; |
2476 | | |
2477 | | KnownPLC::KnownPLC() |
2478 | 5.20k | : m_knowns() |
2479 | 5.20k | { |
2480 | 5.20k | createMapping(); |
2481 | 5.20k | } |
2482 | | |
2483 | | KnownPLC::~KnownPLC() |
2484 | 5.20k | { |
2485 | 5.20k | } |
2486 | | |
2487 | | PLC KnownPLC::get(std::string const &name) |
2488 | 4.67k | { |
2489 | 4.67k | auto pos = m_knowns.find(name); |
2490 | 4.67k | if (pos == m_knowns.end()) return PLC(); |
2491 | 4.67k | return pos->second; |
2492 | 4.67k | } |
2493 | | |
2494 | | void KnownPLC::createMapping() |
2495 | 5.20k | { |
2496 | 5.20k | m_knowns["BTEP"] = |
2497 | 5.20k | PLC(WPS4TextInternal::BTE, PLC::P_ABS, PLC::T_CST, '\0', 0x80); |
2498 | 5.20k | m_knowns["BTEC"] = |
2499 | 5.20k | PLC(WPS4TextInternal::BTE,PLC::P_ABS, PLC::T_CST, '\0', 0x80); |
2500 | 5.20k | m_knowns["EOBJ"] = |
2501 | 5.20k | PLC(WPS4TextInternal::OBJECT,PLC::P_UNKNOWN, PLC::T_COMPLEX, 0x7); |
2502 | 5.20k | m_knowns["FTNp"] = |
2503 | 5.20k | PLC(WPS4TextInternal::FTNp,PLC::P_REL, PLC::T_CST, 0x6); |
2504 | 5.20k | m_knowns["FTNd"] = |
2505 | 5.20k | PLC(WPS4TextInternal::FTNd,PLC::P_REL, PLC::T_COMPLEX, 0x6); |
2506 | 5.20k | m_knowns["BKMK"] = |
2507 | 5.20k | PLC(WPS4TextInternal::BKMK,PLC::P_REL, PLC::T_COMPLEX); |
2508 | 5.20k | m_knowns["DTTM"] = |
2509 | 5.20k | PLC(WPS4TextInternal::DTTM,PLC::P_REL, PLC::T_COMPLEX, 0xf); |
2510 | 5.20k | } |
2511 | | } |
2512 | | |
2513 | | bool WPS4Text::readPLC |
2514 | | (WPSEntry const &zone, |
2515 | | std::vector<long> &textPtrs, std::vector<long> &listValues, WPS4Text::DataParser parser) |
2516 | 5.01k | { |
2517 | 5.01k | textPtrs.resize(0); |
2518 | 5.01k | listValues.resize(0); |
2519 | 5.01k | long size = zone.length(); |
2520 | 5.01k | if (zone.begin() <= 0 || size < 8) return false; |
2521 | 4.67k | auto plcType = m_state->m_knownPLC.get(zone.type()); |
2522 | | |
2523 | 4.67k | libwps::DebugStream f; |
2524 | 4.67k | ascii().addPos(zone.begin()); |
2525 | 4.67k | m_input->seek(zone.begin(), librevenge::RVNG_SEEK_SET); |
2526 | | |
2527 | 4.67k | long lastPos = 0; |
2528 | 4.67k | std::vector<DataFOD> fods; |
2529 | 4.67k | unsigned numElt = 0; |
2530 | 4.67k | f << "pos=("; |
2531 | 183k | while (numElt*4+4 <= unsigned(size)) |
2532 | 183k | { |
2533 | 183k | auto newPos = long(libwps::readU32(m_input)); |
2534 | 183k | if (plcType.m_pos == WPS4PLCInternal::PLC::P_UNKNOWN) |
2535 | 743 | { |
2536 | 743 | if (newPos < m_textPositions.begin()) |
2537 | 430 | plcType.m_pos = WPS4PLCInternal::PLC::P_REL; |
2538 | 313 | else if (newPos+m_textPositions.begin() > m_textPositions.end()) |
2539 | 249 | plcType.m_pos = WPS4PLCInternal::PLC::P_ABS; |
2540 | 64 | else if (plcType.m_textChar=='\0') |
2541 | 0 | { |
2542 | 0 | WPS_DEBUG_MSG(("WPS4Text:readPLC Can not decide position for PLC: %s\n", zone.type().c_str())); |
2543 | 0 | plcType.m_pos = WPS4PLCInternal::PLC::P_REL; |
2544 | 0 | } |
2545 | 64 | else |
2546 | 64 | { |
2547 | 64 | long actPos = m_input->tell(); |
2548 | 64 | m_input->seek(newPos, librevenge::RVNG_SEEK_SET); |
2549 | 64 | if (libwps::readU8(m_input) == plcType.m_textChar) |
2550 | 3 | plcType.m_pos = WPS4PLCInternal::PLC::P_ABS; |
2551 | 61 | else plcType.m_pos = WPS4PLCInternal::PLC::P_REL; |
2552 | 64 | m_input->seek(actPos, librevenge::RVNG_SEEK_SET); |
2553 | 64 | } |
2554 | 743 | } |
2555 | | |
2556 | 183k | if (plcType.m_pos == WPS4PLCInternal::PLC::P_REL) |
2557 | 67.1k | newPos += m_textPositions.begin(); |
2558 | | |
2559 | 183k | if (newPos < lastPos || |
2560 | 183k | newPos > m_textPositions.end()) |
2561 | 2.58k | { |
2562 | | // sometimes the convertissor do not their jobs correctly |
2563 | | // for the last element |
2564 | 2.58k | if (plcType.m_pos == WPS4PLCInternal::PLC::P_REL && |
2565 | 1.16k | newPos == m_textPositions.end()+m_textPositions.begin()) |
2566 | 632 | newPos = m_textPositions.end(); |
2567 | 1.95k | else |
2568 | 1.95k | return false; |
2569 | 2.58k | } |
2570 | | |
2571 | 181k | textPtrs.push_back(newPos); |
2572 | | |
2573 | 181k | DataFOD fod; |
2574 | 181k | fod.m_type = DataFOD::ATTR_PLC; |
2575 | 181k | fod.m_pos = newPos; |
2576 | | |
2577 | 181k | f << std::hex << newPos << ", "; |
2578 | 181k | if (newPos == m_textPositions.end()) break; |
2579 | | |
2580 | 178k | numElt++; |
2581 | 178k | lastPos = newPos; |
2582 | 178k | fods.push_back(fod); |
2583 | 178k | } |
2584 | 2.72k | f << ")"; |
2585 | | |
2586 | 2.72k | if (long(numElt) < 1) return false; |
2587 | | |
2588 | 2.69k | long dataSize = (size-4*long(numElt)-4)/long(numElt); |
2589 | 2.69k | if (dataSize > 100) return false; |
2590 | 2.68k | if (size!= long(numElt)*(4+dataSize)+4) return false; |
2591 | | |
2592 | 2.54k | ascii().addNote(f.str().c_str()); |
2593 | | |
2594 | 2.54k | if (!dataSize) |
2595 | 109 | { |
2596 | 811 | for (size_t i = 0; i < numElt; ++i) |
2597 | 702 | { |
2598 | 702 | listValues.push_back(-1); |
2599 | 702 | fods[i].m_id = int(m_state->m_plcList.size()); |
2600 | 702 | } |
2601 | 109 | WPS4TextInternal::DataPLC plc; |
2602 | 109 | plc.m_name = zone.type(); |
2603 | 109 | plc.m_type = plcType.m_type; |
2604 | 109 | m_state->m_plcList.push_back(plc); |
2605 | 109 | m_FODList = mergeSortedFODLists(fods, m_FODList); |
2606 | 109 | return true; |
2607 | 109 | } |
2608 | | |
2609 | | // ok we have some data |
2610 | 2.43k | bool ok = true; |
2611 | 2.43k | long pos = m_input->tell(); |
2612 | 2.43k | auto pars = parser; |
2613 | 2.43k | if ((dataSize == 3 || dataSize > 4) && !pars) |
2614 | 129 | pars = &WPS4Text::defDataParser; |
2615 | | |
2616 | 52.8k | for (size_t i = 0; i < numElt; ++i) |
2617 | 50.5k | { |
2618 | 50.5k | WPS4TextInternal::DataPLC plc; |
2619 | | |
2620 | 50.5k | if (!pars && dataSize <= 4) |
2621 | 45.6k | { |
2622 | 45.6k | switch (dataSize) |
2623 | 45.6k | { |
2624 | 43.7k | case 1: |
2625 | 43.7k | plc.m_value = libwps::readU8(m_input); |
2626 | 43.7k | break; |
2627 | 1.02k | case 2: |
2628 | 1.02k | plc.m_value = libwps::readU16(m_input); |
2629 | 1.02k | break; |
2630 | 485 | case 4: |
2631 | 485 | plc.m_value = long(libwps::readU32(m_input)); |
2632 | 485 | break; |
2633 | 375 | default: |
2634 | 375 | WPS_DEBUG_MSG(("WPS4Text:readPLC: unexpected PLC size\n")); |
2635 | 375 | WPS_FALLTHROUGH; |
2636 | 375 | case 0: |
2637 | 375 | plc.m_value = 0; |
2638 | 45.6k | } |
2639 | 45.6k | plc.m_value *=plcType.m_cstFactor; |
2640 | 45.6k | } |
2641 | 4.96k | else if (pars) |
2642 | 4.96k | { |
2643 | 4.96k | std::string mess; |
2644 | 4.96k | if (!(this->*pars)(textPtrs[i], textPtrs[i+1], int(i), pos+dataSize-1, mess)) |
2645 | 143 | { |
2646 | 143 | ok = false; |
2647 | 143 | break; |
2648 | 143 | } |
2649 | 4.82k | plc.m_extra = mess; |
2650 | 4.82k | m_input->seek(pos+dataSize, librevenge::RVNG_SEEK_SET); |
2651 | 4.82k | } |
2652 | | |
2653 | 50.4k | listValues.push_back(plc.m_value); |
2654 | | |
2655 | 50.4k | fods[i].m_id = int(m_state->m_plcList.size()); |
2656 | 50.4k | fods[i].m_defPos = pos; |
2657 | | |
2658 | 50.4k | plc.m_name = zone.type(); |
2659 | 50.4k | plc.m_type = plcType.m_type; |
2660 | 50.4k | m_state->m_plcList.push_back(plc); |
2661 | | |
2662 | 50.4k | f.str(""); |
2663 | 50.4k | f << "ZZ" << zone.type() << i << ":" << plc; |
2664 | 50.4k | ascii().addPos(pos); |
2665 | 50.4k | ascii().addNote(f.str().c_str()); |
2666 | | |
2667 | 50.4k | pos += dataSize; |
2668 | 50.4k | } |
2669 | | |
2670 | 2.43k | if (ok) m_FODList = mergeSortedFODLists(fods, m_FODList); |
2671 | 2.43k | return true; |
2672 | 2.43k | } |
2673 | | |
2674 | | /* vim:set shiftwidth=4 softtabstop=4 noexpandtab: */ |