/src/libmwaw/src/lib/MoreText.cxx
Line | Count | Source |
1 | | /* -*- Mode: C++; c-default-style: "k&r"; indent-tabs-mode: nil; tab-width: 2; c-basic-offset: 2 -*- */ |
2 | | |
3 | | /* libmwaw |
4 | | * Version: MPL 2.0 / LGPLv2+ |
5 | | * |
6 | | * The contents of this file are subject to the Mozilla Public License Version |
7 | | * 2.0 (the "License"); you may not use this file except in compliance with |
8 | | * the License or as specified alternatively below. You may obtain a copy of |
9 | | * the License at http://www.mozilla.org/MPL/ |
10 | | * |
11 | | * Software distributed under the License is distributed on an "AS IS" basis, |
12 | | * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License |
13 | | * for the specific language governing rights and limitations under the |
14 | | * License. |
15 | | * |
16 | | * Major Contributor(s): |
17 | | * Copyright (C) 2002 William Lachance (wrlach@gmail.com) |
18 | | * Copyright (C) 2002,2004 Marc Maurer (uwog@uwog.net) |
19 | | * Copyright (C) 2004-2006 Fridrich Strba (fridrich.strba@bluewin.ch) |
20 | | * Copyright (C) 2006, 2007 Andrew Ziem |
21 | | * Copyright (C) 2011, 2012 Alonso Laurent (alonso@loria.fr) |
22 | | * |
23 | | * |
24 | | * All Rights Reserved. |
25 | | * |
26 | | * For minor contributions see the git repository. |
27 | | * |
28 | | * Alternatively, the contents of this file may be used under the terms of |
29 | | * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"), |
30 | | * in which case the provisions of the LGPLv2+ are applicable |
31 | | * instead of those above. |
32 | | */ |
33 | | |
34 | | #include <cstring> |
35 | | #include <iomanip> |
36 | | #include <iostream> |
37 | | #include <limits> |
38 | | #include <map> |
39 | | #include <sstream> |
40 | | |
41 | | #include <librevenge/librevenge.h> |
42 | | |
43 | | #include "MWAWTextListener.hxx" |
44 | | #include "MWAWDebug.hxx" |
45 | | #include "MWAWFont.hxx" |
46 | | #include "MWAWFontConverter.hxx" |
47 | | #include "MWAWList.hxx" |
48 | | #include "MWAWPageSpan.hxx" |
49 | | #include "MWAWParagraph.hxx" |
50 | | #include "MWAWPictData.hxx" |
51 | | #include "MWAWPosition.hxx" |
52 | | #include "MWAWRSRCParser.hxx" |
53 | | #include "MWAWSubDocument.hxx" |
54 | | |
55 | | #include "MoreParser.hxx" |
56 | | |
57 | | #include "MoreText.hxx" |
58 | | |
59 | | /** Internal: the structures of a MoreText */ |
60 | | namespace MoreTextInternal |
61 | | { |
62 | | //////////////////////////////////////// |
63 | | //! Internal: the paragraph of a MoreText |
64 | | struct Paragraph final : public MWAWParagraph { |
65 | | //! constructor |
66 | | Paragraph() |
67 | 102M | : MWAWParagraph() |
68 | 102M | , m_listType(0) |
69 | 102M | , m_customListLevel() |
70 | 102M | , m_pageBreak(false) |
71 | 102M | , m_keepOutlineTogether(false) |
72 | 102M | { |
73 | 102M | m_marginsFromParent[0]=0.3; |
74 | 102M | m_marginsFromParent[1]=0; |
75 | 102M | } |
76 | 11.0M | Paragraph(Paragraph const &)=default; |
77 | 5.63k | Paragraph &operator=(Paragraph const &)=default; |
78 | | //! destructor |
79 | | ~Paragraph() final; |
80 | | //! set the left margin in inch |
81 | | void setLeftMargin(double margin, bool fromParent) |
82 | 30.5k | { |
83 | 30.5k | if (fromParent) { |
84 | 27.9k | m_marginsFromParent[0]=margin; |
85 | 27.9k | m_margins[1]=0; |
86 | 27.9k | } |
87 | 2.66k | else { |
88 | 2.66k | m_marginsFromParent[0]=-100; |
89 | 2.66k | m_margins[1]=margin; |
90 | 2.66k | } |
91 | 30.5k | } |
92 | | //! set the right margin in inch |
93 | | void setRightMargin(double margin, bool fromParent) |
94 | 62.6k | { |
95 | 62.6k | if (fromParent) { |
96 | 59.6k | m_marginsFromParent[1]=margin; |
97 | 59.6k | m_margins[2]=0; |
98 | 59.6k | } |
99 | 3.05k | else { |
100 | 3.05k | m_marginsFromParent[1]=-100; |
101 | 3.05k | m_margins[2]=margin; |
102 | 3.05k | } |
103 | 62.6k | } |
104 | | //! update the paragraph to obtain the final paragraph |
105 | | void updateToFinalState(MWAWParagraph const &parent, int level, MWAWListManager &listManager) |
106 | 101k | { |
107 | 101k | bool leftUseParent=m_marginsFromParent[0]>-10; |
108 | 101k | if (leftUseParent) |
109 | 101k | m_margins[1]=*parent.m_margins[1]+m_marginsFromParent[0]; |
110 | 101k | if (m_marginsFromParent[1]>-10) |
111 | 101k | m_margins[2]=*parent.m_margins[2]+m_marginsFromParent[1]; |
112 | 101k | if (level<0) |
113 | 0 | return; |
114 | | |
115 | 101k | MWAWListLevel listLevel; |
116 | 101k | switch (m_listType) { |
117 | 100k | case 1: // leader |
118 | 100k | listLevel.m_type = MWAWListLevel::BULLET; |
119 | 100k | listLevel.m_bullet = "+"; // in fact + + and - |
120 | 100k | break; |
121 | 0 | case 2: // hardvard |
122 | 0 | listLevel.m_suffix = (level <= 3) ? "." : ")"; |
123 | 0 | if (level == 1) listLevel.m_type = MWAWListLevel::UPPER_ROMAN; |
124 | 0 | else if (level == 2) listLevel.m_type = MWAWListLevel::UPPER_ALPHA; |
125 | 0 | else if (level == 3) listLevel.m_type = MWAWListLevel::DECIMAL; |
126 | 0 | else if (level == 4) listLevel.m_type = MWAWListLevel::LOWER_ALPHA; |
127 | 0 | else if ((level%3)==2) { |
128 | 0 | listLevel.m_prefix = "("; |
129 | 0 | listLevel.m_type = MWAWListLevel::DECIMAL; |
130 | 0 | } |
131 | 0 | else if ((level%3)==0) { |
132 | 0 | listLevel.m_prefix = "("; |
133 | 0 | listLevel.m_type = MWAWListLevel::LOWER_ALPHA; |
134 | 0 | } |
135 | 0 | else |
136 | 0 | listLevel.m_type = MWAWListLevel::LOWER_ROMAN; |
137 | 0 | break; |
138 | 0 | case 3: // numeric |
139 | 0 | listLevel.m_type = MWAWListLevel::DECIMAL; |
140 | 0 | listLevel.m_suffix = "."; |
141 | 0 | break; |
142 | 0 | case 4: // legal |
143 | 0 | listLevel.m_type = MWAWListLevel::DECIMAL; |
144 | 0 | listLevel.m_numBeforeLabels = level-1; |
145 | 0 | listLevel.m_suffix = "."; |
146 | 0 | listLevel.m_labelWidth = 0.2*level; |
147 | 0 | break; |
148 | 0 | case 5: // bullets |
149 | 0 | listLevel.m_type = MWAWListLevel::BULLET; |
150 | 0 | libmwaw::appendUnicode(0x2022, listLevel.m_bullet); |
151 | 0 | break; |
152 | 380 | case 0: // none |
153 | 380 | return; |
154 | 0 | default: |
155 | 0 | if (m_listType<11) |
156 | 0 | return; |
157 | | |
158 | 0 | listLevel=m_customListLevel; |
159 | 0 | break; |
160 | 101k | } |
161 | | |
162 | 100k | m_listLevelIndex = level+1; |
163 | 100k | std::shared_ptr<MWAWList> parentList; |
164 | 100k | if (*parent.m_listId>=0) |
165 | 9.55k | parentList=listManager.getList(*parent.m_listId); |
166 | 100k | auto list=listManager.getNewList(parentList, level+1, listLevel); |
167 | 100k | if (list) |
168 | 100k | m_listId=list->getId(); |
169 | 0 | else |
170 | 0 | m_listLevel=listLevel; |
171 | | |
172 | 100k | m_margins[1]=m_margins[1].get()-listLevel.m_labelWidth; |
173 | 100k | } |
174 | | //! the left and right margins from parent in inches |
175 | | double m_marginsFromParent[2]; |
176 | | //! the list type (0: none, 1: leader, ...) |
177 | | int m_listType; |
178 | | //! a custom list level ( only defined if m_listType>=0xb) |
179 | | MWAWListLevel m_customListLevel; |
180 | | //! true if we need to add a page break before |
181 | | bool m_pageBreak; |
182 | | //! true if we need to keep outline together |
183 | | bool m_keepOutlineTogether; |
184 | | }; |
185 | | |
186 | | Paragraph::~Paragraph() |
187 | 113M | { |
188 | 113M | } |
189 | | |
190 | | //////////////////////////////////////// |
191 | | //! Internal: the outline data of a MoreText |
192 | | struct Outline { |
193 | | //! constructor |
194 | | Outline() |
195 | 1.27M | { |
196 | | // set to default value |
197 | 5.08M | for (auto &font : m_fonts) font=MWAWFont(3,12); |
198 | 1.27M | m_paragraphs[0].m_listType=1; |
199 | 1.27M | } |
200 | | //! the paragraphs : organizer, slide, tree, unknowns |
201 | | Paragraph m_paragraphs[4]; |
202 | | //! the fonts : organizer, slide, tree unknowns |
203 | | MWAWFont m_fonts[4]; |
204 | | }; |
205 | | |
206 | | //////////////////////////////////////// |
207 | | //! Internal and low level: the outline modifier header of a MoreText |
208 | | struct OutlineMod { |
209 | | //! constructor |
210 | | OutlineMod() |
211 | 3.62G | : m_type(-1) |
212 | 3.62G | , m_flags(0) |
213 | 3.62G | , m_entry() |
214 | 3.62G | , m_extra("") |
215 | 3.62G | { |
216 | 7.25G | for (auto &unkn : m_unknowns) unkn=0; |
217 | 3.62G | } |
218 | | //! returns the data id to change in Outline |
219 | | int getModId() const |
220 | 3.72G | { |
221 | 3.72G | if (m_unknowns[0] || (m_flags&0xF)!= 1) |
222 | 3.72G | return 3; |
223 | 4.25M | switch (m_flags>>4) { |
224 | 160k | case 1: |
225 | 160k | return 0; |
226 | 304k | case 2: |
227 | 304k | return 1; |
228 | 39.1k | case 4: |
229 | 39.1k | return 2; |
230 | 3.75M | default: |
231 | 3.75M | break; |
232 | 4.25M | } |
233 | 3.75M | return 3; |
234 | 4.25M | } |
235 | | //! operator<< |
236 | | friend std::ostream &operator<<(std::ostream &o, OutlineMod const &head) |
237 | 0 | { |
238 | 0 | switch (head.m_flags>>4) { |
239 | 0 | case 1: // organizer |
240 | 0 | break; |
241 | 0 | case 2: |
242 | 0 | o << "slide,"; |
243 | 0 | break; |
244 | 0 | case 4: |
245 | 0 | o << "tree,"; |
246 | 0 | break; |
247 | 0 | default: |
248 | 0 | o << "##wh=" << std::hex << (head.m_flags>>4) << std::dec << ","; |
249 | 0 | break; |
250 | 0 | } |
251 | 0 | switch (head.m_type) { |
252 | 0 | case 0x301: |
253 | 0 | o << "font,"; |
254 | 0 | break; |
255 | 0 | case 0x402: |
256 | 0 | o << "fSize,"; |
257 | 0 | break; |
258 | 0 | case 0x603: |
259 | 0 | o << "fFlags,"; |
260 | 0 | break; |
261 | 0 | case 0x804: |
262 | 0 | o << "fColor,"; |
263 | 0 | break; |
264 | 0 | case 0xa05: |
265 | 0 | o << "interline,"; |
266 | 0 | break; |
267 | 0 | case 0xc0f: |
268 | 0 | o << "firstIndent,"; |
269 | 0 | break; |
270 | 0 | case 0xf07: |
271 | 0 | o << "tabs,"; |
272 | 0 | break; |
273 | 0 | case 0x1006: |
274 | 0 | o << "justify,"; |
275 | 0 | break; |
276 | 0 | case 0x1208: |
277 | 0 | o << "bef/afterspace,"; |
278 | 0 | break; |
279 | 0 | case 0x1409: |
280 | 0 | o << "lMargin,"; |
281 | 0 | break; |
282 | 0 | case 0x160a: |
283 | 0 | o << "rMargin,"; |
284 | 0 | break; |
285 | 0 | case 0x190b: |
286 | 0 | o << "list[type],"; |
287 | 0 | break; |
288 | 0 | case 0x1a0c: |
289 | 0 | o << "break,"; |
290 | 0 | break; |
291 | 0 | case 0x1c0d: |
292 | 0 | o << "keepline,"; |
293 | 0 | break; |
294 | 0 | case 0x1e0e: |
295 | 0 | o << "keep[outline],"; |
296 | 0 | break; |
297 | 0 | case -1: |
298 | 0 | break; |
299 | 0 | default: |
300 | 0 | // 2914|2b15|3319|3b1c|6532|6934|7137|773a|7b3c -> backside|backpattern |
301 | 0 | o << "type=" << std::hex << head.m_type << std::dec << ","; |
302 | 0 | break; |
303 | 0 | } |
304 | 0 | for (int i=0; i<2; i++) { // unkn0=0|1|2(related to clone?), unkn1=0|1|999 |
305 | 0 | if (head.m_unknowns[i]) |
306 | 0 | o << "unkn" << i << "=" << head.m_unknowns[i] << ","; |
307 | 0 | } |
308 | 0 | if (head.m_flags&0xF) |
309 | 0 | o << "fl=" << std::hex << (head.m_flags&0xF) << std::dec << ","; |
310 | 0 | if (head.m_entry.valid()) |
311 | 0 | o << std::hex << head.m_entry.begin() << "<->" << head.m_entry.end() << std::dec << ","; |
312 | 0 | o << head.m_extra; |
313 | 0 | return o; |
314 | 0 | } |
315 | | //! the type |
316 | | int m_type; |
317 | | //! the flag |
318 | | int m_flags; |
319 | | //! the data entry |
320 | | MWAWEntry m_entry; |
321 | | //! some unknown flags |
322 | | int m_unknowns[2]; |
323 | | //! extra data |
324 | | std::string m_extra; |
325 | | }; |
326 | | |
327 | | //////////////////////////////////////// |
328 | | //! Internal: the comment data of a MoreText |
329 | | struct Comment { |
330 | | //! constructor |
331 | | Comment() |
332 | 1.15M | : m_entry() |
333 | 1.15M | , m_extra("") |
334 | 1.15M | { |
335 | 1.15M | } |
336 | | //! operator<< |
337 | | friend std::ostream &operator<<(std::ostream &o, Comment const &comment) |
338 | 0 | { |
339 | 0 | o << comment.m_extra; |
340 | 0 | return o; |
341 | 0 | } |
342 | | //! the text entry |
343 | | MWAWEntry m_entry; |
344 | | //! extra data |
345 | | std::string m_extra; |
346 | | }; |
347 | | |
348 | | //////////////////////////////////////// |
349 | | //! Internal: the topic data of a MoreText |
350 | | struct Topic { |
351 | | //! an enum used to define the different type of data attached to a topic |
352 | | enum AttachementType { AOutline=0, AComment, ASpeakerNote }; |
353 | | //! constructor |
354 | | Topic() |
355 | 2.14M | : m_entry() |
356 | 2.14M | , m_level(0) |
357 | 2.14M | , m_isCloned(false) |
358 | 2.14M | , m_cloneId(-1) |
359 | 2.14M | , m_numPageBreak(-1) |
360 | 2.14M | , m_isStartSlide(false) |
361 | 2.14M | , m_extra("") |
362 | 2.14M | { |
363 | 6.43M | for (auto &hasData : m_hasList) hasData=false; |
364 | 6.43M | for (auto &attachData : m_attachList) attachData=-1; |
365 | 2.14M | } |
366 | | //! operator<< |
367 | | friend std::ostream &operator<<(std::ostream &o, Topic const &topic) |
368 | 0 | { |
369 | 0 | if (topic.m_level>0) |
370 | 0 | o << "level=" << topic.m_level << ","; |
371 | 0 | if (topic.m_hasList[AOutline]) |
372 | 0 | o << "outline,"; |
373 | 0 | if (topic.m_hasList[AComment]) |
374 | 0 | o << "comment,"; |
375 | 0 | if (topic.m_hasList[ASpeakerNote]) |
376 | 0 | o << "speakerNote,"; |
377 | 0 | if (topic.m_isCloned) |
378 | 0 | o << "cloned,"; |
379 | 0 | if (topic.m_cloneId >= 0) |
380 | 0 | o << "cloneId=" << topic.m_cloneId << ","; |
381 | 0 | if (topic.m_isStartSlide) |
382 | 0 | o << "newSlide,"; |
383 | 0 | o << topic.m_extra; |
384 | 0 | return o; |
385 | 0 | } |
386 | | //! the text entry |
387 | | MWAWEntry m_entry; |
388 | | //! the topic level |
389 | | int m_level; |
390 | | //! true if the entry is cloned |
391 | | bool m_isCloned; |
392 | | //! if not 0, indicate that we must cloned the cloneId^th clone |
393 | | int m_cloneId; |
394 | | //! a list of boolean use to note if a topic is associated with a Outline, ... |
395 | | bool m_hasList[3]; |
396 | | //! a list of id to retrieve the attachment |
397 | | int m_attachList[3]; |
398 | | //! the number of pages in the sub list |
399 | | int m_numPageBreak; |
400 | | //! true if we start a new slide |
401 | | bool m_isStartSlide; |
402 | | //! extra data |
403 | | std::string m_extra; |
404 | | }; |
405 | | |
406 | | //////////////////////////////////////// |
407 | | //! Internal: the state of a MoreText |
408 | | struct State { |
409 | | //! constructor |
410 | | State() |
411 | 73.3k | : m_version(-1) |
412 | 73.3k | , m_topicList() |
413 | 73.3k | , m_commentList() |
414 | 73.3k | , m_speakerList() |
415 | 73.3k | , m_outlineList() |
416 | 73.3k | , m_actualComment(0) |
417 | 73.3k | , m_actualSpeaker(0) |
418 | 73.3k | , m_actualOutline(0) |
419 | 73.3k | , m_numPages(-1) |
420 | 73.3k | , m_actualPage(1) |
421 | 73.3k | { |
422 | 73.3k | } |
423 | | //! the file version |
424 | | mutable int m_version; |
425 | | //! the topic list |
426 | | std::vector<Topic> m_topicList; |
427 | | //! the header/footer/comment list |
428 | | std::vector<Comment> m_commentList; |
429 | | //! the speaker note list |
430 | | std::vector<MWAWEntry> m_speakerList; |
431 | | //! the outline list |
432 | | std::vector<Outline> m_outlineList; |
433 | | //! the actual comment |
434 | | int m_actualComment; |
435 | | //! the actual speaker note |
436 | | int m_actualSpeaker; |
437 | | //! the actual outline |
438 | | int m_actualOutline; |
439 | | int m_numPages /* the number of pages */, m_actualPage /* the actual page */; |
440 | | }; |
441 | | |
442 | | //////////////////////////////////////// |
443 | | //! Internal: the subdocument of a MoreText |
444 | | class SubDocument final : public MWAWSubDocument |
445 | | { |
446 | | public: |
447 | | SubDocument(MoreText &pars, MWAWInputStreamPtr const &input, int zId, int what) |
448 | 1.94k | : MWAWSubDocument(pars.m_mainParser, input, MWAWEntry()) |
449 | 1.94k | , m_textParser(&pars) |
450 | 1.94k | , m_id(zId) |
451 | 1.94k | , m_what(what) |
452 | 1.94k | { |
453 | 1.94k | } |
454 | | |
455 | | //! destructor |
456 | 0 | ~SubDocument() final {} |
457 | | |
458 | | //! operator!= |
459 | | bool operator!=(MWAWSubDocument const &doc) const final; |
460 | | |
461 | | //! the parser function |
462 | | void parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType type) final; |
463 | | |
464 | | protected: |
465 | | /** the text parser */ |
466 | | MoreText *m_textParser; |
467 | | //! the subdocument id |
468 | | int m_id; |
469 | | //! a int to know what to send 0: header/footer, 1: comment, 2:note |
470 | | int m_what; |
471 | | private: |
472 | | SubDocument(SubDocument const &orig) = delete; |
473 | | SubDocument &operator=(SubDocument const &orig) = delete; |
474 | | }; |
475 | | |
476 | | void SubDocument::parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType /*type*/) |
477 | 1.94k | { |
478 | 1.94k | if (!listener.get()) { |
479 | 0 | MWAW_DEBUG_MSG(("MoreTextInternal::SubDocument::parse: no listener\n")); |
480 | 0 | return; |
481 | 0 | } |
482 | 1.94k | if (!m_textParser) { |
483 | 0 | MWAW_DEBUG_MSG(("MoreTextInternal::SubDocument::parse: no parser\n")); |
484 | 0 | return; |
485 | 0 | } |
486 | | |
487 | 1.94k | long pos = m_input->tell(); |
488 | 1.94k | switch (m_what) { |
489 | 380 | case 0: { |
490 | 380 | std::vector<MWAWParagraph> paraStack; |
491 | 380 | m_textParser->sendTopic(m_id,0,paraStack); |
492 | 380 | break; |
493 | 0 | } |
494 | 336 | case 1: |
495 | 336 | m_textParser->sendComment(m_id); |
496 | 336 | break; |
497 | 1.23k | case 2: |
498 | 1.23k | m_textParser->sendSpeakerNote(m_id); |
499 | 1.23k | break; |
500 | 0 | default: |
501 | 0 | MWAW_DEBUG_MSG(("SubDocument::parse: unknow value in m_what\n")); |
502 | 0 | break; |
503 | 1.94k | } |
504 | 1.94k | m_input->seek(pos, librevenge::RVNG_SEEK_SET); |
505 | 1.94k | } |
506 | | |
507 | | bool SubDocument::operator!=(MWAWSubDocument const &doc) const |
508 | 0 | { |
509 | 0 | if (MWAWSubDocument::operator!=(doc)) return true; |
510 | 0 | auto const *sDoc = dynamic_cast<SubDocument const *>(&doc); |
511 | 0 | if (!sDoc) return true; |
512 | 0 | if (m_textParser != sDoc->m_textParser) return true; |
513 | 0 | if (m_id != sDoc->m_id) return true; |
514 | 0 | return m_what != sDoc->m_what; |
515 | 0 | } |
516 | | } |
517 | | |
518 | | //////////////////////////////////////////////////////////// |
519 | | // constructor/destructor, ... |
520 | | //////////////////////////////////////////////////////////// |
521 | | MoreText::MoreText(MoreParser &parser) |
522 | 73.3k | : m_parserState(parser.getParserState()) |
523 | 73.3k | , m_state(new MoreTextInternal::State) |
524 | 73.3k | , m_mainParser(&parser) |
525 | 73.3k | { |
526 | 73.3k | } |
527 | | |
528 | | MoreText::~MoreText() |
529 | 73.3k | { |
530 | 73.3k | } |
531 | | |
532 | | int MoreText::version() const |
533 | 1.07M | { |
534 | 1.07M | if (m_state->m_version < 0) |
535 | 17.9k | m_state->m_version = m_parserState->m_version; |
536 | 1.07M | return m_state->m_version; |
537 | 1.07M | } |
538 | | |
539 | | int MoreText::numPages() const |
540 | 24.2k | { |
541 | 24.2k | if (m_state->m_numPages >= 0) |
542 | 24.2k | return m_state->m_numPages; |
543 | | |
544 | 0 | MWAW_DEBUG_MSG(("MoreText::createZones is not called\n")); |
545 | 0 | const_cast<MoreText *>(this)->createZones(); |
546 | 0 | return m_state->m_numPages; |
547 | 24.2k | } |
548 | | |
549 | | std::shared_ptr<MWAWSubDocument> MoreText::getHeaderFooter(bool header) |
550 | 48.5k | { |
551 | 48.5k | std::shared_ptr<MWAWSubDocument> res; |
552 | 48.5k | size_t id=header ? 1 : 2; |
553 | 48.5k | if (id >= m_state->m_topicList.size()) |
554 | 577 | return res; |
555 | 47.9k | auto const &topic= m_state->m_topicList[id]; |
556 | | // check if the content is empty |
557 | 47.9k | int comment=topic.m_attachList[MoreTextInternal::Topic::AComment]; |
558 | 47.9k | if (comment < 0 || comment >= int(m_state->m_commentList.size())) |
559 | 47.5k | return res; |
560 | 380 | if (m_state->m_commentList[size_t(comment)].m_entry.length()<=4) |
561 | 0 | return res; |
562 | 380 | res.reset(new MoreTextInternal::SubDocument(*this, m_parserState->m_input, int(id), 0)); |
563 | 380 | return res; |
564 | 380 | } |
565 | | |
566 | | //////////////////////////////////////////////////////////// |
567 | | // Intermediate level |
568 | | //////////////////////////////////////////////////////////// |
569 | | |
570 | | // |
571 | | // find/send the different zones |
572 | | // |
573 | | bool MoreText::createZones() |
574 | 24.2k | { |
575 | 24.2k | if (m_state->m_topicList.empty()) |
576 | 0 | return false; |
577 | | |
578 | | // first create the list of cloned topic |
579 | 24.2k | std::vector<int> clonedList; |
580 | 2.16M | for (size_t i=0; i < m_state->m_topicList.size(); i++) { |
581 | 2.14M | auto const &topic=m_state->m_topicList[i]; |
582 | 2.14M | if (topic.m_isCloned) |
583 | 530k | clonedList.push_back(int(i)); |
584 | 2.14M | } |
585 | | // now associated each topic with its outline, its comment, its original topic (if clone) |
586 | 24.2k | auto numCloned=int(clonedList.size()); |
587 | 24.2k | size_t actAttach[3]= {0,0,0}; |
588 | 24.2k | size_t numAttach[3]= {0,0,0}; |
589 | 24.2k | numAttach[MoreTextInternal::Topic::AOutline]=m_state->m_outlineList.size(); |
590 | 24.2k | numAttach[MoreTextInternal::Topic::AComment]=m_state->m_commentList.size(); |
591 | 24.2k | numAttach[MoreTextInternal::Topic::ASpeakerNote]=m_state->m_speakerList.size(); |
592 | 24.2k | int n=0; |
593 | 2.14M | for (auto &topic : m_state->m_topicList) { |
594 | 2.14M | ++n; |
595 | 8.57M | for (int j=0; j < 3; j++) { |
596 | 6.43M | if (!topic.m_hasList[j]) |
597 | 5.22M | continue; |
598 | 1.20M | if (actAttach[j] >= numAttach[j]) { |
599 | 714k | MWAW_DEBUG_MSG(("MoreText::createZones: can not find attach-%d for topic %d\n", j, n-1)); |
600 | 714k | continue; |
601 | 714k | } |
602 | 493k | topic.m_attachList[j]=int(actAttach[j]++); |
603 | 493k | switch (j) { |
604 | 195k | case MoreTextInternal::Topic::AOutline: |
605 | 195k | break; |
606 | 138k | case MoreTextInternal::Topic::AComment: // no need to add empty comment |
607 | 138k | if (m_state->m_commentList[size_t(topic.m_attachList[j])].m_entry.length() <= 4) |
608 | 130k | topic.m_attachList[j]=-1; |
609 | 138k | break; |
610 | 160k | case MoreTextInternal::Topic::ASpeakerNote: // no need to add empty speaker note |
611 | 160k | if (m_state->m_speakerList[size_t(topic.m_attachList[j])].length() <= 4) |
612 | 150k | topic.m_attachList[j]=-1; |
613 | 160k | break; |
614 | 0 | default: |
615 | 0 | break; |
616 | 493k | } |
617 | 493k | } |
618 | 2.14M | int cloneId=topic.m_cloneId; |
619 | 2.14M | if (cloneId < 0) |
620 | 1.81M | continue; |
621 | 331k | if (cloneId==0 || cloneId > numCloned) { |
622 | 316k | MWAW_DEBUG_MSG(("MoreText::createZones: can not find original for topic %d\n", n-1)); |
623 | 316k | topic.m_cloneId=-1; |
624 | 316k | } |
625 | 15.0k | else |
626 | 15.0k | topic.m_cloneId=clonedList[size_t(cloneId-1)]; |
627 | 331k | } |
628 | | |
629 | | // now check that we have no loop |
630 | 2.16M | for (size_t i=0; i < m_state->m_topicList.size(); i++) { |
631 | 2.14M | auto const &topic=m_state->m_topicList[i]; |
632 | 2.14M | if (topic.m_cloneId<0) |
633 | 2.12M | continue; |
634 | 15.0k | std::set<size_t> parent; |
635 | 15.0k | checkTopicList(i, parent); |
636 | 15.0k | } |
637 | | // now compute the number of page |
638 | 24.2k | int nPages = 1; |
639 | 2.14M | for (auto const &topic : m_state->m_topicList) { |
640 | 2.14M | if (topic.m_numPageBreak >= 0) { |
641 | 14.7k | nPages+=topic.m_numPageBreak; |
642 | 14.7k | } |
643 | 2.14M | int outId=topic.m_attachList[MoreTextInternal::Topic::AOutline]; |
644 | 2.14M | if (outId<0) continue; |
645 | 195k | if (m_state->m_outlineList[size_t(outId)].m_paragraphs[0].m_pageBreak) |
646 | 0 | nPages++; |
647 | 195k | } |
648 | 24.2k | m_state->m_actualPage = 1; |
649 | 24.2k | m_state->m_numPages = nPages; |
650 | 24.2k | return true; |
651 | 24.2k | } |
652 | | |
653 | | int MoreText::getLastTopicChildId(int tId) const |
654 | 29.2k | { |
655 | 29.2k | size_t numTopic=m_state->m_topicList.size(); |
656 | 29.2k | if (tId < 0||tId>= int(numTopic)) { |
657 | 0 | MWAW_DEBUG_MSG(("MoreText::getLastTopicChildId: can not find topic %d\n", tId)); |
658 | 0 | return tId; |
659 | 0 | } |
660 | 29.2k | auto p=size_t(tId); |
661 | 29.2k | int level=m_state->m_topicList[p].m_level; |
662 | 29.2k | while (p+1<numTopic && m_state->m_topicList[p].m_level>level) |
663 | 0 | p++; |
664 | 29.2k | return int(p); |
665 | 29.2k | } |
666 | | |
667 | | int MoreText::checkTopicList(size_t tId, std::set<size_t> &parent) |
668 | 15.0k | { |
669 | 15.0k | size_t numTopic=m_state->m_topicList.size(); |
670 | 15.0k | if (tId>=numTopic) { |
671 | 0 | MWAW_DEBUG_MSG(("MoreText::checkTopicList: can not find topic %d\n", int(tId))); |
672 | 0 | return 0; |
673 | 0 | } |
674 | 15.0k | if (parent.find(tId)!=parent.end()) { |
675 | 0 | MWAW_DEBUG_MSG(("MoreText::checkTopicList: repairing fails\n")); |
676 | 0 | throw libmwaw::ParseException(); |
677 | 0 | } |
678 | 15.0k | parent.insert(tId); |
679 | 15.0k | auto &topic=m_state->m_topicList[tId]; |
680 | 15.0k | int nPages=0; |
681 | 15.0k | int outId=topic.m_attachList[MoreTextInternal::Topic::AOutline]; |
682 | 15.0k | if (outId>=0) { |
683 | 2.57k | if (m_state->m_outlineList[size_t(outId)].m_paragraphs[0].m_pageBreak) |
684 | 0 | nPages++; |
685 | 2.57k | } |
686 | 15.0k | auto id=int(tId); |
687 | 15.0k | if (topic.m_cloneId>=0) { |
688 | 15.0k | if (parent.find(size_t(topic.m_cloneId))!=parent.end()) { |
689 | 283 | MWAW_DEBUG_MSG(("MoreText::checkTopicList: find a loop, remove a clone\n")); |
690 | 283 | topic.m_cloneId=-1; |
691 | 283 | parent.erase(tId); |
692 | 283 | return 0; |
693 | 283 | } |
694 | 14.7k | id = topic.m_cloneId; |
695 | 14.7k | parent.insert(size_t(id)); |
696 | 14.7k | } |
697 | 14.7k | int lastTId=getLastTopicChildId(id); |
698 | 14.7k | for (int i=id+1; i<=lastTId; i++) |
699 | 0 | nPages+=checkTopicList(size_t(i), parent); |
700 | 14.7k | topic.m_numPageBreak=nPages; |
701 | 14.7k | parent.erase(tId); |
702 | 14.7k | if (id!=int(tId)) |
703 | 14.7k | parent.erase(size_t(tId)); |
704 | 14.7k | return nPages; |
705 | 15.0k | } |
706 | | |
707 | | // try read to the file text position |
708 | | bool MoreText::readTopic(MWAWEntry const &entry) |
709 | 24.3k | { |
710 | 24.3k | if (!entry.valid() || (entry.length()%10)) { |
711 | 88 | MWAW_DEBUG_MSG(("MoreText::readTopic: the entry is bad\n")); |
712 | 88 | return false; |
713 | 88 | } |
714 | | // topic 0-2: ?, header,footer, topic 3: title, after document |
715 | 24.2k | long pos = entry.begin(); |
716 | 24.2k | MWAWInputStreamPtr &input= m_parserState->m_input; |
717 | 24.2k | libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile; |
718 | 24.2k | libmwaw::DebugStream f; |
719 | | |
720 | 24.2k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
721 | 24.2k | entry.setParsed(true); |
722 | | |
723 | 24.2k | ascFile.addPos(pos); |
724 | 24.2k | ascFile.addNote("Entries(Topic)"); |
725 | | |
726 | 24.2k | auto N=int(entry.length()/10); |
727 | 2.16M | for (int i=0; i < N; i++) { |
728 | 2.14M | pos=input->tell(); |
729 | 2.14M | MoreTextInternal::Topic topic; |
730 | 2.14M | f.str(""); |
731 | 2.14M | topic.m_level = static_cast<int>(input->readLong(2)); |
732 | 2.14M | bool isAClone=false; |
733 | 2.14M | auto flag = static_cast<int>(input->readULong(2)); // some flag ? |
734 | 2.14M | if ((flag&1)==0) f << "hidden,"; |
735 | 2.14M | if (flag&4) f << "marked,"; |
736 | 2.14M | if (flag&0x10) topic.m_isCloned=true; |
737 | 2.14M | if (flag&0x20) isAClone=true; |
738 | 2.14M | if (flag&0x40) { |
739 | 466k | topic.m_hasList[MoreTextInternal::Topic::ASpeakerNote]=true; |
740 | 466k | f << "S" << m_state->m_actualSpeaker++ << ","; |
741 | 466k | } |
742 | 2.14M | if (flag&0x80) { |
743 | 369k | topic.m_hasList[MoreTextInternal::Topic::AComment]=true; |
744 | 369k | f << "C" << m_state->m_actualComment++ << ","; |
745 | 369k | } |
746 | 2.14M | if (flag&0x400) f << "showComment,"; |
747 | 2.14M | if (flag&0x2000) topic.m_isStartSlide=true; |
748 | 2.14M | if (flag&0x8000) { |
749 | 372k | topic.m_hasList[MoreTextInternal::Topic::AOutline]=true; |
750 | 372k | f << "O" << m_state->m_actualOutline++ << ","; |
751 | 372k | } |
752 | | // find only bits: 5208 |
753 | 2.14M | flag &= 0x5B4A; |
754 | 2.14M | if (flag) f << "fl=" << std::hex << flag << std::dec << ","; |
755 | 2.14M | long fPos = input->readLong(4); |
756 | 2.14M | if (isAClone) |
757 | 528k | topic.m_cloneId=static_cast<int>(fPos); |
758 | 1.61M | else { |
759 | 1.61M | f << "pos=" << std::hex << fPos << std::dec << ","; |
760 | 1.61M | topic.m_entry.setBegin(fPos); |
761 | 1.61M | if (!m_mainParser->checkAndFindSize(topic.m_entry)) { |
762 | 1.51M | MWAW_DEBUG_MSG(("MoreText::readTopic: can not read a text position\n")); |
763 | 1.51M | f << "###"; |
764 | 1.51M | topic.m_entry = MWAWEntry(); |
765 | 1.51M | } |
766 | 1.61M | } |
767 | 2.14M | auto val = static_cast<int>(input->readLong(2)); // a small number 1 or 2 |
768 | 2.14M | if (val) |
769 | 1.50M | f << "f1=" << val << ","; |
770 | 2.14M | topic.m_extra=f.str(); |
771 | 2.14M | m_state->m_topicList.push_back(topic); |
772 | | |
773 | 2.14M | f.str(""); |
774 | 2.14M | f << "Topic-" << i << ":" << topic; |
775 | 2.14M | ascFile.addPos(pos); |
776 | 2.14M | ascFile.addNote(f.str().c_str()); |
777 | 2.14M | input->seek(pos+10, librevenge::RVNG_SEEK_SET); |
778 | 2.14M | } |
779 | 24.2k | return true; |
780 | 24.3k | } |
781 | | |
782 | | bool MoreText::readComment(MWAWEntry const &entry) |
783 | 11.0k | { |
784 | 11.0k | if (!entry.valid() || (entry.length()%8)) { |
785 | 160 | MWAW_DEBUG_MSG(("MoreText::readComment: the entry is bad\n")); |
786 | 160 | return false; |
787 | 160 | } |
788 | | // comment0? comment1: header, comment2: footer |
789 | 10.9k | long pos = entry.begin(); |
790 | 10.9k | MWAWInputStreamPtr &input= m_parserState->m_input; |
791 | 10.9k | libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile; |
792 | 10.9k | libmwaw::DebugStream f; |
793 | | |
794 | 10.9k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
795 | 10.9k | entry.setParsed(true); |
796 | | |
797 | 10.9k | ascFile.addPos(pos); |
798 | 10.9k | ascFile.addNote("Entries(Comment)"); |
799 | | |
800 | 10.9k | auto N=int(entry.length()/8); |
801 | 1.16M | for (int i=0; i < N; i++) { |
802 | 1.15M | pos=input->tell(); |
803 | 1.15M | MoreTextInternal::Comment comment; |
804 | 1.15M | f.str(""); |
805 | 1.15M | long fPos = input->readLong(4); |
806 | 1.15M | f << "pos=" << std::hex << fPos << std::dec << ","; |
807 | 1.15M | comment.m_entry.setBegin(fPos); |
808 | 1.15M | if (!m_mainParser->checkAndFindSize(comment.m_entry)) { |
809 | 1.08M | MWAW_DEBUG_MSG(("MoreText::readComment: can not read a file position\n")); |
810 | 1.08M | f << "###"; |
811 | 1.08M | comment.m_entry.setLength(0); |
812 | 1.08M | } |
813 | 1.15M | auto val = static_cast<int>(input->readLong(2)); // always 4 ? |
814 | 1.15M | if (val != 4) |
815 | 1.14M | f << "f0=" << val << ","; |
816 | 1.15M | val = static_cast<int>(input->readULong(2)); // some flag ? find 0x3333 0x200d ... |
817 | 1.15M | if (val) f << "fl=" << std::hex << val << std::dec << ","; |
818 | | |
819 | 1.15M | comment.m_extra=f.str(); |
820 | 1.15M | m_state->m_commentList.push_back(comment); |
821 | 1.15M | f.str(""); |
822 | 1.15M | f << "Comment-C" << i << ":" << comment; |
823 | 1.15M | ascFile.addPos(pos); |
824 | 1.15M | ascFile.addNote(f.str().c_str()); |
825 | 1.15M | input->seek(pos+8, librevenge::RVNG_SEEK_SET); |
826 | 1.15M | } |
827 | 10.9k | return true; |
828 | 11.0k | } |
829 | | |
830 | | bool MoreText::readSpeakerNote(MWAWEntry const &entry) |
831 | 7.10k | { |
832 | 7.10k | if (!entry.valid() || (entry.length()%4)) { |
833 | 198 | MWAW_DEBUG_MSG(("MoreText::readSpeakerNote: the entry is bad\n")); |
834 | 198 | return false; |
835 | 198 | } |
836 | | |
837 | 6.90k | long pos = entry.begin(); |
838 | 6.90k | MWAWInputStreamPtr &input= m_parserState->m_input; |
839 | 6.90k | libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile; |
840 | 6.90k | libmwaw::DebugStream f; |
841 | | |
842 | 6.90k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
843 | 6.90k | entry.setParsed(true); |
844 | | |
845 | 6.90k | f << "Entries(SpeakerNote):"; |
846 | 6.90k | auto N=int(entry.length()/4); |
847 | 2.46M | for (int i=0; i < N; i++) { |
848 | 2.45M | long fPos = input->readLong(4); |
849 | 2.45M | f << "S" << i << ":pos=" << std::hex << fPos << std::dec << ","; |
850 | 2.45M | MWAWEntry tEntry; |
851 | 2.45M | tEntry.setBegin(fPos); |
852 | 2.45M | if (!m_mainParser->checkAndFindSize(tEntry)) { |
853 | 2.08M | MWAW_DEBUG_MSG(("MoreText::readSpeakerNote: can not read a file position\n")); |
854 | 2.08M | f << "###"; |
855 | 2.08M | tEntry.setLength(0); |
856 | 2.08M | } |
857 | 2.45M | m_state->m_speakerList.push_back(tEntry); |
858 | 2.45M | } |
859 | 6.90k | ascFile.addPos(pos); |
860 | 6.90k | ascFile.addNote(f.str().c_str()); |
861 | 6.90k | return true; |
862 | 7.10k | } |
863 | | |
864 | | // |
865 | | // send the text |
866 | | // |
867 | | bool MoreText::sendMainText() |
868 | 24.2k | { |
869 | 24.2k | libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile; |
870 | 24.2k | libmwaw::DebugStream f; |
871 | 24.2k | std::vector<MWAWParagraph> paraStack; |
872 | | /* skip 0: unknown, 1: header(comment), 2: footer(comment), 3: title?, after text */ |
873 | 2.07M | for (size_t i=4; i < m_state->m_topicList.size(); i++) { |
874 | 2.04M | auto const &topic = m_state->m_topicList[i]; |
875 | 2.04M | MWAWEntry const &entry=topic.m_entry; |
876 | 2.04M | if (!entry.valid()) { // a clone ? |
877 | 1.94M | sendTopic(int(i),0,paraStack); |
878 | 1.94M | continue; |
879 | 1.94M | } |
880 | 100k | ascFile.addPos(entry.end()); |
881 | 100k | ascFile.addNote("_"); |
882 | 100k | if (sendTopic(int(i),0,paraStack)) |
883 | 100k | continue; |
884 | 0 | ascFile.addPos(entry.end()); |
885 | 0 | ascFile.addNote("_"); |
886 | 0 | f.str(""); |
887 | 0 | f << "Topic-" << i << "[data]:"; |
888 | 0 | ascFile.addPos(entry.begin()); |
889 | 0 | ascFile.addNote(f.str().c_str()); |
890 | 0 | } |
891 | 24.2k | return true; |
892 | 24.2k | } |
893 | | |
894 | | bool MoreText::sendComment(int cId) |
895 | 336 | { |
896 | 336 | MWAWTextListenerPtr listener=m_parserState->m_textListener; |
897 | 336 | if (!listener) { |
898 | 0 | MWAW_DEBUG_MSG(("MoreText::sendComment: can not find a listener!")); |
899 | 0 | return true; |
900 | 0 | } |
901 | 336 | if (cId < 0 || cId >= int(m_state->m_commentList.size())) { |
902 | 0 | MWAW_DEBUG_MSG(("MoreText::sendComment: can not find the comment %d!", cId)); |
903 | 0 | return false; |
904 | 0 | } |
905 | 336 | return sendText(m_state->m_commentList[size_t(cId)].m_entry, MWAWFont(3,12)); |
906 | 336 | } |
907 | | |
908 | | bool MoreText::sendSpeakerNote(int nId) |
909 | 1.23k | { |
910 | 1.23k | MWAWTextListenerPtr listener=m_parserState->m_textListener; |
911 | 1.23k | if (!listener) { |
912 | 0 | MWAW_DEBUG_MSG(("MoreText::sendSpeakerNote: can not find a listener!")); |
913 | 0 | return true; |
914 | 0 | } |
915 | 1.23k | if (nId < 0 || nId >= int(m_state->m_speakerList.size())) { |
916 | 0 | MWAW_DEBUG_MSG(("MoreText::sendSpeakerNote: can not find the speaker note %d!", nId)); |
917 | 0 | return false; |
918 | 0 | } |
919 | 1.23k | return sendText(m_state->m_speakerList[size_t(nId)], MWAWFont(3,12)); |
920 | 1.23k | } |
921 | | |
922 | | bool MoreText::sendTopic(int tId, int dLevel, std::vector<MWAWParagraph> ¶Stack) |
923 | 2.04M | { |
924 | 2.04M | MWAWTextListenerPtr listener=m_parserState->m_textListener; |
925 | 2.04M | if (!listener) { |
926 | 0 | MWAW_DEBUG_MSG(("MoreText::sendTopic: can not find a listener!")); |
927 | 0 | return true; |
928 | 0 | } |
929 | 2.04M | if (tId < 0 || tId >= int(m_state->m_topicList.size())) { |
930 | 0 | MWAW_DEBUG_MSG(("MoreText::sendTopic: can not find the topic note %d!", tId)); |
931 | 0 | return false; |
932 | 0 | } |
933 | 2.04M | auto const &topic=m_state->m_topicList[size_t(tId)]; |
934 | 2.04M | MWAWEntry entry=topic.m_entry; |
935 | 2.04M | int level=topic.m_level+dLevel; |
936 | 2.04M | if (level < 0) { |
937 | 355k | if (tId>=4) { |
938 | 355k | MWAW_DEBUG_MSG(("MoreText::sendTopic: oops level is negatif!\n")); |
939 | 355k | } |
940 | 355k | level=0; |
941 | 355k | } |
942 | | // data to send clone child |
943 | 2.04M | int actId=tId, lastId = tId, cloneDLevel=0; |
944 | 2.04M | if (tId==1||tId==2) { |
945 | | // header/footer: the data are in the comment... |
946 | 380 | int comment=topic.m_attachList[MoreTextInternal::Topic::AComment]; |
947 | 380 | if (comment<0||comment>=int(m_state->m_commentList.size())) |
948 | 0 | return false; |
949 | 380 | entry=m_state->m_commentList[size_t(comment)].m_entry; |
950 | 380 | } |
951 | 2.04M | else if (topic.m_cloneId>=0 && topic.m_cloneId < static_cast<int>(m_state->m_topicList.size())) { |
952 | 14.4k | auto const &cTopic = m_state->m_topicList[size_t(topic.m_cloneId)]; |
953 | 14.4k | entry=cTopic.m_entry; |
954 | 14.4k | actId = topic.m_cloneId; |
955 | 14.4k | lastId = getLastTopicChildId(topic.m_cloneId); |
956 | 14.4k | cloneDLevel = cTopic.m_level-level;; |
957 | 14.4k | } |
958 | 2.04M | if (!entry.valid()) |
959 | 1.94M | return false; |
960 | | // retrieve the ouline |
961 | 101k | MWAWFont font(3,12); |
962 | 101k | MoreTextInternal::Paragraph para; |
963 | 101k | int outl=topic.m_attachList[MoreTextInternal::Topic::AOutline]; |
964 | 101k | if (outl>=0 && outl < static_cast<int>(m_state->m_outlineList.size())) { |
965 | 5.63k | auto const &outline=m_state->m_outlineList[size_t(outl)]; |
966 | 5.63k | if (outline.m_paragraphs[0].m_pageBreak) |
967 | 0 | m_mainParser->newPage(++m_state->m_actualPage); |
968 | 5.63k | para=outline.m_paragraphs[0]; |
969 | 5.63k | font = outline.m_fonts[0]; |
970 | 5.63k | } |
971 | 95.4k | else if (tId>=4) { |
972 | | /* default: leader is default for a paragraph |
973 | | |
974 | | note: sometimes, some small level are bold by default, I do not understand why ? */ |
975 | 95.1k | para.m_listType=1; |
976 | 95.1k | } |
977 | 101k | if (tId==1||tId==2) // force no list in header footer |
978 | 380 | para.m_listType=0; |
979 | 101k | if (level >= int(paraStack.size())) |
980 | 24.5k | paraStack.resize(size_t(level+1)); |
981 | 101k | if (level>0) |
982 | 54.3k | para.updateToFinalState(paraStack[size_t(level-1)], level, |
983 | 54.3k | *m_parserState->m_listManager); |
984 | 46.7k | else |
985 | 46.7k | para.updateToFinalState(MWAWParagraph(),0, *m_parserState->m_listManager); |
986 | 101k | if (level>=0) |
987 | 101k | paraStack[size_t(level)]=para; |
988 | | |
989 | 101k | listener->setParagraph(para); |
990 | 101k | bool ok=sendText(entry, font); |
991 | 101k | if (tId==1||tId==2) |
992 | 380 | return true; |
993 | | // send potential comment and speakernote |
994 | 100k | int comment=topic.m_attachList[MoreTextInternal::Topic::AComment]; |
995 | 100k | if (comment>=0) { |
996 | 336 | MWAWSubDocumentPtr doc(new MoreTextInternal::SubDocument(*this, m_parserState->m_input, comment, 1)); |
997 | 336 | listener->insertComment(doc); |
998 | 336 | } |
999 | 100k | int speaker=topic.m_attachList[MoreTextInternal::Topic::ASpeakerNote]; |
1000 | 100k | if (speaker>=0) { |
1001 | 1.23k | MWAWSubDocumentPtr doc(new MoreTextInternal::SubDocument(*this, m_parserState->m_input, speaker, 2)); |
1002 | 1.23k | listener->insertComment(doc); |
1003 | 1.23k | } |
1004 | | |
1005 | 100k | listener->insertEOL(); |
1006 | 100k | for (int i=actId+1; i <= lastId; i++) |
1007 | 0 | sendTopic(i, dLevel+cloneDLevel, paraStack); |
1008 | 100k | return ok; |
1009 | 101k | } |
1010 | | |
1011 | | bool MoreText::sendText(MWAWEntry const &entry, MWAWFont const &font) |
1012 | 102k | { |
1013 | 102k | MWAWTextListenerPtr listener=m_parserState->m_textListener; |
1014 | 102k | if (!listener) { |
1015 | 0 | MWAW_DEBUG_MSG(("MoreText::sendText: can not find a listener!")); |
1016 | 0 | return true; |
1017 | 0 | } |
1018 | | |
1019 | 102k | MWAWInputStreamPtr &input= m_parserState->m_input; |
1020 | 102k | libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile; |
1021 | 102k | libmwaw::DebugStream f; |
1022 | 102k | long pos = entry.begin(); |
1023 | 102k | long endPos = entry.end(); |
1024 | 102k | if (entry.length()==4) { // no text, we can stop here |
1025 | 41.1k | ascFile.addPos(pos); |
1026 | 41.1k | ascFile.addNote("Entries(Text):"); |
1027 | 41.1k | ascFile.addPos(entry.end()); |
1028 | 41.1k | ascFile.addNote("_"); |
1029 | 41.1k | return true; |
1030 | 41.1k | } |
1031 | | |
1032 | 61.4k | if (entry.length()<4) { |
1033 | 0 | MWAW_DEBUG_MSG(("MoreText::sendText: the entry is bad\n")); |
1034 | 0 | return false; |
1035 | 0 | } |
1036 | | |
1037 | 61.4k | input->seek(pos+4, librevenge::RVNG_SEEK_SET); |
1038 | 61.4k | listener->setFont(font); |
1039 | 61.4k | f << "Entries(Text):"; |
1040 | 61.4k | int val; |
1041 | 61.4k | MWAWFont ft(font); |
1042 | 61.4k | MWAWColor defCol; |
1043 | 61.4k | font.getColor(defCol); |
1044 | 61.4k | uint32_t defFlags=font.flags(); |
1045 | 61.4k | bool defHasUnderline=font.getUnderline().isSet(); |
1046 | 61.4k | listener->setFont(ft); |
1047 | 1.92G | while (!input->isEnd()) { |
1048 | 1.92G | long actPos = input->tell(); |
1049 | 1.92G | if (actPos >= endPos) |
1050 | 59.4k | break; |
1051 | 1.92G | auto c=static_cast<unsigned char>(input->readULong(1)); |
1052 | 1.92G | if (c!=0x1b) { |
1053 | 1.92G | listener->insertCharacter(c); |
1054 | 1.92G | f << c; |
1055 | 1.92G | continue; |
1056 | 1.92G | } |
1057 | 4.23M | if (actPos+1 >= endPos) { |
1058 | 1.20k | f << "@[#]"; |
1059 | 1.20k | MWAW_DEBUG_MSG(("MoreText::sendText: text end by 0x1b\n")); |
1060 | 1.20k | continue; |
1061 | 1.20k | } |
1062 | 4.22M | auto fld=static_cast<int>(input->readULong(1)); |
1063 | 4.22M | bool sendFont=true; |
1064 | 4.22M | switch (fld) { |
1065 | 41.3k | case 0x9: |
1066 | 41.3k | listener->insertTab(); |
1067 | 41.3k | f << "\t"; |
1068 | 41.3k | break; |
1069 | 52.3k | case 0xd: // EOL in header/footer |
1070 | 52.3k | listener->insertEOL(); |
1071 | 52.3k | f << char(0xd); |
1072 | 52.3k | break; |
1073 | 3.17k | case 0x2d: // geneva |
1074 | 3.17k | ft.setId(font.id()); |
1075 | 3.17k | sendFont=false; |
1076 | 3.17k | f << "@[fId=def]"; |
1077 | 3.17k | break; |
1078 | 28.7k | case 0x2e: // 12 |
1079 | 28.7k | ft.setSize(font.size()); |
1080 | 28.7k | sendFont=false; |
1081 | 28.7k | f << "@[fSz=def]"; |
1082 | 28.7k | break; |
1083 | 14.8k | case 0x2f: // black |
1084 | 14.8k | ft.setColor(defCol); |
1085 | 14.8k | sendFont=false; |
1086 | 14.8k | f << "@[fCol=def]"; |
1087 | 14.8k | break; |
1088 | 25.3k | case 0x30: // font |
1089 | 25.3k | if (actPos+4+2 > endPos) { |
1090 | 604 | f << "@[#fId]"; |
1091 | 604 | MWAW_DEBUG_MSG(("MoreText::sendText: field font seems too short\n")); |
1092 | 604 | break; |
1093 | 604 | } |
1094 | 24.7k | val = static_cast<int>(input->readULong(2)); |
1095 | 24.7k | if (!(val&0x8000)) { |
1096 | 20.2k | MWAW_DEBUG_MSG(("MoreText::sendText: field fId: unexpected id\n")); |
1097 | 20.2k | f << "@[#fId]"; |
1098 | 20.2k | input->seek(-2, librevenge::RVNG_SEEK_CUR); |
1099 | 20.2k | break; |
1100 | 20.2k | } |
1101 | 4.55k | f << "@[fId=" << (val&0x7FFF) << "]"; |
1102 | 4.55k | ft.setId(val&0x7FFF); |
1103 | 4.55k | sendFont = false; |
1104 | 4.55k | val = static_cast<int>(input->readULong(2)); |
1105 | 4.55k | if (val!=0x1b30) { |
1106 | 4.48k | MWAW_DEBUG_MSG(("MoreText::sendText: field fId: unexpected end field\n")); |
1107 | 4.48k | f << "###"; |
1108 | 4.48k | input->seek(-2, librevenge::RVNG_SEEK_CUR); |
1109 | 4.48k | break; |
1110 | 4.48k | } |
1111 | 64 | break; |
1112 | 161k | case 0x31: |
1113 | 161k | if (actPos+4+2 > endPos) { |
1114 | 893 | f << "@[#fSz]"; |
1115 | 893 | MWAW_DEBUG_MSG(("MoreText::sendText: field fSz seems too short\n")); |
1116 | 893 | break; |
1117 | 893 | } |
1118 | 160k | val = static_cast<int>(input->readLong(2)); |
1119 | 160k | f << "@[fSz=" << val << "]"; |
1120 | 160k | if (val <= 0) { |
1121 | 86.0k | MWAW_DEBUG_MSG(("MoreText::sendText: field fSz seems bad\n")); |
1122 | 86.0k | f << "###"; |
1123 | 86.0k | } |
1124 | 74.8k | else { |
1125 | 74.8k | ft.setSize(float(val)); |
1126 | 74.8k | sendFont = false; |
1127 | 74.8k | } |
1128 | 160k | val = static_cast<int>(input->readULong(2)); |
1129 | 160k | if (val!=0x1b31) { |
1130 | 129k | MWAW_DEBUG_MSG(("MoreText::sendText: field fSz: unexpected end field\n")); |
1131 | 129k | f << "###"; |
1132 | 129k | input->seek(-2, librevenge::RVNG_SEEK_CUR); |
1133 | 129k | break; |
1134 | 129k | } |
1135 | 31.6k | break; |
1136 | 42.3k | case 0x38: { |
1137 | 42.3k | if (actPos+4+10 > endPos) { |
1138 | 602 | f << "@[#fCol]"; |
1139 | 602 | MWAW_DEBUG_MSG(("MoreText::sendText: field fCol seems too short\n")); |
1140 | 602 | break; |
1141 | 602 | } |
1142 | 41.6k | uint16_t values[5]; |
1143 | 208k | for (auto &v : values) v=static_cast<uint16_t>(input->readULong(2)); |
1144 | 41.6k | if (values[0]!=0xe || values[4]!=0xe) { |
1145 | 41.5k | MWAW_DEBUG_MSG(("MoreText::sendText: field fCol: color sep seems bad\n")); |
1146 | 41.5k | f << "@[fCol###]"; |
1147 | 41.5k | } |
1148 | 190 | else { |
1149 | 190 | MWAWColor col(static_cast<unsigned char>(values[1]>>8), |
1150 | 190 | static_cast<unsigned char>(values[2]>>8), |
1151 | 190 | static_cast<unsigned char>(values[3]>>8)); |
1152 | 190 | ft.setColor(col); |
1153 | 190 | sendFont = false; |
1154 | 190 | f << "@[fCol=" << col << "]"; |
1155 | 190 | } |
1156 | 41.6k | val = static_cast<int>(input->readULong(2)); |
1157 | 41.6k | if (val!=0x1b38) { |
1158 | 40.8k | MWAW_DEBUG_MSG(("MoreText::sendText: field fCol: unexpected end field\n")); |
1159 | 40.8k | f << "###"; |
1160 | 40.8k | input->seek(-2, librevenge::RVNG_SEEK_CUR); |
1161 | 40.8k | break; |
1162 | 40.8k | } |
1163 | 890 | break; |
1164 | 41.6k | } |
1165 | 19.5k | case 0x41: |
1166 | 19.5k | ft.set(MWAWFont::Script(33)); |
1167 | 19.5k | sendFont = false; |
1168 | 19.5k | f << "@[supersc]"; |
1169 | 19.5k | break; |
1170 | 11.3k | case 0x42: // in fact, (line bold)^bold |
1171 | 11.3k | if (defFlags&MWAWFont::boldBit) |
1172 | 0 | ft.setFlags(ft.flags()&uint32_t(~MWAWFont::boldBit)); |
1173 | 11.3k | else |
1174 | 11.3k | ft.setFlags(ft.flags()|MWAWFont::boldBit); |
1175 | 11.3k | sendFont = false; |
1176 | 11.3k | f << "@[b]"; |
1177 | 11.3k | break; |
1178 | 4.09k | case 0x49: // in fact, (line italic)^italic |
1179 | 4.09k | if (defFlags&MWAWFont::italicBit) |
1180 | 0 | ft.setFlags(ft.flags()&uint32_t(~MWAWFont::italicBit)); |
1181 | 4.09k | else |
1182 | 4.09k | ft.setFlags(ft.flags()|MWAWFont::italicBit); |
1183 | 4.09k | sendFont = false; |
1184 | 4.09k | f << "@[it]"; |
1185 | 4.09k | break; |
1186 | 3.25k | case 0x4c: |
1187 | 3.25k | ft.set(MWAWFont::Script(-33)); |
1188 | 3.25k | sendFont = false; |
1189 | 3.25k | f << "@[subsc]"; |
1190 | 3.25k | break; |
1191 | 13.2k | case 0x4f: |
1192 | 13.2k | if (defFlags&MWAWFont::outlineBit) |
1193 | 0 | ft.setFlags(ft.flags()&uint32_t(~MWAWFont::outlineBit)); |
1194 | 13.2k | else |
1195 | 13.2k | ft.setFlags(ft.flags()|MWAWFont::outlineBit); |
1196 | 13.2k | sendFont = false; |
1197 | 13.2k | f << "@[outline]"; |
1198 | 13.2k | break; |
1199 | 5.91k | case 0x53: |
1200 | 5.91k | if (defFlags&MWAWFont::shadowBit) |
1201 | 0 | ft.setFlags(ft.flags()&uint32_t(~MWAWFont::shadowBit)); |
1202 | 5.91k | else |
1203 | 5.91k | ft.setFlags(ft.flags()|MWAWFont::shadowBit); |
1204 | 5.91k | sendFont = false; |
1205 | 5.91k | f << "@[shadow]"; |
1206 | 5.91k | break; |
1207 | 9.93k | case 0x55: |
1208 | 9.93k | ft.setUnderlineStyle(defHasUnderline ? MWAWFont::Line::None : MWAWFont::Line::Simple); |
1209 | 9.93k | sendFont = false; |
1210 | 9.93k | f << "@[underl]"; |
1211 | 9.93k | break; |
1212 | 3.33k | case 0x61: |
1213 | 3.33k | ft.set(MWAWFont::Script()); |
1214 | 3.33k | sendFont = false; |
1215 | 3.33k | f << "@[script=def]"; |
1216 | 3.33k | break; |
1217 | 5.53k | case 0x62: |
1218 | 5.53k | if ((defFlags&MWAWFont::boldBit)==0) |
1219 | 5.53k | ft.setFlags(ft.flags()&uint32_t(~MWAWFont::boldBit)); |
1220 | 1 | else |
1221 | 1 | ft.setFlags(ft.flags()|MWAWFont::boldBit); |
1222 | 5.53k | sendFont = false; |
1223 | 5.53k | f << "@[/b]"; |
1224 | 5.53k | break; |
1225 | 5.15k | case 0x69: |
1226 | 5.15k | if ((defFlags&MWAWFont::italicBit)==0) |
1227 | 5.15k | ft.setFlags(ft.flags()&uint32_t(~MWAWFont::italicBit)); |
1228 | 0 | else |
1229 | 0 | ft.setFlags(ft.flags()|MWAWFont::italicBit); |
1230 | 5.15k | sendFont = false; |
1231 | 5.15k | f << "@[/it]"; |
1232 | 5.15k | break; |
1233 | 3.58k | case 0x6f: |
1234 | 3.58k | if ((defFlags&MWAWFont::outlineBit)==0) |
1235 | 3.58k | ft.setFlags(ft.flags()&uint32_t(~MWAWFont::outlineBit)); |
1236 | 0 | else |
1237 | 0 | ft.setFlags(ft.flags()|MWAWFont::outlineBit); |
1238 | 3.58k | sendFont = false; |
1239 | 3.58k | f << "@[/outline]"; |
1240 | 3.58k | break; |
1241 | 4.44k | case 0x73: |
1242 | 4.44k | if ((defFlags&MWAWFont::shadowBit)==0) |
1243 | 4.44k | ft.setFlags(ft.flags()&uint32_t(~MWAWFont::shadowBit)); |
1244 | 0 | else |
1245 | 0 | ft.setFlags(ft.flags()|MWAWFont::shadowBit); |
1246 | 4.44k | sendFont = false; |
1247 | 4.44k | f << "@[/shadow]"; |
1248 | 4.44k | break; |
1249 | 3.19k | case 0x75: |
1250 | 3.19k | ft.setUnderlineStyle(defHasUnderline ? MWAWFont::Line::Simple : MWAWFont::Line::None); |
1251 | 3.19k | sendFont = false; |
1252 | 3.19k | f << "@[/underl]"; |
1253 | 3.19k | break; |
1254 | 9.01k | case 0xb9: { |
1255 | 9.01k | if (actPos+4+8 > endPos) { |
1256 | 627 | f << "@[#field]"; |
1257 | 627 | MWAW_DEBUG_MSG(("MoreText::sendText: field b9 seems too short\n")); |
1258 | 627 | break; |
1259 | 627 | } |
1260 | 8.39k | uint16_t values[4]; |
1261 | 33.5k | for (auto &v : values) v=static_cast<uint16_t>(input->readULong(2)); |
1262 | 8.39k | if (values[0]!=0xc || values[3]!=0xc) { |
1263 | 8.39k | MWAW_DEBUG_MSG(("MoreText::sendText: field the separator seems bad\n")); |
1264 | 8.39k | f << "@[field###]"; |
1265 | 8.39k | } |
1266 | 0 | else { |
1267 | 0 | switch (values[1]) { |
1268 | 0 | case 1: |
1269 | 0 | listener->insertUnicodeString(librevenge::RVNGString("#Slide#")); |
1270 | 0 | f << "@[slide/title"; |
1271 | 0 | if (values[2]) f << ":" << values[2]; // always 0? |
1272 | 0 | f << "]"; |
1273 | 0 | break; |
1274 | 0 | case 3: |
1275 | 0 | listener->insertField(MWAWField(MWAWField::Title)); |
1276 | 0 | f << "@[title"; |
1277 | 0 | if (values[2]) f << ":" << values[2]; // always 0? |
1278 | 0 | f << "]"; |
1279 | 0 | break; |
1280 | 0 | case 4: |
1281 | 0 | listener->insertUnicodeString(librevenge::RVNGString("#Folder#")); |
1282 | 0 | f << "@[folder]"; |
1283 | 0 | if (values[2]) f << ":" << values[2]; // always 0? |
1284 | 0 | f << "]"; |
1285 | 0 | break; |
1286 | 0 | case 5: |
1287 | 0 | listener->insertField(MWAWField(MWAWField::PageNumber)); |
1288 | 0 | f << "@[pNumber"; |
1289 | 0 | if (values[2]!=0xa) f << ":" << values[2]; |
1290 | 0 | f << "]"; |
1291 | 0 | break; |
1292 | 0 | case 6: // actual time |
1293 | 0 | case 7: // last modif |
1294 | 0 | listener->insertField(MWAWField(MWAWField::Time)); |
1295 | 0 | f << "@[time"; |
1296 | 0 | if (values[1]==7) f << "2"; |
1297 | 0 | if (values[2]!=1) f << ":" << values[2]; |
1298 | 0 | f << "]"; |
1299 | 0 | break; |
1300 | 0 | case 8: // actual date |
1301 | 0 | case 9: // last modif |
1302 | 0 | listener->insertField(MWAWField(MWAWField::Date)); |
1303 | 0 | f << "@[date"; |
1304 | 0 | if (values[1]==7) f << "2"; |
1305 | 0 | if (values[2]!=0x200) f << ":" << values[2]; |
1306 | 0 | f << "]"; |
1307 | 0 | break; |
1308 | 0 | case 0xc: |
1309 | 0 | listener->insertField(MWAWField(MWAWField::PageCount)); |
1310 | 0 | f << "@[pNumber"; |
1311 | 0 | if (values[2]!=0xa) f << ":" << values[2]; |
1312 | 0 | f << "]"; |
1313 | 0 | break; |
1314 | 0 | default: |
1315 | 0 | f << "@[field=##" << values[1] << ":" << values[2] << "]"; |
1316 | 0 | MWAW_DEBUG_MSG(("MoreText::sendText: unknown field\n")); |
1317 | 0 | break; |
1318 | 0 | } |
1319 | 0 | } |
1320 | 8.39k | val = static_cast<int>(input->readULong(2)); |
1321 | 8.39k | if (val!=0x1bb9) { |
1322 | 6.64k | MWAW_DEBUG_MSG(("MoreText::sendText: field b9: unexpected end field\n")); |
1323 | 6.64k | f << "###"; |
1324 | 6.64k | input->seek(-2, librevenge::RVNG_SEEK_CUR); |
1325 | 6.64k | } |
1326 | 8.39k | break; |
1327 | 8.39k | } |
1328 | 35.8k | case 0xf9: { |
1329 | 35.8k | if (actPos+22 > endPos) { |
1330 | 493 | f << "@[#picture]"; |
1331 | 493 | MWAW_DEBUG_MSG(("MoreText::sendText: field f9 seems too short\n")); |
1332 | 493 | break; |
1333 | 493 | } |
1334 | 35.3k | auto sz=long(input->readULong(4)); |
1335 | 35.3k | if (sz<22 || actPos+sz>=endPos) { |
1336 | 5.28k | MWAW_DEBUG_MSG(("MoreText::sendText: field f9: bad field size\n")); |
1337 | 5.28k | f << "###"; |
1338 | 5.28k | input->seek(actPos+2, librevenge::RVNG_SEEK_CUR); |
1339 | 5.28k | break; |
1340 | 5.28k | } |
1341 | 30.1k | input->seek(actPos+sz-6, librevenge::RVNG_SEEK_SET); |
1342 | 30.1k | if (static_cast<int>(input->readULong(4))!=sz && |
1343 | 29.0k | static_cast<int>(input->readULong(2))!=int(0x1b00|fld)) { |
1344 | 22.4k | MWAW_DEBUG_MSG(("MoreText::sendText: find a unknown picture end field\n")); |
1345 | 22.4k | f << "@[#" << std::hex << fld << std::dec << ":" << sz << "]"; |
1346 | 22.4k | input->seek(actPos+2, librevenge::RVNG_SEEK_SET); |
1347 | 22.4k | break; |
1348 | 22.4k | } |
1349 | 7.66k | input->seek(actPos+6, librevenge::RVNG_SEEK_SET); |
1350 | 7.66k | f << "[picture:"; |
1351 | 7.66k | val = static_cast<int>(input->readLong(2)); |
1352 | 7.66k | if (val!=0x100) |
1353 | 6.85k | f << "type=" << std::hex << val << std::dec << ","; |
1354 | 7.66k | float dim[4]; |
1355 | 30.6k | for (auto &d : dim) d = float(input->readLong(2)); |
1356 | 7.66k | MWAWBox2f bdbox(MWAWVec2f(dim[1],dim[0]), MWAWVec2f(dim[3],dim[2])); |
1357 | 7.66k | f << "bdbox=" << bdbox << ","; |
1358 | 7.66k | if (sz>22) { |
1359 | 7.66k | std::shared_ptr<MWAWPict> pict(MWAWPictData::get(input, static_cast<int>(sz)-22)); |
1360 | 7.66k | MWAWEmbeddedObject picture; |
1361 | 7.66k | if (pict && pict->getBinary(picture)) { |
1362 | 7.66k | MWAWPosition pictPos(MWAWVec2f(0,0), bdbox.size(), librevenge::RVNG_POINT); |
1363 | 7.66k | pictPos.m_anchorTo = MWAWPosition::Char; |
1364 | 7.66k | listener->insertPicture(pictPos, picture); |
1365 | 7.66k | } |
1366 | | #ifdef DEBUG_WITH_FILES |
1367 | | if (1) { |
1368 | | librevenge::RVNGBinaryData file; |
1369 | | input->seek(actPos+16, librevenge::RVNG_SEEK_SET); |
1370 | | input->readDataBlock(sz-22, file); |
1371 | | static int volatile pictName = 0; |
1372 | | libmwaw::DebugStream f2; |
1373 | | f2 << "Pict-" << ++pictName << ".pct"; |
1374 | | libmwaw::Debug::dumpFile(file, f2.str().c_str()); |
1375 | | ascFile.skipZone(actPos+16, actPos+sz-7); |
1376 | | } |
1377 | | #endif |
1378 | 7.66k | } |
1379 | 7.66k | input->seek(actPos+sz, librevenge::RVNG_SEEK_SET); |
1380 | 7.66k | break; |
1381 | 30.1k | } |
1382 | 3.72M | default: { |
1383 | 3.72M | auto sz=static_cast<int>(input->readULong(2)); |
1384 | 3.72M | if (sz>4 && actPos+sz<=endPos) { |
1385 | 3.04M | input->seek(actPos+sz-4, librevenge::RVNG_SEEK_SET); |
1386 | 3.04M | if (static_cast<int>(input->readULong(2))==sz && |
1387 | 113k | static_cast<int>(input->readULong(2))==int(0x1b00|fld)) { |
1388 | 62.0k | MWAW_DEBUG_MSG(("MoreText::sendText: find a unknown field, but can infer size\n")); |
1389 | 62.0k | f << "@[#" << std::hex << fld << std::dec << ":" << sz << "]"; |
1390 | 62.0k | break; |
1391 | 62.0k | } |
1392 | 2.98M | input->seek(actPos+2, librevenge::RVNG_SEEK_SET); |
1393 | 2.98M | } |
1394 | 3.66M | MWAW_DEBUG_MSG(("MoreText::sendText: find a unknown field\n")); |
1395 | 3.66M | f << "@[#" << std::hex << fld << std::dec << "]"; |
1396 | 3.66M | break; |
1397 | 3.72M | } |
1398 | 4.22M | } |
1399 | 4.22M | if (!sendFont) |
1400 | 218k | listener->setFont(ft); |
1401 | 4.22M | } |
1402 | 61.4k | ascFile.addPos(pos); |
1403 | 61.4k | ascFile.addNote(f.str().c_str()); |
1404 | 61.4k | ascFile.addPos(entry.end()); |
1405 | 61.4k | ascFile.addNote("_"); |
1406 | 61.4k | return true; |
1407 | 61.4k | } |
1408 | | |
1409 | | ////////////////////////////////////////////// |
1410 | | // Fonts |
1411 | | ////////////////////////////////////////////// |
1412 | | bool MoreText::readFonts(MWAWEntry const &entry) |
1413 | 6.29k | { |
1414 | 6.29k | MWAWInputStreamPtr &input= m_parserState->m_input; |
1415 | 6.29k | if (!entry.valid() || !input || !input->checkPosition(entry.end())) { |
1416 | 0 | MWAW_DEBUG_MSG(("MoreText::readFonts: the entry is bad\n")); |
1417 | 0 | return false; |
1418 | 0 | } |
1419 | | |
1420 | 6.29k | long pos = entry.begin(); |
1421 | 6.29k | long endPos = entry.end(); |
1422 | 6.29k | libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile; |
1423 | 6.29k | libmwaw::DebugStream f; |
1424 | | |
1425 | 6.29k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
1426 | 6.29k | entry.setParsed(true); |
1427 | | |
1428 | 6.29k | int n=0; |
1429 | 48.8k | while (1) { |
1430 | 48.8k | pos=input->tell(); |
1431 | 48.8k | if (pos+1 > endPos) { |
1432 | 52 | MWAW_DEBUG_MSG(("MoreText::readFonts: problem reading a font\n")); |
1433 | 52 | break; |
1434 | 52 | } |
1435 | 48.7k | auto fSz=int(input->readULong(1)); |
1436 | 48.7k | if (fSz==0) |
1437 | 5.47k | break; |
1438 | 43.2k | if (pos+1+fSz+2 > endPos) { |
1439 | 772 | input->seek(-1, librevenge::RVNG_SEEK_CUR); |
1440 | 772 | break; |
1441 | 772 | } |
1442 | 42.5k | f.str(""); |
1443 | 42.5k | if (n==0) |
1444 | 3.32k | f << "Entries(Fonts)-" << n++ << ","; |
1445 | 39.1k | else |
1446 | 39.1k | f << "Fonts-" << n++ << ":"; |
1447 | 42.5k | std::string name(""); |
1448 | 1.19M | for (int i=0; i < fSz; i++) |
1449 | 1.15M | name+=char(input->readULong(1)); |
1450 | 42.5k | if ((fSz&1)==0) input->seek(1, librevenge::RVNG_SEEK_CUR); |
1451 | 42.5k | auto id=static_cast<int>(input->readULong(2)); |
1452 | 42.5k | f << name << ",id=" << id << ","; |
1453 | 42.5k | if (!name.empty()) |
1454 | 42.5k | m_parserState->m_fontConverter->setCorrespondance(id, name); |
1455 | 42.5k | ascFile.addPos(pos); |
1456 | 42.5k | ascFile.addNote(f.str().c_str()); |
1457 | 42.5k | } |
1458 | | |
1459 | 6.29k | pos = input->tell(); |
1460 | 6.29k | if (pos != endPos) { |
1461 | 6.20k | MWAW_DEBUG_MSG(("MoreText::readFonts: problem reading a font\n")); |
1462 | 6.20k | ascFile.addPos(pos); |
1463 | 6.20k | ascFile.addNote("Fonts:###"); |
1464 | 6.20k | } |
1465 | | |
1466 | 6.29k | return true; |
1467 | 6.29k | } |
1468 | | |
1469 | | ////////////////////////////////////////////// |
1470 | | // outline |
1471 | | ////////////////////////////////////////////// |
1472 | | bool MoreText::readOutlineList(MWAWEntry const &entry) |
1473 | 18.5k | { |
1474 | 18.5k | if (!entry.valid() || (entry.length()%4)) { |
1475 | 100 | MWAW_DEBUG_MSG(("MoreText::readOutlineList: the entry is bad\n")); |
1476 | 100 | return false; |
1477 | 100 | } |
1478 | | |
1479 | 18.4k | long pos = entry.begin(); |
1480 | 18.4k | MWAWInputStreamPtr &input= m_parserState->m_input; |
1481 | 18.4k | libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile; |
1482 | 18.4k | libmwaw::DebugStream f; |
1483 | | |
1484 | 18.4k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
1485 | 18.4k | entry.setParsed(true); |
1486 | | |
1487 | 18.4k | f << "Entries(Outline):"; |
1488 | 18.4k | auto N=int(entry.length()/4); |
1489 | 18.4k | std::vector<MWAWEntry> posList; |
1490 | 3.63M | for (int i=0; i < N; i++) { |
1491 | 3.61M | MWAWEntry tEntry; |
1492 | 3.61M | tEntry.setBegin(input->readLong(4)); |
1493 | 3.61M | tEntry.setId(int(i)); |
1494 | 3.61M | if (!m_mainParser->checkAndFindSize(tEntry)) { |
1495 | 3.44M | MWAW_DEBUG_MSG(("MoreText::readOutlineList: can not read a file position\n")); |
1496 | 3.44M | f << "###,"; |
1497 | 3.44M | } |
1498 | 173k | else |
1499 | 173k | f << std::hex << tEntry.begin() << "<->" << tEntry.end() << ","; |
1500 | 3.61M | posList.push_back(tEntry); |
1501 | 3.61M | } |
1502 | 18.4k | ascFile.addPos(pos); |
1503 | 18.4k | ascFile.addNote(f.str().c_str()); |
1504 | | |
1505 | 3.61M | for (auto const &tEntry : posList) { |
1506 | 3.61M | if (!tEntry.valid()) |
1507 | 2.47M | continue; |
1508 | 1.13M | MoreTextInternal::Outline outline; |
1509 | 1.13M | if (readOutline(tEntry, outline)) { |
1510 | 1.00M | m_state->m_outlineList.push_back(outline); |
1511 | 1.00M | continue; |
1512 | 1.00M | } |
1513 | 132k | m_state->m_outlineList.push_back(MoreTextInternal::Outline()); |
1514 | 132k | ascFile.addPos(tEntry.begin()); |
1515 | 132k | ascFile.addNote("Outline-data:###"); |
1516 | 132k | ascFile.addPos(tEntry.end()); |
1517 | 132k | ascFile.addNote("_"); |
1518 | 132k | } |
1519 | 18.4k | return true; |
1520 | 18.5k | } |
1521 | | |
1522 | | bool MoreText::readOutline(MWAWEntry const &entry, MoreTextInternal::Outline &outline) |
1523 | 1.13M | { |
1524 | 1.13M | if (!entry.valid() || entry.length()<8) { |
1525 | 68.0k | MWAW_DEBUG_MSG(("MoreText::readOutline: the entry is bad\n")); |
1526 | 68.0k | return false; |
1527 | 68.0k | } |
1528 | 1.07M | int vers = version(); |
1529 | 1.07M | long pos = entry.begin(); |
1530 | 1.07M | long endPos = entry.end(); |
1531 | 1.07M | MWAWInputStreamPtr &input= m_parserState->m_input; |
1532 | 1.07M | libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile; |
1533 | 1.07M | libmwaw::DebugStream f; |
1534 | | |
1535 | 1.07M | input->seek(pos+4, librevenge::RVNG_SEEK_SET); // skip size |
1536 | | |
1537 | 1.07M | f << "Outline[O" << entry.id() << "]:"; |
1538 | 1.07M | auto val=static_cast<int>(input->readULong(2)); |
1539 | 1.07M | if (val!=6*(vers-1)) { |
1540 | 1.07M | MWAW_DEBUG_MSG(("MoreText::readOutline: find unexpected type\n")); |
1541 | 1.07M | f << "#f0=" << val << ","; |
1542 | 1.07M | } |
1543 | 1.07M | auto N=static_cast<int>(input->readULong(2)); |
1544 | 1.07M | f << "N=" << N << ","; |
1545 | 1.07M | long lastListPos = pos+8+N*16; |
1546 | 1.07M | if (lastListPos > endPos) { |
1547 | 64.1k | MWAW_DEBUG_MSG(("MoreText::readOutline: can not read length\n")); |
1548 | 64.1k | return false; |
1549 | 64.1k | } |
1550 | 1.00M | ascFile.addPos(pos); |
1551 | 1.00M | ascFile.addNote(f.str().c_str()); |
1552 | | |
1553 | 1.00M | std::vector<MoreTextInternal::OutlineMod> outlineModList; |
1554 | 3.63G | for (int n=0; n<N; n++) { |
1555 | 3.62G | pos = input->tell(); |
1556 | 3.62G | f.str(""); |
1557 | | |
1558 | 3.62G | MoreTextInternal::OutlineMod outlineMod; |
1559 | 3.62G | val=int(input->readLong(1)); |
1560 | 3.62G | if (val!=6*(vers-1)) |
1561 | 3.62G | f << "#f0=" << val << ","; |
1562 | | |
1563 | 3.62G | outlineMod.m_flags=int(input->readULong(1)); |
1564 | 7.25G | for (auto &unkn : outlineMod.m_unknowns) unkn=int(input->readLong(2)); |
1565 | 3.62G | outlineMod.m_type=int(input->readULong(2)); |
1566 | 3.62G | int values[4]; |
1567 | 14.5G | for (auto &v : values) v = static_cast<int>(input->readULong(2)); |
1568 | 3.62G | int const which= outlineMod.getModId(); |
1569 | 3.62G | auto ¶ = outline.m_paragraphs[which]; |
1570 | 3.62G | MWAWFont &font=outline.m_fonts[which]; |
1571 | 3.62G | uint32_t fFlags=font.flags(); |
1572 | 3.62G | bool haveExtra=false; |
1573 | 3.62G | switch (outlineMod.m_type) { |
1574 | 294k | case 0x301: // font name |
1575 | 323k | case 0xf07: // left indent+tabs |
1576 | 323k | haveExtra=true; |
1577 | 323k | break; |
1578 | 220k | case 0x402: |
1579 | | // size can be very big, force it to be smallest than 100 |
1580 | 220k | if (values[0]>0 && values[0] <= 100) { |
1581 | 36.3k | font.setSize(float(values[0])); |
1582 | 36.3k | f << "sz=" << values[0] << ","; |
1583 | 36.3k | } |
1584 | 183k | else { |
1585 | 183k | MWAW_DEBUG_MSG(("MoreText::readOutline: the font size seems bad\n")); |
1586 | 183k | f << "##sz=" << values[0] << ","; |
1587 | 183k | } |
1588 | 220k | break; |
1589 | 124k | case 0x603: { |
1590 | 124k | uint32_t bit=0; |
1591 | 124k | switch (values[0]) { |
1592 | 17.4k | case 0: |
1593 | 17.4k | f << "plain"; |
1594 | 17.4k | if (values[1]==1) |
1595 | 4.22k | fFlags=0; |
1596 | 17.4k | break; |
1597 | 4.91k | case 1: |
1598 | 4.91k | bit = MWAWFont::boldBit; |
1599 | 4.91k | f << "b"; |
1600 | 4.91k | break; |
1601 | 4.99k | case 2: |
1602 | 4.99k | bit = MWAWFont::italicBit; |
1603 | 4.99k | f << "it"; |
1604 | 4.99k | break; |
1605 | 5.87k | case 3: |
1606 | 5.87k | if (values[1]==1) |
1607 | 1.11k | font.setUnderlineStyle(MWAWFont::Line::Simple); |
1608 | 5.87k | f << "underl"; |
1609 | 5.87k | break; |
1610 | 4.93k | case 4: |
1611 | 4.93k | bit = MWAWFont::outlineBit; |
1612 | 4.93k | f << "outline"; |
1613 | 4.93k | break; |
1614 | 1.43k | case 5: |
1615 | 1.43k | bit = MWAWFont::shadowBit; |
1616 | 1.43k | f << "shadow"; |
1617 | 1.43k | break; |
1618 | 85.1k | default: |
1619 | 85.1k | f << "##fl=" << std::hex << values[0] << std::dec; |
1620 | 85.1k | break; |
1621 | 124k | } |
1622 | 124k | if (values[1]==1) { |
1623 | 7.73k | if (bit) fFlags = fFlags & (~bit); |
1624 | 7.73k | f << "[of],"; |
1625 | 7.73k | } |
1626 | 117k | else if (values[1]!=0) |
1627 | 102k | f << "=##" << values[1] << ","; |
1628 | 14.7k | else |
1629 | 14.7k | fFlags |= bit; |
1630 | 124k | values[1]=0; |
1631 | 124k | break; |
1632 | 124k | } |
1633 | 94.1k | case 0x804: { |
1634 | 94.1k | MWAWColor col(static_cast<unsigned char>(static_cast<uint16_t>(values[0])>>8), |
1635 | 94.1k | static_cast<unsigned char>(static_cast<uint16_t>(values[1])>>8), |
1636 | 94.1k | static_cast<unsigned char>(static_cast<uint16_t>(values[2])>>8)); |
1637 | 94.1k | font.setColor(col); |
1638 | 94.1k | f << col << ","; |
1639 | 94.1k | values[1]=values[2]=0; |
1640 | 94.1k | break; |
1641 | 124k | } |
1642 | 140k | case 0xa05: |
1643 | 140k | if (values[0]&0x8000) { |
1644 | 3.13k | para.setInterline(double(values[0]&0x7FFF)/20., librevenge::RVNG_POINT, MWAWParagraph::AtLeast); |
1645 | 3.13k | f << "interline=" << *para.m_spacings[0] << "pt,"; |
1646 | 3.13k | } |
1647 | 137k | else { |
1648 | 137k | para.setInterline(double(values[0])/double(0x1000), librevenge::RVNG_PERCENT); |
1649 | 137k | f << "interline=" << 100* *para.m_spacings[0] << "%,"; |
1650 | 137k | } |
1651 | 140k | break; |
1652 | 26.2k | case 0xc0f: // firstIndent |
1653 | 26.2k | para.m_margins[0] = double(values[0])/1440.; |
1654 | 26.2k | f << "indent=" << *para.m_margins[0] << ","; |
1655 | 26.2k | break; |
1656 | 172k | case 0x1006: |
1657 | 172k | switch (values[0]) { |
1658 | 123k | case 0: |
1659 | 123k | para.m_justify = MWAWParagraph::JustificationLeft; |
1660 | 123k | f << "left,"; |
1661 | 123k | break; |
1662 | 3.02k | case 1: |
1663 | 3.02k | para.m_justify = MWAWParagraph::JustificationCenter; |
1664 | 3.02k | f << "center,"; |
1665 | 3.02k | break; |
1666 | 3.98k | case 2: |
1667 | 3.98k | para.m_justify = MWAWParagraph::JustificationRight; |
1668 | 3.98k | f << "right,"; |
1669 | 3.98k | break; |
1670 | 5.70k | case 3: |
1671 | 5.70k | para.m_justify = MWAWParagraph::JustificationFull; |
1672 | 5.70k | f << "full,"; |
1673 | 5.70k | break; |
1674 | 36.6k | default: |
1675 | 36.6k | f << "##justify=" << values[0] << ","; |
1676 | 36.6k | break; |
1677 | 172k | } |
1678 | 172k | break; |
1679 | 172k | case 0x1208: |
1680 | 53.7k | if (values[0] & 0x8000) { |
1681 | 4.41k | para.m_spacings[1]=double(values[0]&0x7FFF)/1440.; |
1682 | 4.41k | f << "bef=" << double(values[0]&0x7FFF)/20. << "pt,"; |
1683 | 4.41k | } |
1684 | 49.3k | else { |
1685 | | // assume 12pt |
1686 | 49.3k | para.m_spacings[1]=double(values[0])/double(0x1000)*12./72.; |
1687 | 49.3k | if (values[0]) |
1688 | 42.6k | f << "bef=" << 100.*double(values[0])/double(0x1000) << "%,"; |
1689 | 49.3k | } |
1690 | | |
1691 | 53.7k | if (values[1] & 0x8000) { |
1692 | 10.8k | para.m_spacings[2]=double(values[1]&0x7FFF)/1440.; |
1693 | 10.8k | f << "aft=" << double(values[1]&0x7FFF)/20. << "pt,"; |
1694 | 10.8k | } |
1695 | 42.9k | else { |
1696 | 42.9k | para.m_spacings[2]=double(values[1])/double(0x1000)*12./72.; |
1697 | 42.9k | if (values[1]) |
1698 | 42.1k | f << "aft=" << 100.*double(values[1])/double(0x1000) << "%,"; |
1699 | 42.9k | } |
1700 | 53.7k | values[1]=0; |
1701 | 53.7k | break; |
1702 | 30.5k | case 0x1409: // lMargin in TWIP |
1703 | 30.5k | para.setLeftMargin(double(values[0]&0x7FFF)/1440., (values[0]&0x8000)==0); |
1704 | 30.5k | if (values[0]&0x8000) |
1705 | 2.66k | f << "indent=" << double(values[0]&0x7FFF)/1440. << ","; |
1706 | 27.9k | else // checkme |
1707 | 27.9k | f << "indent=" << double(values[0])/1440. << "[fromParent],"; |
1708 | 30.5k | break; |
1709 | 62.6k | case 0x160a: // rMargin in TWIP |
1710 | 62.6k | para.setRightMargin(double(values[0]&0x7FFF)/1440., (values[0]&0x8000)==0); |
1711 | 62.6k | if (values[0]&0x8000) |
1712 | 3.05k | f << "indent=" << double(values[0]&0x7FFF)/1440. << ","; |
1713 | 59.6k | else // checkme |
1714 | 59.6k | f << "indent=" << double(values[0])/1440. << "[fromParent],"; |
1715 | 62.6k | break; |
1716 | 16.9k | case 0x1a0c: |
1717 | 16.9k | para.m_pageBreak=(values[0]==0x100); |
1718 | 16.9k | if (values[0]==0x100) |
1719 | 79 | f << "pagebreak,"; |
1720 | 16.8k | else if (values[0]==0) |
1721 | 160 | f << "no,"; |
1722 | 16.7k | else |
1723 | 16.7k | f << "##break=" << std::hex << values[0] << std::dec << ","; |
1724 | 16.9k | break; |
1725 | 27.8k | case 0x1c0d: |
1726 | 27.8k | if (values[0]==0x100) { |
1727 | 2.10k | para.m_breakStatus = (*para.m_breakStatus)|MWAWParagraph::NoBreakWithNextBit; |
1728 | 2.10k | f << "together,"; |
1729 | 2.10k | } |
1730 | 25.7k | else if (values[0]==0) { |
1731 | 2.22k | para.m_breakStatus = (*para.m_breakStatus)|int(~MWAWParagraph::NoBreakWithNextBit); |
1732 | 2.22k | f << "no,"; |
1733 | 2.22k | } |
1734 | 23.4k | else |
1735 | 23.4k | f << "#keepLine=" << std::hex << values[0] << std::dec << ","; |
1736 | 27.8k | break; |
1737 | 16.3k | case 0x1e0e: |
1738 | 16.3k | para.m_keepOutlineTogether = (values[0]==0x100); |
1739 | 16.3k | if (values[0]==0x100) |
1740 | 16 | f << "together,"; |
1741 | 16.2k | else if (values[0]==0) |
1742 | 2.55k | f << "no,"; |
1743 | 13.7k | else |
1744 | 13.7k | f << "#keepOutline=" << std::hex << values[0] << std::dec << ","; |
1745 | 16.3k | break; |
1746 | 267k | case 0x190b: |
1747 | 267k | para.m_listType = values[0]; |
1748 | 267k | switch (values[0]) { |
1749 | 2.04k | case 0: |
1750 | 2.04k | f << "no,"; |
1751 | 2.04k | break; |
1752 | 91 | case 1: |
1753 | 91 | f << "leader,"; |
1754 | 91 | break; |
1755 | 249 | case 2: |
1756 | 249 | f << "hardvard,"; |
1757 | 249 | break; |
1758 | 7.06k | case 3: |
1759 | 7.06k | f << "numeric,"; |
1760 | 7.06k | break; |
1761 | 8 | case 4: |
1762 | 8 | f << "legal,"; |
1763 | 8 | break; |
1764 | 1.76k | case 5: |
1765 | 1.76k | f << "bullets,"; |
1766 | 1.76k | break; |
1767 | 256k | default: |
1768 | 256k | if (values[0]>=11) { |
1769 | 251k | f << "custom[" << values[0] << "],"; |
1770 | 251k | haveExtra=true; |
1771 | 251k | break; |
1772 | 251k | } |
1773 | 4.87k | f << "##bullet=" << values[0] << ","; |
1774 | 4.87k | break; |
1775 | 267k | } |
1776 | 267k | break; |
1777 | 3.62G | default: |
1778 | 3.62G | if (values[0]) |
1779 | 322M | f << "f2=" << std::hex << values[0] << std::dec << ","; |
1780 | | // use heuristic to define extra data |
1781 | 3.62G | if (values[0]>0x2800) |
1782 | 141M | haveExtra = (values[0] & 0x0100); |
1783 | 3.48G | else |
1784 | 3.48G | haveExtra=values[1]==0; |
1785 | 3.62G | break; |
1786 | 3.62G | } |
1787 | 3.62G | font.setFlags(fFlags); |
1788 | 3.62G | if (values[1]) f << "g0=" << std::hex << values[1] << std::dec << ","; |
1789 | | |
1790 | 3.62G | if (haveExtra && values[3]>0 && |
1791 | 97.7M | lastListPos+values[2]+values[3] <= endPos) { |
1792 | 97.5M | outlineMod.m_entry.setBegin(lastListPos+values[2]); |
1793 | 97.5M | outlineMod.m_entry.setLength(values[3]); |
1794 | 97.5M | outlineMod.m_entry.setId(n); |
1795 | 97.5M | } |
1796 | 3.53G | else { |
1797 | 10.5G | for (int i=2; i < 4; i++) { |
1798 | 7.06G | if (values[i]) |
1799 | 472M | f << "g" << i-1 << "=" << std::hex << values[i] << std::dec << ","; |
1800 | 7.06G | } |
1801 | 3.53G | } |
1802 | 3.62G | outlineMod.m_extra=f.str(); |
1803 | 3.62G | f.str(""); |
1804 | 3.62G | f << "Outline[O" << entry.id() << "-" << n << "]:" << outlineMod; |
1805 | 3.62G | outlineModList.push_back(outlineMod); |
1806 | 3.62G | ascFile.addPos(pos); |
1807 | 3.62G | ascFile.addNote(f.str().c_str()); |
1808 | 3.62G | input->seek(pos+16, librevenge::RVNG_SEEK_SET); |
1809 | 3.62G | } |
1810 | | |
1811 | 1.00M | int n=0; |
1812 | 3.62G | for (auto const &outlineMod : outlineModList) { |
1813 | 3.62G | n++; |
1814 | 3.62G | if (!outlineMod.m_entry.valid()) |
1815 | 3.53G | continue; |
1816 | 97.5M | f.str(""); |
1817 | 97.5M | f << "Outline[O" << entry.id() << "-A" << n-1 << "]:"; |
1818 | 97.5M | bool ok=false; |
1819 | | |
1820 | 97.5M | auto ¶ = outline.m_paragraphs[outlineMod.getModId()]; |
1821 | 97.5M | switch (outlineMod.m_type) { |
1822 | 253k | case 0x301: { |
1823 | 253k | std::string fName; |
1824 | 253k | int fId; |
1825 | 253k | ok = readFont(outlineMod.m_entry, fName,fId); |
1826 | 253k | if (!ok) break; |
1827 | 1.24k | f << "font=["; |
1828 | 1.24k | f << "name=" << fName; |
1829 | 1.24k | if (fId>=0) { |
1830 | 1.24k | f << ":" << fId; |
1831 | 1.24k | MWAWFont &font=outline.m_fonts[outlineMod.getModId()]; |
1832 | 1.24k | font.setId(fId); |
1833 | 1.24k | } |
1834 | 1.24k | f << "],"; |
1835 | 1.24k | break; |
1836 | 253k | } |
1837 | 27.7k | case 0xf07: { |
1838 | 27.7k | std::string mess; |
1839 | 27.7k | ok = readTabs(outlineMod.m_entry, para, mess); |
1840 | 27.7k | if (!ok) break; |
1841 | 374 | f << "tabs=[" << mess << "],"; |
1842 | 374 | break; |
1843 | 27.7k | } |
1844 | 250k | case 0x190b: { |
1845 | 250k | ok = readCustomListLevel(outlineMod.m_entry, para.m_customListLevel); |
1846 | 250k | if (!ok) break; |
1847 | 12.2k | f << para.m_customListLevel << ","; |
1848 | 12.2k | break; |
1849 | 250k | } |
1850 | 97.0M | default: |
1851 | 97.0M | break; |
1852 | 97.5M | } |
1853 | | // can be also pattern or backside or custom header |
1854 | 97.5M | if (!ok) { |
1855 | 97.5M | f << "[" << outlineMod << "]"; |
1856 | 97.5M | if (!parseUnknown(outlineMod.m_entry, 0)) |
1857 | 97.1M | f << "###"; |
1858 | 97.5M | } |
1859 | 97.5M | ascFile.addPos(outlineMod.m_entry.begin()); |
1860 | 97.5M | ascFile.addNote(f.str().c_str()); |
1861 | 97.5M | } |
1862 | 1.00M | ascFile.addPos(endPos); |
1863 | 1.00M | ascFile.addNote("_"); |
1864 | 1.00M | return true; |
1865 | 1.00M | } |
1866 | | |
1867 | | ////////////////////////////////////////////// |
1868 | | // small structure |
1869 | | ////////////////////////////////////////////// |
1870 | | bool MoreText::readFont(MWAWEntry const &entry, std::string &fName, int &fId) |
1871 | 97.4M | { |
1872 | 97.4M | fName=""; |
1873 | 97.4M | fId=-1; |
1874 | 97.4M | MWAWInputStreamPtr &input= m_parserState->m_input; |
1875 | 97.4M | if (entry.length() < 2 || !input->checkPosition(entry.end())) |
1876 | 82.2M | return false; |
1877 | 15.1M | long pos = entry.begin(); |
1878 | 15.1M | input->seek(pos, librevenge::RVNG_SEEK_SET); |
1879 | | |
1880 | 15.1M | auto fSz=static_cast<int>(input->readULong(1)); |
1881 | 15.1M | long remain=entry.length()-long(1+fSz); |
1882 | 15.1M | if (fSz==0 || remain<0 || remain==1) |
1883 | 7.28M | return false; |
1884 | 7.88M | if (remain>=2 && remain!=2+(1-(fSz%2))) |
1885 | 7.74M | return false; |
1886 | 2.46M | for (int i=0; i < fSz; i++) { |
1887 | 2.41M | auto c=char(input->readULong(1)); |
1888 | 2.41M | if (c==0) return false; |
1889 | 2.33M | fName+=c; |
1890 | 2.33M | } |
1891 | 56.8k | if (remain==0) { // let try to retrieve the font id |
1892 | 31.5k | fId=m_parserState->m_fontConverter->getId(fName); |
1893 | 31.5k | return true; |
1894 | 31.5k | } |
1895 | 25.3k | if ((fSz%2)==0) input->seek(1,librevenge::RVNG_SEEK_CUR); |
1896 | 25.3k | fId=static_cast<int>(input->readULong(2)); |
1897 | 25.3k | return true; |
1898 | 56.8k | } |
1899 | | |
1900 | | bool MoreText::readCustomListLevel(MWAWEntry const &entry, MWAWListLevel &level) |
1901 | 250k | { |
1902 | 250k | level=MWAWListLevel(); |
1903 | 250k | MWAWInputStreamPtr &input= m_parserState->m_input; |
1904 | 250k | if (entry.length()<22 || !input || !input->checkPosition(entry.end())) |
1905 | 109k | return false; |
1906 | | |
1907 | 141k | libmwaw::DebugStream f; |
1908 | 141k | long pos = entry.begin(); |
1909 | 141k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
1910 | 141k | MWAWFont font; |
1911 | 141k | auto fId=static_cast<int>(input->readULong(2)); |
1912 | 141k | if (fId==0xFFFF) // default |
1913 | 7.94k | ; |
1914 | 133k | else if (fId&0x8000) { |
1915 | 22.1k | f << "fId=" << (fId&0x7FFF) << ","; |
1916 | 22.1k | font.setId(fId&0x7FFF); |
1917 | 22.1k | } |
1918 | 110k | else |
1919 | 110k | f << "#fId=" << std::hex << fId << std::dec << ","; |
1920 | 141k | auto fSz = static_cast<int>(input->readLong(2)); |
1921 | 141k | if (fSz != -1) { |
1922 | 132k | font.setSize(float(fSz)); |
1923 | 132k | f << "fSz=" << fSz << ","; |
1924 | 132k | } |
1925 | 141k | auto fFlags=static_cast<int>(input->readULong(1)); |
1926 | 141k | uint32_t flags=0; |
1927 | 141k | if (fFlags&1) flags |= MWAWFont::boldBit; |
1928 | 141k | if (fFlags&2) flags |= MWAWFont::italicBit; |
1929 | 141k | if (fFlags&4) font.setUnderlineStyle(MWAWFont::Line::Simple); |
1930 | 141k | if (fFlags&8) flags |= MWAWFont::outlineBit; |
1931 | 141k | if (fFlags&0x10) flags |= MWAWFont::shadowBit; |
1932 | 141k | if (fFlags&0xE0) |
1933 | 42.2k | f << "#fFlags=" << std::hex << (fFlags&0xE0) << std::dec << ","; |
1934 | 141k | font.setFlags(flags); |
1935 | | |
1936 | 141k | auto fColor = static_cast<int>(input->readLong(1)); |
1937 | 141k | if (fColor==1) |
1938 | 6.28k | input->seek(6, librevenge::RVNG_SEEK_CUR); |
1939 | 134k | else if (fColor==3) { |
1940 | 5.62k | unsigned char color[3]; |
1941 | 16.8k | for (auto &c : color) c=static_cast<unsigned char>(input->readULong(2)>>8); |
1942 | 5.62k | font.setColor(MWAWColor(color[0], color[1], color[2])); |
1943 | 5.62k | } |
1944 | 129k | else { |
1945 | 129k | f << "#fCol=" << fColor << ","; |
1946 | 129k | input->seek(6, librevenge::RVNG_SEEK_CUR); |
1947 | 129k | } |
1948 | | #if defined(DEBUG_WITH_FILES) |
1949 | | f << "font=[" << font.getDebugString(m_parserState->m_fontConverter) << "],"; |
1950 | | #endif |
1951 | | |
1952 | | // now 4 bool |
1953 | 141k | bool bVal[4]= {false, false, false, false }; |
1954 | 141k | long val; |
1955 | 705k | for (int i=0; i < 4; i++) { |
1956 | 564k | val = input->readLong(1); |
1957 | 564k | if (!val) continue; |
1958 | 339k | if (val!=1) { |
1959 | 325k | f << "#g" << i << "=" << val << ","; |
1960 | 325k | continue; |
1961 | 325k | } |
1962 | 14.2k | bVal[i]=true; |
1963 | 14.2k | } |
1964 | 423k | for (int i=0; i<2; i++) { // g1: field left ident modify? |
1965 | 282k | if (bVal[i]) |
1966 | 6.32k | f << "g" << i << "=true,"; |
1967 | 282k | } |
1968 | 141k | if (bVal[2]) // or flush left at |
1969 | 2.65k | f << "flushRight,"; |
1970 | 141k | if (!bVal[3]) |
1971 | 135k | f << "useFirstlineIdent,"; |
1972 | 141k | val = input->readLong(2); |
1973 | 141k | if (val!=0x2d0) // default 0.5" |
1974 | 131k | f << "leftIdent=" << double(val)/1440. << ","; |
1975 | 141k | val = input->readLong(2); |
1976 | 141k | if (val != 0xb) |
1977 | 141k | f << "f6=" << val << ","; |
1978 | 141k | if (fId!=0xFFFF) { // maybe the font name |
1979 | 133k | auto fontSz=static_cast<int>(input->readULong(1)); |
1980 | 133k | if (!fontSz || input->tell()+fontSz >= entry.end()) |
1981 | 81.5k | input->seek(-1,librevenge::RVNG_SEEK_CUR); |
1982 | 51.5k | else { |
1983 | 51.5k | std::string fName(""); |
1984 | 4.00M | for (int i=0; i<fontSz; i++) |
1985 | 3.94M | fName+=char(input->readULong(1)); |
1986 | 51.5k | f << "fName=" << fName << ","; |
1987 | 51.5k | int newId=m_parserState->m_fontConverter->getId(fName); |
1988 | 51.5k | if (newId > 0) |
1989 | 50.2k | font.setId(fId=newId); |
1990 | 51.5k | } |
1991 | 133k | } |
1992 | | |
1993 | 141k | auto labelSz = static_cast<int>(input->readULong(1)); |
1994 | 141k | if (input->tell()+labelSz != entry.end()) |
1995 | 128k | return false; |
1996 | | |
1997 | 12.2k | f << "label="; |
1998 | 12.2k | if (fId == 0xFFFF) |
1999 | 1.05k | fId=3; |
2000 | 1.45M | for (int c=0; c < labelSz; c++) { |
2001 | 1.43M | auto ch=static_cast<unsigned char>(input->readULong(1)); |
2002 | 1.43M | f << ch; |
2003 | 1.43M | int unicode = m_parserState->m_fontConverter->unicode(fId, static_cast<unsigned char>(ch)); |
2004 | 1.43M | if (unicode!=-1) |
2005 | 631k | libmwaw::appendUnicode(uint32_t(unicode), level.m_label); |
2006 | 806k | else if (ch==0x9 || ch > 0x1f) |
2007 | 159k | libmwaw::appendUnicode(static_cast<uint32_t>(c), level.m_label); |
2008 | 646k | else { |
2009 | 646k | f << "##"; |
2010 | 646k | MWAW_DEBUG_MSG(("MoreText::readCustomListLevel: label char seems bad\n")); |
2011 | 646k | libmwaw::appendUnicode('#', level.m_label); |
2012 | 646k | } |
2013 | 1.43M | } |
2014 | 12.2k | f << ","; |
2015 | 12.2k | level.m_type=MWAWListLevel::LABEL; |
2016 | 12.2k | level.m_extra=f.str(); |
2017 | 12.2k | if (input->tell()!=entry.end()) |
2018 | 0 | m_parserState->m_asciiFile.addDelimiter(input->tell(),'|'); |
2019 | 12.2k | return true; |
2020 | 141k | } |
2021 | | |
2022 | | bool MoreText::readTabs(MWAWEntry const &entry, MoreTextInternal::Paragraph ¶, |
2023 | | std::string &mess) |
2024 | 97.5M | { |
2025 | 97.5M | mess=""; |
2026 | 97.5M | if (entry.length() < 4) |
2027 | 5.85M | return false; |
2028 | 91.7M | MWAWInputStreamPtr &input= m_parserState->m_input; |
2029 | 91.7M | libmwaw::DebugStream f; |
2030 | | |
2031 | 91.7M | long pos = entry.begin(); |
2032 | 91.7M | input->seek(pos, librevenge::RVNG_SEEK_SET); |
2033 | | |
2034 | 91.7M | auto nTabs=static_cast<int>(input->readULong(2)); |
2035 | 91.7M | if (entry.length()!=4+4*nTabs) |
2036 | 91.3M | return false; |
2037 | 374k | auto repeat=static_cast<int>(input->readLong(2)); |
2038 | 374k | if (uint16_t(repeat)==0x8000) // special case |
2039 | 35 | f << "def[center,right],"; |
2040 | 374k | else |
2041 | 374k | f << "repeat=" << double(repeat)/1440. << ","; |
2042 | 374k | para.m_tabs->resize(0); |
2043 | 7.65M | for (int i=0; i < nTabs; i++) { |
2044 | 7.27M | libmwaw::DebugStream f2; |
2045 | 7.27M | MWAWTabStop tab; |
2046 | 7.27M | tab.m_position = double(input->readULong(2))/1440.; |
2047 | 7.27M | auto val=static_cast<int>(input->readULong(1)); |
2048 | 7.27M | switch (val&0xF) { |
2049 | 293k | case 1: // left |
2050 | 293k | break; |
2051 | 178k | case 2: |
2052 | 178k | tab.m_alignment=MWAWTabStop::CENTER; |
2053 | 178k | break; |
2054 | 134k | case 3: |
2055 | 134k | tab.m_alignment=MWAWTabStop::RIGHT; |
2056 | 134k | break; |
2057 | 268k | case 4: |
2058 | 268k | tab.m_alignment=MWAWTabStop::DECIMAL; |
2059 | 268k | break; |
2060 | 6.40M | default: |
2061 | 6.40M | f2 << "#align=" << (val&0xF) << ","; |
2062 | 6.40M | break; |
2063 | 7.27M | } |
2064 | 7.27M | switch (val>>4) { |
2065 | 5.64M | case 0: // none |
2066 | 5.64M | break; |
2067 | 91.6k | case 1: |
2068 | 91.6k | tab.m_leaderCharacter = '_'; |
2069 | 91.6k | break; |
2070 | 123k | case 3: // more large space |
2071 | 123k | f2 << "dot[large],"; |
2072 | 123k | MWAW_FALLTHROUGH; |
2073 | 334k | case 2: |
2074 | 334k | tab.m_leaderCharacter = '.'; |
2075 | 334k | break; |
2076 | 1.20M | default: |
2077 | 1.20M | f2 << "#leader=" << (val>>4) << ","; |
2078 | 1.20M | break; |
2079 | 7.27M | } |
2080 | 7.27M | auto decimalChar = char(input->readULong(1)); |
2081 | 7.27M | if (decimalChar) { |
2082 | 2.27M | int unicode= m_parserState->m_fontConverter->unicode(3, static_cast<unsigned char>(decimalChar)); |
2083 | 2.27M | if (unicode==-1) |
2084 | 758k | tab.m_decimalCharacter = uint16_t(decimalChar); |
2085 | 1.52M | else |
2086 | 1.52M | tab.m_decimalCharacter = uint16_t(unicode); |
2087 | 2.27M | } |
2088 | 7.27M | f << "tab" << i << "=[" << tab << "," << f2.str() << "],"; |
2089 | 7.27M | para.m_tabs->push_back(tab); |
2090 | 7.27M | } |
2091 | 374k | mess=f.str(); |
2092 | 374k | return true; |
2093 | 374k | } |
2094 | | |
2095 | | ////////////////////////////////////////////// |
2096 | | // unknown structure |
2097 | | ////////////////////////////////////////////// |
2098 | | bool MoreText::parseUnknown(MWAWEntry const &entry, long fDecal) |
2099 | 97.5M | { |
2100 | 97.5M | MWAWInputStreamPtr &input= m_parserState->m_input; |
2101 | 97.5M | libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile; |
2102 | 97.5M | libmwaw::DebugStream f; |
2103 | | |
2104 | 97.5M | MoreStruct::Pattern pattern; |
2105 | 97.5M | long pos = entry.begin(); |
2106 | 97.5M | input->seek(pos, librevenge::RVNG_SEEK_SET); |
2107 | 97.5M | if (m_mainParser->readPattern(entry.end(),pattern)) { |
2108 | 14.6k | f << pattern; |
2109 | 14.6k | if (input->tell()!=entry.end()) |
2110 | 14.2k | ascFile.addDelimiter(input->tell(),'|'); |
2111 | 14.6k | ascFile.addPos(pos+fDecal); |
2112 | 14.6k | ascFile.addNote(f.str().c_str()); |
2113 | 14.6k | return true; |
2114 | 14.6k | } |
2115 | | // can we find a backsidde here |
2116 | 97.5M | input->seek(pos, librevenge::RVNG_SEEK_SET); |
2117 | 97.5M | std::string extra(""); |
2118 | 97.5M | if (m_mainParser->readBackside(entry.end(), extra)) { |
2119 | 21.2k | f << extra; |
2120 | 21.2k | if (input->tell()!=entry.end()) |
2121 | 20.3k | ascFile.addDelimiter(input->tell(),'|'); |
2122 | 21.2k | ascFile.addPos(pos+fDecal); |
2123 | 21.2k | ascFile.addNote(f.str().c_str()); |
2124 | 21.2k | return true; |
2125 | 21.2k | } |
2126 | | |
2127 | 97.5M | std::string mess; |
2128 | 97.5M | MoreTextInternal::Paragraph para; |
2129 | 97.5M | if (readTabs(entry, para, mess)) { |
2130 | 374k | f << "tabs=[" << mess << "],"; |
2131 | 374k | ascFile.addPos(pos+fDecal); |
2132 | 374k | ascFile.addNote(f.str().c_str()); |
2133 | 374k | return true; |
2134 | 374k | } |
2135 | | |
2136 | 97.1M | std::string fName; |
2137 | 97.1M | int fId; |
2138 | 97.1M | if (readFont(entry, fName,fId)) { |
2139 | 55.5k | f << "font=["; |
2140 | 55.5k | f << "name=" << fName; |
2141 | 55.5k | if (fId>=0) f << ":" << fId; |
2142 | 55.5k | f << "],"; |
2143 | 55.5k | ascFile.addPos(pos+fDecal); |
2144 | 55.5k | ascFile.addNote(f.str().c_str()); |
2145 | 55.5k | return true; |
2146 | 55.5k | } |
2147 | 97.1M | return false; |
2148 | 97.1M | } |
2149 | | |
2150 | | // vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: |