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 "MWAWPosition.hxx"
46 #include "MWAWPrinter.hxx"
47 #include "MWAWRSRCParser.hxx"
48 #include "MWAWSubDocument.hxx"
49
50 #include "ZWrtText.hxx"
51
52 #include "ZWrtParser.hxx"
53
54 /** Internal: the structures of a ZWrtParser */
55 namespace ZWrtParserInternal
56 {
57 ////////////////////////////////////////
58 //! Internal: the state of a ZWrtParser
59 struct State {
60 //! constructor
StateZWrtParserInternal::State61 State()
62 : m_actPage(0)
63 , m_numPages(0)
64 , m_headerUsed(true)
65 , m_footerUsed(true)
66 , m_headerHeight(0)
67 , m_footerHeight(0)
68 {
69 }
70
71 int m_actPage /** the actual page */, m_numPages /** the number of page of the final document */;
72
73 //! true if the header is used
74 bool m_headerUsed;
75 //! true if the footer is used
76 bool m_footerUsed;
77 int m_headerHeight /** the header height if known */,
78 m_footerHeight /** the footer height if known */;
79 };
80
81 ////////////////////////////////////////
82 //! Internal: the subdocument of a ZWrtParser
83 class SubDocument final : public MWAWSubDocument
84 {
85 public:
SubDocument(ZWrtParser & pars,MWAWInputStreamPtr const & input,bool header)86 SubDocument(ZWrtParser &pars, MWAWInputStreamPtr const &input, bool header)
87 : MWAWSubDocument(&pars, input, MWAWEntry())
88 , m_isHeader(header)
89 {
90 }
91
92 //! destructor
~SubDocument()93 ~SubDocument() final {}
94
95 //! operator!=
operator !=(MWAWSubDocument const & doc) const96 bool operator!=(MWAWSubDocument const &doc) const final
97 {
98 if (MWAWSubDocument::operator!=(doc)) return true;
99 auto const *sDoc = dynamic_cast<SubDocument const *>(&doc);
100 if (!sDoc) return true;
101 if (m_isHeader != sDoc->m_isHeader) return true;
102 return false;
103 }
104
105 //! the parser function
106 void parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType type) final;
107
108 protected:
109 //! true if we need to send the parser
110 int m_isHeader;
111 };
112
parse(MWAWListenerPtr & listener,libmwaw::SubDocumentType)113 void SubDocument::parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType /*type*/)
114 {
115 if (!listener.get()) {
116 MWAW_DEBUG_MSG(("ZWrtParserInternal::SubDocument::parse: no listener\n"));
117 return;
118 }
119 auto *parser=dynamic_cast<ZWrtParser *>(m_parser);
120 if (!parser) {
121 MWAW_DEBUG_MSG(("ZWrtParserInternal::SubDocument::parse: no parser\n"));
122 return;
123 }
124
125 parser->sendHeaderFooter(m_isHeader);
126 }
127 }
128
129
130 ////////////////////////////////////////////////////////////
131 // constructor/destructor, ...
132 ////////////////////////////////////////////////////////////
ZWrtParser(MWAWInputStreamPtr const & input,MWAWRSRCParserPtr const & rsrcParser,MWAWHeader * header)133 ZWrtParser::ZWrtParser(MWAWInputStreamPtr const &input, MWAWRSRCParserPtr const &rsrcParser, MWAWHeader *header)
134 : MWAWTextParser(input, rsrcParser, header)
135 , m_state()
136 , m_textParser()
137 {
138 init();
139 }
140
~ZWrtParser()141 ZWrtParser::~ZWrtParser()
142 {
143 }
144
init()145 void ZWrtParser::init()
146 {
147 resetTextListener();
148 setAsciiName("main-1");
149
150 m_state.reset(new ZWrtParserInternal::State);
151
152 // reduce the margin (in case, the page is not defined)
153 getPageSpan().setMargins(0.1);
154
155 m_textParser.reset(new ZWrtText(*this));
156 }
157
rsrcInput()158 MWAWInputStreamPtr ZWrtParser::rsrcInput()
159 {
160 return getRSRCParser()->getInput();
161 }
162
rsrcAscii()163 libmwaw::DebugFile &ZWrtParser::rsrcAscii()
164 {
165 return getRSRCParser()->ascii();
166 }
167
168 ////////////////////////////////////////////////////////////
169 // position and height
170 ////////////////////////////////////////////////////////////
getPageLeftTop() const171 MWAWVec2f ZWrtParser::getPageLeftTop() const
172 {
173 return MWAWVec2f(float(getPageSpan().getMarginLeft()),
174 float(getPageSpan().getMarginTop()+m_state->m_headerHeight/72.0));
175 }
176
177 ////////////////////////////////////////////////////////////
178 // interface with the text parser
179 ////////////////////////////////////////////////////////////
sendHeaderFooter(bool header)180 bool ZWrtParser::sendHeaderFooter(bool header)
181 {
182 MWAWInputStreamPtr rsrc = rsrcInput();
183 long rsrcPos = rsrc->tell();
184 m_textParser->sendHeaderFooter(header);
185 rsrc->seek(rsrcPos, librevenge::RVNG_SEEK_SET);
186 return true;
187 }
188
189 ////////////////////////////////////////////////////////////
190 // new page
191 ////////////////////////////////////////////////////////////
newPage(int number)192 void ZWrtParser::newPage(int number)
193 {
194 if (number <= m_state->m_actPage || number > m_state->m_numPages)
195 return;
196
197 while (m_state->m_actPage < number) {
198 m_state->m_actPage++;
199 if (!getTextListener() || m_state->m_actPage == 1)
200 continue;
201 getTextListener()->insertBreak(MWAWTextListener::PageBreak);
202 }
203 }
204
205 ////////////////////////////////////////////////////////////
206 // the parser
207 ////////////////////////////////////////////////////////////
parse(librevenge::RVNGTextInterface * docInterface)208 void ZWrtParser::parse(librevenge::RVNGTextInterface *docInterface)
209 {
210 if (!getInput().get() || !getRSRCParser() || !checkHeader(nullptr)) throw(libmwaw::ParseException());
211 bool ok = false;
212 try {
213 checkHeader(nullptr);
214 ok = createZones();
215 if (ok) {
216 createDocument(docInterface);
217 m_textParser->sendMainText();
218 #ifdef DEBUG
219 m_textParser->flushExtra();
220 #endif
221 }
222 }
223 catch (...) {
224 MWAW_DEBUG_MSG(("ZWrtParser::parse: exception catched when parsing\n"));
225 ok = false;
226 }
227
228 resetTextListener();
229 if (!ok) throw(libmwaw::ParseException());
230 }
231
232 ////////////////////////////////////////////////////////////
233 // create the document
234 ////////////////////////////////////////////////////////////
createDocument(librevenge::RVNGTextInterface * documentInterface)235 void ZWrtParser::createDocument(librevenge::RVNGTextInterface *documentInterface)
236 {
237 if (!documentInterface) return;
238 if (getTextListener()) {
239 MWAW_DEBUG_MSG(("ZWrtParser::createDocument: listener already exist\n"));
240 return;
241 }
242
243 // update the page
244 m_state->m_actPage = 0;
245
246 // create the page list
247 int numPages = 1;
248 if (m_textParser->numPages() > numPages)
249 numPages = m_textParser->numPages();
250 m_state->m_numPages = numPages;
251
252 MWAWPageSpan ps(getPageSpan());
253 if (m_state->m_headerUsed && m_textParser->hasHeaderFooter(true)) {
254 MWAWHeaderFooter header(MWAWHeaderFooter::HEADER, MWAWHeaderFooter::ALL);
255 header.m_subDocument.reset(new ZWrtParserInternal::SubDocument(*this, getInput(), true));
256 ps.setHeaderFooter(header);
257 }
258 if (m_state->m_footerUsed && m_textParser->hasHeaderFooter(false)) {
259 MWAWHeaderFooter footer(MWAWHeaderFooter::FOOTER, MWAWHeaderFooter::ALL);
260 footer.m_subDocument.reset(new ZWrtParserInternal::SubDocument(*this, getInput(), false));
261 ps.setHeaderFooter(footer);
262 }
263 ps.setPageSpan(m_state->m_numPages+1);
264 std::vector<MWAWPageSpan> pageList(1,ps);
265 MWAWTextListenerPtr listen(new MWAWTextListener(*getParserState(), pageList, documentInterface));
266 setTextListener(listen);
267 listen->startDocument();
268 }
269
270
271 ////////////////////////////////////////////////////////////
272 //
273 // Intermediate level
274 //
275 ////////////////////////////////////////////////////////////
createZones()276 bool ZWrtParser::createZones()
277 {
278 MWAWRSRCParserPtr rsrcParser = getRSRCParser();
279 if (!rsrcParser) {
280 MWAW_DEBUG_MSG(("ZWrtParser::createZones: can not find the entry map\n"));
281 return false;
282 }
283 auto &entryMap = rsrcParser->getEntriesMap();
284
285 // the 128 zones
286 char const *zNames[] = {"BBAR", "HTML", "PRIN", "RANG", "WPOS", "PGPT"};
287 for (int z = 0; z < 6; z++) {
288 auto it = entryMap.lower_bound(zNames[z]);
289 while (it != entryMap.end()) {
290 if (it->first != zNames[z])
291 break;
292 MWAWEntry const &entry = it++->second;
293 bool done=true;
294 switch (z) {
295 case 0:
296 done=readBarState(entry);
297 break;
298 case 1:
299 done=readHTMLPref(entry);
300 break;
301 case 2:
302 done=readPrintInfo(entry);
303 break;
304 case 3:
305 done=readSectionRange(entry);
306 break;
307 case 4:
308 done=readWindowPos(entry);
309 break;
310 case 5:
311 done=readCPRT(entry);
312 break;
313 default:
314 done=false;
315 break;
316 }
317 if (done || !entry.valid()) continue;
318 readUnknownZone(entry);
319 }
320 }
321
322 // 1001 and following
323 char const *sNames[] = {"CPOS", "SLEN"};
324 for (int z = 0; z < 2; z++) {
325 auto it = entryMap.lower_bound(sNames[z]);
326 while (it != entryMap.end()) {
327 if (it->first != sNames[z])
328 break;
329 MWAWEntry const &entry = it++->second;
330 bool done=true;
331 switch (z) {
332 case 0:
333 done=readCPos(entry);
334 break;
335 case 1:
336 done=readSLen(entry);
337 break;
338 default:
339 done = false;
340 }
341 if (done || !entry.valid()) continue;
342 readUnknownZone(entry);
343 }
344 }
345 if (!m_textParser->createZones())
346 return false;
347 return true;
348 }
349
350 ////////////////////////////////////////////////////////////
351 // read the print info
352 ////////////////////////////////////////////////////////////
readPrintInfo(MWAWEntry const & entry)353 bool ZWrtParser::readPrintInfo(MWAWEntry const &entry)
354 {
355 if (!entry.valid()) {
356 MWAW_DEBUG_MSG(("ZWrtParser::readPrintInfo: the entry is bad\n"));
357 return false;
358 }
359
360 if (entry.id()!=128) {
361 MWAW_DEBUG_MSG(("ZWrtParser::readPrintInfo: the entry id is odd\n"));
362 }
363 long pos = entry.begin();
364 MWAWInputStreamPtr input = rsrcInput();
365 libmwaw::DebugFile &ascFile = rsrcAscii();
366 libmwaw::DebugStream f;
367 f << "Entries(" << entry.type() << ")[" << entry << "]:";
368 entry.setParsed(true);
369
370 std::vector<ZWField> fields;
371 if (!getFieldList(entry, fields)) {
372 MWAW_DEBUG_MSG(("ZWrtParser::readPrintInfo: can not get fields list\n"));
373 f << "###";
374 ascFile.addPos(pos-4);
375 ascFile.addNote(f.str().c_str());
376 return false;
377 }
378
379 size_t numFields = fields.size();
380 if (numFields < 6) {
381 MWAW_DEBUG_MSG(("ZWrtParser::readPrintInfo: the fields list seems very short\n"));
382 }
383 bool boolVal;
384 float floatVal;
385 int intVal;
386 std::string strVal;
387 int margins[4]= {0,0,0,0};
388 bool marginsOk=true;
389 for (size_t ff = 0; ff < numFields; ff++) {
390 ZWField const &field = fields[ff];
391 bool done = false;
392 switch (ff) {
393 case 0: // T
394 case 1: // B
395 case 2: // L
396 case 3: // R
397 done = field.getInt(input, intVal);
398 if (!done) {
399 marginsOk = false;
400 break;
401 }
402 margins[ff]=intVal;
403 break;
404 case 4: // 2,-2,-4
405 done = field.getInt(input, intVal);
406 if (!done||!intVal)
407 break;
408 f << "autoResize=" << intVal << ",";
409 break;
410 case 5: //1.2
411 done = field.getFloat(input, floatVal);
412 if (!done)
413 break;
414 f << "lineSpacing=" << floatVal << ",";
415 break;
416 case 6:
417 case 7: // always set
418 case 8: // always set
419 done = field.getBool(input, boolVal);
420 if (!done)
421 break;
422 if (!boolVal)
423 continue;
424 switch (ff) { // checkme: does not seems to works in all case...
425 case 6:
426 f << "sectionAddNewPage,";
427 break;
428 case 7:
429 f << "useHeader,";
430 break;
431 case 8:
432 f << "useFooter,";
433 break;
434 default:
435 f << "#f" << ff << "Set,";
436 break;
437 }
438 break;
439 default:
440 break;
441 }
442 if (done)
443 continue;
444 if (fields[ff].getDebugString(input, strVal))
445 f << "#f" << ff << "=\"" << strVal << "\",";
446 else
447 f << "#f" << ff << ",";
448 }
449 if (marginsOk) {
450 getPageSpan().setMarginTop(double(margins[0])/72.0);
451 getPageSpan().setMarginBottom(double(margins[1])/72.0);
452 getPageSpan().setMarginLeft(double(margins[2])/72.0);
453 getPageSpan().setMarginRight(double(margins[3])/72.0);
454 }
455 f << "margins=(" << margins[2] << "x" << margins[0] << "<->" << margins[3] << "x" << margins[1] << "),";
456 ascFile.addPos(pos-4);
457 ascFile.addNote(f.str().c_str());
458 return true;
459 }
460
461 // read the print info xml data
readCPRT(MWAWEntry const & entry)462 bool ZWrtParser::readCPRT(MWAWEntry const &entry)
463 {
464 if (entry.length() < 0x10) {
465 MWAW_DEBUG_MSG(("ZWrtParser::readCPRT: data seems to short\n"));
466 return false;
467 }
468
469 MWAWInputStreamPtr input = rsrcInput();
470 long pos = entry.begin();
471 input->seek(pos, librevenge::RVNG_SEEK_SET);
472 #ifdef DEBUG_WITH_FILES
473 libmwaw::DebugFile &ascFile = rsrcAscii();
474 librevenge::RVNGBinaryData file;
475 input->readDataBlock(entry.length(), file);
476
477 static int volatile cprtName = 0;
478 libmwaw::DebugStream f;
479 f << "CPRT" << ++cprtName << ".plist";
480 libmwaw::Debug::dumpFile(file, f.str().c_str());
481
482 ascFile.addPos(pos-4);
483 ascFile.addNote(f.str().c_str());
484 ascFile.skipZone(entry.begin(),entry.end()-1);
485 #endif
486 return true;
487 }
488
489 ////////////////////////////////////////////////////////////
490 // read the bar state/windows pos, ...
491 ////////////////////////////////////////////////////////////
readBarState(MWAWEntry const & entry)492 bool ZWrtParser::readBarState(MWAWEntry const &entry)
493 {
494 if (!entry.valid()) {
495 MWAW_DEBUG_MSG(("ZWrtParser::readBarState: the entry is bad\n"));
496 return false;
497 }
498
499 if (entry.id()!=128) {
500 MWAW_DEBUG_MSG(("ZWrtParser::readBarState: the entry id is odd\n"));
501 }
502 long pos = entry.begin();
503 MWAWInputStreamPtr input = rsrcInput();
504 libmwaw::DebugFile &ascFile = rsrcAscii();
505 libmwaw::DebugStream f;
506 f << "Entries(" << entry.type() << ")[" << entry << "]:";
507 entry.setParsed(true);
508
509 std::vector<ZWField> fields;
510 if (!getFieldList(entry, fields) || !fields.size()) {
511 MWAW_DEBUG_MSG(("ZWrtParser::readBarState: can not get fields list\n"));
512 f << "###";
513 ascFile.addPos(pos-4);
514 ascFile.addNote(f.str().c_str());
515 return false;
516 }
517 std::string res("");
518 if (fields[0].getString(input, res))
519 f << "set=" << res << ",";
520 else
521 f << "#set,";
522 size_t numFields = fields.size();
523 if (numFields > 1) {
524 MWAW_DEBUG_MSG(("ZWrtParser::readBarState: find extra fields\n"));
525 }
526 for (size_t ff = 1; ff < numFields; ff++) {
527 if (fields[ff].getDebugString(input, res))
528 f << "#f" << ff << "=\"" << res << "\",";
529 else
530 f << "#f" << ff << ",";
531 }
532
533 ascFile.addPos(pos-4);
534 ascFile.addNote(f.str().c_str());
535 return true;
536 }
537
readHTMLPref(MWAWEntry const & entry)538 bool ZWrtParser::readHTMLPref(MWAWEntry const &entry)
539 {
540 if (!entry.valid()) {
541 MWAW_DEBUG_MSG(("ZWrtParser::readHTMLPref: the entry is bad\n"));
542 return false;
543 }
544
545 if (entry.id()!=128) {
546 MWAW_DEBUG_MSG(("ZWrtParser::readHTMLPref: the entry id is odd\n"));
547 }
548 long pos = entry.begin();
549 MWAWInputStreamPtr input = rsrcInput();
550 libmwaw::DebugFile &ascFile = rsrcAscii();
551 libmwaw::DebugStream f;
552 f << "Entries(" << entry.type() << ")[" << entry << "]:";
553 entry.setParsed(true);
554
555 std::vector<ZWField> fields;
556 if (!getFieldList(entry, fields)) {
557 MWAW_DEBUG_MSG(("ZWrtParser::readHTMLPref: can not get fields list\n"));
558 f << "###";
559 ascFile.addPos(pos-4);
560 ascFile.addNote(f.str().c_str());
561 return false;
562 }
563
564 size_t numFields = fields.size();
565 if (numFields < 4) {
566 MWAW_DEBUG_MSG(("ZWrtParser::readHTMLPref: the fields list seems very short\n"));
567 }
568 std::string strVal;
569 bool boolVal;
570 for (size_t ff = 0; ff < numFields; ff++) {
571 ZWField const &field = fields[ff];
572 bool done = false;
573 switch (ff) {
574 case 0:
575 case 1:
576 case 2: // always true?
577 case 3: // true if name?
578 done = field.getBool(input, boolVal);
579 if (!done || !boolVal)
580 break;
581 f << "f" << ff << "Set,";
582 break;
583 case 4: // find one time sidebar
584 done = field.getString(input, strVal);
585 if (!done||!strVal.length())
586 break;
587 f << "name=" << strVal << ",";
588 break;
589 default:
590 break;
591 }
592 if (done)
593 continue;
594 if (fields[ff].getDebugString(input, strVal))
595 f << "#f" << ff << "=\"" << strVal << "\",";
596 else
597 f << "#f" << ff << ",";
598 }
599 ascFile.addPos(pos-4);
600 ascFile.addNote(f.str().c_str());
601 return true;
602 }
603
readSectionRange(MWAWEntry const & entry)604 bool ZWrtParser::readSectionRange(MWAWEntry const &entry)
605 {
606 long pos = entry.begin();
607 if (pos <= 0) {
608 MWAW_DEBUG_MSG(("ZWrtParser::readSectionRange: the entry is bad\n"));
609 return false;
610 }
611
612 MWAWInputStreamPtr input = rsrcInput();
613 libmwaw::DebugFile &ascFile = rsrcAscii();
614 libmwaw::DebugStream f;
615 f << "Entries(" << entry.type() << ")[" << entry << "]:";
616 entry.setParsed(true);
617
618 if (entry.length() <= 0) {
619 ascFile.addPos(pos-4);
620 ascFile.addNote(f.str().c_str());
621 return true;
622 }
623 input->seek(pos, librevenge::RVNG_SEEK_SET);
624 pos -= 4;
625 std::string name("");
626 int num=0;
627 while (!input->isEnd()) {
628 bool done=input->tell()>=entry.end();
629 char c = done ? char(0xa) : char(input->readULong(1));
630 if (c==0) {
631 MWAW_DEBUG_MSG(("ZWrtParser::readSectionRange: find a 0 char\n"));
632 name +="##[0]";
633 continue;
634 }
635 if (c!=0xa) {
636 name += c;
637 continue;
638 }
639
640 f << name;
641 ascFile.addPos(pos);
642 ascFile.addNote(f.str().c_str());
643 pos = input->tell();
644 name = "";
645 f.str("");
646 f << entry.type() << "-" << ++num << ":";
647 if (done)
648 break;
649 }
650 if (name.length()) {
651 f << name;
652 ascFile.addPos(pos);
653 ascFile.addNote(f.str().c_str());
654 }
655 return true;
656 }
657
readWindowPos(MWAWEntry const & entry)658 bool ZWrtParser::readWindowPos(MWAWEntry const &entry)
659 {
660 if (!entry.valid()) {
661 MWAW_DEBUG_MSG(("ZWrtParser::readWindowPos: the entry is bad\n"));
662 return false;
663 }
664
665 if (entry.id()!=128) {
666 MWAW_DEBUG_MSG(("ZWrtParser::readWindowPos: the entry id is odd\n"));
667 }
668 long pos = entry.begin();
669 MWAWInputStreamPtr input = rsrcInput();
670 libmwaw::DebugFile &ascFile = rsrcAscii();
671 libmwaw::DebugStream f;
672 f << "Entries(" << entry.type() << ")[" << entry << "]:";
673 entry.setParsed(true);
674
675 std::vector<ZWField> fields;
676 if (!getFieldList(entry, fields)) {
677 MWAW_DEBUG_MSG(("ZWrtParser::readWindowPos: can not get fields list\n"));
678 f << "###";
679 ascFile.addPos(pos-4);
680 ascFile.addNote(f.str().c_str());
681 return false;
682 }
683
684 size_t numFields = fields.size();
685 if (numFields < 6) {
686 MWAW_DEBUG_MSG(("ZWrtParser::readWindowPos: the fields list seems very short\n"));
687 }
688 std::string strVal;
689 int intVal;
690 int dim[4]= {0,0,0,0};
691 for (size_t ff = 0; ff < numFields; ff++) {
692 ZWField const &field = fields[ff];
693 bool done = false;
694 switch (ff) {
695 case 0:
696 case 1:
697 case 2:
698 case 3:
699 done = field.getInt(input, intVal);
700 if (!done)
701 break;
702 dim[ff]=intVal;
703 break;
704 case 4: // 137|139|144
705 case 5: // 0|3|9|12 ( actual section ?)
706 done = field.getInt(input, intVal);
707 if (!done||!intVal)
708 break;
709 f << "f" << ff << "=" << intVal << ",";
710 break;
711 default:
712 break;
713 }
714 if (done)
715 continue;
716 if (fields[ff].getDebugString(input, strVal))
717 f << "#f" << ff << "=\"" << strVal << "\",";
718 else
719 f << "#f" << ff << ",";
720 }
721 f << "pos=(" << dim[0] << "x" << dim[1] << "<->" << dim[2] << "x" << dim[3] << "),";
722 ascFile.addPos(pos-4);
723 ascFile.addNote(f.str().c_str());
724 return true;
725 }
726
727 ////////////////////////////////////////////////////////////
728 // read a section zone ...
729 ////////////////////////////////////////////////////////////
730
731 // read a cursor position in a section ?
readCPos(MWAWEntry const & entry)732 bool ZWrtParser::readCPos(MWAWEntry const &entry)
733 {
734 if (!entry.valid()) {
735 MWAW_DEBUG_MSG(("ZWrtParser::readCPos: the entry is bad\n"));
736 return false;
737 }
738
739 long pos = entry.begin();
740 MWAWInputStreamPtr input = rsrcInput();
741 libmwaw::DebugFile &ascFile = rsrcAscii();
742 libmwaw::DebugStream f;
743 f << "Entries(" << entry.type() << ")[" << entry << "]:";
744 entry.setParsed(true);
745
746 std::vector<ZWField> fields;
747 if (!getFieldList(entry, fields) || !fields.size()) {
748 MWAW_DEBUG_MSG(("ZWrtParser::readCPos: can not get fields list\n"));
749 f << "###";
750 ascFile.addPos(pos-4);
751 ascFile.addNote(f.str().c_str());
752 return false;
753 }
754 int intVal;
755 size_t ff=0;
756 if (fields[ff++].getInt(input, intVal)) {
757 if (intVal)
758 f << "cPos=" << intVal << ",";
759 }
760 else {
761 MWAW_DEBUG_MSG(("ZWrtParser::readCPos: can not read cursor pos\n"));
762 ff = 0;
763 }
764 size_t numFields = fields.size();
765 if (numFields > 1) {
766 MWAW_DEBUG_MSG(("ZWrtParser::readCPos: find extra fields\n"));
767 }
768 std::string res;
769 for (; ff < numFields; ff++) {
770 if (fields[ff].getDebugString(input, res))
771 f << "#f" << ff << "=\"" << res << "\",";
772 else
773 f << "#f" << ff << ",";
774 }
775
776 ascFile.addPos(pos-4);
777 ascFile.addNote(f.str().c_str());
778 return true;
779 }
780
781 // read a cursor position in a section ?
readSLen(MWAWEntry const & entry)782 bool ZWrtParser::readSLen(MWAWEntry const &entry)
783 {
784 if (!entry.valid()) {
785 MWAW_DEBUG_MSG(("ZWrtParser::readSLen: the entry is bad\n"));
786 return false;
787 }
788
789 long pos = entry.begin();
790 MWAWInputStreamPtr input = rsrcInput();
791 libmwaw::DebugFile &ascFile = rsrcAscii();
792 libmwaw::DebugStream f;
793 f << "Entries(" << entry.type() << ")[" << entry << "]:";
794 entry.setParsed(true);
795
796 std::vector<ZWField> fields;
797 if (!getFieldList(entry, fields) || !fields.size()) {
798 MWAW_DEBUG_MSG(("ZWrtParser::readSLen: can not get fields list\n"));
799 f << "###";
800 ascFile.addPos(pos-4);
801 ascFile.addNote(f.str().c_str());
802 return false;
803 }
804 int intVal;
805 size_t ff=0;
806 if (fields[ff++].getInt(input, intVal)) {
807 if (intVal)
808 f << "len?=" << intVal << ",";
809 }
810 else {
811 MWAW_DEBUG_MSG(("ZWrtParser::readSLen: can not read cursor pos\n"));
812 ff = 0;
813 }
814 size_t numFields = fields.size();
815 if (numFields > 1) {
816 MWAW_DEBUG_MSG(("ZWrtParser::readSLen: find extra fields\n"));
817 }
818 std::string res;
819 for (; ff < numFields; ff++) {
820 if (fields[ff].getDebugString(input, res))
821 f << "#f" << ff << "=\"" << res << "\",";
822 else
823 f << "#f" << ff << ",";
824 }
825
826 ascFile.addPos(pos-4);
827 ascFile.addNote(f.str().c_str());
828 return true;
829 }
830
831 ////////////////////////////////////////////////////////////
832 // read a generic zone ...
833 ////////////////////////////////////////////////////////////
readUnknownZone(MWAWEntry const & entry)834 bool ZWrtParser::readUnknownZone(MWAWEntry const &entry)
835 {
836 if (entry.begin() <= 0) {
837 MWAW_DEBUG_MSG(("ZWrtParser::readUnknownZone: the entry is bad\n"));
838 return false;
839 }
840
841 MWAWInputStreamPtr input = rsrcInput();
842 libmwaw::DebugFile &ascFile = rsrcAscii();
843 long pos = entry.begin();
844
845 libmwaw::DebugStream f;
846 f << "Entries(" << entry.type() << ")[" << entry << "]:";
847 entry.setParsed(true);
848
849 std::vector<ZWField> fields;
850 if (!getFieldList(entry, fields)) {
851 MWAW_DEBUG_MSG(("ZWrtParser::readUnknownZone: can not get fields list\n"));
852 f << "###";
853 ascFile.addPos(pos-4);
854 ascFile.addNote(f.str().c_str());
855 return false;
856 }
857 std::string res("");
858 size_t numFields = fields.size();
859 for (size_t ff = 0; ff < numFields; ff++) {
860 if (fields[ff].getDebugString(input, res))
861 f << "f" << ff << "=\"" << res << "\",";
862 else
863 f << "#f" << ff << ",";
864 }
865
866 ascFile.addPos(pos-4);
867 ascFile.addNote(f.str().c_str());
868 return true;
869 }
870
871 ////////////////////////////////////////////////////////////
872 //
873 // Low level
874 //
875 ////////////////////////////////////////////////////////////
876
877 ////////////////////////////////////////////////////////////
878 // read the header
879 ////////////////////////////////////////////////////////////
checkHeader(MWAWHeader * header,bool strict)880 bool ZWrtParser::checkHeader(MWAWHeader *header, bool strict)
881 {
882 *m_state = ZWrtParserInternal::State();
883 if (!getRSRCParser())
884 return false;
885 // check if the RANG section exists
886 MWAWEntry entry = getRSRCParser()->getEntry("RANG", 128);
887 if (entry.begin()<=0) { // length can be 0, so ...
888 MWAW_DEBUG_MSG(("ZWrtParser::checkHeader: can not find the RANG[128] resource\n"));
889 return false;
890 }
891 if (getInput()->hasDataFork() && getInput()->size()>0) {
892 MWAW_DEBUG_MSG(("ZWrtParser::checkHeader: find some data fork\n"));
893 if (strict)
894 return false;
895 }
896 if (header)
897 header->reset(MWAWDocument::MWAW_T_ZWRITE, 1);
898
899 return true;
900 }
901
902 ////////////////////////////////////////////////////////////
903 // read a list of field
904 ////////////////////////////////////////////////////////////
getFieldList(MWAWEntry const & entry,std::vector<ZWField> & list)905 bool ZWrtParser::getFieldList(MWAWEntry const &entry, std::vector<ZWField> &list)
906 {
907 list.resize(0);
908 MWAWInputStreamPtr input = rsrcInput();
909 long pos=entry.begin();
910 input->seek(entry.begin(), librevenge::RVNG_SEEK_SET);
911 while (!input->isEnd()) {
912 long actPos=input->tell();
913 long done = actPos>=entry.end();
914 char c= done ? '\t' : char(input->readULong(1));
915 if (c=='\t') {
916 ZWField field;
917 field.m_pos.setBegin(pos);
918 field.m_pos.setEnd(actPos);
919 pos = actPos+1;
920 list.push_back(field);
921 if (done)
922 return true;
923 continue;
924 }
925 }
926 return true;
927 }
928
929 ////////////////////////////////////////////////////////////
930 // field function
931 ////////////////////////////////////////////////////////////
getString(MWAWInputStreamPtr & input,std::string & str) const932 bool ZWField::getString(MWAWInputStreamPtr &input, std::string &str) const
933 {
934 str="";
935 if (!m_pos.valid())
936 return true;
937 input->seek(m_pos.begin(), librevenge::RVNG_SEEK_SET);
938 while (!input->isEnd() && input->tell()!=m_pos.end()) {
939 auto c=char(input->readULong(1));
940 if (c==0) {
941 MWAW_DEBUG_MSG(("ZWField::getString::readFieldString: find a zero entry\n"));
942 str += "##[0]";
943 continue;
944 }
945 str += c;
946 }
947 return true;
948 }
949
getDebugString(MWAWInputStreamPtr & input,std::string & str) const950 bool ZWField::getDebugString(MWAWInputStreamPtr &input, std::string &str) const
951 {
952 str="";
953 if (!m_pos.valid())
954 return true;
955 input->seek(m_pos.begin(), librevenge::RVNG_SEEK_SET);
956 std::stringstream ss;
957 while (!input->isEnd() && input->tell()!=m_pos.end()) {
958 auto c=char(input->readULong(1));
959 if (static_cast<unsigned char>(c)<=0x1f && c!= 0x9)
960 ss << "##[" << std::hex << int(c) << std::dec << "]";
961 else
962 ss << c;
963 }
964 str = ss.str();
965 return true;
966 }
967
getBool(MWAWInputStreamPtr & input,bool & val) const968 bool ZWField::getBool(MWAWInputStreamPtr &input, bool &val) const
969 {
970 val = false;
971 if (m_pos.length()==0 && m_pos.begin()>0)
972 return true;
973 std::string str;
974 if (!getString(input,str) || str.length() != 1) {
975 MWAW_DEBUG_MSG(("ZWField::getBool: can not read field\n"));
976 return false;
977 }
978 if (str[0]=='T')
979 val = true;
980 else if (str[0]=='F')
981 val = false;
982 else {
983 MWAW_DEBUG_MSG(("ZWField::getBool: find unexpected char %x\n", static_cast<unsigned int>(str[0])));
984 return false;
985 }
986 return true;
987 }
988
getInt(MWAWInputStreamPtr & input,int & val) const989 bool ZWField::getInt(MWAWInputStreamPtr &input, int &val) const
990 {
991 val = 0;
992 std::string str;
993 if (!getString(input,str) || str.length() == 0) {
994 MWAW_DEBUG_MSG(("ZWField::getInt: can not read field\n"));
995 return false;
996 }
997 int sign = 1;
998 size_t numChar = str.length();
999 size_t p = 0;
1000 if (str[0]=='-') {
1001 sign = -1;
1002 p++;
1003 }
1004 while (p < numChar) {
1005 char c = str[p++];
1006 if (c>='0' && c <= '9') {
1007 val = 10*val+(c-'0');
1008 continue;
1009 }
1010 MWAW_DEBUG_MSG(("ZWField::getInt: find unexpected char %x\n", static_cast<unsigned int>(c)));
1011 val *= sign;
1012 return false;
1013 }
1014 val *= sign;
1015 return true;
1016 }
1017
getFloat(MWAWInputStreamPtr & input,float & val) const1018 bool ZWField::getFloat(MWAWInputStreamPtr &input, float &val) const
1019 {
1020 val = 0;
1021 std::string str;
1022 if (!getString(input,str) || str.length() == 0) {
1023 MWAW_DEBUG_MSG(("ZWField::getFloat: can not read field\n"));
1024 return false;
1025 }
1026 std::stringstream ss;
1027 ss << str;
1028 ss >> val;
1029 return !(!ss);
1030 }
1031
getIntList(MWAWInputStreamPtr & input,std::vector<int> & list) const1032 bool ZWField::getIntList(MWAWInputStreamPtr &input, std::vector<int> &list) const
1033 {
1034 list.resize(0);
1035 std::string str;
1036 if (!getString(input,str) || str.length() == 0) {
1037 MWAW_DEBUG_MSG(("ZWField::getIntList: can not read field\n"));
1038 return false;
1039 }
1040 int sign = 1, val=0;
1041 size_t numChar = str.length();
1042 size_t p = 0;
1043 while (p <= numChar) {
1044 if (p==numChar) {
1045 list.push_back(sign*val);
1046 break;
1047 }
1048 char c = str[p++];
1049 if (c==',') {
1050 list.push_back(sign*val);
1051 val = 0;
1052 sign = 1;
1053 continue;
1054 }
1055 if (c=='-') {
1056 if (val != 0 || sign != 1) {
1057 MWAW_DEBUG_MSG(("ZWField::getIntList: find a int inside a word\n"));
1058 return list.size();
1059 }
1060 sign = -1;
1061 }
1062 if (c>='0' && c <= '9') {
1063 val = 10*val+(c-'0');
1064 continue;
1065 }
1066 MWAW_DEBUG_MSG(("ZWField::getIntList: find unexpected char %x\n", static_cast<unsigned int>(c)));
1067 return list.size();
1068 }
1069 return true;
1070 }
1071
1072 // vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab:
1073