/src/libmwaw/src/lib/ActaParser.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 <set> |
38 | | #include <sstream> |
39 | | |
40 | | #include <librevenge/librevenge.h> |
41 | | |
42 | | #include "MWAWTextListener.hxx" |
43 | | #include "MWAWFontConverter.hxx" |
44 | | #include "MWAWHeader.hxx" |
45 | | #include "MWAWList.hxx" |
46 | | #include "MWAWParagraph.hxx" |
47 | | #include "MWAWPosition.hxx" |
48 | | #include "MWAWPrinter.hxx" |
49 | | #include "MWAWRSRCParser.hxx" |
50 | | #include "MWAWSubDocument.hxx" |
51 | | |
52 | | #include "ActaText.hxx" |
53 | | |
54 | | #include "ActaParser.hxx" |
55 | | |
56 | | /** Internal: the structures of a ActaParser */ |
57 | | namespace ActaParserInternal |
58 | | { |
59 | | //////////////////////////////////////// |
60 | | //! Internal: class used to store a list type in ActaParser |
61 | | struct Label { |
62 | | //! constructor |
63 | | explicit Label(int type=-1) |
64 | 45.1k | : m_type(type) { } |
65 | | //! operator<< |
66 | | friend std::ostream &operator<<(std::ostream &o, Label const &lbl) |
67 | 0 | { |
68 | 0 | switch (lbl.m_type) { |
69 | 0 | case 0: |
70 | 0 | o << "noLabel,"; |
71 | 0 | break; |
72 | 0 | case 2: |
73 | 0 | o << "checkbox,"; |
74 | 0 | break; |
75 | 0 | case 0xb: |
76 | 0 | o << "decimal,"; // 1.0, |
77 | 0 | break; |
78 | 0 | case 0xc: |
79 | 0 | o << "I A...,"; |
80 | 0 | break; |
81 | 0 | case 0xe: |
82 | 0 | o << "custom,"; |
83 | 0 | break; |
84 | 0 | default: |
85 | 0 | o << "#labelType=" << lbl.m_type << ","; |
86 | 0 | break; |
87 | 0 | } |
88 | 0 | return o; |
89 | 0 | } |
90 | | //! operator== |
91 | | bool operator==(Label const &lbl) const |
92 | 1.59k | { |
93 | 1.59k | return m_type==lbl.m_type; |
94 | 1.59k | } |
95 | | //! operator=! |
96 | | bool operator!=(Label const &lbl) const |
97 | 1.59k | { |
98 | 1.59k | return !operator==(lbl); |
99 | 1.59k | } |
100 | | //! the label type |
101 | | int m_type; |
102 | | }; |
103 | | |
104 | | //////////////////////////////////////// |
105 | | //! Internal: class used to store the printing preferences in ActaParser |
106 | | struct Printing { |
107 | | //! constructor |
108 | | Printing() |
109 | 44.0k | : m_font() |
110 | 44.0k | { |
111 | 44.0k | for (int &flag : m_flags) |
112 | 88.1k | flag=0; |
113 | 44.0k | } |
114 | | //! returns true if the header is empty |
115 | | bool isEmpty() const |
116 | 6.27k | { |
117 | 6.27k | return (m_flags[1]&7)==0; |
118 | 6.27k | } |
119 | | //! operator== |
120 | | bool operator==(Printing const &print) const |
121 | 0 | { |
122 | 0 | if (m_font != print.m_font) |
123 | 0 | return false; |
124 | 0 | for (int i=0; i<2; i++) { |
125 | 0 | if (m_flags[i]!=print.m_flags[i]) |
126 | 0 | return false; |
127 | 0 | } |
128 | 0 | return true; |
129 | 0 | } |
130 | | //! operator=! |
131 | | bool operator!=(Printing const &print) const |
132 | 0 | { |
133 | 0 | return !operator==(print); |
134 | 0 | } |
135 | | //! operator<< |
136 | | friend std::ostream &operator<<(std::ostream &o, Printing const &print) |
137 | 0 | { |
138 | 0 | if (print.m_flags[0]==1) |
139 | 0 | o << "useFooter,"; |
140 | 0 | else if (print.m_flags[0]) |
141 | 0 | o << "#fl0=" << print.m_flags[0] << ","; |
142 | 0 | int flag = print.m_flags[1]; |
143 | 0 | if (flag&1) |
144 | 0 | o << "title,"; |
145 | 0 | if (flag&2) |
146 | 0 | o << "date,"; |
147 | 0 | if (flag&4) |
148 | 0 | o << "pagenumber,"; |
149 | 0 | flag &= 0xFFF8; |
150 | 0 | if (flag) |
151 | 0 | o << "#flags=" << std::hex << flag << std::dec << ","; |
152 | 0 | return o; |
153 | 0 | } |
154 | | //! the font |
155 | | MWAWFont m_font; |
156 | | //! the flags |
157 | | int m_flags[2]; |
158 | | }; |
159 | | |
160 | | //////////////////////////////////////// |
161 | | //! Internal: class used to store the optional preferences in ActaParser |
162 | | struct Option { |
163 | | //! constructor |
164 | | explicit Option(int flags=0) |
165 | 1.86k | : m_flags(flags) { } |
166 | | //! operator<< |
167 | | friend std::ostream &operator<<(std::ostream &o, Option const &opt) |
168 | 0 | { |
169 | 0 | int flag = opt.m_flags; |
170 | 0 | if (flag&0x1000) |
171 | 0 | o << "speaker[dial],"; |
172 | 0 | if (flag&0x4) |
173 | 0 | o << "smart['\"],"; |
174 | 0 | if (flag&0x8) |
175 | 0 | o << "open[startup],"; |
176 | 0 | // flag&0x10: always ? |
177 | 0 | if (flag&0x20) |
178 | 0 | o << "nolabel[picture],"; |
179 | 0 | if (flag&0x40) |
180 | 0 | o << "noframe[current],"; |
181 | 0 | if (flag&0x80) |
182 | 0 | o << "nolabel[clipboard],"; |
183 | 0 |
|
184 | 0 | flag &= 0xEF13; |
185 | 0 | if (flag) // find also flag&(10|400|4000|8000) |
186 | 0 | o << "option[flags]=" << std::hex << flag << std::dec << ","; |
187 | 0 | return o; |
188 | 0 | } |
189 | | //! the flags |
190 | | int m_flags; |
191 | | }; |
192 | | |
193 | | //////////////////////////////////////// |
194 | | //! Internal: the state of a ActaParser |
195 | | struct State { |
196 | | //! constructor |
197 | | State() |
198 | 43.5k | : m_printerPreferences() |
199 | 43.5k | , m_title("") |
200 | 43.5k | , m_label() |
201 | 43.5k | , m_stringLabel("") |
202 | 43.5k | , m_actPage(0) |
203 | 43.5k | , m_numPages(0) |
204 | 43.5k | , m_headerHeight(0) |
205 | 43.5k | , m_footerHeight(0) |
206 | 43.5k | { |
207 | 43.5k | } |
208 | | |
209 | | //! the printer preferences |
210 | | Printing m_printerPreferences; |
211 | | //! the title (if defined) |
212 | | std::string m_title; |
213 | | //! the list type |
214 | | Label m_label; |
215 | | //! the custom label (if defined) |
216 | | std::string m_stringLabel; |
217 | | int m_actPage /** the actual page */, m_numPages /** the number of page of the final document */; |
218 | | |
219 | | int m_headerHeight /** the header height if known */, |
220 | | m_footerHeight /** the footer height if known */; |
221 | | }; |
222 | | |
223 | | //////////////////////////////////////// |
224 | | //! Internal: the subdocument of a ActaParser |
225 | | class SubDocument final : public MWAWSubDocument |
226 | | { |
227 | | public: |
228 | | SubDocument(ActaParser &pars, MWAWInputStreamPtr const &input) : |
229 | 2 | MWAWSubDocument(&pars, input, MWAWEntry()) {} |
230 | | |
231 | | //! destructor |
232 | 0 | ~SubDocument() final {} |
233 | | |
234 | | //! operator!= |
235 | | bool operator!=(MWAWSubDocument const &doc) const final |
236 | 0 | { |
237 | 0 | if (MWAWSubDocument::operator!=(doc)) return true; |
238 | 0 | auto const *sDoc = dynamic_cast<SubDocument const *>(&doc); |
239 | 0 | if (!sDoc) return true; |
240 | 0 | return false; |
241 | 0 | } |
242 | | |
243 | | //! the parser function |
244 | | void parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType type) final; |
245 | | |
246 | | protected: |
247 | | }; |
248 | | |
249 | | void SubDocument::parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType /*type*/) |
250 | 2 | { |
251 | 2 | if (!listener.get()) { |
252 | 0 | MWAW_DEBUG_MSG(("ActaParserInternal::SubDocument::parse: no listener\n")); |
253 | 0 | return; |
254 | 0 | } |
255 | 2 | auto *parser=dynamic_cast<ActaParser *>(m_parser); |
256 | 2 | if (!parser) { |
257 | 0 | MWAW_DEBUG_MSG(("ActaParserInternal::SubDocument::parse: can not find main parser\n")); |
258 | 0 | return; |
259 | 0 | } |
260 | 2 | parser->sendHeaderFooter(); |
261 | 2 | } |
262 | | } |
263 | | |
264 | | |
265 | | //////////////////////////////////////////////////////////// |
266 | | // constructor/destructor, ... |
267 | | //////////////////////////////////////////////////////////// |
268 | | ActaParser::ActaParser(MWAWInputStreamPtr const &input, MWAWRSRCParserPtr const &rsrcParser, MWAWHeader *header) |
269 | 18.3k | : MWAWTextParser(input, rsrcParser, header) |
270 | 18.3k | , m_state() |
271 | 18.3k | , m_textParser() |
272 | 18.3k | { |
273 | 18.3k | init(); |
274 | 18.3k | } |
275 | | |
276 | | ActaParser::~ActaParser() |
277 | 18.3k | { |
278 | 18.3k | } |
279 | | |
280 | | void ActaParser::init() |
281 | 18.3k | { |
282 | 18.3k | resetTextListener(); |
283 | 18.3k | setAsciiName("main-1"); |
284 | | |
285 | 18.3k | m_state.reset(new ActaParserInternal::State); |
286 | | |
287 | | // reduce the margin (in case, the page is not defined) |
288 | 18.3k | getPageSpan().setMargins(0.1); |
289 | | |
290 | 18.3k | m_textParser.reset(new ActaText(*this)); |
291 | 18.3k | } |
292 | | |
293 | | MWAWInputStreamPtr ActaParser::rsrcInput() |
294 | 1.08k | { |
295 | 1.08k | return getRSRCParser()->getInput(); |
296 | 1.08k | } |
297 | | |
298 | | libmwaw::DebugFile &ActaParser::rsrcAscii() |
299 | 1.08k | { |
300 | 1.08k | return getRSRCParser()->ascii(); |
301 | 1.08k | } |
302 | | |
303 | | //////////////////////////////////////////////////////////// |
304 | | // position and height |
305 | | //////////////////////////////////////////////////////////// |
306 | | MWAWVec2f ActaParser::getPageLeftTop() const |
307 | 0 | { |
308 | 0 | return MWAWVec2f(float(getPageSpan().getMarginLeft()), |
309 | 0 | float(getPageSpan().getMarginTop()+m_state->m_headerHeight/72.0)); |
310 | 0 | } |
311 | | |
312 | | //////////////////////////////////////////////////////////// |
313 | | // interface with the text parser |
314 | | //////////////////////////////////////////////////////////// |
315 | | |
316 | | std::shared_ptr<MWAWList> ActaParser::getMainList() |
317 | 6.27k | { |
318 | 6.27k | MWAWListLevel level; |
319 | 6.27k | level.m_labelAfterSpace=0.05; |
320 | 6.27k | std::vector<MWAWListLevel> levels; |
321 | 6.27k | switch (m_state->m_label.m_type) { |
322 | 188 | case 0: // none |
323 | 188 | level.m_type=MWAWListLevel::NONE; |
324 | 188 | levels.resize(10, level); |
325 | 188 | break; |
326 | 5 | case 2: // checkbox |
327 | 5 | level.m_type=MWAWListLevel::BULLET; |
328 | 5 | libmwaw::appendUnicode(0x2610, level.m_bullet); |
329 | 5 | levels.resize(10, level); |
330 | 5 | break; |
331 | 0 | case 0xb: // 1.0 1.1 1.1.1 1.1.1.1 1.1.1.1.1 ... |
332 | 0 | level.m_suffix = "."; |
333 | 0 | level.m_type=MWAWListLevel::DECIMAL; |
334 | 0 | for (int i=0; i < 10; i++) { |
335 | 0 | level.m_numBeforeLabels=i; |
336 | 0 | levels.push_back(level); |
337 | 0 | } |
338 | 0 | break; |
339 | 0 | case 0xc: // I. A. 1. a. i. [(1). (a). ]* |
340 | 0 | level.m_suffix = "."; |
341 | 0 | level.m_type=MWAWListLevel::UPPER_ROMAN; |
342 | 0 | levels.push_back(level); |
343 | 0 | level.m_type=MWAWListLevel::UPPER_ALPHA; |
344 | 0 | levels.push_back(level); |
345 | 0 | level.m_type=MWAWListLevel::DECIMAL; |
346 | 0 | levels.push_back(level); |
347 | 0 | level.m_type=MWAWListLevel::LOWER_ALPHA; |
348 | 0 | levels.push_back(level); |
349 | 0 | level.m_type=MWAWListLevel::LOWER_ROMAN; |
350 | 0 | levels.push_back(level); |
351 | 0 | level.m_prefix = "("; |
352 | 0 | level.m_suffix = ")."; |
353 | 0 | for (int i=0; i < 4; i++) { |
354 | 0 | level.m_type=MWAWListLevel::DECIMAL; |
355 | 0 | levels.push_back(level); |
356 | 0 | level.m_type=MWAWListLevel::LOWER_ALPHA; |
357 | 0 | levels.push_back(level); |
358 | 0 | } |
359 | 0 | break; |
360 | 6.08k | default: // ok, switch to custom or by default bullet |
361 | 6.08k | case 0xe: { //custom |
362 | 6.08k | level.m_type=MWAWListLevel::BULLET; |
363 | 6.08k | libmwaw::appendUnicode(0x2022, level.m_bullet); |
364 | 6.08k | auto fontConvert=getFontConverter(); |
365 | 6.08k | if (!fontConvert) { |
366 | 0 | MWAW_DEBUG_MSG(("ActaParser::getMainList: can not find the listener\n")); |
367 | 0 | } |
368 | 6.08k | else { |
369 | 25.1k | for (size_t i=0; i<m_state->m_stringLabel.size(); ++i) { // checkme |
370 | 19.1k | int unicode=fontConvert->unicode(3, static_cast<unsigned char>(m_state->m_stringLabel[1])); |
371 | 19.1k | level.m_bullet=""; |
372 | 19.1k | libmwaw::appendUnicode((unicode > 0) ? uint32_t(unicode):0x2022, level.m_bullet); |
373 | 19.1k | levels.push_back(level); |
374 | 19.1k | } |
375 | 6.08k | } |
376 | 62.1k | while (levels.size() < 10) |
377 | 56.1k | levels.push_back(level); |
378 | 6.08k | break; |
379 | 6.08k | } |
380 | 6.27k | } |
381 | 6.27k | std::shared_ptr<MWAWList> list; |
382 | 6.27k | MWAWListManagerPtr listManager=getParserState()->m_listManager; |
383 | 6.27k | if (!listManager) { |
384 | 0 | MWAW_DEBUG_MSG(("ActaParser::getMainList: can not find the list manager\n")); |
385 | 0 | return list; |
386 | 0 | } |
387 | | |
388 | 83.4k | for (size_t s=0; s < levels.size(); s++) { |
389 | 77.1k | list = listManager->getNewList(list, int(s+1), levels[s]); |
390 | 77.1k | if (!list) break; |
391 | 77.1k | } |
392 | 6.27k | return list; |
393 | 6.27k | } |
394 | | //////////////////////////////////////////////////////////// |
395 | | // new page |
396 | | //////////////////////////////////////////////////////////// |
397 | | void ActaParser::newPage(int number) |
398 | 10.3k | { |
399 | 10.3k | if (number <= m_state->m_actPage || number > m_state->m_numPages) |
400 | 0 | return; |
401 | | |
402 | 22.6k | while (m_state->m_actPage < number) { |
403 | 12.3k | m_state->m_actPage++; |
404 | 12.3k | if (!getTextListener() || m_state->m_actPage == 1) |
405 | 1.96k | continue; |
406 | 10.3k | getTextListener()->insertBreak(MWAWTextListener::PageBreak); |
407 | 10.3k | } |
408 | 10.3k | } |
409 | | |
410 | | //////////////////////////////////////////////////////////// |
411 | | // the parser |
412 | | //////////////////////////////////////////////////////////// |
413 | | void ActaParser::parse(librevenge::RVNGTextInterface *docInterface) |
414 | 6.80k | { |
415 | 6.80k | if (!getInput().get() || !checkHeader(nullptr)) throw(libmwaw::ParseException()); |
416 | 6.80k | bool ok = false; |
417 | 6.80k | try { |
418 | | // create the asciiFile |
419 | 6.80k | ascii().setStream(getInput()); |
420 | 6.80k | ascii().open(asciiName()); |
421 | | |
422 | 6.80k | checkHeader(nullptr); |
423 | 6.80k | ok = createZones(); |
424 | 6.80k | if (ok) { |
425 | 6.27k | createDocument(docInterface); |
426 | 6.27k | m_textParser->sendMainText(); |
427 | 6.27k | } |
428 | 6.80k | ascii().reset(); |
429 | 6.80k | } |
430 | 6.80k | catch (...) { |
431 | 0 | MWAW_DEBUG_MSG(("ActaParser::parse: exception catched when parsing\n")); |
432 | 0 | ok = false; |
433 | 0 | } |
434 | | |
435 | 6.80k | resetTextListener(); |
436 | 6.80k | if (!ok) throw(libmwaw::ParseException()); |
437 | 6.80k | } |
438 | | |
439 | | //////////////////////////////////////////////////////////// |
440 | | // create the document |
441 | | //////////////////////////////////////////////////////////// |
442 | | void ActaParser::createDocument(librevenge::RVNGTextInterface *documentInterface) |
443 | 6.27k | { |
444 | 6.27k | if (!documentInterface) return; |
445 | 6.27k | if (getTextListener()) { |
446 | 0 | MWAW_DEBUG_MSG(("ActaParser::createDocument: listener already exist\n")); |
447 | 0 | return; |
448 | 0 | } |
449 | | |
450 | | // update the page |
451 | 6.27k | m_state->m_actPage = 0; |
452 | | |
453 | | // create the page list |
454 | 6.27k | int numPages = 1; |
455 | 6.27k | if (m_textParser->numPages() > numPages) |
456 | 1.96k | numPages = m_textParser->numPages(); |
457 | 6.27k | m_state->m_numPages = numPages; |
458 | | |
459 | 6.27k | MWAWPageSpan ps(getPageSpan()); |
460 | 6.27k | ps.setPageSpan(m_state->m_numPages+1); |
461 | 6.27k | if (!m_state->m_printerPreferences.isEmpty()) { |
462 | 2 | MWAWHeaderFooter hF(m_state->m_printerPreferences.m_flags[0]!=1 ? |
463 | 2 | MWAWHeaderFooter::HEADER : MWAWHeaderFooter::FOOTER, |
464 | 2 | MWAWHeaderFooter::ALL); |
465 | 2 | hF.m_subDocument.reset(new ActaParserInternal::SubDocument(*this, getInput())); |
466 | 2 | ps.setHeaderFooter(hF); |
467 | 2 | } |
468 | 6.27k | std::vector<MWAWPageSpan> pageList(1,ps); |
469 | 6.27k | MWAWTextListenerPtr listen(new MWAWTextListener(*getParserState(), pageList, documentInterface)); |
470 | 6.27k | setTextListener(listen); |
471 | 6.27k | listen->startDocument(); |
472 | 6.27k | } |
473 | | |
474 | | void ActaParser::sendHeaderFooter() |
475 | 2 | { |
476 | 2 | MWAWTextListenerPtr listener=getTextListener(); |
477 | 2 | if (!listener) { |
478 | 0 | MWAW_DEBUG_MSG(("ActaParser::sendHeaderFooter: can not find the listener\n")); |
479 | 0 | return; |
480 | 0 | } |
481 | 2 | auto const &print=m_state->m_printerPreferences; |
482 | 2 | MWAWParagraph para; |
483 | 2 | para.m_justify=MWAWParagraph::JustificationCenter; |
484 | 2 | listener->setParagraph(para); |
485 | 2 | listener->setFont(print.m_font); |
486 | 2 | bool printDone=false; |
487 | 8 | for (int i=0, wh=1; i < 3; i++, wh*=2) { |
488 | 6 | if ((print.m_flags[1]&wh)==0) |
489 | 1 | continue; |
490 | 5 | if (printDone) |
491 | 3 | listener->insertChar(' '); |
492 | 5 | switch (i) { |
493 | 2 | case 0: |
494 | 2 | if (!m_state->m_title.length()) { |
495 | 1 | listener->insertField(MWAWField(MWAWField::Title)); |
496 | 1 | break; |
497 | 1 | } |
498 | 1 | for (auto c : m_state->m_title) |
499 | 4 | listener->insertCharacter(static_cast<unsigned char>(c)); |
500 | 1 | break; |
501 | 2 | case 1: { |
502 | 2 | MWAWField field(MWAWField::Date); |
503 | 2 | field.m_DTFormat="%b %d, %Y"; |
504 | 2 | listener->insertField(field); |
505 | 2 | break; |
506 | 2 | } |
507 | 1 | case 2: |
508 | 1 | listener->insertField(MWAWField(MWAWField::PageNumber)); |
509 | 1 | break; |
510 | 0 | default: |
511 | 0 | MWAW_DEBUG_MSG(("ActaParser::sendHeaderFooter: unexpected step\n")); |
512 | 0 | break; |
513 | 5 | } |
514 | 5 | printDone=true; |
515 | 5 | } |
516 | 2 | if (!printDone) |
517 | 0 | listener->insertChar(' '); |
518 | 2 | } |
519 | | |
520 | | //////////////////////////////////////////////////////////// |
521 | | // |
522 | | // Intermediate level |
523 | | // |
524 | | //////////////////////////////////////////////////////////// |
525 | | bool ActaParser::createZones() |
526 | 6.80k | { |
527 | 6.80k | MWAWInputStreamPtr input = getInput(); |
528 | 6.80k | readRSRCZones(); |
529 | 6.80k | if (version()>=3) { |
530 | 1.79k | input->setReadInverted(true); |
531 | 1.79k | if (!readEndDataV3()) { |
532 | 201 | ascii().addPos(input->tell()); |
533 | 201 | ascii().addNote("Entries(Loose)"); |
534 | 201 | } |
535 | 1.79k | input->setReadInverted(false); |
536 | 1.79k | } |
537 | 6.80k | return m_textParser->createZones(); |
538 | 6.80k | } |
539 | | |
540 | | bool ActaParser::readRSRCZones() |
541 | 6.80k | { |
542 | 6.80k | MWAWRSRCParserPtr rsrcParser = getRSRCParser(); |
543 | 6.80k | if (!rsrcParser) |
544 | 5.96k | return true; |
545 | 840 | if (version() < 3) { // never seens so, better ignore |
546 | 1 | MWAW_DEBUG_MSG(("ActaParser::readRSRCZones: find a resource fork in v1-v2!!!\n")); |
547 | 1 | return false; |
548 | 1 | } |
549 | | |
550 | | |
551 | 839 | auto const &entryMap = rsrcParser->getEntriesMap(); |
552 | | |
553 | | // STR:0 -> title name, STR:1 custom label |
554 | 839 | auto it = entryMap.lower_bound("STR "); |
555 | 1.65k | while (it != entryMap.end()) { |
556 | 1.46k | if (it->first != "STR ") |
557 | 649 | break; |
558 | 815 | MWAWEntry const &entry = it++->second; |
559 | 815 | entry.setParsed(true); |
560 | 815 | std::string str(""); |
561 | 815 | if (!rsrcParser->parseSTR(entry,str) || str.length()==0) |
562 | 687 | continue; |
563 | 128 | switch (entry.id()) { |
564 | 10 | case 0: |
565 | 10 | m_state->m_title=str; |
566 | 10 | break; |
567 | 30 | case 1: |
568 | 30 | m_state->m_stringLabel=str; |
569 | 30 | break; |
570 | 88 | default: |
571 | 88 | MWAW_DEBUG_MSG(("ActaParser::readRSRCZones: find unexpected STR:%d\n", entry.id())); |
572 | 88 | break; |
573 | 128 | } |
574 | 128 | } |
575 | | // the 0 zone |
576 | 839 | char const *zNames[] = {"PSET", "WSIZ", "LABL", "QOPT", "QHDR"}; |
577 | 5.03k | for (int z = 0; z < 5; z++) { |
578 | 4.19k | it = entryMap.lower_bound(zNames[z]); |
579 | 7.48k | while (it != entryMap.end()) { |
580 | 6.60k | if (it->first != zNames[z]) |
581 | 3.31k | break; |
582 | 3.28k | MWAWEntry const &entry = it++->second; |
583 | 3.28k | switch (z) { |
584 | 466 | case 0: |
585 | 466 | readPrintInfo(entry); |
586 | 466 | break; |
587 | 662 | case 1: |
588 | 662 | readWindowPos(entry); |
589 | 662 | break; |
590 | 767 | case 2: |
591 | 767 | readLabel(entry); |
592 | 767 | break; |
593 | 511 | case 3: |
594 | 511 | readOption(entry); |
595 | 511 | break; |
596 | 883 | case 4: |
597 | 883 | readHFProperties(entry); |
598 | 883 | break; |
599 | 0 | default: |
600 | 0 | break; |
601 | 3.28k | } |
602 | 3.28k | } |
603 | 4.19k | } |
604 | 839 | return true; |
605 | 839 | } |
606 | | |
607 | | bool ActaParser::readEndDataV3() |
608 | 1.79k | { |
609 | 1.79k | if (version()<3) |
610 | 0 | return true; |
611 | 1.79k | MWAWInputStreamPtr input = getInput(); |
612 | 1.79k | libmwaw::DebugStream f; |
613 | 1.79k | input->seek(-8, librevenge::RVNG_SEEK_END); |
614 | 1.79k | ascii().addPos(input->tell()); |
615 | 1.79k | auto pos=static_cast<long>(input->readULong(4)); |
616 | 1.79k | if (pos < 18 || !input->checkPosition(pos)) { |
617 | 201 | MWAW_DEBUG_MSG(("ActaParser::readEndDataV3: oops begin of ressource is bad\n")); |
618 | 201 | ascii().addNote("###"); |
619 | 201 | return false; |
620 | 201 | } |
621 | 1.59k | ascii().addNote("_"); |
622 | | |
623 | 1.59k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
624 | | |
625 | 1.59k | f << "Entries(QOpt):"; |
626 | 1.59k | ActaParserInternal::Label lbl(static_cast<int>(input->readLong(1))); |
627 | 1.59k | f << lbl << ","; |
628 | 1.59k | if (m_state->m_label!=lbl) { |
629 | 1.38k | if (m_state->m_label.m_type) { |
630 | 1.36k | MWAW_DEBUG_MSG(("ActaParser::readEndDataV3: oops the label seems set and different\n")); |
631 | 1.36k | } |
632 | 21 | else |
633 | 21 | m_state->m_label = lbl; |
634 | 1.38k | } |
635 | 1.59k | auto val=static_cast<int>(input->readLong(1)); |
636 | 1.59k | if (val != 1) // always 1 |
637 | 848 | f << "f0=" << val << ","; |
638 | 1.59k | ActaParserInternal::Option opt(static_cast<int>(input->readULong(2))); |
639 | 1.59k | f << opt; |
640 | | // string: name, followed by abbreviation |
641 | 4.69k | for (int i = 0; i < 2; i++) { |
642 | 3.15k | long fPos=input->tell(); |
643 | 3.15k | auto fSz = static_cast<int>(input->readULong(1)); |
644 | 3.15k | if (!input->checkPosition(fPos+fSz+1)) { |
645 | 58 | MWAW_DEBUG_MSG(("ActaText::readEndDataV3: can not read following string\n")); |
646 | 58 | f << "###"; |
647 | 58 | ascii().addPos(pos); |
648 | 58 | ascii().addNote(f.str().c_str()); |
649 | 58 | return true; |
650 | 58 | } |
651 | 3.10k | if (!fSz) continue; |
652 | 1.68k | std::string str(""); |
653 | 45.3k | for (int s=0; s < fSz; s++) |
654 | 43.6k | str+=static_cast<char>(input->readULong(1)); |
655 | 1.68k | if (!str.length()) |
656 | 0 | continue; |
657 | 1.68k | f << "str" << i << "=" << str << ","; |
658 | 1.68k | std::string &which=(i==0) ? m_state->m_title : m_state->m_stringLabel; |
659 | 1.68k | if (which.length()) { |
660 | 30 | if (which != str) { |
661 | 15 | MWAW_DEBUG_MSG(("ActaText::readEndDataV3: find a different string\n")); |
662 | 15 | f << "###"; |
663 | 15 | } |
664 | 30 | continue; |
665 | 30 | } |
666 | 1.65k | which = str; |
667 | 1.65k | } |
668 | 1.54k | val=static_cast<int>(input->readLong(1)); |
669 | 1.54k | if (val) // always 0 or a another string |
670 | 535 | f << "f1=" << val << ","; |
671 | | |
672 | | // from here unknown: maybe related to the printer definition... |
673 | 1.54k | float dim[2]; |
674 | 1.54k | for (float &i : dim) // very unsure... |
675 | 3.08k | i = float(input->readULong(2))/256.f; |
676 | 1.54k | f << "dim?=" << dim[1] << "x" << dim[0] << ","; |
677 | 1.54k | ascii().addPos(pos); |
678 | 1.54k | ascii().addNote(f.str().c_str()); |
679 | | |
680 | 1.54k | pos = input->tell(); |
681 | 1.54k | f.str(""); |
682 | 1.54k | f << "Entries(Loose):"; |
683 | 1.54k | auto type = static_cast<int>(input->readULong(1)); |
684 | 1.54k | f << "type?=" << std::hex << type << ","; |
685 | 1.54k | ascii().addPos(pos); |
686 | 1.54k | ascii().addNote("Entries(Loose)"); |
687 | | |
688 | 1.54k | if (type!=255 || !input->checkPosition(pos+200)) |
689 | 1.16k | return true; |
690 | | |
691 | 379 | input->seek(pos+198, librevenge::RVNG_SEEK_SET); |
692 | 379 | pos = input->tell(); |
693 | 379 | auto N=static_cast<int>(input->readLong(2)); |
694 | 379 | if (N<0 || !input->checkPosition(pos+2+34*N)) |
695 | 60 | return true; |
696 | 319 | f.str(""); |
697 | 319 | f << "Entries(Font):N=" << N << ","; |
698 | 319 | ascii().addPos(pos); |
699 | 319 | ascii().addNote(f.str().c_str()); |
700 | 32.1k | for (int i= 0; i < N; i++) { |
701 | 31.8k | pos=input->tell(); |
702 | 31.8k | f.str(""); |
703 | 31.8k | f << "Font-" << i << ":"; |
704 | 31.8k | std::string str(""); |
705 | 404k | while (input->tell()<pos+32) { |
706 | 395k | auto c=static_cast<char>(input->readULong(1)); |
707 | 395k | if (!c) break; |
708 | 372k | str+=c; |
709 | 372k | } |
710 | 31.8k | if (str.length()) |
711 | 21.0k | f << str << ","; |
712 | 31.8k | input->seek(pos+32, librevenge::RVNG_SEEK_SET); |
713 | 95.4k | for (int j = 0; j < 2; j++) { |
714 | 63.6k | val = static_cast<int>(input->readLong(1)); |
715 | 63.6k | if (val) f << "f" << j << "=" << std::hex << val << std::dec << ","; |
716 | 63.6k | } |
717 | 31.8k | ascii().addPos(pos); |
718 | 31.8k | ascii().addNote(f.str().c_str()); |
719 | 31.8k | } |
720 | | |
721 | 319 | pos = input->tell(); |
722 | 319 | ascii().addPos(pos); |
723 | 319 | ascii().addNote("Entries(Loose)[II]"); |
724 | 319 | return true; |
725 | 379 | } |
726 | | |
727 | | //////////////////////////////////////////////////////////// |
728 | | // read the print info |
729 | | //////////////////////////////////////////////////////////// |
730 | | bool ActaParser::readPrintInfo(MWAWEntry const &entry) |
731 | 466 | { |
732 | 466 | if (!entry.valid() || entry.length() != 120) { |
733 | 351 | MWAW_DEBUG_MSG(("ActaParser::readPrintInfo: the entry is bad\n")); |
734 | 351 | return false; |
735 | 351 | } |
736 | | |
737 | 115 | long pos = entry.begin(); |
738 | 115 | MWAWInputStreamPtr input = rsrcInput(); |
739 | 115 | libmwaw::DebugFile &ascFile = rsrcAscii(); |
740 | 115 | libmwaw::DebugStream f; |
741 | | |
742 | 115 | input->seek(pos, librevenge::RVNG_SEEK_SET); |
743 | 115 | libmwaw::PrinterInfo info; |
744 | 115 | if (!info.read(input)) return false; |
745 | 54 | f << "Entries(PrintInfo):"<< info; |
746 | 54 | entry.setParsed(true); |
747 | | |
748 | 54 | MWAWVec2i paperSize = info.paper().size(); |
749 | 54 | MWAWVec2i pageSize = info.page().size(); |
750 | 54 | if (pageSize.x() <= 0 || pageSize.y() <= 0 || |
751 | 54 | paperSize.x() <= 0 || paperSize.y() <= 0) return false; |
752 | | |
753 | | // define margin from print info |
754 | 54 | MWAWVec2i lTopMargin= -1 * info.paper().pos(0); |
755 | 54 | MWAWVec2i rBotMargin=info.paper().pos(1) - info.page().pos(1); |
756 | | |
757 | | // move margin left | top |
758 | 54 | int decalX = lTopMargin.x() > 14 ? lTopMargin.x()-14 : 0; |
759 | 54 | int decalY = lTopMargin.y() > 14 ? lTopMargin.y()-14 : 0; |
760 | 54 | lTopMargin -= MWAWVec2i(decalX, decalY); |
761 | 54 | rBotMargin += MWAWVec2i(decalX, decalY); |
762 | | |
763 | | // decrease right | bottom |
764 | 54 | int rightMarg = rBotMargin.x() -10; |
765 | 54 | if (rightMarg < 0) rightMarg=0; |
766 | 54 | int botMarg = rBotMargin.y() -50; |
767 | 54 | if (botMarg < 0) botMarg=0; |
768 | | |
769 | 54 | getPageSpan().setMarginTop(lTopMargin.y()/72.0); |
770 | 54 | getPageSpan().setMarginBottom(botMarg/72.0); |
771 | 54 | getPageSpan().setMarginLeft(lTopMargin.x()/72.0); |
772 | 54 | getPageSpan().setMarginRight(rightMarg/72.0); |
773 | 54 | getPageSpan().setFormLength(paperSize.y()/72.); |
774 | 54 | getPageSpan().setFormWidth(paperSize.x()/72.); |
775 | | |
776 | 54 | ascFile.addPos(pos-4); |
777 | 54 | ascFile.addNote(f.str().c_str()); |
778 | 54 | return true; |
779 | 54 | } |
780 | | |
781 | | //////////////////////////////////////////////////////////// |
782 | | // read the windows positon info |
783 | | //////////////////////////////////////////////////////////// |
784 | | bool ActaParser::readWindowPos(MWAWEntry const &entry) |
785 | 662 | { |
786 | 662 | if (!entry.valid() || entry.length() != 8) { |
787 | 547 | MWAW_DEBUG_MSG(("ActaParser::readWindowPos: the entry is bad\n")); |
788 | 547 | return false; |
789 | 547 | } |
790 | | |
791 | 115 | long pos = entry.begin(); |
792 | 115 | MWAWInputStreamPtr input = rsrcInput(); |
793 | 115 | libmwaw::DebugFile &ascFile = rsrcAscii(); |
794 | 115 | libmwaw::DebugStream f; |
795 | | |
796 | 115 | input->seek(pos, librevenge::RVNG_SEEK_SET); |
797 | 115 | f << "Entries(WindowPos):"; |
798 | 115 | entry.setParsed(true); |
799 | 115 | int dim[4]; |
800 | 115 | for (int &i : dim) |
801 | 460 | i = static_cast<int>(input->readLong(2)); |
802 | 115 | f << "pos=" << dim[1] << "x" << dim[0] << "<->" << dim[3] << "x" << dim[2] << ","; |
803 | 115 | ascFile.addPos(pos-4); |
804 | 115 | ascFile.addNote(f.str().c_str()); |
805 | 115 | return true; |
806 | 662 | } |
807 | | |
808 | | //////////////////////////////////////////////////////////// |
809 | | // small resource fork |
810 | | //////////////////////////////////////////////////////////// |
811 | | |
812 | | // label kind |
813 | | bool ActaParser::readLabel(MWAWEntry const &entry) |
814 | 767 | { |
815 | 767 | if (!entry.valid() || entry.length() != 2) { |
816 | 465 | MWAW_DEBUG_MSG(("ActaParser::readLabel: the entry is bad\n")); |
817 | 465 | return false; |
818 | 465 | } |
819 | | |
820 | 302 | long pos = entry.begin(); |
821 | 302 | MWAWInputStreamPtr input = rsrcInput(); |
822 | 302 | libmwaw::DebugFile &ascFile = rsrcAscii(); |
823 | 302 | libmwaw::DebugStream f; |
824 | | |
825 | 302 | input->seek(pos, librevenge::RVNG_SEEK_SET); |
826 | 302 | f << "Entries(Label):"; |
827 | 302 | entry.setParsed(true); |
828 | 302 | m_state->m_label.m_type=static_cast<int>(input->readLong(2)); |
829 | 302 | f << m_state->m_label; |
830 | 302 | ascFile.addPos(pos-4); |
831 | 302 | ascFile.addNote(f.str().c_str()); |
832 | 302 | return true; |
833 | 767 | } |
834 | | |
835 | | // header/footer properties |
836 | | bool ActaParser::readHFProperties(MWAWEntry const &entry) |
837 | 883 | { |
838 | 883 | if (!entry.valid() || entry.length() != 20) { |
839 | 598 | MWAW_DEBUG_MSG(("ActaParser::readHFProperties: the entry is bad\n")); |
840 | 598 | return false; |
841 | 598 | } |
842 | | |
843 | 285 | long pos = entry.begin(); |
844 | 285 | MWAWInputStreamPtr input = rsrcInput(); |
845 | 285 | libmwaw::DebugFile &ascFile = rsrcAscii(); |
846 | 285 | libmwaw::DebugStream f; |
847 | | |
848 | 285 | input->seek(pos, librevenge::RVNG_SEEK_SET); |
849 | 285 | f << "Entries(QHDR):"; |
850 | 285 | entry.setParsed(true); |
851 | 855 | for (int st = 0; st < 2; st++) { |
852 | 570 | if (st==0) |
853 | 285 | f << "headerFooter=["; |
854 | 285 | else |
855 | 285 | f << "unknown=["; |
856 | 570 | ActaParserInternal::Printing print; |
857 | 570 | print.m_font.setId(static_cast<int>(input->readLong(2))); |
858 | 570 | print.m_font.setSize(static_cast<float>(input->readLong(2))); |
859 | 570 | auto flag=static_cast<int>(input->readLong(2)); |
860 | 570 | uint32_t flags = 0; |
861 | 570 | if (flag&0x1) flags |= MWAWFont::boldBit; |
862 | 570 | if (flag&0x2) flags |= MWAWFont::italicBit; |
863 | 570 | if (flag&0x4) print.m_font.setUnderlineStyle(MWAWFont::Line::Simple); |
864 | 570 | if (flag&0x8) flags |= MWAWFont::embossBit; |
865 | 570 | if (flag&0x10) flags |= MWAWFont::shadowBit; |
866 | 570 | print.m_font.setFlags(flags); |
867 | | #ifdef DEBUG |
868 | | f << "font=[" << print.m_font.getDebugString(getFontConverter()) << "],"; |
869 | | #endif |
870 | 570 | flag &= 0xE0; |
871 | 570 | if (flag) |
872 | 2 | f << "#font[flags]=" << std::hex << flags << std::dec << ","; |
873 | 570 | for (int &i : print.m_flags) |
874 | 1.14k | i = static_cast<int>(input->readULong(2)); |
875 | 570 | f << print << "],"; |
876 | 570 | if (st==0) |
877 | 285 | m_state->m_printerPreferences = print; |
878 | 570 | } |
879 | | |
880 | 285 | ascFile.addPos(pos-4); |
881 | 285 | ascFile.addNote(f.str().c_str()); |
882 | 285 | return true; |
883 | 883 | } |
884 | | |
885 | | // Option : small modificator change |
886 | | bool ActaParser::readOption(MWAWEntry const &entry) |
887 | 511 | { |
888 | 511 | if (!entry.valid() || entry.length() != 2) { |
889 | 246 | MWAW_DEBUG_MSG(("ActaParser::readOption: the entry is bad\n")); |
890 | 246 | return false; |
891 | 246 | } |
892 | | |
893 | 265 | long pos = entry.begin(); |
894 | 265 | MWAWInputStreamPtr input = rsrcInput(); |
895 | 265 | libmwaw::DebugFile &ascFile = rsrcAscii(); |
896 | 265 | libmwaw::DebugStream f; |
897 | | |
898 | 265 | input->seek(pos, librevenge::RVNG_SEEK_SET); |
899 | 265 | f << "Entries(Option):"; |
900 | 265 | entry.setParsed(true); |
901 | 265 | ActaParserInternal::Option opt(static_cast<int>(input->readULong(2))); |
902 | 265 | f << opt; |
903 | 265 | ascFile.addPos(pos-4); |
904 | 265 | ascFile.addNote(f.str().c_str()); |
905 | 265 | return true; |
906 | 511 | } |
907 | | //////////////////////////////////////////////////////////// |
908 | | // |
909 | | // Low level |
910 | | // |
911 | | //////////////////////////////////////////////////////////// |
912 | | |
913 | | //////////////////////////////////////////////////////////// |
914 | | // read the header |
915 | | //////////////////////////////////////////////////////////// |
916 | | bool ActaParser::checkHeader(MWAWHeader *header, bool strict) |
917 | 25.1k | { |
918 | 25.1k | *m_state = ActaParserInternal::State(); |
919 | 25.1k | MWAWInputStreamPtr input = getInput(); |
920 | 25.1k | if (!input || !input->hasDataFork() || !input->checkPosition(22)) |
921 | 253 | return false; |
922 | | |
923 | 24.9k | libmwaw::DebugStream f; |
924 | 24.9k | f << "FileHeader:"; |
925 | | |
926 | | // first check end of file |
927 | 24.9k | input->seek(-4,librevenge::RVNG_SEEK_END); |
928 | 24.9k | int last[2]; |
929 | 24.9k | for (int &i : last) |
930 | 49.8k | i=static_cast<int>(input->readLong(2)); |
931 | 24.9k | int vers=-1; |
932 | 24.9k | if (last[0]==0x4E4C && last[1]==0x544F) |
933 | 7.14k | vers=3; |
934 | 17.7k | else if (last[1]==0) |
935 | 17.5k | vers=1; |
936 | 24.9k | if (vers<=0) |
937 | 172 | return false; |
938 | 24.7k | setVersion(vers); |
939 | | |
940 | | // ok, now check the beginning of the file |
941 | 24.7k | int val; |
942 | 24.7k | input->seek(0, librevenge::RVNG_SEEK_SET); |
943 | 24.7k | if (vers==3) { |
944 | 7.14k | val=static_cast<int>(input->readULong(2)); |
945 | 7.14k | if (val!=3) { |
946 | 2.94k | if (strict) return false; |
947 | 2.08k | if (val < 1 || val > 4) |
948 | 98 | return false; |
949 | 1.98k | f << "#vers=" << val << ","; |
950 | 1.98k | MWAW_DEBUG_MSG(("ActaParser::checkHeader: find unexpected version: %d\n", val)); |
951 | 1.98k | } |
952 | 7.14k | } |
953 | 23.7k | val = static_cast<int>(input->readULong(2)); // depth ( first topic must have depth=1) |
954 | 23.7k | if (val != 1) |
955 | 138 | return false; |
956 | 23.6k | val = static_cast<int>(input->readULong(2)); // type |
957 | 23.6k | if (val != 1 && val !=2) |
958 | 207 | return false; |
959 | | |
960 | | // check that the first text size is valid |
961 | 23.4k | input->seek(vers==1 ? 18 : 20, librevenge::RVNG_SEEK_SET); |
962 | 23.4k | auto sz=static_cast<long>(input->readULong(4)); |
963 | 23.4k | if (!input->checkPosition(input->tell()+sz)) |
964 | 2.03k | return false; |
965 | | |
966 | 21.3k | if (header) |
967 | 7.79k | header->reset(MWAWDocument::MWAW_T_ACTA, vers); |
968 | 21.3k | if (vers >= 3) { |
969 | 5.78k | ascii().addPos(0); |
970 | 5.78k | ascii().addNote(f.str().c_str()); |
971 | 5.78k | } |
972 | 21.3k | return true; |
973 | 23.4k | } |
974 | | |
975 | | |
976 | | |
977 | | // vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: |