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