/src/libmwaw/src/lib/ClarisWksText.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 <iomanip> |
35 | | #include <iostream> |
36 | | #include <limits> |
37 | | #include <map> |
38 | | #include <sstream> |
39 | | |
40 | | #include <librevenge/librevenge.h> |
41 | | |
42 | | #include "MWAWFont.hxx" |
43 | | #include "MWAWFontConverter.hxx" |
44 | | #include "MWAWGraphicListener.hxx" |
45 | | #include "MWAWListener.hxx" |
46 | | #include "MWAWParagraph.hxx" |
47 | | #include "MWAWParser.hxx" |
48 | | #include "MWAWPosition.hxx" |
49 | | #include "MWAWSection.hxx" |
50 | | |
51 | | #include "ClarisWksDocument.hxx" |
52 | | #include "ClarisWksStruct.hxx" |
53 | | #include "ClarisWksStyleManager.hxx" |
54 | | |
55 | | #include "ClarisWksText.hxx" |
56 | | |
57 | | /** Internal: the structures of a ClarisWksText */ |
58 | | namespace ClarisWksTextInternal |
59 | | { |
60 | | /** the different plc type */ |
61 | | enum PLCType { P_Font, P_Ruler, P_Child, P_Section, P_TextZone, P_Token, P_Unknown}; |
62 | | |
63 | | /** Internal : the different plc types: mainly for debugging */ |
64 | | struct PLC { |
65 | | /// the constructor |
66 | | PLC() |
67 | 2.50M | : m_type(P_Unknown) |
68 | 2.50M | , m_id(-1) |
69 | 2.50M | , m_extra("") |
70 | 2.50M | { |
71 | 2.50M | } |
72 | | //! operator<< |
73 | | friend std::ostream &operator<<(std::ostream &o, PLC const &plc); |
74 | | /** the PLC types */ |
75 | | PLCType m_type; |
76 | | /** the id */ |
77 | | int m_id; |
78 | | /** extra data */ |
79 | | std::string m_extra; |
80 | | }; |
81 | | |
82 | | std::ostream &operator<<(std::ostream &o, PLC const &plc) |
83 | 0 | { |
84 | 0 | switch (plc.m_type) { |
85 | 0 | case P_Font: |
86 | 0 | o << "F"; |
87 | 0 | break; |
88 | 0 | case P_Ruler: |
89 | 0 | o << "R"; |
90 | 0 | break; |
91 | 0 | case P_Child: |
92 | 0 | o << "C"; |
93 | 0 | break; |
94 | 0 | case P_Section: |
95 | 0 | o << "S"; |
96 | 0 | break; |
97 | 0 | case P_TextZone: |
98 | 0 | o << "TZ"; |
99 | 0 | break; |
100 | 0 | case P_Token: |
101 | 0 | o << "Tok"; |
102 | 0 | break; |
103 | 0 | case P_Unknown: |
104 | | #if !defined(__clang__) |
105 | | default: |
106 | | #endif |
107 | 0 | o << "#Unkn"; |
108 | 0 | break; |
109 | 0 | } |
110 | 0 | if (plc.m_id >= 0) o << plc.m_id; |
111 | 0 | else o << "_"; |
112 | 0 | if (plc.m_extra.length()) o << ":" << plc.m_extra; |
113 | 0 | return o; |
114 | 0 | } |
115 | | |
116 | | /** Internal: class to store the paragraph properties */ |
117 | | struct Paragraph final : public MWAWParagraph { |
118 | | //! constructor |
119 | | Paragraph() |
120 | 3.90M | : MWAWParagraph() |
121 | 3.90M | , m_labelType(0) |
122 | 3.90M | { |
123 | 3.90M | } |
124 | 2.74M | Paragraph(Paragraph const &)=default; |
125 | 1.85M | Paragraph &operator=(Paragraph const &)=default; |
126 | | //! destructor |
127 | | ~Paragraph() final; |
128 | | //! operator<< |
129 | | friend std::ostream &operator<<(std::ostream &o, Paragraph const &ind) |
130 | 0 | { |
131 | 0 | o << static_cast<MWAWParagraph const &>(ind) << ","; |
132 | 0 | if (ind.m_labelType > 0 && ind.m_labelType < 12) { |
133 | 0 | static char const* const labelNames[] = { |
134 | 0 | "none", "diamond", "bullet", "checkbox", "hardvard", "leader", "legal", |
135 | 0 | "upperalpha", "alpha", "numeric", "upperroman", "roman" |
136 | 0 | }; |
137 | 0 | o << "label=" << labelNames[ind.m_labelType] << ","; |
138 | 0 | } |
139 | 0 | else if (ind.m_labelType) |
140 | 0 | o << "#labelType=" << ind.m_labelType << ","; |
141 | 0 | return o; |
142 | 0 | } |
143 | | //! update the list level |
144 | | void updateListLevel(); |
145 | | //! the label |
146 | | int m_labelType; |
147 | | }; |
148 | | |
149 | | Paragraph::~Paragraph() |
150 | 6.64M | { |
151 | 6.64M | } |
152 | | |
153 | | void Paragraph::updateListLevel() |
154 | 2.04M | { |
155 | 2.04M | int extraLevel = m_labelType!=0 ? 1 : 0; |
156 | 2.04M | if (*m_listLevelIndex+extraLevel<=0) |
157 | 2.04M | return; |
158 | 1.54k | int lev = *m_listLevelIndex+extraLevel; |
159 | 1.54k | m_listLevelIndex = lev; |
160 | 1.54k | MWAWListLevel theLevel; |
161 | 1.54k | theLevel.m_labelWidth=0.2; |
162 | 1.54k | switch (m_labelType) { |
163 | 50 | case 0: |
164 | 50 | theLevel.m_type = MWAWListLevel::NONE; |
165 | 50 | break; |
166 | 174 | case 1: // diamond |
167 | 174 | theLevel.m_type = MWAWListLevel::BULLET; |
168 | 174 | libmwaw::appendUnicode(0x25c7, theLevel.m_bullet); |
169 | 174 | break; |
170 | 176 | case 3: // checkbox |
171 | 176 | theLevel.m_type = MWAWListLevel::BULLET; |
172 | 176 | libmwaw::appendUnicode(0x2610, theLevel.m_bullet); |
173 | 176 | break; |
174 | 24 | case 4: { |
175 | 24 | theLevel.m_suffix = (lev <= 3) ? "." : ")"; |
176 | 24 | if (lev == 1) theLevel.m_type = MWAWListLevel::UPPER_ROMAN; |
177 | 0 | else if (lev == 2) theLevel.m_type = MWAWListLevel::UPPER_ALPHA; |
178 | 0 | else if (lev == 3) theLevel.m_type = MWAWListLevel::DECIMAL; |
179 | 0 | else if (lev == 4) theLevel.m_type = MWAWListLevel::LOWER_ALPHA; |
180 | 0 | else if ((lev%3)==2) { |
181 | 0 | theLevel.m_prefix = "("; |
182 | 0 | theLevel.m_type = MWAWListLevel::DECIMAL; |
183 | 0 | } |
184 | 0 | else if ((lev%3)==0) { |
185 | 0 | theLevel.m_prefix = "("; |
186 | 0 | theLevel.m_type = MWAWListLevel::LOWER_ALPHA; |
187 | 0 | } |
188 | 0 | else |
189 | 0 | theLevel.m_type = MWAWListLevel::LOWER_ROMAN; |
190 | 24 | break; |
191 | 0 | } |
192 | 26 | case 5: // leader |
193 | 26 | theLevel.m_type = MWAWListLevel::BULLET; |
194 | 26 | theLevel.m_bullet = "+"; // in fact + + and - |
195 | 26 | break; |
196 | 138 | case 6: // legal |
197 | 138 | theLevel.m_type = MWAWListLevel::DECIMAL; |
198 | 138 | theLevel.m_numBeforeLabels = lev-1; |
199 | 138 | theLevel.m_suffix = "."; |
200 | 138 | theLevel.m_labelWidth = 0.2*lev; |
201 | 138 | break; |
202 | 4 | case 7: |
203 | 4 | theLevel.m_type = MWAWListLevel::UPPER_ALPHA; |
204 | 4 | theLevel.m_suffix = "."; |
205 | 4 | break; |
206 | 14 | case 8: |
207 | 14 | theLevel.m_type = MWAWListLevel::LOWER_ALPHA; |
208 | 14 | theLevel.m_suffix = "."; |
209 | 14 | break; |
210 | 329 | case 9: |
211 | 329 | theLevel.m_type = MWAWListLevel::DECIMAL; |
212 | 329 | theLevel.m_suffix = "."; |
213 | 329 | break; |
214 | 3 | case 10: |
215 | 3 | theLevel.m_type = MWAWListLevel::UPPER_ROMAN; |
216 | 3 | theLevel.m_suffix = "."; |
217 | 3 | break; |
218 | 1 | case 11: |
219 | 1 | theLevel.m_type = MWAWListLevel::LOWER_ROMAN; |
220 | 1 | theLevel.m_suffix = "."; |
221 | 1 | break; |
222 | 24 | case 2: // bullet |
223 | 603 | default: |
224 | 603 | theLevel.m_type = MWAWListLevel::BULLET; |
225 | 603 | libmwaw::appendUnicode(0x2022, theLevel.m_bullet); |
226 | 603 | break; |
227 | 1.54k | } |
228 | 1.54k | m_margins[1]=m_margins[1].get()-theLevel.m_labelWidth; |
229 | 1.54k | m_listLevel=theLevel; |
230 | 1.54k | } |
231 | | |
232 | | struct ParagraphPLC { |
233 | | ParagraphPLC() |
234 | 780k | : m_rulerId(-1) |
235 | 780k | , m_styleId(-1) |
236 | 780k | , m_flags(0) |
237 | 780k | , m_extra("") |
238 | 780k | { |
239 | 780k | } |
240 | | |
241 | | friend std::ostream &operator<<(std::ostream &o, ParagraphPLC const &info) |
242 | 0 | { |
243 | 0 | if (info.m_rulerId >= 0) o << "P" << info.m_rulerId <<","; |
244 | 0 | if (info.m_styleId >= 0) o << "LK" << info.m_styleId <<","; |
245 | 0 | switch (info.m_flags&3) { |
246 | 0 | case 0: // normal |
247 | 0 | break; |
248 | 0 | case 1: |
249 | 0 | o << "hidden,"; |
250 | 0 | break; |
251 | 0 | case 2: |
252 | 0 | o << "collapsed,"; |
253 | 0 | break; |
254 | 0 | default: |
255 | 0 | o<< "hidden/collapsed,"; |
256 | 0 | break; |
257 | 0 | } |
258 | 0 | if (info.m_flags&4) |
259 | 0 | o << "flags4,"; |
260 | 0 |
|
261 | 0 | auto listType=int((info.m_flags>>3)&0xF); |
262 | 0 | if (listType>0 && listType < 12) { |
263 | 0 | static char const* const labelNames[] = { |
264 | 0 | "none", "diamond", "bullet", "checkbox", "hardvard", "leader", "legal", |
265 | 0 | "upperalpha", "alpha", "numeric", "upperroman", "roman" |
266 | 0 | }; |
267 | 0 | o << labelNames[listType] << ","; |
268 | 0 | } |
269 | 0 | else if (listType) |
270 | 0 | o << "#listType=" << listType << ","; |
271 | 0 | if (info.m_flags&0x80) o << "flags80,"; |
272 | 0 | auto listLevel=int((info.m_flags>>8)&0xF); |
273 | 0 | if (listLevel) o << "level=" << listLevel+1; |
274 | 0 | if (info.m_flags>>12) o << "flags=" << std::hex << (info.m_flags>>12) << std::dec << ","; |
275 | 0 | if (info.m_extra.length()) o << info.m_extra; |
276 | 0 | return o; |
277 | 0 | } |
278 | | |
279 | | /** the ruler id */ |
280 | | int m_rulerId; |
281 | | /** the style id ( via the style lookup table )*/ |
282 | | int m_styleId; |
283 | | /** some flags */ |
284 | | int m_flags; |
285 | | /** extra data */ |
286 | | std::string m_extra; |
287 | | }; |
288 | | |
289 | | /** internal class used to store a section */ |
290 | | struct Section { |
291 | | //! the constructor |
292 | | Section() |
293 | 278k | : m_pos(0) |
294 | 278k | , m_numColumns(1) |
295 | 278k | , m_columnsWidth() |
296 | 278k | , m_columnsSep() |
297 | 278k | , m_startOnNewPage(false) |
298 | 278k | , m_firstPage(0) |
299 | 278k | , m_hasTitlePage(false) |
300 | 278k | , m_continuousHF(true) |
301 | 278k | , m_leftRightHF(false) |
302 | 278k | , m_extra("") |
303 | 278k | { |
304 | 1.11M | for (auto &id : m_HFId) id=0; |
305 | 278k | } |
306 | | //! returns a section |
307 | | MWAWSection getSection() const |
308 | 148k | { |
309 | 148k | MWAWSection sec; |
310 | 148k | if (m_numColumns <= 1) |
311 | 38.1k | return sec; |
312 | 110k | size_t numCols = m_columnsWidth.size(); |
313 | 110k | if (m_numColumns != int(numCols)) { |
314 | 0 | MWAW_DEBUG_MSG(("ClarisWksTextInternal::Section::getSection: unexpected number of columns\n")); |
315 | 0 | return sec; |
316 | 0 | } |
317 | 110k | bool hasSep = numCols==m_columnsSep.size(); |
318 | 110k | if (!hasSep && m_columnsSep.size()) { |
319 | 0 | MWAW_DEBUG_MSG(("ClarisWksTextInternal::Section::getSection: can not used column separator\n")); |
320 | 0 | return sec; |
321 | 0 | } |
322 | 110k | sec.m_columns.resize(size_t(numCols)); |
323 | 460k | for (size_t c=0; c < numCols; c++) { |
324 | 349k | sec.m_columns[c].m_width = double(m_columnsWidth[c]); |
325 | 349k | sec.m_columns[c].m_widthUnit = librevenge::RVNG_POINT; |
326 | 349k | if (!hasSep) continue; |
327 | 349k | sec.m_columns[c].m_margins[libmwaw::Left]= |
328 | 349k | double(m_columnsSep[c])/72.*(c==0 ? 1. : 0.5); |
329 | 349k | if (c+1!=numCols) |
330 | 238k | sec.m_columns[c].m_margins[libmwaw::Right]=double(m_columnsSep[c+1])/2.0/72.; |
331 | 349k | } |
332 | 110k | return sec; |
333 | 110k | } |
334 | | //! operator << |
335 | | friend std::ostream &operator<<(std::ostream &o, Section const &sec) |
336 | 0 | { |
337 | 0 | o << "pos=" << sec.m_pos << ","; |
338 | 0 | if (sec.m_numColumns != 1) o << "numCols=" << sec.m_numColumns << ","; |
339 | 0 | o << "col[width]=["; |
340 | 0 | for (auto const &w : sec.m_columnsWidth) |
341 | 0 | o << w << ","; |
342 | 0 | o << "],"; |
343 | 0 | if (sec.m_columnsSep.size()) { |
344 | 0 | o << "col[sepW]=["; |
345 | 0 | for (auto const &sep : sec.m_columnsSep) |
346 | 0 | o << sep << ","; |
347 | 0 | o << "],"; |
348 | 0 | } |
349 | 0 | if (sec.m_firstPage) o << "first[page]=" << sec.m_firstPage << ","; |
350 | 0 | if (sec.m_hasTitlePage) o << "title[page],"; |
351 | 0 | if (sec.m_continuousHF) o << "continuousHF,"; |
352 | 0 | if (sec.m_leftRightHF) o << "leftRightHF,"; |
353 | 0 | if (sec.m_HFId[0]) o << "id[header]=" << sec.m_HFId[0] << ","; |
354 | 0 | if (sec.m_HFId[1] || sec.m_HFId[0]!=sec.m_HFId[1]) o << "id[header2]=" << sec.m_HFId[1] << ","; |
355 | 0 | if (sec.m_HFId[2]) o << "id[footer]=" << sec.m_HFId[2] << ","; |
356 | 0 | if (sec.m_HFId[3] || sec.m_HFId[2]!=sec.m_HFId[3]) o << "id[footer2]=" << sec.m_HFId[3] << ","; |
357 | 0 | if (sec.m_extra.length()) o << sec.m_extra; |
358 | 0 | return o; |
359 | 0 | } |
360 | | /** the character position */ |
361 | | long m_pos; |
362 | | /** the number of column */ |
363 | | int m_numColumns; |
364 | | /** the columns width */ |
365 | | std::vector<int> m_columnsWidth; |
366 | | /** the columns separator */ |
367 | | std::vector<int> m_columnsSep; |
368 | | /** a new section generates a page break */ |
369 | | bool m_startOnNewPage; |
370 | | /** the first page */ |
371 | | int m_firstPage; |
372 | | /** true if the first page is a title page(ie. no header/footer) */ |
373 | | bool m_hasTitlePage; |
374 | | /** true if the header/footer are shared with previous sections */ |
375 | | bool m_continuousHF; |
376 | | /** true if the left/right header/footer are different */ |
377 | | bool m_leftRightHF; |
378 | | /** the header/footer id*/ |
379 | | int m_HFId[4]; |
380 | | /** a string to store unparsed data */ |
381 | | std::string m_extra; |
382 | | }; |
383 | | |
384 | | /** internal class used to store a text zone */ |
385 | | struct TextZoneInfo { |
386 | | //! constructor |
387 | | TextZoneInfo() |
388 | 1.07M | : m_pos(0) |
389 | 1.07M | , m_N(0) |
390 | 1.07M | , m_extra("") |
391 | 1.07M | { |
392 | 1.07M | } |
393 | | //! operator<< |
394 | | friend std::ostream &operator<<(std::ostream &o, TextZoneInfo const &info) |
395 | 0 | { |
396 | 0 | o << "pos=" << info.m_pos << ","; |
397 | 0 | if (info.m_N >= 0) o << "size=" << info.m_N <<","; |
398 | 0 | if (info.m_extra.length()) o << info.m_extra; |
399 | 0 | return o; |
400 | 0 | } |
401 | | long m_pos; |
402 | | //! the number of character |
403 | | int m_N; |
404 | | //! extra data |
405 | | std::string m_extra; |
406 | | }; |
407 | | |
408 | | enum TokenType { TKN_UNKNOWN, TKN_FOOTNOTE, TKN_PAGENUMBER, TKN_GRAPHIC, TKN_FIELD }; |
409 | | |
410 | | /** Internal: class to store field definition: TOKN entry*/ |
411 | | struct Token { |
412 | | //! constructor |
413 | | Token() |
414 | 8.88M | : m_type(TKN_UNKNOWN) |
415 | 8.88M | , m_zoneId(-1) |
416 | 8.88M | , m_page(-1) |
417 | 8.88M | , m_descent(0) |
418 | 8.88M | , m_fieldEntry() |
419 | 8.88M | , m_extra("") |
420 | 8.88M | { |
421 | 26.6M | for (auto &unkn : m_unknown) unkn=0; |
422 | 17.7M | for (auto &size : m_size) size=0; |
423 | 8.88M | } |
424 | | //! operator << |
425 | | friend std::ostream &operator<<(std::ostream &o, Token const &tok); |
426 | | //! the type |
427 | | TokenType m_type; |
428 | | //! the zone id which correspond to this type |
429 | | int m_zoneId; |
430 | | //! the page |
431 | | int m_page; |
432 | | //! the size(?) |
433 | | int m_size[2]; |
434 | | //! the descent |
435 | | int m_descent; |
436 | | //! the field name entry |
437 | | MWAWEntry m_fieldEntry; |
438 | | //! the unknown zone |
439 | | int m_unknown[3]; |
440 | | //! a string used to store the parsing errors |
441 | | std::string m_extra; |
442 | | }; |
443 | | //! operator<< for Token |
444 | | std::ostream &operator<<(std::ostream &o, Token const &tok) |
445 | 0 | { |
446 | 0 | switch (tok.m_type) { |
447 | 0 | case TKN_FOOTNOTE: |
448 | 0 | o << "footnoote,"; |
449 | 0 | break; |
450 | 0 | case TKN_FIELD: |
451 | 0 | o << "field[linked],"; |
452 | 0 | break; |
453 | 0 | case TKN_PAGENUMBER: |
454 | 0 | switch (tok.m_unknown[0]) { |
455 | 0 | case 0: |
456 | 0 | o << "field[pageNumber],"; |
457 | 0 | break; |
458 | 0 | case 1: |
459 | 0 | o << "field[sectionNumber],"; |
460 | 0 | break; |
461 | 0 | case 2: |
462 | 0 | o << "field[sectionInPageNumber],"; |
463 | 0 | break; |
464 | 0 | case 3: |
465 | 0 | o << "field[pageCount],"; |
466 | 0 | break; |
467 | 0 | default: |
468 | 0 | o << "field[pageNumber=#" << tok.m_unknown[0] << "],"; |
469 | 0 | break; |
470 | 0 | } |
471 | 0 | break; |
472 | 0 | case TKN_GRAPHIC: |
473 | 0 | o << "graphic,"; |
474 | 0 | break; |
475 | 0 | case TKN_UNKNOWN: |
476 | | #if !defined(__clang__) |
477 | | default: |
478 | | #endif |
479 | 0 | o << "##field[unknown]" << ","; |
480 | 0 | break; |
481 | 0 | } |
482 | 0 | if (tok.m_zoneId != -1) o << "zoneId=" << tok.m_zoneId << ","; |
483 | 0 | if (tok.m_page != -1) o << "page?=" << tok.m_page << ","; |
484 | 0 | o << "pos?=" << tok.m_size[0] << "x" << tok.m_size[1] << ","; |
485 | 0 | if (tok.m_descent) o << "descent=" << tok.m_descent << ","; |
486 | 0 | for (int i = 0; i < 3; i++) { |
487 | 0 | if (tok.m_unknown[i] == 0 || (i==0 && tok.m_type==TKN_PAGENUMBER)) |
488 | 0 | continue; |
489 | 0 | o << "#unkn" << i << "=" << std::hex << tok.m_unknown[i] << std::dec << ","; |
490 | 0 | } |
491 | 0 | if (!tok.m_extra.empty()) o << "err=[" << tok.m_extra << "]"; |
492 | 0 | return o; |
493 | 0 | } |
494 | | |
495 | | struct Zone final : public ClarisWksStruct::DSET { |
496 | | //! constructor |
497 | | explicit Zone(ClarisWksStruct::DSET const &dset = ClarisWksStruct::DSET()) |
498 | 1.15M | : ClarisWksStruct::DSET(dset) |
499 | 1.15M | , m_zones() |
500 | 1.15M | , m_numChar(0) |
501 | 1.15M | , m_numTextZone(0) |
502 | 1.15M | , m_numParagInfo(0) |
503 | 1.15M | , m_numFont(0) |
504 | 1.15M | , m_fatherId(0) |
505 | 1.15M | , m_unknown(0) |
506 | 1.15M | , m_fontList() |
507 | 1.15M | , m_paragraphList() |
508 | 1.15M | , m_sectionList() |
509 | 1.15M | , m_tokenList() |
510 | 1.15M | , m_textZoneList() |
511 | 1.15M | , m_plcMap() |
512 | 1.15M | { |
513 | 1.15M | } |
514 | | //!destructor |
515 | | ~Zone() final; |
516 | | //! operator<< |
517 | | friend std::ostream &operator<<(std::ostream &o, Zone const &doc) |
518 | 0 | { |
519 | 0 | o << static_cast<ClarisWksStruct::DSET const &>(doc); |
520 | 0 | if (doc.m_numChar) o << "numChar=" << doc.m_numChar << ","; |
521 | 0 | if (doc.m_numTextZone) o << "numTextZone=" << doc.m_numTextZone << ","; |
522 | 0 | if (doc.m_numParagInfo) o << "numParag=" << doc.m_numParagInfo << ","; |
523 | 0 | if (doc.m_numFont) o << "numFont=" << doc.m_numFont << ","; |
524 | 0 | if (doc.m_fatherId) o << "id[father]=" << doc.m_fatherId << ","; |
525 | 0 | if (doc.m_unknown) o << "unkn=" << doc.m_unknown << ","; |
526 | 0 | return o; |
527 | 0 | } |
528 | | |
529 | | /** remove a child from a list. |
530 | | |
531 | | Normally, this function is not called, so optimizing it is not usefull |
532 | | */ |
533 | | void removeChild(int cId, bool normalChild) final |
534 | 2.01M | { |
535 | 2.01M | DSET::removeChild(cId, normalChild); |
536 | 4.24G | for (auto &token : m_tokenList) { |
537 | 4.24G | if (token.m_zoneId!=cId) continue; |
538 | 1.95M | token.m_zoneId=0; |
539 | 1.95M | return; |
540 | 4.24G | } |
541 | | // normally, section list point only to the text zone (ie. the |
542 | | // child of the header/footer group), so remove child is not |
543 | | // called on it |
544 | 63.3k | MWAW_DEBUG_MSG(("ClarisWksTextInternal::Zone can not detach %d\n", cId)); |
545 | 63.3k | } |
546 | | |
547 | | std::vector<MWAWEntry> m_zones; // the text zones |
548 | | int m_numChar /** the number of char in text zone */; |
549 | | int m_numTextZone /** the number of text zone ( ie. number of page ? ) */; |
550 | | int m_numParagInfo /** the number of paragraph info */; |
551 | | int m_numFont /** the number of font */; |
552 | | int m_fatherId /** the father id */; |
553 | | int m_unknown /** an unknown flags */; |
554 | | |
555 | | std::vector<MWAWFont> m_fontList /** the list of fonts */; |
556 | | std::vector<ParagraphPLC> m_paragraphList /** the list of paragraph */; |
557 | | std::vector<Section> m_sectionList /** the list of section */; |
558 | | std::vector<Token> m_tokenList /** the list of token */; |
559 | | std::vector<TextZoneInfo> m_textZoneList /** the list of zone */; |
560 | | std::multimap<long, PLC> m_plcMap /** the plc map */; |
561 | | }; |
562 | | |
563 | | Zone::~Zone() |
564 | 1.15M | { |
565 | 1.15M | } |
566 | | //////////////////////////////////////// |
567 | | //! Internal: the state of a ClarisWksText |
568 | | struct State { |
569 | | //! constructor |
570 | | State() |
571 | 402k | : m_version(-1) |
572 | 402k | , m_paragraphsList() |
573 | 402k | , m_zoneMap() |
574 | 402k | { |
575 | 402k | } |
576 | | |
577 | | //! the file version |
578 | | mutable int m_version; |
579 | | //! the list of paragraph |
580 | | std::vector<Paragraph> m_paragraphsList; |
581 | | //! the list of text zone |
582 | | std::map<int, std::shared_ptr<Zone> > m_zoneMap; |
583 | | }; |
584 | | |
585 | | //////////////////////////////////////// |
586 | | //! Internal: the subdocument of a ClarisWksDocument |
587 | | class SubDocument final : public MWAWSubDocument |
588 | | { |
589 | | public: |
590 | | SubDocument(ClarisWksText &parser, MWAWInputStreamPtr const &input, int zoneId) |
591 | 9.96k | : MWAWSubDocument(nullptr, input, MWAWEntry()) |
592 | 9.96k | , m_textParser(parser) |
593 | 9.96k | , m_id(zoneId) {} |
594 | | |
595 | | //! destructor |
596 | 0 | ~SubDocument() final {} |
597 | | |
598 | | //! operator!= |
599 | | bool operator!=(MWAWSubDocument const &doc) const final |
600 | 0 | { |
601 | 0 | if (MWAWSubDocument::operator!=(doc)) return true; |
602 | 0 | auto const *sDoc = dynamic_cast<SubDocument const *>(&doc); |
603 | 0 | if (!sDoc) return true; |
604 | 0 | if (&m_textParser != &sDoc->m_textParser) return true; |
605 | 0 | if (m_id != sDoc->m_id) return true; |
606 | 0 | return false; |
607 | 0 | } |
608 | | |
609 | | //! the parser function |
610 | | void parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType type) final; |
611 | | |
612 | | protected: |
613 | | //! the document manager |
614 | | ClarisWksText &m_textParser; |
615 | | //! the subdocument id |
616 | | int m_id; |
617 | | }; |
618 | | |
619 | | void SubDocument::parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType) |
620 | 43.2k | { |
621 | 43.2k | if (!listener.get()) { |
622 | 0 | MWAW_DEBUG_MSG(("ClarisWksTextInternal::SubDocument::parse: no listener\n")); |
623 | 0 | return; |
624 | 0 | } |
625 | 43.2k | if (m_id == -1) { // a number used to send linked frame |
626 | 7.78k | listener->insertChar(' '); |
627 | 7.78k | return; |
628 | 7.78k | } |
629 | 35.5k | if (m_id == 0) { |
630 | 0 | MWAW_DEBUG_MSG(("ClarisWksTextInternal::SubDocument::parse: unknown zone\n")); |
631 | 0 | return; |
632 | 0 | } |
633 | | |
634 | 35.5k | m_textParser.m_document.sendZone(m_id, listener); |
635 | 35.5k | } |
636 | | |
637 | | } |
638 | | |
639 | | //////////////////////////////////////////////////////////// |
640 | | // constructor/destructor, ... |
641 | | //////////////////////////////////////////////////////////// |
642 | | ClarisWksText::ClarisWksText(ClarisWksDocument &document) |
643 | 402k | : m_document(document) |
644 | 402k | , m_parserState(document.m_parserState) |
645 | 402k | , m_state(new ClarisWksTextInternal::State) |
646 | 402k | , m_mainParser(&document.getMainParser()) |
647 | 402k | { |
648 | 402k | } |
649 | | |
650 | | ClarisWksText::~ClarisWksText() |
651 | 402k | { |
652 | 402k | } |
653 | | |
654 | | int ClarisWksText::version() const |
655 | 5.11M | { |
656 | 5.11M | if (m_state->m_version < 0) |
657 | 192k | m_state->m_version = m_parserState->m_version; |
658 | 5.11M | return m_state->m_version; |
659 | 5.11M | } |
660 | | |
661 | | int ClarisWksText::numPages() const |
662 | 135k | { |
663 | 135k | auto iter = m_state->m_zoneMap.find(1); |
664 | 135k | if (iter == m_state->m_zoneMap.end()) |
665 | 121k | return 1; |
666 | 14.2k | int numPage = 1; |
667 | 14.2k | MWAWInputStreamPtr &input= m_parserState->m_input; |
668 | 14.2k | long pos = input->tell(); |
669 | 15.8k | for (auto const &entry : iter->second->m_zones) { |
670 | 15.8k | input->seek(entry.begin()+4, librevenge::RVNG_SEEK_SET); |
671 | 15.8k | auto numC = int(entry.length()-4); |
672 | 14.0M | for (int ch = 0; ch < numC; ch++) { |
673 | 13.9M | auto c = char(input->readULong(1)); |
674 | 13.9M | if (c==0xb || c==0x1) |
675 | 564k | numPage++; |
676 | 13.9M | } |
677 | 15.8k | } |
678 | 14.2k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
679 | 14.2k | return numPage; |
680 | 135k | } |
681 | | |
682 | | bool ClarisWksText::updatePageSpanList(MWAWPageSpan const &page, std::vector<MWAWPageSpan> &spanList) |
683 | 129k | { |
684 | 129k | auto it = m_state->m_zoneMap.find(1); |
685 | 129k | if (it==m_state->m_zoneMap.end() || !it->second || m_parserState->m_kind==MWAWDocument::MWAW_K_PRESENTATION) |
686 | 115k | return false; |
687 | 14.1k | auto const &zone=*it->second; |
688 | 14.1k | size_t numSection=zone.m_sectionList.size(); |
689 | 14.1k | if (!numSection) return false; |
690 | 7.49k | int nPages=m_document.numPages(); |
691 | 7.49k | int actPage=0; |
692 | 7.49k | spanList.resize(0); |
693 | 17.7k | for (size_t i=0; i<numSection; ++i) { |
694 | 10.9k | auto const &sec=zone.m_sectionList[i]; |
695 | 10.9k | int lastPage=nPages; |
696 | 10.9k | bool ok=true; |
697 | 12.6k | while (i+1<numSection) { |
698 | 5.88k | if (zone.m_sectionList[i+1].m_continuousHF) { |
699 | 1.74k | ++i; |
700 | 1.74k | continue; |
701 | 1.74k | } |
702 | 4.13k | if (zone.m_sectionList[i+1].m_firstPage<actPage) { |
703 | 708 | MWAW_DEBUG_MSG(("ClarisWksText::updatePageSpanList: problem with the %d first page\n", int(i+1))); |
704 | 708 | ok=false; |
705 | 708 | break; |
706 | 708 | } |
707 | 3.42k | lastPage=zone.m_sectionList[i+1].m_firstPage; |
708 | 3.42k | break; |
709 | 4.13k | } |
710 | 10.9k | if (!ok) |
711 | 708 | break; |
712 | 10.2k | if (lastPage>nPages) { |
713 | 1.34k | MWAW_DEBUG_MSG(("ClarisWksText::updatePageSpanList: some first page seems to big\n")); |
714 | 1.34k | lastPage=nPages; |
715 | 1.34k | } |
716 | 10.2k | if (sec.m_hasTitlePage && actPage<lastPage) { |
717 | | // title page have no header/footer |
718 | 649 | MWAWPageSpan ps(page); |
719 | 649 | ps.setPageSpan(1); |
720 | 649 | spanList.push_back(ps); |
721 | 649 | ++actPage; |
722 | 649 | } |
723 | 10.2k | if (actPage<lastPage) { |
724 | 7.66k | MWAWPageSpan ps(page); |
725 | 7.66k | ps.setPageSpan(lastPage-actPage); |
726 | 38.3k | for (int j=0; j<4; ++j) { |
727 | 30.6k | int zId=sec.m_HFId[j]; |
728 | 30.6k | if (!zId) continue; |
729 | 10.2k | if ((j%2)==1 && zId==sec.m_HFId[j-1]) continue; |
730 | | /* try to retrieve the father group zone */ |
731 | 9.96k | auto fIt=m_state->m_zoneMap.find(zId); |
732 | 9.96k | if (fIt!=m_state->m_zoneMap.end() && fIt->second && fIt->second->m_fatherId) |
733 | 288 | zId=fIt->second->m_fatherId; |
734 | 9.96k | MWAWHeaderFooter hF(j<2 ? MWAWHeaderFooter::HEADER : MWAWHeaderFooter::FOOTER, |
735 | 9.96k | (j%2) ? MWAWHeaderFooter::EVEN : sec.m_HFId[j]==sec.m_HFId[j+1] ? |
736 | 4.68k | MWAWHeaderFooter::ALL : MWAWHeaderFooter::ODD); |
737 | 9.96k | hF.m_subDocument.reset(new ClarisWksTextInternal::SubDocument(*this, m_parserState->m_input, zId)); |
738 | 9.96k | ps.setHeaderFooter(hF); |
739 | 9.96k | } |
740 | 7.66k | spanList.push_back(ps); |
741 | 7.66k | } |
742 | 10.2k | actPage=lastPage; |
743 | 10.2k | } |
744 | 7.49k | if (actPage<nPages) { |
745 | 316 | MWAWPageSpan ps(page); |
746 | 316 | ps.setPageSpan(nPages-actPage); |
747 | 316 | spanList.push_back(ps); |
748 | 316 | } |
749 | 7.49k | return true; |
750 | 14.1k | } |
751 | | |
752 | | //////////////////////////////////////////////////////////// |
753 | | // Intermediate level |
754 | | //////////////////////////////////////////////////////////// |
755 | | |
756 | | //////////////////////////////////////////////////////////// |
757 | | // a document part |
758 | | //////////////////////////////////////////////////////////// |
759 | | std::shared_ptr<ClarisWksStruct::DSET> ClarisWksText::readDSETZone(ClarisWksStruct::DSET const &zone, MWAWEntry const &entry, bool &complete) |
760 | 1.15M | { |
761 | 1.15M | complete = false; |
762 | 1.15M | if (!entry.valid() || zone.m_fileType != 1) |
763 | 0 | return std::shared_ptr<ClarisWksStruct::DSET>(); |
764 | 1.15M | int const vers = version(); |
765 | 1.15M | long pos = entry.begin(); |
766 | 1.15M | MWAWInputStreamPtr &input= m_parserState->m_input; |
767 | 1.15M | input->seek(pos+8+16, librevenge::RVNG_SEEK_SET); // avoid header+8 generic number |
768 | 1.15M | libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile; |
769 | 1.15M | libmwaw::DebugStream f; |
770 | 1.15M | f << "Entries(DSETT):"; |
771 | | |
772 | 1.15M | std::shared_ptr<ClarisWksTextInternal::Zone> textZone(new ClarisWksTextInternal::Zone(zone)); |
773 | 1.15M | textZone->m_unknown = static_cast<int>(input->readULong(2)); // alway 0 ? |
774 | 1.15M | textZone->m_fatherId = static_cast<int>(input->readULong(2)); |
775 | 1.15M | textZone->m_numChar = static_cast<int>(input->readULong(4)); |
776 | 1.15M | textZone->m_numTextZone = static_cast<int>(input->readULong(2)); |
777 | 1.15M | textZone->m_numParagInfo = static_cast<int>(input->readULong(2)); |
778 | 1.15M | textZone->m_numFont = static_cast<int>(input->readULong(2)); |
779 | 1.15M | switch (textZone->m_textType >> 4) { |
780 | 35.4k | case 2: |
781 | 35.4k | textZone->m_position = ClarisWksStruct::DSET::P_Header; |
782 | 35.4k | break; |
783 | 19.2k | case 4: |
784 | 19.2k | textZone->m_position = ClarisWksStruct::DSET::P_Footer; |
785 | 19.2k | break; |
786 | 10.6k | case 6: |
787 | 10.6k | textZone->m_position = ClarisWksStruct::DSET::P_Footnote; |
788 | 10.6k | break; |
789 | 239k | case 8: |
790 | 239k | textZone->m_position = ClarisWksStruct::DSET::P_Frame; |
791 | 239k | break; |
792 | 484k | case 0xe: |
793 | 484k | textZone->m_position = ClarisWksStruct::DSET::P_Table; |
794 | 484k | break; |
795 | 308k | case 0: |
796 | 308k | if (zone.m_id==1) { |
797 | 89.3k | textZone->m_position = ClarisWksStruct::DSET::P_Main; |
798 | 89.3k | break; |
799 | 89.3k | } |
800 | 219k | MWAW_FALLTHROUGH; |
801 | 280k | default: |
802 | 280k | MWAW_DEBUG_MSG(("ClarisWksText::readDSETZone: find unknown position %d\n", (textZone->m_textType >> 4))); |
803 | 280k | f << "#position="<< (textZone->m_textType >> 4) << ","; |
804 | 280k | break; |
805 | 1.15M | } |
806 | | // find 2,3,6,a,b,e,f |
807 | 1.15M | if (textZone->m_textType != ClarisWksStruct::DSET::P_Unknown) |
808 | 1.15M | textZone->m_textType &= 0xF; |
809 | 1.15M | f << *textZone << ","; |
810 | | |
811 | 1.15M | if (long(input->tell())%2) |
812 | 575k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
813 | 1.15M | ascFile.addDelimiter(input->tell(), '|'); |
814 | 1.15M | ascFile.addPos(pos); |
815 | 1.15M | ascFile.addNote(f.str().c_str()); |
816 | | |
817 | | // read the last part |
818 | 1.15M | int data0Length = 0; |
819 | 1.15M | switch (vers) { |
820 | 211k | case 1: |
821 | 211k | data0Length = 24; |
822 | 211k | break; |
823 | 190k | case 2: |
824 | 190k | data0Length = 28; |
825 | 190k | break; |
826 | | // case 3: ??? |
827 | 71.9k | case 4: |
828 | 292k | case 5: |
829 | 541k | case 6: |
830 | 541k | data0Length = 30; |
831 | 541k | break; |
832 | 215k | default: |
833 | 215k | break; |
834 | 1.15M | } |
835 | | |
836 | 1.15M | auto N = int(zone.m_numData); |
837 | 1.15M | if (long(input->tell())+N*data0Length > entry.end()) { |
838 | 52.5k | MWAW_DEBUG_MSG(("ClarisWksText::readDSETZone: file is too short\n")); |
839 | 52.5k | return std::shared_ptr<ClarisWksStruct::DSET>(); |
840 | 52.5k | } |
841 | | |
842 | 1.10M | input->seek(entry.end()-N*data0Length, librevenge::RVNG_SEEK_SET); |
843 | 1.10M | ClarisWksTextInternal::PLC plc; |
844 | 1.10M | plc.m_type = ClarisWksTextInternal::P_Child; |
845 | 1.10M | int numExtraHId=0; |
846 | 1.10M | if (data0Length) { |
847 | 1.91M | for (int i = 0; i < N; i++) { |
848 | | /* definition of a list of text zone ( one by column and one by page )*/ |
849 | 1.01M | pos = input->tell(); |
850 | 1.01M | f.str(""); |
851 | 1.01M | f << "DSETT-" << i << ":"; |
852 | 1.01M | ClarisWksStruct::DSET::Child child; |
853 | 1.01M | child.m_posC = long(input->readULong(4)); |
854 | 1.01M | child.m_type = ClarisWksStruct::DSET::C_SubText; |
855 | 1.01M | int dim[2]; |
856 | 2.03M | for (auto &d : dim) d = static_cast<int>(input->readLong(2)); |
857 | 1.01M | child.m_box = MWAWBox2f(MWAWVec2f(0,0), MWAWVec2f(float(dim[0]), float(dim[1]))); |
858 | 1.01M | textZone->m_childs.push_back(child); |
859 | 1.01M | plc.m_id = i; |
860 | 1.01M | textZone->m_plcMap.insert(std::map<long, ClarisWksTextInternal::PLC>::value_type(child.m_posC, plc)); |
861 | | |
862 | 1.01M | f << child; |
863 | 1.01M | f << "ptr=" << std::hex << input->readULong(4) << std::dec << ","; |
864 | 1.01M | f << "f0=" << input->readLong(2) << ","; // a small number : number of line ? |
865 | 1.01M | f << "y[real]=" << input->readLong(2) << ","; |
866 | 4.06M | for (int j = 1; j < 4; j++) { |
867 | 3.05M | auto val = static_cast<int>(input->readLong(2)); |
868 | 3.05M | if (val) |
869 | 945k | f << "f" << j << "=" << val << ","; |
870 | 3.05M | } |
871 | 1.01M | auto order = static_cast<int>(input->readLong(2)); |
872 | | // simple id or 0: main text ?, 1 : header/footnote ?, 2: footer => id or order? |
873 | 1.01M | if (order) |
874 | 557k | f << "order?=" << order << ","; |
875 | | |
876 | 1.01M | if (vers>=2) { |
877 | 752k | long id=static_cast<int>(input->readULong(4)); |
878 | 752k | if (id) { |
879 | 265k | f << "ID=" << std::hex << id << std::dec << ","; |
880 | 265k | ++numExtraHId; |
881 | 265k | } |
882 | 752k | } |
883 | 1.01M | long actPos = input->tell(); |
884 | 1.01M | if (actPos != pos && actPos != pos+data0Length) |
885 | 554k | ascFile.addDelimiter(input->tell(),'|'); |
886 | 1.01M | input->seek(pos+data0Length, librevenge::RVNG_SEEK_SET); |
887 | | |
888 | 1.01M | ascFile.addPos(pos); |
889 | 1.01M | ascFile.addNote(f.str().c_str()); |
890 | 1.01M | } |
891 | 901k | } |
892 | | |
893 | 1.10M | input->seek(entry.end(), librevenge::RVNG_SEEK_SET); |
894 | | |
895 | | // now normally three zones: paragraph, font, token |
896 | 1.10M | bool ok = true; |
897 | 31.6M | for (int z = 0; z < 4+textZone->m_numTextZone; z++) { |
898 | 31.0M | pos = input->tell(); |
899 | 31.0M | auto sz = long(input->readULong(4)); |
900 | 31.0M | if (!sz) { |
901 | 28.1M | f.str(""); |
902 | 28.1M | f << "DSETT-Z" << z; |
903 | 28.1M | ascFile.addPos(pos); |
904 | 28.1M | ascFile.addNote(f.str().c_str()); |
905 | 28.1M | continue; |
906 | 28.1M | } |
907 | | |
908 | 2.93M | MWAWEntry zEntry; |
909 | 2.93M | zEntry.setBegin(pos); |
910 | 2.93M | zEntry.setLength(sz+4); |
911 | | |
912 | 2.93M | if (!input->checkPosition(zEntry.end())) { |
913 | 456k | MWAW_DEBUG_MSG(("ClarisWksText::readDSETZone: entry for %d zone is too short\n", z)); |
914 | 456k | ascFile.addPos(pos); |
915 | 456k | ascFile.addNote("###"); |
916 | 456k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
917 | 456k | if (z > 4) { |
918 | 62.0k | ok = false; |
919 | 62.0k | break; |
920 | 62.0k | } |
921 | 394k | return textZone; |
922 | 456k | } |
923 | | |
924 | 2.47M | switch (z) { |
925 | 631k | case 0: |
926 | 631k | ok = readParagraphs(zEntry, *textZone); |
927 | 631k | break; |
928 | 618k | case 1: |
929 | 618k | ok = readFonts(zEntry, *textZone); |
930 | 618k | break; |
931 | 134k | case 2: |
932 | 134k | ok = readTokens(zEntry, *textZone); |
933 | 134k | break; |
934 | 536k | case 3: |
935 | 536k | ok = readTextZoneSize(zEntry, *textZone); |
936 | 536k | break; |
937 | 555k | default: |
938 | 555k | textZone->m_zones.push_back(zEntry); |
939 | 555k | break; |
940 | 2.47M | } |
941 | 2.47M | if (!ok) { |
942 | 666k | if (z >= 4) { |
943 | 25.5k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
944 | 25.5k | MWAW_DEBUG_MSG(("ClarisWksText::readDSETZone: can not find text %d zone\n", z-4)); |
945 | 25.5k | if (z > 4) break; |
946 | 16.1k | return textZone; |
947 | 25.5k | } |
948 | 641k | f.str(""); |
949 | 641k | f << "DSETT-Z" << z << "#"; |
950 | 641k | ascFile.addPos(pos); |
951 | 641k | ascFile.addNote(f.str().c_str()); |
952 | 641k | } |
953 | 2.45M | if (input->tell() < zEntry.end() || !ok) |
954 | 1.17M | input->seek(zEntry.end(), librevenge::RVNG_SEEK_SET); |
955 | 2.45M | } |
956 | | |
957 | 695k | if (ok && vers >= 2) { |
958 | 524k | pos = input->tell(); |
959 | 524k | if (!readTextSection(*textZone)) |
960 | 50.5k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
961 | 524k | } |
962 | 725k | for (int i=0; ok && i<numExtraHId; ++i) { |
963 | 69.1k | pos=input->tell(); |
964 | 69.1k | auto sz=long(input->readULong(4)); |
965 | 69.1k | if (sz<10 || !input->checkPosition(pos+4+sz)) { |
966 | 39.1k | MWAW_DEBUG_MSG(("ClarisWksText::readDSETZone:: can not read an extra block\n")); |
967 | 39.1k | ascFile.addPos(pos); |
968 | 39.1k | ascFile.addNote("DSETT-extra:###"); |
969 | 39.1k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
970 | 39.1k | ok=false; |
971 | 39.1k | break; |
972 | 39.1k | } |
973 | 29.9k | f.str(""); |
974 | 29.9k | f << "DSETT-extra:"; |
975 | | /* Checkme: no sure how to read this unfrequent structures */ |
976 | 29.9k | auto val=static_cast<int>(input->readLong(2)); // 2 (with size=34 or 4c)|a(with size=a or e)|3c (with size 3c) |
977 | 29.9k | f << "type?=" << val << ","; |
978 | 29.9k | int dim[4]; |
979 | 119k | for (auto &d : dim) d=static_cast<int>(input->readLong(2)); |
980 | 29.9k | f << "dim=" << dim[1] << "x" << dim[0] << "<->" << dim[3] << "x" << dim[2] << ","; |
981 | 29.9k | if (sz!=10) ascFile.addDelimiter(input->tell(),'|'); |
982 | 29.9k | ascFile.addPos(pos); |
983 | 29.9k | ascFile.addNote(f.str().c_str()); |
984 | 29.9k | input->seek(pos+4+sz, librevenge::RVNG_SEEK_SET); |
985 | 29.9k | } |
986 | 6.97M | for (auto const &token : textZone->m_tokenList) { |
987 | 6.97M | if (token.m_zoneId > 0) |
988 | 3.48M | textZone->m_otherChilds.push_back(token.m_zoneId); |
989 | 6.97M | } |
990 | | |
991 | 695k | if (m_state->m_zoneMap.find(textZone->m_id) != m_state->m_zoneMap.end()) { |
992 | 401k | MWAW_DEBUG_MSG(("ClarisWksText::readDSETZone: zone %d already exists!!!\n", textZone->m_id)); |
993 | 401k | } |
994 | 293k | else |
995 | 293k | m_state->m_zoneMap[textZone->m_id] = textZone; |
996 | | |
997 | 695k | if (ok) { |
998 | | // look for unparsed zone |
999 | 562k | pos=input->tell(); |
1000 | 562k | auto sz=long(input->readULong(4)); |
1001 | 562k | if (input->checkPosition(pos+4+sz)) { |
1002 | 131k | if (sz) { |
1003 | 36.4k | MWAW_DEBUG_MSG(("ClarisWksText::readDSETZone:: find some extra block\n")); |
1004 | 36.4k | input->seek(pos+4+sz, librevenge::RVNG_SEEK_SET); |
1005 | 36.4k | ascFile.addPos(pos); |
1006 | 36.4k | ascFile.addNote("Entries(TextEnd):###"); |
1007 | 36.4k | } |
1008 | 94.7k | else { |
1009 | | // probably a problem, but... |
1010 | 94.7k | ascFile.addPos(pos); |
1011 | 94.7k | ascFile.addNote("_"); |
1012 | 94.7k | } |
1013 | 131k | } |
1014 | 431k | else |
1015 | 431k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
1016 | 562k | } |
1017 | 695k | complete = ok; |
1018 | 695k | return textZone; |
1019 | 1.10M | } |
1020 | | |
1021 | | //////////////////////////////////////////////////////////// |
1022 | | // |
1023 | | // Low level |
1024 | | // |
1025 | | //////////////////////////////////////////////////////////// |
1026 | | |
1027 | | //////////////////////////////////////////////////////////// |
1028 | | // the fonts properties |
1029 | | //////////////////////////////////////////////////////////// |
1030 | | bool ClarisWksText::readFonts(MWAWEntry const &entry, ClarisWksTextInternal::Zone &zone) |
1031 | 618k | { |
1032 | 618k | long pos = entry.begin(); |
1033 | | |
1034 | 618k | int fontSize = 0; |
1035 | 618k | switch (version()) { |
1036 | 101k | case 1: |
1037 | 183k | case 2: |
1038 | 270k | case 3: |
1039 | 270k | fontSize = 10; |
1040 | 270k | break; |
1041 | 33.6k | case 4: |
1042 | 151k | case 5: |
1043 | 151k | fontSize = 12; |
1044 | 151k | break; |
1045 | 196k | case 6: |
1046 | 196k | fontSize = 18; |
1047 | 196k | break; |
1048 | 0 | default: |
1049 | 0 | break; |
1050 | 618k | } |
1051 | 618k | if (fontSize == 0) |
1052 | 0 | return false; |
1053 | 618k | if ((entry.length()%fontSize) != 4) |
1054 | 361k | return false; |
1055 | | |
1056 | 256k | auto numElt = int((entry.length()-4)/fontSize); |
1057 | 256k | long actC = -1; |
1058 | | |
1059 | 256k | MWAWInputStreamPtr &input= m_parserState->m_input; |
1060 | 256k | input->seek(pos+4, librevenge::RVNG_SEEK_SET); // skip header |
1061 | | // first check char pos is ok |
1062 | 706k | for (int i = 0; i < numElt; i++) { |
1063 | 466k | pos = input->tell(); |
1064 | 466k | auto newC = long(input->readULong(4)); |
1065 | 466k | if (newC < actC) return false; |
1066 | 449k | actC = newC; |
1067 | 449k | input->seek(pos+fontSize, librevenge::RVNG_SEEK_SET); |
1068 | 449k | } |
1069 | | |
1070 | 239k | pos = entry.begin(); |
1071 | 239k | libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile; |
1072 | 239k | ascFile.addPos(pos); |
1073 | 239k | ascFile.addNote("Entries(Font)"); |
1074 | | |
1075 | 239k | input->seek(pos+4, librevenge::RVNG_SEEK_SET); // skip header |
1076 | 239k | ClarisWksTextInternal::PLC plc; |
1077 | 239k | plc.m_type = ClarisWksTextInternal::P_Font; |
1078 | 633k | for (int i = 0; i < numElt; i++) { |
1079 | 394k | MWAWFont font; |
1080 | 394k | int posChar; |
1081 | 394k | if (!m_document.getStyleManager()->readFontAndPos(i, posChar, font)) return false; |
1082 | 394k | zone.m_fontList.push_back(font); |
1083 | 394k | plc.m_id = i; |
1084 | 394k | zone.m_plcMap.insert(std::map<long, ClarisWksTextInternal::PLC>::value_type(posChar, plc)); |
1085 | 394k | } |
1086 | | |
1087 | 239k | return true; |
1088 | 239k | } |
1089 | | |
1090 | | //////////////////////////////////////////////////////////// |
1091 | | // the paragraphs properties |
1092 | | //////////////////////////////////////////////////////////// |
1093 | | bool ClarisWksText::readParagraphs(MWAWEntry const &entry, ClarisWksTextInternal::Zone &zone) |
1094 | 631k | { |
1095 | 631k | long pos = entry.begin(); |
1096 | | |
1097 | 631k | int const vers = version(); |
1098 | 631k | int styleSize = vers==1 ? 6 : 8; |
1099 | 631k | if ((entry.length()%styleSize) != 4) |
1100 | 107k | return false; |
1101 | | |
1102 | 524k | auto numElt = int((entry.length()-4)/styleSize); |
1103 | 524k | long actC = -1; |
1104 | | |
1105 | 524k | MWAWInputStreamPtr &input= m_parserState->m_input; |
1106 | 524k | input->seek(pos+4, librevenge::RVNG_SEEK_SET); // skip header |
1107 | | // first check char pos is ok |
1108 | 1.43M | for (int i = 0; i < numElt; i++) { |
1109 | 954k | pos = input->tell(); |
1110 | 954k | auto newC = long(input->readULong(4)); |
1111 | 954k | if (newC < actC) return false; |
1112 | 912k | actC = newC; |
1113 | 912k | input->seek(pos+styleSize, librevenge::RVNG_SEEK_SET); |
1114 | 912k | } |
1115 | | |
1116 | 481k | libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile; |
1117 | 481k | pos = entry.begin(); |
1118 | 481k | ascFile.addPos(pos); |
1119 | 481k | ascFile.addNote("Entries(ParaPLC)"); |
1120 | | |
1121 | 481k | libmwaw::DebugStream f; |
1122 | 481k | input->seek(pos+4, librevenge::RVNG_SEEK_SET); // skip header |
1123 | 481k | ClarisWksTextInternal::PLC plc; |
1124 | 481k | plc.m_type = ClarisWksTextInternal::P_Ruler; |
1125 | 1.26M | for (int i = 0; i < numElt; i++) { |
1126 | 780k | pos = input->tell(); |
1127 | 780k | ClarisWksTextInternal::ParagraphPLC info; |
1128 | | |
1129 | 780k | auto posC = long(input->readULong(4)); |
1130 | 780k | f.str(""); |
1131 | 780k | f << "ParaPLC-R" << i << ": pos=" << posC << ","; |
1132 | 780k | info.m_rulerId = static_cast<int>(input->readLong(2)); |
1133 | 780k | if (styleSize >= 8) |
1134 | 709k | info.m_flags = static_cast<int>(input->readLong(2)); |
1135 | | |
1136 | 780k | if (vers > 2) { |
1137 | 602k | info.m_styleId = info.m_rulerId; |
1138 | 602k | ClarisWksStyleManager::Style style; |
1139 | 602k | if (m_document.getStyleManager()->get(info.m_rulerId, style)) { |
1140 | 39.5k | info.m_rulerId = style.m_rulerId; |
1141 | | #if 0 |
1142 | | f << "[style=" << style << "]"; |
1143 | | #endif |
1144 | 39.5k | } |
1145 | 602k | } |
1146 | 780k | f << info; |
1147 | | |
1148 | 780k | if (long(input->tell()) != pos+styleSize) |
1149 | 0 | ascFile.addDelimiter(input->tell(), '|'); |
1150 | 780k | zone.m_paragraphList.push_back(info); |
1151 | 780k | plc.m_id = i; |
1152 | 780k | zone.m_plcMap.insert(std::map<long, ClarisWksTextInternal::PLC>::value_type(posC, plc)); |
1153 | 780k | input->seek(pos+styleSize, librevenge::RVNG_SEEK_SET); |
1154 | 780k | ascFile.addPos(pos); |
1155 | 780k | ascFile.addNote(f.str().c_str()); |
1156 | 780k | } |
1157 | | |
1158 | 481k | return true; |
1159 | 524k | } |
1160 | | |
1161 | | //////////////////////////////////////////////////////////// |
1162 | | // zone which corresponds to the token |
1163 | | //////////////////////////////////////////////////////////// |
1164 | | bool ClarisWksText::readTokens(MWAWEntry const &entry, ClarisWksTextInternal::Zone &zone) |
1165 | 134k | { |
1166 | 134k | long pos = entry.begin(); |
1167 | | |
1168 | 134k | int dataSize = 0; |
1169 | 134k | int const vers=version(); |
1170 | 134k | switch (vers) { |
1171 | 34.8k | case 1: |
1172 | 52.6k | case 2: |
1173 | 78.1k | case 3: |
1174 | 88.1k | case 4: |
1175 | 117k | case 5: |
1176 | 117k | dataSize = 32; |
1177 | 117k | break; |
1178 | 17.5k | case 6: |
1179 | 17.5k | dataSize = 36; |
1180 | 17.5k | break; |
1181 | 0 | default: |
1182 | 0 | break; |
1183 | 134k | } |
1184 | 134k | if (!dataSize || (entry.length()%dataSize) != 4) |
1185 | 41.2k | return false; |
1186 | | |
1187 | 93.3k | MWAWInputStreamPtr &input= m_parserState->m_input; |
1188 | 93.3k | libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile; |
1189 | 93.3k | ascFile.addPos(pos); |
1190 | 93.3k | ascFile.addNote("Entries(Token)"); |
1191 | | |
1192 | 93.3k | auto numElt = int((entry.length()-4)/dataSize); |
1193 | 93.3k | input->seek(pos+4, librevenge::RVNG_SEEK_SET); // skip header |
1194 | | |
1195 | 93.3k | libmwaw::DebugStream f; |
1196 | 93.3k | ClarisWksTextInternal::PLC plc; |
1197 | 93.3k | plc.m_type = ClarisWksTextInternal::P_Token; |
1198 | 93.3k | int val; |
1199 | 93.3k | std::vector<int> fieldList; |
1200 | 8.97M | for (int i = 0; i < numElt; i++) { |
1201 | 8.88M | pos = input->tell(); |
1202 | | |
1203 | 8.88M | auto posC = static_cast<int>(input->readULong(4)); |
1204 | 8.88M | ClarisWksTextInternal::Token token; |
1205 | | |
1206 | 8.88M | auto type = static_cast<int>(input->readLong(2)); |
1207 | 8.88M | f.str(""); |
1208 | 8.88M | switch (type) { |
1209 | 3.44M | case 0: |
1210 | 3.44M | token.m_type = ClarisWksTextInternal::TKN_FOOTNOTE; |
1211 | 3.44M | break; |
1212 | 269k | case 1: |
1213 | 269k | token.m_type = ClarisWksTextInternal::TKN_GRAPHIC; |
1214 | 269k | break; |
1215 | 85.5k | case 2: |
1216 | | /* find in v4-v6, does not seem to exist in v1-v2 */ |
1217 | 85.5k | token.m_type = ClarisWksTextInternal::TKN_PAGENUMBER; |
1218 | 85.5k | break; |
1219 | 119k | case 3: |
1220 | 119k | token.m_type = ClarisWksTextInternal::TKN_FIELD; |
1221 | 119k | fieldList.push_back(i); |
1222 | 119k | break; |
1223 | 4.95M | default: |
1224 | 4.95M | f << "#type=" << type << ","; |
1225 | 4.95M | break; |
1226 | 8.88M | } |
1227 | | |
1228 | 8.88M | token.m_unknown[0] = static_cast<int>(input->readLong(2)); |
1229 | 8.88M | token.m_zoneId = static_cast<int>(input->readLong(2)); |
1230 | 8.88M | token.m_unknown[1] = static_cast<int>(input->readLong(1)); |
1231 | 8.88M | token.m_page = static_cast<int>(input->readLong(1)); |
1232 | 8.88M | token.m_unknown[2] = static_cast<int>(input->readLong(2)); |
1233 | 26.6M | for (int j = 0; j < 2; j++) |
1234 | 17.7M | token.m_size[1-j] = static_cast<int>(input->readLong(2)); |
1235 | 35.5M | for (int j = 0; j < 3; j++) { |
1236 | 26.6M | val = static_cast<int>(input->readLong(2)); |
1237 | 26.6M | if (val) f << "f" << j << "=" << val << ","; |
1238 | 26.6M | } |
1239 | 8.88M | val = static_cast<int>(input->readLong(2)); |
1240 | 8.88M | if (vers>=6) // checkme: ok for v6 & graphic, not for v2 |
1241 | 462k | token.m_descent = val; |
1242 | 8.41M | else if (val) |
1243 | 5.10M | f << "f3=" << val << ","; |
1244 | 8.88M | token.m_extra = f.str(); |
1245 | 8.88M | f.str(""); |
1246 | 8.88M | f << "Token-" << i << ": pos=" << posC << "," << token; |
1247 | 8.88M | zone.m_tokenList.push_back(token); |
1248 | 8.88M | plc.m_id = i; |
1249 | 8.88M | zone.m_plcMap.insert(std::map<long, ClarisWksTextInternal::PLC>::value_type(posC, plc)); |
1250 | | |
1251 | 8.88M | if (long(input->tell()) != pos && long(input->tell()) != pos+dataSize) |
1252 | 8.88M | ascFile.addDelimiter(input->tell(), '|'); |
1253 | 8.88M | ascFile.addPos(pos); |
1254 | 8.88M | ascFile.addNote(f.str().c_str()); |
1255 | 8.88M | input->seek(pos+dataSize, librevenge::RVNG_SEEK_SET); |
1256 | 8.88M | } |
1257 | | |
1258 | 93.3k | input->seek(entry.end(), librevenge::RVNG_SEEK_SET); |
1259 | 108k | for (size_t i=0; i < fieldList.size(); ++i) { |
1260 | 59.7k | pos=input->tell(); |
1261 | 59.7k | auto sz=long(input->readULong(4)); |
1262 | 59.7k | f.str(""); |
1263 | 59.7k | f << "Token[field-" << i << "]:"; |
1264 | 59.7k | if (!input->checkPosition(pos+sz+4) || long(input->readULong(1))+1!=sz) { |
1265 | 44.2k | MWAW_DEBUG_MSG(("ClarisWksText::readTokens: can find token field name %d\n", int(i))); |
1266 | 44.2k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
1267 | 44.2k | f << "###"; |
1268 | 44.2k | ascFile.addPos(pos); |
1269 | 44.2k | ascFile.addNote(f.str().c_str()); |
1270 | 44.2k | return false; |
1271 | 44.2k | } |
1272 | 15.4k | MWAWEntry fieldEntry; |
1273 | 15.4k | fieldEntry.setBegin(input->tell()); |
1274 | 15.4k | fieldEntry.setEnd(pos+sz+4); |
1275 | 15.4k | if (size_t(fieldList[i])<zone.m_tokenList.size()) |
1276 | 15.4k | zone.m_tokenList[size_t(fieldList[i])].m_fieldEntry=fieldEntry; |
1277 | 0 | else { |
1278 | 0 | MWAW_DEBUG_MSG(("ClarisWksText::readTokens: oops the token id seems bad\n")); |
1279 | 0 | } |
1280 | 15.4k | input->seek(fieldEntry.end(), librevenge::RVNG_SEEK_SET); |
1281 | 15.4k | f << "###id"; |
1282 | 15.4k | ascFile.addPos(pos); |
1283 | 15.4k | ascFile.addNote(f.str().c_str()); |
1284 | 15.4k | } |
1285 | 49.0k | return true; |
1286 | 93.3k | } |
1287 | | |
1288 | | // read the different section definition |
1289 | | bool ClarisWksText::readTextSection(ClarisWksTextInternal::Zone &zone) |
1290 | 524k | { |
1291 | 524k | int const vers = version(); |
1292 | 524k | MWAWInputStreamPtr &input= m_parserState->m_input; |
1293 | 524k | long pos = input->tell(); |
1294 | 524k | ClarisWksStruct::Struct header; |
1295 | 524k | if (!header.readHeader(input,true)) { |
1296 | 50.5k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
1297 | 50.5k | MWAW_DEBUG_MSG(("ClarisWksText::readTextSection: unexpected size\n")); |
1298 | 50.5k | return false; |
1299 | 50.5k | } |
1300 | 474k | libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile; |
1301 | 474k | if (header.m_size == 0) { |
1302 | 391k | ascFile.addPos(pos); |
1303 | 391k | ascFile.addNote("Nop"); |
1304 | 391k | return true; |
1305 | 391k | } |
1306 | 82.4k | long endPos =pos+4+header.m_size; |
1307 | 82.4k | libmwaw::DebugStream f; |
1308 | 82.4k | f << "Entries(TextSection):"; |
1309 | | |
1310 | 82.4k | if ((vers > 3 && header.m_dataSize != 0x4e) || (vers <= 3 && header.m_dataSize < 60)) { |
1311 | 8.81k | f << "###"; |
1312 | 8.81k | ascFile.addPos(pos); |
1313 | 8.81k | ascFile.addNote(f.str().c_str()); |
1314 | 8.81k | input->seek(endPos, librevenge::RVNG_SEEK_SET); |
1315 | 8.81k | MWAW_DEBUG_MSG(("ClarisWksText::readTextSection: unexpected size\n")); |
1316 | 8.81k | return true; |
1317 | 8.81k | } |
1318 | 73.6k | if (header.m_headerSize) { |
1319 | 1.59k | ascFile.addDelimiter(input->tell(), '|'); |
1320 | 1.59k | input->seek(header.m_headerSize, librevenge::RVNG_SEEK_CUR); |
1321 | 1.59k | } |
1322 | 73.6k | ascFile.addPos(pos); |
1323 | 73.6k | ascFile.addNote(f.str().c_str()); |
1324 | | |
1325 | 73.6k | ClarisWksTextInternal::PLC plc; |
1326 | 73.6k | plc.m_type = ClarisWksTextInternal::P_Section; |
1327 | 352k | for (long i= 0; i < header.m_numData; i++) { |
1328 | 278k | ClarisWksTextInternal::Section sec; |
1329 | | |
1330 | 278k | pos = input->tell(); |
1331 | 278k | f.str(""); |
1332 | 278k | sec.m_pos = input->readLong(4); |
1333 | 278k | sec.m_firstPage= static_cast<int>(input->readLong(2)); |
1334 | 1.11M | for (int j = 0; j < 3; j++) { |
1335 | | /** find f0=O| (for second section)[1|2|4] |
1336 | | f1=0| (for second section [2e,4e,5b] , f2=0|2d|4d|5a */ |
1337 | 836k | auto val = int(input->readLong(2)); |
1338 | 836k | if (val) f << "f" << j << "=" << val << ","; |
1339 | 836k | } |
1340 | 278k | sec.m_numColumns = static_cast<int>(input->readULong(2)); |
1341 | 278k | if (!sec.m_numColumns || sec.m_numColumns > 10) { |
1342 | 229k | MWAW_DEBUG_MSG(("ClarisWksText::readTextSection: num columns seems odd\n")); |
1343 | 229k | f << "#numColumns=" << sec.m_numColumns << ","; |
1344 | 229k | sec.m_numColumns = 1; |
1345 | 229k | } |
1346 | 651k | for (int c = 0; c < sec.m_numColumns; c++) |
1347 | 372k | sec.m_columnsWidth.push_back(static_cast<int>(input->readULong(2))); |
1348 | 278k | input->seek(pos+32, librevenge::RVNG_SEEK_SET); |
1349 | 651k | for (int c = 0; c < sec.m_numColumns; c++) |
1350 | 372k | sec.m_columnsSep.push_back(static_cast<int>(input->readLong(2))); |
1351 | 278k | input->seek(pos+52, librevenge::RVNG_SEEK_SET); |
1352 | 278k | auto val = static_cast<int>(input->readULong(2)); |
1353 | 278k | switch ((val&3)) { |
1354 | 51.5k | case 1: |
1355 | 51.5k | f << "newPage[begin],"; |
1356 | 51.5k | break; |
1357 | 52.9k | case 2: // checkme |
1358 | 52.9k | f << "leftPage[begin],"; |
1359 | 52.9k | break; |
1360 | 19.3k | case 3: // checkme |
1361 | 19.3k | f << "rightPage[begin],"; |
1362 | 19.3k | break; |
1363 | 154k | case 0: // begin on new line |
1364 | 154k | default: |
1365 | 154k | break; |
1366 | 278k | } |
1367 | 278k | sec.m_startOnNewPage=(val&3)!=0; |
1368 | 278k | val &=0xFFFC; |
1369 | 278k | if (val) f << "g0=" << std::hex << val << std::dec << ","; |
1370 | 278k | val = static_cast<int>(input->readULong(2)); // 0|1 |
1371 | 278k | if (val) f << "g1=" << std::hex << val << std::dec << ","; |
1372 | 278k | val = static_cast<int>(input->readULong(2)); // 0 or 1 |
1373 | 278k | sec.m_hasTitlePage=(val&1); |
1374 | 278k | val &= 0xFFFE; |
1375 | 278k | if (val) f << "g2=" << std::hex << val << std::dec << ","; |
1376 | | |
1377 | 278k | val = static_cast<int>(input->readULong(2)); // 0 or 100 |
1378 | 278k | sec.m_continuousHF=(val&0x100); |
1379 | 278k | sec.m_leftRightHF=(val&1); |
1380 | 278k | val &= 0xFEFE; |
1381 | 278k | if (val) f << "g3=" << std::hex << val << std::dec << ","; |
1382 | 278k | val = static_cast<int>(input->readULong(2)); // 0 ? |
1383 | 278k | if (val) f << "g4=" << std::hex << val << std::dec << ","; |
1384 | 278k | int prevHFId=0; |
1385 | 1.11M | for (int &j : sec.m_HFId) { |
1386 | 1.11M | auto hFId=static_cast<int>(input->readLong(4)); |
1387 | 1.11M | j=hFId; |
1388 | 1.11M | if (!hFId || prevHFId==hFId) continue; |
1389 | 772k | zone.m_otherChilds.push_back(hFId); |
1390 | 772k | prevHFId=hFId; |
1391 | 772k | } |
1392 | 278k | sec.m_extra = f.str(); |
1393 | 278k | zone.m_sectionList.push_back(sec); |
1394 | 278k | plc.m_id = int(i); |
1395 | 278k | zone.m_plcMap.insert(std::map<long, ClarisWksTextInternal::PLC>::value_type(sec.m_pos, plc)); |
1396 | 278k | f.str(""); |
1397 | 278k | f << "TextSection-S" << i << ":" << sec; |
1398 | 278k | if (input->tell() != pos+header.m_dataSize) |
1399 | 248k | ascFile.addDelimiter(input->tell(), '|'); |
1400 | 278k | ascFile.addPos(pos); |
1401 | 278k | ascFile.addNote(f.str().c_str()); |
1402 | 278k | input->seek(pos+header.m_dataSize, librevenge::RVNG_SEEK_SET); |
1403 | 278k | } |
1404 | | |
1405 | 73.6k | return true; |
1406 | 73.6k | } |
1407 | | |
1408 | | //////////////////////////////////////////////////////////// |
1409 | | // read the different size for the text |
1410 | | //////////////////////////////////////////////////////////// |
1411 | | bool ClarisWksText::readTextZoneSize(MWAWEntry const &entry, ClarisWksTextInternal::Zone &zone) |
1412 | 536k | { |
1413 | 536k | long pos = entry.begin(); |
1414 | | |
1415 | 536k | int dataSize = 10; |
1416 | 536k | if ((entry.length()%dataSize) != 4) |
1417 | 26.3k | return false; |
1418 | | |
1419 | 510k | libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile; |
1420 | 510k | libmwaw::DebugStream f; |
1421 | 510k | ascFile.addPos(pos); |
1422 | 510k | ascFile.addNote("Entries(TextZoneSz)"); |
1423 | | |
1424 | 510k | auto numElt = int((entry.length()-4)/dataSize); |
1425 | | |
1426 | 510k | MWAWInputStreamPtr &input= m_parserState->m_input; |
1427 | 510k | input->seek(pos+4, librevenge::RVNG_SEEK_SET); // skip header |
1428 | | |
1429 | 510k | ClarisWksTextInternal::PLC plc; |
1430 | 510k | plc.m_type = ClarisWksTextInternal::P_TextZone; |
1431 | 1.58M | for (int i = 0; i < numElt; i++) { |
1432 | 1.07M | pos = input->tell(); |
1433 | 1.07M | f.str(""); |
1434 | 1.07M | f << "TextZoneSz-" << i << ":"; |
1435 | 1.07M | ClarisWksTextInternal::TextZoneInfo info; |
1436 | 1.07M | info.m_pos = long(input->readULong(4)); |
1437 | 1.07M | info.m_N = static_cast<int>(input->readULong(2)); |
1438 | 1.07M | f << info; |
1439 | 1.07M | zone.m_textZoneList.push_back(info); |
1440 | 1.07M | plc.m_id = i; |
1441 | 1.07M | zone.m_plcMap.insert(std::map<long, ClarisWksTextInternal::PLC>::value_type(info.m_pos, plc)); |
1442 | | |
1443 | 1.07M | if (long(input->tell()) != pos+dataSize) |
1444 | 1.07M | ascFile.addDelimiter(input->tell(), '|'); |
1445 | 1.07M | ascFile.addPos(pos); |
1446 | 1.07M | ascFile.addNote(f.str().c_str()); |
1447 | 1.07M | input->seek(pos+dataSize, librevenge::RVNG_SEEK_SET); |
1448 | 1.07M | } |
1449 | | |
1450 | 510k | input->seek(entry.end(), librevenge::RVNG_SEEK_SET); |
1451 | 510k | return true; |
1452 | 536k | } |
1453 | | |
1454 | | bool ClarisWksText::canSendTextAsGraphic(ClarisWksTextInternal::Zone const &zone) const |
1455 | 1.53M | { |
1456 | 1.53M | size_t numSection=zone.m_sectionList.size(); |
1457 | 1.53M | if (numSection>1) return false; |
1458 | 1.53M | if (numSection==1 && zone.m_sectionList[0].m_numColumns>1) |
1459 | 71.4k | return false; |
1460 | 2.60M | for (auto const &tok : zone.m_tokenList) { |
1461 | 2.60M | if (tok.m_type!=ClarisWksTextInternal::TKN_UNKNOWN && |
1462 | 981k | tok.m_type!=ClarisWksTextInternal::TKN_PAGENUMBER && |
1463 | 833k | tok.m_type!=ClarisWksTextInternal::TKN_FIELD) |
1464 | 731k | return false; |
1465 | 2.60M | } |
1466 | 729k | return true; |
1467 | 1.46M | } |
1468 | | |
1469 | | bool ClarisWksText::sendText(ClarisWksTextInternal::Zone const &zone, MWAWListenerPtr listener) |
1470 | 1.90M | { |
1471 | 1.90M | zone.m_parsed=true; |
1472 | 1.90M | bool localListener=false; |
1473 | 1.90M | if (listener) |
1474 | 1.74M | localListener=true; |
1475 | 161k | else |
1476 | 161k | listener=m_parserState->getMainListener(); |
1477 | 1.90M | if (!listener || !listener->canWriteText()) { |
1478 | 4.89k | MWAW_DEBUG_MSG(("ClarisWksText::sendText: can not find a listener\n")); |
1479 | 4.89k | return false; |
1480 | 4.89k | } |
1481 | | // Removeme when all is ok |
1482 | 1.90M | if (listener->isParagraphOpened()) |
1483 | 225k | listener->insertEOL(); |
1484 | 1.90M | long actC = 0; |
1485 | 1.90M | bool main = zone.m_id == 1; |
1486 | 1.90M | auto numParaPLC = int(zone.m_paragraphList.size()); |
1487 | 1.90M | auto numParagraphs = int(m_state->m_paragraphsList.size()); |
1488 | 1.90M | int actPage = 1; |
1489 | 1.90M | size_t numZones = zone.m_zones.size(); |
1490 | 1.90M | if (main) { |
1491 | 36.0k | if (!localListener) |
1492 | 16.1k | m_document.newPage(actPage); |
1493 | 19.9k | else { |
1494 | 19.9k | MWAW_DEBUG_MSG(("ClarisWksText::sendText: try to send main zone as graphic\n")); |
1495 | 19.9k | main=false; |
1496 | 19.9k | } |
1497 | 36.0k | } |
1498 | 1.90M | int numCols = 1; |
1499 | 1.90M | int numSection = 0, numSectionInPage=0; |
1500 | 1.90M | size_t nextSection = 0; |
1501 | 1.90M | long nextSectionPos = main ? 0 : -1; |
1502 | 1.90M | if (zone.m_sectionList.size()) |
1503 | 187k | nextSectionPos = zone.m_sectionList[0].m_pos; |
1504 | 1.90M | int actListId=-1; |
1505 | 1.90M | long actListCPos=-1; |
1506 | 1.90M | MWAWInputStreamPtr &input= m_parserState->m_input; |
1507 | 1.90M | libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile; |
1508 | 1.90M | std::multimap<long, ClarisWksTextInternal::PLC>::const_iterator plcIt; |
1509 | 3.69M | for (size_t z = 0; z < numZones; z++) { |
1510 | 1.79M | MWAWEntry const &entry = zone.m_zones[z]; |
1511 | 1.79M | long pos = entry.begin(); |
1512 | 1.79M | libmwaw::DebugStream f, f2; |
1513 | | |
1514 | 1.79M | auto numC = int(entry.length()-4); |
1515 | 1.79M | bool lastIsSectionBreak=false; |
1516 | 1.79M | input->seek(pos+4, librevenge::RVNG_SEEK_SET); // skip header |
1517 | | |
1518 | 241M | for (int i = 0; i < numC; i++) { |
1519 | 241M | if (nextSectionPos>=0 && actC >= nextSectionPos) { |
1520 | 159k | if (actC != nextSectionPos) { |
1521 | 1.70k | MWAW_DEBUG_MSG(("ClarisWksText::sendText: find a section inside a complex char!!!\n")); |
1522 | 1.70k | f << "###"; |
1523 | 1.70k | } |
1524 | 159k | numSection++; |
1525 | 159k | numSectionInPage++; |
1526 | 159k | MWAWSection section; |
1527 | 159k | if (nextSection < zone.m_sectionList.size()) { |
1528 | 148k | section = zone.m_sectionList[nextSection].getSection(); |
1529 | 148k | if (main && lastIsSectionBreak && zone.m_sectionList[nextSection].m_startOnNewPage) |
1530 | 44 | m_document.newPage(++actPage); |
1531 | 148k | if (++nextSection < zone.m_sectionList.size()) |
1532 | 2.76k | nextSectionPos = zone.m_sectionList[nextSection].m_pos; |
1533 | 146k | else |
1534 | 146k | nextSectionPos = -1; |
1535 | 148k | } |
1536 | 10.4k | else { |
1537 | 10.4k | section=m_document.getMainSection(); |
1538 | 10.4k | nextSectionPos = -1; |
1539 | 10.4k | } |
1540 | 159k | numCols = section.numColumns(); |
1541 | 159k | int actCols = localListener ? 1 : listener->getSection().numColumns(); |
1542 | 159k | if (numCols > 1 || actCols > 1) { |
1543 | 111k | if (listener->isSectionOpened()) |
1544 | 71.8k | listener->closeSection(); |
1545 | 111k | listener->openSection(section); |
1546 | 111k | } |
1547 | 159k | } |
1548 | 240M | else if (numSectionInPage==0) |
1549 | 2.43M | numSectionInPage++; |
1550 | 241M | plcIt = zone.m_plcMap.find(actC); |
1551 | 241M | bool seeToken = false; |
1552 | 290M | while (plcIt != zone.m_plcMap.end() && plcIt->first<=actC) { |
1553 | 49.4M | if (actC != plcIt->first) { |
1554 | 0 | MWAW_DEBUG_MSG(("ClarisWksText::sendText: find a plc inside a complex char!!!\n")); |
1555 | 0 | f << "###"; |
1556 | 0 | } |
1557 | 49.4M | auto const &plc = plcIt++->second; |
1558 | 49.4M | f << "[" << plc << "]"; |
1559 | 49.4M | switch (plc.m_type) { |
1560 | 434k | case ClarisWksTextInternal::P_Font: |
1561 | 434k | if (plc.m_id < 0 || plc.m_id >= int(zone.m_fontList.size())) { |
1562 | 0 | MWAW_DEBUG_MSG(("ClarisWksText::sendText: can not find font %d\n", plc.m_id)); |
1563 | 0 | f << "###"; |
1564 | 0 | break; |
1565 | 0 | } |
1566 | 434k | listener->setFont(zone.m_fontList[size_t(plc.m_id)]); |
1567 | 434k | break; |
1568 | 700k | case ClarisWksTextInternal::P_Ruler: { |
1569 | 700k | if (plc.m_id < 0 || plc.m_id >= numParaPLC) |
1570 | 0 | break; |
1571 | 700k | auto const ¶PLC = zone.m_paragraphList[size_t(plc.m_id)]; |
1572 | 700k | f << "[" << paraPLC << "]"; |
1573 | 700k | if (paraPLC.m_rulerId < 0 || paraPLC.m_rulerId >= numParagraphs) |
1574 | 645k | break; |
1575 | 54.6k | auto para = m_state->m_paragraphsList[size_t(paraPLC.m_rulerId)]; |
1576 | 54.6k | if (*para.m_listLevelIndex>0 && actC >= actListCPos) |
1577 | 1.86k | actListId=findListId(zone, actListId, actC, actListCPos); |
1578 | | #if 0 |
1579 | | // to use when the style manager is able to retrieve the correct style name |
1580 | | if (actListId <= 0 && paraPLC.m_styleId >= 0) { |
1581 | | std::string styleName; |
1582 | | if (m_document.getStyleManager()->getRulerName(paraPLC.m_styleId, styleName)) { |
1583 | | librevenge::RVNGString sfinalName(""); |
1584 | | for (size_t c=0; c < styleName.size(); ++c) { |
1585 | | int unicode= m_parserState->m_fontConverter->unicode(3, static_cast<unsigned char>(styleName[c])); |
1586 | | if (unicode==-1) |
1587 | | sfinalName.append(char(styleName[c])); |
1588 | | else |
1589 | | libmwaw::appendUnicode(static_cast<uint32_t>(unicode), sfinalName); |
1590 | | } |
1591 | | para.m_styleName = librevenge::RVNGString(sfinalName,true).cstr(); |
1592 | | } |
1593 | | } |
1594 | | #endif |
1595 | 54.6k | setProperty(*listener, para, actListId); |
1596 | 54.6k | break; |
1597 | 700k | } |
1598 | 46.4M | case ClarisWksTextInternal::P_Token: { |
1599 | 46.4M | if (plc.m_id < 0 || plc.m_id >= int(zone.m_tokenList.size())) { |
1600 | 0 | MWAW_DEBUG_MSG(("ClarisWksText::sendText: can not find the token %d\n", plc.m_id)); |
1601 | 0 | f << "###"; |
1602 | 0 | break; |
1603 | 0 | } |
1604 | 46.4M | auto const &token = zone.m_tokenList[size_t(plc.m_id)]; |
1605 | 46.4M | switch (token.m_type) { |
1606 | 35.4M | case ClarisWksTextInternal::TKN_FOOTNOTE: |
1607 | 35.4M | if (m_parserState->m_kind==MWAWDocument::MWAW_K_PAINT) { |
1608 | 478k | MWAW_DEBUG_MSG(("ClarisWksText::sendText: can not send footnote in a paint file\n")); |
1609 | 478k | f << "###"; |
1610 | 478k | break; |
1611 | 478k | } |
1612 | 34.9M | if (token.m_zoneId>0) |
1613 | 4.85M | m_document.sendFootnote(token.m_zoneId); |
1614 | 30.1M | else |
1615 | 30.1M | f << "###"; |
1616 | 34.9M | break; |
1617 | 654k | case ClarisWksTextInternal::TKN_PAGENUMBER: |
1618 | 654k | switch (token.m_unknown[0]) { |
1619 | 127k | case 1: |
1620 | 204k | case 2: { |
1621 | 204k | std::stringstream s; |
1622 | 204k | int num = token.m_unknown[0]==1 ? numSection : numSectionInPage; |
1623 | 204k | s << num; |
1624 | 204k | listener->insertUnicodeString(librevenge::RVNGString(s.str().c_str())); |
1625 | 204k | break; |
1626 | 127k | } |
1627 | 24.0k | case 3: |
1628 | 24.0k | listener->insertField(MWAWField(MWAWField::PageCount)); |
1629 | 24.0k | break; |
1630 | 193k | case 0: |
1631 | 426k | default: |
1632 | 426k | listener->insertField(MWAWField(MWAWField::PageNumber)); |
1633 | 654k | } |
1634 | 654k | break; |
1635 | 1.31M | case ClarisWksTextInternal::TKN_GRAPHIC: |
1636 | 1.31M | if (m_parserState->m_kind==MWAWDocument::MWAW_K_PAINT) { |
1637 | 8.42k | MWAW_DEBUG_MSG(("ClarisWksText::sendText: can not send graphic in a paint file\n")); |
1638 | 8.42k | f << "###"; |
1639 | 8.42k | break; |
1640 | 8.42k | } |
1641 | 1.31M | if (m_parserState->m_kind==MWAWDocument::MWAW_K_PRESENTATION) { |
1642 | 156k | MWAW_DEBUG_MSG(("ClarisWksText::sendText: find a graphic in text zone, may cause some problem\n")); |
1643 | 156k | f << "#"; |
1644 | 156k | } |
1645 | 1.31M | if (token.m_zoneId>0) { |
1646 | | // fixme |
1647 | 645k | MWAWPosition tPos; |
1648 | 645k | if (token.m_descent != 0) { |
1649 | 732 | tPos=MWAWPosition(MWAWVec2f(0,float(token.m_descent)), MWAWVec2f(), librevenge::RVNG_POINT); |
1650 | 732 | tPos.setRelativePosition(MWAWPosition::Char, MWAWPosition::XLeft, MWAWPosition::YBottom); |
1651 | 732 | } |
1652 | 645k | m_document.sendZone(token.m_zoneId, MWAWListenerPtr(), tPos); |
1653 | 645k | } |
1654 | 664k | else |
1655 | 664k | f << "###"; |
1656 | 1.31M | break; |
1657 | 460k | case ClarisWksTextInternal::TKN_FIELD: |
1658 | 460k | listener->insertUnicode(0xab); |
1659 | 460k | if (token.m_fieldEntry.valid() && |
1660 | 86.1k | input->checkPosition(token.m_fieldEntry.end())) { |
1661 | 86.1k | long actPos=input->tell(); |
1662 | 86.1k | input->seek(token.m_fieldEntry.begin(), librevenge::RVNG_SEEK_SET); |
1663 | 86.1k | long endFPos=token.m_fieldEntry.end(); |
1664 | 17.9M | while (!input->isEnd() && input->tell() < token.m_fieldEntry.end()) |
1665 | 17.9M | listener->insertCharacter(static_cast<unsigned char>(input->readULong(1)), input, endFPos); |
1666 | 86.1k | input->seek(actPos, librevenge::RVNG_SEEK_SET); |
1667 | 86.1k | } |
1668 | 374k | else { |
1669 | 374k | MWAW_DEBUG_MSG(("ClarisWksText::sendText: can not find field token data\n")); |
1670 | 374k | listener->insertCharacter(' '); |
1671 | 374k | } |
1672 | 460k | listener->insertUnicode(0xbb); |
1673 | 460k | break; |
1674 | 8.58M | case ClarisWksTextInternal::TKN_UNKNOWN: |
1675 | | #if !defined(__clang__) |
1676 | | default: |
1677 | | #endif |
1678 | 8.58M | break; |
1679 | 46.4M | } |
1680 | 46.4M | seeToken = true; |
1681 | 46.4M | break; |
1682 | 46.4M | } |
1683 | | /* checkme: normally, this corresponds to the first |
1684 | | character following a 0xb/0x1, so we do not need to a |
1685 | | column/page break here */ |
1686 | 985k | case ClarisWksTextInternal::P_Child: |
1687 | 1.13M | case ClarisWksTextInternal::P_Section: |
1688 | 1.88M | case ClarisWksTextInternal::P_TextZone: |
1689 | 1.88M | case ClarisWksTextInternal::P_Unknown: |
1690 | | #if !defined(__clang__) |
1691 | | default: |
1692 | | #endif |
1693 | 1.88M | break; |
1694 | 49.4M | } |
1695 | 49.4M | } |
1696 | 241M | auto c = char(input->readULong(1)); |
1697 | 241M | lastIsSectionBreak=(c==0xc); |
1698 | 241M | actC++; |
1699 | 241M | if (c == '\0') { |
1700 | 150M | if (i == numC-1) break; |
1701 | 149M | MWAW_DEBUG_MSG(("ClarisWksText::sendText: OOPS, find 0 reading the text\n")); |
1702 | 149M | f << "###0x0"; |
1703 | 149M | continue; |
1704 | 150M | } |
1705 | 90.4M | f << c; |
1706 | 90.4M | if (seeToken && static_cast<unsigned char>(c) < 32) continue; |
1707 | 89.9M | switch (c) { |
1708 | 8.75M | case 0x1: // fixme: column break |
1709 | 8.75M | if (numCols) { |
1710 | 8.75M | listener->insertBreak(MWAWListener::ColumnBreak); |
1711 | 8.75M | break; |
1712 | 8.75M | } |
1713 | 0 | MWAW_DEBUG_MSG(("ClarisWksText::sendText: Find unexpected char 1\n")); |
1714 | 0 | f << "###"; |
1715 | 0 | MWAW_FALLTHROUGH; |
1716 | 1.14M | case 0xb: // page break |
1717 | 1.14M | numSectionInPage = 0; |
1718 | 1.14M | if (main) |
1719 | 55.9k | m_document.newPage(++actPage); |
1720 | 1.14M | break; |
1721 | 3.77M | case 0x2: // token footnote ( normally already done) |
1722 | 3.77M | break; |
1723 | 1.91M | case 0x3: // token graphic |
1724 | 1.91M | break; |
1725 | 1.15M | case 0x4: |
1726 | 1.15M | listener->insertField(MWAWField(MWAWField::Date)); |
1727 | 1.15M | break; |
1728 | 1.50M | case 0x5: { |
1729 | 1.50M | MWAWField field(MWAWField::Time); |
1730 | 1.50M | field.m_DTFormat="%H:%M"; |
1731 | 1.50M | listener->insertField(field); |
1732 | 1.50M | break; |
1733 | 0 | } |
1734 | 862k | case 0x6: // normally already done, but if we do not find the token, ... |
1735 | 862k | listener->insertField(MWAWField(MWAWField::PageNumber)); |
1736 | 862k | break; |
1737 | 736k | case 0x7: // footnote index (ok to ignore : index of the footnote ) |
1738 | 736k | break; |
1739 | 937k | case 0x8: // potential breaking <<hyphen>> |
1740 | 937k | break; |
1741 | 641k | case 0x9: |
1742 | 641k | listener->insertTab(); |
1743 | 641k | break; |
1744 | 1.96M | case 0xa: |
1745 | 1.96M | listener->insertEOL(true); |
1746 | 1.96M | break; |
1747 | 461k | case 0xc: // new section: this is treated after, at the beginning of the for loop |
1748 | 461k | break; |
1749 | 1.24M | case 0xd: |
1750 | 1.24M | f2.str(""); |
1751 | 1.24M | f2 << "Entries(TextContent):" << f.str(); |
1752 | 1.24M | ascFile.addPos(pos); |
1753 | 1.24M | ascFile.addNote(f2.str().c_str()); |
1754 | 1.24M | f.str(""); |
1755 | 1.24M | pos = input->tell(); |
1756 | | |
1757 | | // ignore last end of line returns |
1758 | 1.24M | if (z != numZones-1 || i != numC-2) |
1759 | 1.22M | listener->insertEOL(); |
1760 | 1.24M | break; |
1761 | | |
1762 | 64.8M | default: { |
1763 | 64.8M | int extraChar = listener->insertCharacter |
1764 | 64.8M | (static_cast<unsigned char>(c), input, input->tell()+(numC-1-i)); |
1765 | 64.8M | if (extraChar) { |
1766 | 147k | i += extraChar; |
1767 | 147k | actC += extraChar; |
1768 | 147k | } |
1769 | 64.8M | } |
1770 | 89.9M | } |
1771 | 89.9M | } |
1772 | 1.79M | if (f.str().length()) { |
1773 | 0 | f2.str(""); |
1774 | 0 | f2 << "Entries(TextContent):" << f.str(); |
1775 | 0 | ascFile.addPos(pos); |
1776 | 0 | ascFile.addNote(f2.str().c_str()); |
1777 | 0 | } |
1778 | 1.79M | } |
1779 | | |
1780 | 1.90M | return true; |
1781 | 1.90M | } |
1782 | | |
1783 | | int ClarisWksText::findListId(ClarisWksTextInternal::Zone const &zone, int actListId, long actC, long &lastPos) |
1784 | 1.86k | { |
1785 | | // retrieve the actual list |
1786 | 1.86k | std::shared_ptr<MWAWList> actList; |
1787 | 1.86k | if (actListId>0) |
1788 | 195 | actList = m_parserState->m_listManager->getList(actListId); |
1789 | | |
1790 | 1.86k | auto numParaPLC= int(zone.m_paragraphList.size()); |
1791 | 1.86k | auto numParagraphs = int(m_state->m_paragraphsList.size()); |
1792 | 1.86k | auto plcIt=zone.m_plcMap.find(actC); |
1793 | 1.86k | int listId = -1; |
1794 | 1.86k | int maxLevelSet = -1; |
1795 | | // find the last position which can correspond to the actual list |
1796 | 11.4k | while (plcIt!=zone.m_plcMap.end()) { |
1797 | 9.60k | lastPos = plcIt->first; |
1798 | 9.60k | auto const &plc = plcIt++->second; |
1799 | 9.60k | if (plc.m_type != ClarisWksTextInternal::P_Ruler) |
1800 | 5.55k | continue; |
1801 | 4.05k | if (plc.m_id < 0 || plc.m_id >= numParaPLC) |
1802 | 0 | break; |
1803 | 4.05k | ClarisWksTextInternal::ParagraphPLC const ¶PLC = zone.m_paragraphList[size_t(plc.m_id)]; |
1804 | 4.05k | if (paraPLC.m_rulerId < 0 || paraPLC.m_rulerId >= numParagraphs) |
1805 | 8 | break; |
1806 | 4.04k | ClarisWksTextInternal::Paragraph const ¶=m_state->m_paragraphsList[size_t(paraPLC.m_rulerId)]; |
1807 | 4.04k | int level = *para.m_listLevelIndex; |
1808 | 4.04k | if (level<=0) |
1809 | 1 | continue; |
1810 | 4.04k | auto newList = m_parserState->m_listManager->getNewList(actList, level, *para.m_listLevel); |
1811 | 4.04k | if (!newList) |
1812 | 0 | break; |
1813 | 4.04k | if (level <= maxLevelSet && newList->getId() != listId) |
1814 | 0 | break; |
1815 | 4.04k | if (level > maxLevelSet) maxLevelSet=level; |
1816 | 4.04k | listId = newList->getId(); |
1817 | 4.04k | actList = newList; |
1818 | 4.04k | } |
1819 | 1.86k | return listId; |
1820 | 1.86k | } |
1821 | | |
1822 | | //////////////////////////////////////////////////////////// |
1823 | | // the style definition? |
1824 | | //////////////////////////////////////////////////////////// |
1825 | | |
1826 | | bool ClarisWksText::readSTYL_RULR(int N, int dataSize) |
1827 | 1.50k | { |
1828 | 1.50k | if (dataSize == 0 || N== 0) return true; |
1829 | 1.50k | if (dataSize != 108) { |
1830 | 5 | MWAW_DEBUG_MSG(("ClarisWksText::readSTYL_RULR: Find odd ruler size %d\n", dataSize)); |
1831 | 5 | } |
1832 | 1.50k | MWAWInputStreamPtr &input= m_parserState->m_input; |
1833 | 1.50k | libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile; |
1834 | 1.50k | libmwaw::DebugStream f; |
1835 | 13.7k | for (int i = 0; i < N; i++) { |
1836 | 12.2k | long pos = input->tell(); |
1837 | 12.2k | if (dataSize != 108 || !readParagraph(i)) { |
1838 | 29 | f.str(""); |
1839 | 29 | if (!i) |
1840 | 5 | f << "Entries(RULR)-P0:#"; |
1841 | 24 | else |
1842 | 24 | f << "RULR-P" << i << ":#"; |
1843 | 29 | ascFile.addPos(pos); |
1844 | 29 | ascFile.addNote(f.str().c_str()); |
1845 | 29 | } |
1846 | 12.2k | input->seek(pos+dataSize, librevenge::RVNG_SEEK_SET); |
1847 | 12.2k | } |
1848 | 1.50k | return true; |
1849 | 1.50k | } |
1850 | | |
1851 | | //////////////////////////////////////////////////////////// |
1852 | | // read a list of rulers |
1853 | | //////////////////////////////////////////////////////////// |
1854 | | bool ClarisWksText::readParagraphs() |
1855 | 84.1k | { |
1856 | 84.1k | MWAWInputStreamPtr &input= m_parserState->m_input; |
1857 | 84.1k | libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile; |
1858 | 84.1k | long pos = input->tell(); |
1859 | 84.1k | ClarisWksStruct::Struct header; |
1860 | 84.1k | if (!header.readHeader(input,true)) { |
1861 | 52.1k | MWAW_DEBUG_MSG(("ClarisWksText::readParagraphs: can not read the header\n")); |
1862 | 52.1k | return false; |
1863 | 52.1k | } |
1864 | 32.0k | if (header.m_size==0) { |
1865 | 23.7k | ascFile.addPos(pos); |
1866 | 23.7k | ascFile.addNote("Nop"); |
1867 | 23.7k | return true; |
1868 | 23.7k | } |
1869 | | |
1870 | 8.27k | libmwaw::DebugStream f; |
1871 | 8.27k | f << "Entries(RULR):" << header; |
1872 | 8.27k | if (header.m_headerSize) { |
1873 | 856 | ascFile.addDelimiter(input->tell(),'|'); |
1874 | 856 | input->seek(header.m_headerSize, librevenge::RVNG_SEEK_CUR); |
1875 | 856 | } |
1876 | | |
1877 | 8.27k | ascFile.addPos(pos); |
1878 | 8.27k | ascFile.addNote(f.str().c_str()); |
1879 | | |
1880 | 1.84M | for (long i = 0; i < header.m_numData; i++) { |
1881 | 1.84M | pos = input->tell(); |
1882 | 1.84M | if (!readParagraph(int(i))) { |
1883 | 6.41k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
1884 | 6.41k | return false; |
1885 | 6.41k | } |
1886 | 1.84M | } |
1887 | 1.85k | return true; |
1888 | 8.27k | } |
1889 | | |
1890 | | //////////////////////////////////////////////////////////// |
1891 | | // read a ruler zone |
1892 | | //////////////////////////////////////////////////////////// |
1893 | | bool ClarisWksText::readParagraph(int id) |
1894 | 2.05M | { |
1895 | 2.05M | int dataSize = 0; |
1896 | 2.05M | int vers = version(); |
1897 | 2.05M | switch (vers) { |
1898 | 360k | case 1: |
1899 | 360k | dataSize = 92; |
1900 | 360k | break; |
1901 | 1.57M | case 2: |
1902 | 1.60M | case 3: |
1903 | 1.60M | dataSize = 96; |
1904 | 1.60M | break; |
1905 | 13.8k | case 4: |
1906 | 61.3k | case 5: |
1907 | 87.8k | case 6: |
1908 | 87.8k | if (id >= 0) dataSize = 108; |
1909 | 75.6k | else dataSize = 96; |
1910 | 87.8k | break; |
1911 | 0 | default: |
1912 | 0 | MWAW_DEBUG_MSG(("ClarisWksText::readParagraph: unknown size\n")); |
1913 | 0 | return false; |
1914 | 2.05M | } |
1915 | | |
1916 | 2.05M | ClarisWksTextInternal::Paragraph ruler; |
1917 | 2.05M | MWAWInputStreamPtr &input= m_parserState->m_input; |
1918 | 2.05M | long pos = input->tell(); |
1919 | 2.05M | long endPos = pos+dataSize; |
1920 | 2.05M | if (!input->checkPosition(endPos)) { |
1921 | 6.41k | MWAW_DEBUG_MSG(("ClarisWksText::readParagraph: the zone seems too short\n")); |
1922 | 6.41k | return false; |
1923 | 6.41k | } |
1924 | 2.04M | libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile; |
1925 | 2.04M | libmwaw::DebugStream f; |
1926 | | |
1927 | 2.04M | int val; |
1928 | 2.04M | if (vers >= 4 && id >= 0) { |
1929 | 12.2k | val = static_cast<int>(input->readLong(2)); |
1930 | 12.2k | if (val != -1) f << "f0=" << val << ","; |
1931 | 12.2k | val = static_cast<int>(input->readLong(4)); |
1932 | 12.2k | f << "f1=" << val << ","; |
1933 | 12.2k | int dim[2]; |
1934 | 24.4k | for (auto &d : dim) d = static_cast<int>(input->readLong(2)); |
1935 | 12.2k | f << "dim?=" << dim[0] << "x" << dim[1] << ","; |
1936 | 12.2k | ruler.m_labelType = static_cast<int>(input->readLong(1)); |
1937 | 12.2k | auto listLevel = static_cast<int>(input->readLong(1)); |
1938 | 12.2k | if (listLevel < 0 || listLevel > 10) { |
1939 | 850 | MWAW_DEBUG_MSG(("ClarisWksText::readParagraph: can not determine list level\n")); |
1940 | 850 | f << "##listLevel=" << listLevel << ","; |
1941 | 850 | listLevel = 0; |
1942 | 850 | } |
1943 | 12.2k | ruler.m_listLevelIndex = listLevel; |
1944 | 12.2k | } |
1945 | | |
1946 | 2.04M | val = static_cast<int>(input->readLong(2)); |
1947 | 2.04M | f << "num[used]=" << val << ","; |
1948 | 2.04M | val = static_cast<int>(input->readULong(2)); |
1949 | 2.04M | int align = 0; |
1950 | 2.04M | switch (vers) { |
1951 | 358k | case 1: |
1952 | 1.92M | case 2: |
1953 | 1.95M | case 3: |
1954 | 1.97M | case 4: |
1955 | 2.01M | case 5: |
1956 | 2.01M | align = (val >> 14); |
1957 | 2.01M | val &= 0x3FFF; |
1958 | 2.01M | break; |
1959 | 26.4k | case 6: |
1960 | 26.4k | align = (val >> 13) & 3; |
1961 | 26.4k | val &= 0x9FFF; |
1962 | 26.4k | break; |
1963 | 0 | default: |
1964 | 0 | break; |
1965 | 2.04M | } |
1966 | 2.04M | switch (align) { |
1967 | 1.52M | case 0: |
1968 | 1.52M | break; |
1969 | 223k | case 1: |
1970 | 223k | ruler.m_justify = MWAWParagraph::JustificationCenter; |
1971 | 223k | break; |
1972 | 102k | case 2: |
1973 | 102k | ruler.m_justify = MWAWParagraph::JustificationRight ; |
1974 | 102k | break; |
1975 | 191k | case 3: |
1976 | 191k | ruler.m_justify = MWAWParagraph::JustificationFull; |
1977 | 191k | break; |
1978 | 0 | default: |
1979 | 0 | break; |
1980 | 2.04M | } |
1981 | | |
1982 | | |
1983 | 2.04M | bool inPoint = false; |
1984 | 2.04M | int interline = 0; |
1985 | 2.04M | switch (vers) { |
1986 | 358k | case 1: |
1987 | 358k | inPoint = (val & 0x2000); |
1988 | 358k | interline = val & 0xFF; |
1989 | 358k | val &= 0x1F00; |
1990 | 358k | break; |
1991 | 1.56M | case 2: |
1992 | 1.59M | case 3: |
1993 | 1.61M | case 4: |
1994 | 1.65M | case 5: |
1995 | 1.68M | case 6: { |
1996 | 1.68M | interline = (val >> 3); |
1997 | 1.68M | bool ok = true; |
1998 | 1.68M | switch (val & 7) { |
1999 | 873k | case 0: // PERCENT |
2000 | 873k | ok = interline <= 18; |
2001 | 873k | inPoint = false; |
2002 | 873k | break; |
2003 | 78.4k | case 6: // display unit pica |
2004 | 199k | case 5: // display unit cm |
2005 | 310k | case 4: // display unit mm |
2006 | 399k | case 3: // display unit Inch |
2007 | 523k | case 2: // display unit point |
2008 | 523k | ok = interline <= 512; |
2009 | 523k | inPoint = true; // data always stored in point |
2010 | 523k | break; |
2011 | 289k | default: |
2012 | 289k | ok = false; |
2013 | 289k | break; |
2014 | 1.68M | } |
2015 | 1.68M | if (ok) val = 0; |
2016 | 789k | else { |
2017 | 789k | MWAW_DEBUG_MSG(("ClarisWksText::readParagraph: can not determine interline dimension\n")); |
2018 | 789k | interline = 0; |
2019 | 789k | } |
2020 | 1.68M | break; |
2021 | 1.68M | } |
2022 | 0 | default: |
2023 | 0 | break; |
2024 | 2.04M | } |
2025 | 2.04M | if (interline) { |
2026 | 469k | if (inPoint) |
2027 | 302k | ruler.setInterline(interline, librevenge::RVNG_POINT); |
2028 | 166k | else |
2029 | 166k | ruler.setInterline(1.0+interline*0.5, librevenge::RVNG_PERCENT); |
2030 | 469k | } |
2031 | 2.04M | if (val) f << "#flags=" << std::hex << val << std::dec << ","; |
2032 | 2.04M | for (auto &margin : ruler.m_margins) |
2033 | 6.13M | margin = double(input->readLong(2))/72.; |
2034 | 2.04M | *(ruler.m_margins[2]) -= 28./72.; |
2035 | 2.04M | if (ruler.m_margins[2].get() < 0.0) ruler.m_margins[2] = 0.0; |
2036 | 2.04M | if (vers >= 2) { |
2037 | 5.05M | for (int i = 0; i < 2; i++) { |
2038 | 3.37M | ruler.m_spacings[i+1] = double(input->readULong(1))/72.; |
2039 | 3.37M | input->seek(1, librevenge::RVNG_SEEK_CUR); // flags to define the printing unit |
2040 | 3.37M | } |
2041 | 1.68M | } |
2042 | 2.04M | val = static_cast<int>(input->readLong(1)); |
2043 | 2.04M | if (val) f << "unkn1=" << val << ","; |
2044 | 2.04M | auto numTabs = static_cast<int>(input->readULong(1)); |
2045 | 2.04M | if (long(input->tell())+numTabs*4 > endPos) { |
2046 | 726k | if (numTabs != 255) { // 0xFF seems to be used in v1, v2 |
2047 | 644k | MWAW_DEBUG_MSG(("ClarisWksText::readParagraph: numTabs is too big\n")); |
2048 | 644k | } |
2049 | 726k | f << "numTabs*=" << numTabs << ","; |
2050 | 726k | numTabs = 0; |
2051 | 726k | } |
2052 | 4.82M | for (int i = 0; i < numTabs; i++) { |
2053 | 2.77M | MWAWTabStop tab; |
2054 | 2.77M | tab.m_position = double(input->readLong(2))/72.; |
2055 | 2.77M | val = static_cast<int>(input->readULong(1)); |
2056 | 2.77M | int leaderType = 0; |
2057 | 2.77M | switch (vers) { |
2058 | 671k | case 1: |
2059 | 671k | align = val & 3; |
2060 | 671k | val &= 0xFC; |
2061 | 671k | break; |
2062 | 2.00M | case 2: |
2063 | 2.03M | case 3: |
2064 | 2.05M | case 4: |
2065 | 2.09M | case 5: |
2066 | 2.09M | align = (val >> 6); |
2067 | 2.09M | leaderType = (val & 3); |
2068 | 2.09M | val &= 0x3C; |
2069 | 2.09M | break; |
2070 | 5.85k | case 6: |
2071 | 5.85k | align = (val >> 5); |
2072 | 5.85k | leaderType = (val & 3); |
2073 | 5.85k | val &= 0x9C; |
2074 | 5.85k | break; |
2075 | 0 | default: |
2076 | 0 | break; |
2077 | 2.77M | } |
2078 | 2.77M | switch (align&3) { |
2079 | 271k | case 1: |
2080 | 271k | tab.m_alignment = MWAWTabStop::CENTER; |
2081 | 271k | break; |
2082 | 217k | case 2: |
2083 | 217k | tab.m_alignment = MWAWTabStop::RIGHT; |
2084 | 217k | break; |
2085 | 252k | case 3: |
2086 | 252k | tab.m_alignment = MWAWTabStop::DECIMAL; |
2087 | 252k | break; |
2088 | 2.03M | case 0: // left |
2089 | 2.03M | default: |
2090 | 2.03M | break; |
2091 | 2.77M | } |
2092 | 2.77M | switch (leaderType) { |
2093 | 395k | case 1: |
2094 | 395k | tab.m_leaderCharacter = '.'; |
2095 | 395k | break; |
2096 | 488k | case 2: |
2097 | 488k | tab.m_leaderCharacter = '-'; |
2098 | 488k | break; |
2099 | 331k | case 3: |
2100 | 331k | tab.m_leaderCharacter = '_'; |
2101 | 331k | break; |
2102 | 1.56M | case 0: |
2103 | 1.56M | default: |
2104 | 1.56M | break; |
2105 | 2.77M | } |
2106 | 2.77M | auto decimalChar = char(input->readULong(1)); |
2107 | 2.77M | if (decimalChar) { |
2108 | 2.08M | int unicode= m_parserState->m_fontConverter->unicode(3, static_cast<unsigned char>(decimalChar)); |
2109 | 2.08M | if (unicode==-1) |
2110 | 1.51M | tab.m_decimalCharacter = uint16_t(decimalChar); |
2111 | 563k | else |
2112 | 563k | tab.m_decimalCharacter = uint16_t(unicode); |
2113 | 2.08M | } |
2114 | 2.77M | ruler.m_tabs->push_back(tab); |
2115 | 2.77M | if (val) |
2116 | 1.78M | f << "#unkn[tab" << i << "=" << std::hex << val << std::dec << "],"; |
2117 | 2.77M | } |
2118 | 2.04M | ruler.updateListLevel(); |
2119 | 2.04M | ruler.m_extra = f.str(); |
2120 | | // save the style |
2121 | 2.04M | if (id >= 0) { |
2122 | 1.85M | if (int(m_state->m_paragraphsList.size()) <= id) |
2123 | 1.85M | m_state->m_paragraphsList.resize(size_t(id+1)); |
2124 | 1.85M | m_state->m_paragraphsList[size_t(id)]=ruler; |
2125 | 1.85M | } |
2126 | 2.04M | f.str(""); |
2127 | 2.04M | if (id == 0) |
2128 | 9.54k | f << "Entries(RULR)-P0"; |
2129 | 2.03M | else if (id < 0) |
2130 | 192k | f << "RULR-P_"; |
2131 | 1.84M | else |
2132 | 1.84M | f << "RULR-P" << id; |
2133 | 2.04M | f << ":" << ruler; |
2134 | | |
2135 | 2.04M | if (long(input->tell()) != pos+dataSize) |
2136 | 2.03M | ascFile.addDelimiter(input->tell(), '|'); |
2137 | 2.04M | ascFile.addPos(pos); |
2138 | 2.04M | ascFile.addNote(f.str().c_str()); |
2139 | 2.04M | input->seek(endPos, librevenge::RVNG_SEEK_SET); |
2140 | 2.04M | if (long(input->tell()) != pos+dataSize) |
2141 | 0 | return false; |
2142 | 2.04M | return true; |
2143 | 2.04M | } |
2144 | | |
2145 | | void ClarisWksText::setProperty(MWAWListener &listener, ClarisWksTextInternal::Paragraph const &ruler, int listId) |
2146 | 54.6k | { |
2147 | 54.6k | if (listId <= 0) { |
2148 | 50.7k | listener.setParagraph(ruler); |
2149 | 50.7k | return; |
2150 | 50.7k | } |
2151 | 3.85k | MWAWParagraph para=ruler; |
2152 | 3.85k | para.m_listId=listId; |
2153 | 3.85k | listener.setParagraph(para); |
2154 | 3.85k | } |
2155 | | |
2156 | | bool ClarisWksText::canSendTextAsGraphic(int number) const |
2157 | 1.95M | { |
2158 | 1.95M | auto iter = m_state->m_zoneMap.find(number); |
2159 | 1.95M | if (iter == m_state->m_zoneMap.end() || !iter->second) |
2160 | 414k | return false; |
2161 | 1.53M | return canSendTextAsGraphic(*iter->second); |
2162 | 1.95M | } |
2163 | | |
2164 | | bool ClarisWksText::sendZone(int number, MWAWListenerPtr const &listener) |
2165 | 2.22M | { |
2166 | 2.22M | auto iter = m_state->m_zoneMap.find(number); |
2167 | 2.22M | if (iter == m_state->m_zoneMap.end()) |
2168 | 420k | return false; |
2169 | 1.80M | sendText(*iter->second, listener); |
2170 | 1.80M | return true; |
2171 | 2.22M | } |
2172 | | |
2173 | | void ClarisWksText::flushExtra() |
2174 | 104k | { |
2175 | 104k | std::shared_ptr<MWAWListener> listener=m_parserState->getMainListener(); |
2176 | 104k | if (!listener) return; |
2177 | 210k | for (auto const &iter :m_state->m_zoneMap) { |
2178 | 210k | std::shared_ptr<ClarisWksTextInternal::Zone> zone = iter.second; |
2179 | 210k | if (!zone || zone->m_parsed) |
2180 | 107k | continue; |
2181 | 102k | listener->insertEOL(); |
2182 | 102k | if (zone->m_parsed) // can be a header/footer in draw zone |
2183 | 192 | continue; |
2184 | 101k | sendText(*zone, listener); |
2185 | 101k | } |
2186 | 104k | } |
2187 | | |
2188 | | // vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: |