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 "LightWayTxtGraph.hxx"
51 #include "LightWayTxtText.hxx"
52 
53 #include "LightWayTxtParser.hxx"
54 
55 /** Internal: the structures of a LightWayTxtParser */
56 namespace LightWayTxtParserInternal
57 {
58 ////////////////////////////////////////
59 //! Internal: the state of a LightWayTxtParser
60 struct State {
61   //! constructor
StateLightWayTxtParserInternal::State62   State()
63     : m_isApplication(false)
64     , m_actPage(0)
65     , m_numPages(0)
66     , m_numCol(1)
67     , m_colSep(0)
68     , m_headerHeight(0)
69     , m_footerHeight(0)
70   {
71   }
72 
73   /** true if we are parsing a application document */
74   bool m_isApplication;
75   int m_actPage /** the actual page */, m_numPages /** the number of page of the final document */;
76 
77   int m_numCol /** the number of columns */,
78       m_colSep /** the columns separator width in point */;
79   int m_headerHeight /** the header height if known */,
80       m_footerHeight /** the footer height if known */;
81 };
82 
83 ////////////////////////////////////////
84 //! Internal: the subdocument of a LightWayTxtParser
85 class SubDocument final : public MWAWSubDocument
86 {
87 public:
SubDocument(LightWayTxtParser & pars,MWAWInputStreamPtr const & input,bool header)88   SubDocument(LightWayTxtParser &pars, MWAWInputStreamPtr const &input, bool header)
89     : MWAWSubDocument(&pars, input, MWAWEntry())
90     , m_isHeader(header)
91   {
92   }
93 
94   //! destructor
~SubDocument()95   ~SubDocument() final {}
96 
97   //! operator!=
operator !=(MWAWSubDocument const & doc) const98   bool operator!=(MWAWSubDocument const &doc) const final
99   {
100     if (MWAWSubDocument::operator!=(doc)) return true;
101     auto const *sDoc = dynamic_cast<SubDocument const *>(&doc);
102     if (!sDoc) return true;
103     if (m_isHeader != sDoc->m_isHeader) return true;
104     return false;
105   }
106 
107   //! the parser function
108   void parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType type) final;
109 
110 protected:
111   //! true if we need to send the parser
112   int m_isHeader;
113 };
114 
parse(MWAWListenerPtr & listener,libmwaw::SubDocumentType)115 void SubDocument::parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType /*type*/)
116 {
117   if (!listener.get()) {
118     MWAW_DEBUG_MSG(("LightWayTxtParserInternal::SubDocument::parse: no listener\n"));
119     return;
120   }
121   auto *parser=dynamic_cast<LightWayTxtParser *>(m_parser);
122   if (!parser) {
123     MWAW_DEBUG_MSG(("LightWayTxtParserInternal::SubDocument::parse: no parser\n"));
124     return;
125   }
126 
127   parser->sendHeaderFooter(m_isHeader);
128 }
129 }
130 
131 
132 ////////////////////////////////////////////////////////////
133 // constructor/destructor, ...
134 ////////////////////////////////////////////////////////////
LightWayTxtParser(MWAWInputStreamPtr const & input,MWAWRSRCParserPtr const & rsrcParser,MWAWHeader * header)135 LightWayTxtParser::LightWayTxtParser(MWAWInputStreamPtr const &input, MWAWRSRCParserPtr const &rsrcParser, MWAWHeader *header)
136   : MWAWTextParser(input, rsrcParser, header)
137   , m_state()
138   , m_pageSpanSet(false)
139   , m_graphParser()
140   , m_textParser()
141 {
142   init();
143 }
144 
~LightWayTxtParser()145 LightWayTxtParser::~LightWayTxtParser()
146 {
147 }
148 
init()149 void LightWayTxtParser::init()
150 {
151   resetTextListener();
152   setAsciiName("main-1");
153 
154   m_state.reset(new LightWayTxtParserInternal::State);
155 
156   // reduce the margin (in case, the page is not defined)
157   getPageSpan().setMargins(0.1);
158 
159   m_graphParser.reset(new LightWayTxtGraph(*this));
160   m_textParser.reset(new LightWayTxtText(*this));
161 }
162 
rsrcInput()163 MWAWInputStreamPtr LightWayTxtParser::rsrcInput()
164 {
165   return getRSRCParser()->getInput();
166 }
167 
rsrcAscii()168 libmwaw::DebugFile &LightWayTxtParser::rsrcAscii()
169 {
170   return getRSRCParser()->ascii();
171 }
172 
textInDataFork() const173 bool LightWayTxtParser::textInDataFork() const
174 {
175   return !m_state->m_isApplication;
176 }
177 
178 ////////////////////////////////////////////////////////////
179 // position and height
180 ////////////////////////////////////////////////////////////
getPageLeftTop() const181 MWAWVec2f LightWayTxtParser::getPageLeftTop() const
182 {
183   return MWAWVec2f(float(getPageSpan().getMarginLeft()),
184                    float(getPageSpan().getMarginTop()+m_state->m_headerHeight/72.0));
185 }
186 
187 ////////////////////////////////////////////////////////////
188 // interface with the text parser
189 ////////////////////////////////////////////////////////////
getColumnInfo(int & numCols,int & colSep) const190 bool LightWayTxtParser::getColumnInfo(int &numCols, int &colSep) const
191 {
192   if (m_state->m_numCol < 1) {
193     numCols = 1;
194     colSep = 0;
195     return false;
196   }
197   numCols = m_state->m_numCol;
198   colSep = m_state->m_colSep;
199   return true;
200 }
201 
sendHeaderFooter(bool header)202 bool LightWayTxtParser::sendHeaderFooter(bool header)
203 {
204   MWAWInputStreamPtr input = getInput();
205   MWAWInputStreamPtr rsrc = rsrcInput();
206   long pos = input->tell(), rsrcPos = rsrc ? rsrc->tell() : 0;
207   m_textParser->sendHeaderFooter(header);
208   input->seek(pos, librevenge::RVNG_SEEK_SET);
209   if (rsrc)
210     rsrc->seek(rsrcPos, librevenge::RVNG_SEEK_SET);
211   return true;
212 }
213 
214 ////////////////////////////////////////////////////////////
215 // interface with the graph parser
216 ////////////////////////////////////////////////////////////
sendGraphic(int graphId)217 void LightWayTxtParser::sendGraphic(int graphId)
218 {
219   MWAWInputStreamPtr input = getInput();
220   MWAWInputStreamPtr rsrc = rsrcInput();
221   long pos = input->tell(), rsrcPos = rsrc ? rsrc->tell() : 0;
222   m_graphParser->send(graphId);
223   input->seek(pos, librevenge::RVNG_SEEK_SET);
224   if (rsrc)
225     rsrc->seek(rsrcPos, librevenge::RVNG_SEEK_SET);
226 }
227 
228 ////////////////////////////////////////////////////////////
229 // new page
230 ////////////////////////////////////////////////////////////
newPage(int number)231 void LightWayTxtParser::newPage(int number)
232 {
233   if (number <= m_state->m_actPage || number > m_state->m_numPages)
234     return;
235 
236   while (m_state->m_actPage < number) {
237     m_state->m_actPage++;
238     if (!getTextListener() || m_state->m_actPage == 1)
239       continue;
240     getTextListener()->insertBreak(MWAWTextListener::PageBreak);
241   }
242 }
243 
244 ////////////////////////////////////////////////////////////
245 // the parser
246 ////////////////////////////////////////////////////////////
parse(librevenge::RVNGTextInterface * docInterface)247 void LightWayTxtParser::parse(librevenge::RVNGTextInterface *docInterface)
248 {
249   if (!getInput().get() || !getRSRCParser() || !checkHeader(nullptr))  throw(libmwaw::ParseException());
250   bool ok = false;
251   try {
252     // create the asciiFile
253     ascii().setStream(getInput());
254     ascii().open(asciiName());
255     checkHeader(nullptr);
256     ok = createZones();
257     if (ok) {
258       createDocument(docInterface);
259       m_graphParser->sendPageGraphics();
260       m_textParser->sendMainText();
261 #ifdef DEBUG
262       m_graphParser->flushExtra();
263       m_textParser->flushExtra();
264 #endif
265     }
266     ascii().reset();
267   }
268   catch (...) {
269     MWAW_DEBUG_MSG(("LightWayTxtParser::parse: exception catched when parsing\n"));
270     ok = false;
271   }
272 
273   resetTextListener();
274   if (!ok) throw(libmwaw::ParseException());
275 }
276 
277 ////////////////////////////////////////////////////////////
278 // create the document
279 ////////////////////////////////////////////////////////////
createDocument(librevenge::RVNGTextInterface * documentInterface)280 void LightWayTxtParser::createDocument(librevenge::RVNGTextInterface *documentInterface)
281 {
282   if (!documentInterface) return;
283   if (getTextListener()) {
284     MWAW_DEBUG_MSG(("LightWayTxtParser::createDocument: listener already exist\n"));
285     return;
286   }
287 
288   // update the page
289   m_state->m_actPage = 0;
290 
291   // create the page list
292   int numPages = 1;
293   if (m_graphParser->numPages() > numPages)
294     numPages = m_graphParser->numPages();
295   if (m_textParser->numPages() > numPages)
296     numPages = m_textParser->numPages();
297   m_state->m_numPages = numPages;
298 
299   MWAWPageSpan ps(getPageSpan());
300   if (m_textParser->hasHeaderFooter(true)) {
301     MWAWHeaderFooter header(MWAWHeaderFooter::HEADER, MWAWHeaderFooter::ALL);
302     header.m_subDocument.reset(new LightWayTxtParserInternal::SubDocument(*this, getInput(), true));
303     ps.setHeaderFooter(header);
304   }
305   if (m_textParser->hasHeaderFooter(false)) {
306     MWAWHeaderFooter footer(MWAWHeaderFooter::FOOTER, MWAWHeaderFooter::ALL);
307     footer.m_subDocument.reset(new LightWayTxtParserInternal::SubDocument(*this, getInput(), false));
308     ps.setHeaderFooter(footer);
309   }
310   ps.setPageSpan(m_state->m_numPages+1);
311   std::vector<MWAWPageSpan> pageList(1,ps);
312   MWAWTextListenerPtr listen(new MWAWTextListener(*getParserState(), pageList, documentInterface));
313   setTextListener(listen);
314   listen->startDocument();
315 }
316 
317 
318 ////////////////////////////////////////////////////////////
319 //
320 // Intermediate level
321 //
322 ////////////////////////////////////////////////////////////
createZones()323 bool LightWayTxtParser::createZones()
324 {
325   MWAWRSRCParserPtr rsrcParser = getRSRCParser();
326   if (!rsrcParser) {
327     MWAW_DEBUG_MSG(("LightWayTxtParser::createZones: can not find the entry map\n"));
328     return false;
329   }
330   auto &entryMap = rsrcParser->getEntriesMap();
331 
332   // the different zones
333   auto it = entryMap.lower_bound("LWSR");
334   while (it != entryMap.end()) {
335     if (it->first != "LWSR")
336       break;
337 
338     MWAWEntry const &entry = it++->second;
339     switch (entry.id()) {
340     case 1000:
341       readDocument(entry);
342       break;
343     case 1001:
344       readPrintInfo(entry);
345       break;
346     case 1002: // a list of int ?
347       readLWSR2(entry);
348       break;
349     case 1003:
350       readDocInfo(entry);
351       break;
352     case 1007:
353       readTOCPage(entry);
354       break;
355     default:
356       break;
357     }
358   }
359   it = entryMap.lower_bound("MPSR");
360   while (it != entryMap.end()) {
361     if (it->first != "MPSR")
362       break;
363 
364     MWAWEntry const &entry = it++->second;
365     switch (entry.id()) {
366     case 1005: // a constant block which contains a default font?
367       readMPSR5(entry);
368       break;
369     case 1007:
370       readTOC(entry);
371       break;
372     default:
373       break;
374     }
375   }
376   if (!m_textParser->createZones())
377     return false;
378   m_graphParser->createZones();
379   return true;
380 }
381 
382 ////////////////////////////////////////////////////////////
383 // read the doc/print info
384 ////////////////////////////////////////////////////////////
readDocInfo(MWAWEntry const & entry)385 bool LightWayTxtParser::readDocInfo(MWAWEntry const &entry)
386 {
387   if (entry.id() != 1003)
388     return false;
389   if (!entry.valid() || (entry.length()%0x40)) {
390     MWAW_DEBUG_MSG(("LightWayTxtParser::readDocInfo: the entry seems bad\n"));
391     return false;
392   }
393   MWAWInputStreamPtr input = rsrcInput();
394   libmwaw::DebugFile &ascFile = rsrcAscii();
395   input->seek(entry.begin(), librevenge::RVNG_SEEK_SET);
396   entry.setParsed(true);
397 
398   auto N=int(entry.length()/0x40);
399   libmwaw::DebugStream f;
400   for (int n = 0; n < N; n++) {
401     long pos = input->tell();
402     f.str("");
403     if (n==0)
404       f << "Entries(DocInfo):";
405     else
406       f << "DocInfo-" << n << ":";
407 
408     auto fl=int(input->readULong(1)); // 0|28
409     if (fl) f << "fl0=" << fl << ",";
410     long val=int(input->readULong(1)); // a small number less than 12
411     if (val) f << "f0=" << val << ",";
412     val = input->readLong(2); // 0|3|4|c
413     if (val) f << "f1=" << val << ",";
414     int dim[2];
415     for (auto &d : dim) d = int(input->readLong(2));
416     f << "dim=" << dim[0] << "x" << dim[1] << ",";
417     int margins[4];
418     f << "margins=[";
419     for (auto &margin : margins) {
420       margin = int(input->readLong(2));
421       f << margin << ",";
422     }
423     f << "],";
424     for (int i = 0; i < 6; i++) { // f2=0|1c, f3=7|9|f, f4=f6=f7=0|e, f5=0|e|54|78
425       val = input->readLong(2);
426       if (val) f << "f" << i+2 << "=" << val << ",";
427     }
428     for (int i = 0; i < 6; i++) { // f1=0|1, f2=1, f3=0|1, f4=0|1, f5=0, f6=1
429       val = static_cast<int>(input->readULong(1));
430       if (val) f << "fl" << i+1 << "=" << val << ",";
431     }
432     for (int i = 0; i < 5; i++) { // g0=0|18, g1=0|14, g4=0|..|6
433       val = input->readLong(2);
434       if (val) f << "g" << i << "=" << val << ",";
435     }
436     f << "col?=[" << std::hex;
437     for (int i = 0; i <3; i++)
438       f << input->readULong(2) << ",";
439     f << "]," << std::dec;
440     for (int i = 0; i < 6; i++) { // fl1=0|1, fl2=0|1, fl4=0|1, fl5=0|1
441       val = static_cast<int>(input->readULong(1));
442       if (val) f << "fl" << i << "(2)=" << val << ",";
443     }
444     for (int i = 0; i < 4; i++) { // alway 0?
445       val = input->readLong(2);
446       if (val) f << "h" << i << "=" << val << ",";
447     }
448 
449     ascFile.addPos(n==0 ? pos-4 : pos);
450     ascFile.addNote(f.str().c_str());
451     input->seek(pos+0x40, librevenge::RVNG_SEEK_SET);
452   }
453   return true;
454 }
455 
readPrintInfo(MWAWEntry const & entry)456 bool LightWayTxtParser::readPrintInfo(MWAWEntry const &entry)
457 {
458   if (!entry.valid() || entry.length() < 0x78) {
459     MWAW_DEBUG_MSG(("LightWayTxtParser::readPrintInfo: the entry is bad\n"));
460     return false;
461   }
462   if (entry.id() != 1001) {
463     MWAW_DEBUG_MSG(("LightWayTxtParser::readPrintInfo: the entry id %d is odd\n", entry.id()));
464   }
465   entry.setParsed(true);
466   MWAWInputStreamPtr input = rsrcInput();
467   long pos = entry.begin();
468   input->seek(pos, librevenge::RVNG_SEEK_SET);
469 
470   libmwaw::DebugStream f;
471   // print info
472   libmwaw::PrinterInfo info;
473   if (!info.read(input)) return false;
474   if (entry.id() != 1001)
475     f << "Entries(PrintInfo)[#" << entry.id() << "]:" << info;
476   else
477     f << "Entries(PrintInfo):" << info;
478   if (entry.length() != 0x78)
479     f << "###size=" << entry.length() << ",";
480   rsrcAscii().addPos(pos-4);
481   rsrcAscii().addNote(f.str().c_str());
482   if (m_pageSpanSet)
483     return true;
484 
485   MWAWVec2i paperSize = info.paper().size();
486   MWAWVec2i pageSize = info.page().size();
487   if (pageSize.x() <= 0 || pageSize.y() <= 0 ||
488       paperSize.x() <= 0 || paperSize.y() <= 0) return false;
489 
490   // define margin from print info
491   MWAWVec2i lTopMargin= -1 * info.paper().pos(0);
492   MWAWVec2i rBotMargin=info.paper().pos(1) - info.page().pos(1);
493 
494   // move margin left | top
495   int decalX = lTopMargin.x() > 14 ? lTopMargin.x()-14 : 0;
496   int decalY = lTopMargin.y() > 14 ? lTopMargin.y()-14 : 0;
497   lTopMargin -= MWAWVec2i(decalX, decalY);
498   rBotMargin += MWAWVec2i(decalX, decalY);
499 
500   // decrease right | bottom
501   int rightMarg = rBotMargin.x() -10;
502   if (rightMarg < 0) rightMarg=0;
503   int botMarg = rBotMargin.y() -50;
504   if (botMarg < 0) botMarg=0;
505 
506   getPageSpan().setMarginTop(lTopMargin.y()/72.0);
507   getPageSpan().setMarginBottom(botMarg/72.0);
508   getPageSpan().setMarginLeft(lTopMargin.x()/72.0);
509   getPageSpan().setMarginRight(rightMarg/72.0);
510   getPageSpan().setFormLength(paperSize.y()/72.);
511   getPageSpan().setFormWidth(paperSize.x()/72.);
512 
513   return true;
514 }
515 
516 ////////////////////////////////////////////////////////////
517 // read the TOC data
518 ////////////////////////////////////////////////////////////
readTOCPage(MWAWEntry const & entry)519 bool LightWayTxtParser::readTOCPage(MWAWEntry const &entry)
520 {
521   if (entry.id() != 1007)
522     return false;
523   if (!entry.valid() || entry.length()<0x24) {
524     MWAW_DEBUG_MSG(("LightWayTxtParser::readTOCPage: the entry is bad\n"));
525     return false;
526   }
527   MWAWInputStreamPtr input = rsrcInput();
528   libmwaw::DebugFile &ascFile = rsrcAscii();
529   long pos = entry.begin();
530   input->seek(pos, librevenge::RVNG_SEEK_SET);
531 
532   libmwaw::DebugStream f;
533   f << "Entries(TOCpage)[" << entry.id() << "]:";
534   entry.setParsed(true);
535   int dim[4];
536   for (auto &d : dim) d = static_cast<int>(input->readLong(4));
537   f << "dim?=" << dim[0] << "x" << dim[1]
538     << "<->"  << dim[2] << "x" << dim[3] << ",";
539   for (int i = 0; i < 9; i++) { // f5=1|2|21, f8=256
540     auto val = static_cast<int>(input->readLong(2));
541     if (val) f << "f" << i << "=" << val << ",";
542   }
543   auto N = static_cast<int>(input->readLong(2));
544   f << "N=" << N << ",";
545   if (input->tell()+N>entry.end()) {
546     MWAW_DEBUG_MSG(("LightWayTxtParser::readTOCPage: the page seems bead\n"));
547     f << "###";
548     ascFile.addPos(pos-4);
549     ascFile.addNote(f.str().c_str());
550     return false;
551   }
552   f << "pages=[";
553   for (int i = 0; i < N; i++)
554     f << static_cast<int>(input->readULong(1)) << ",";
555   f << "],";
556   ascFile.addPos(pos-4);
557   ascFile.addNote(f.str().c_str());
558   return true;
559 }
560 
readTOC(MWAWEntry const & entry)561 bool LightWayTxtParser::readTOC(MWAWEntry const &entry)
562 {
563   if (entry.id() != 1007)
564     return false;
565   if (!entry.valid() || entry.length()<2) {
566     MWAW_DEBUG_MSG(("LightWayTxtParser::readTOC: the entry is bad\n"));
567     return false;
568   }
569   MWAWInputStreamPtr input = rsrcInput();
570   libmwaw::DebugFile &ascFile = rsrcAscii();
571   long pos = entry.begin();
572   input->seek(pos, librevenge::RVNG_SEEK_SET);
573 
574   libmwaw::DebugStream f;
575   f << "Entries(TOCdata)[" << entry.id() << "]:";
576   entry.setParsed(true);
577   auto N=static_cast<int>(input->readULong(2));
578   f << "N=" << N << ",";
579   if (long(N*9+2) > entry.length()) {
580     MWAW_DEBUG_MSG(("LightWayTxtParser::readTOC: the number of entry seems bad\n"));
581     f << "###";
582     ascFile.addPos(pos-4);
583     ascFile.addNote(f.str().c_str());
584     return false;
585   }
586   ascFile.addPos(pos-4);
587   ascFile.addNote(f.str().c_str());
588 
589   bool ok = true;
590   for (int i = 0; i < N; i++) {
591     pos = input->tell();
592     if (pos+9 > entry.end()) {
593       ok = false;
594       break;
595     }
596     f.str("");
597     f << "TOCdata-" << i << ":";
598     long cPos[2];
599     for (auto &c : cPos) c = long(input->readULong(4));
600     f << "cpos?=" << cPos[0] << "<->" << cPos[1] << ",";
601     auto nC = static_cast<int>(input->readULong(1));
602     if (pos+9+nC > entry.end()) {
603       ok = false;
604       break;
605     }
606     std::string name("");
607     for (int c = 0; c < nC; c++)
608       name += char(input->readULong(1));
609     f << name;
610     ascFile.addPos(pos);
611     ascFile.addNote(f.str().c_str());
612     f.str("");
613     f << "[TOC" << i << "]";
614     ascii().addPos(cPos[0]);
615     ascii().addNote(f.str().c_str());
616   }
617   if (!ok) {
618     f << "###";
619     MWAW_DEBUG_MSG(("LightWayTxtParser::readTOC: can not read end\n"));
620     ascFile.addPos(pos);
621     ascFile.addNote(f.str().c_str());
622   }
623   return true;
624 }
625 
626 ////////////////////////////////////////////////////////////
627 // read the main document information data then unknown data
628 ////////////////////////////////////////////////////////////
readDocument(MWAWEntry const & entry)629 bool LightWayTxtParser::readDocument(MWAWEntry const &entry)
630 {
631   if (entry.id() != 1000)
632     return false;
633   if (!entry.valid() || entry.length()<0x28) {
634     MWAW_DEBUG_MSG(("LightWayTxtParser::readDocument: the entry seems bad\n"));
635     return false;
636   }
637   MWAWInputStreamPtr input = rsrcInput();
638   libmwaw::DebugFile &ascFile = rsrcAscii();
639   long pos = entry.begin();
640   input->seek(pos, librevenge::RVNG_SEEK_SET);
641 
642   libmwaw::DebugStream f;
643   f << "Entries(Document):";
644   entry.setParsed(true);
645   long val;
646   for (int i=0; i<3; i++) { // fl1=0|2|6, fl2=0|80
647     val = long(input->readULong(1));
648     if (val) f << "fl" << i << std::hex << "=" << val << std::dec << ",";
649   }
650   for (int i=0; i<2; i++) { // f0=0|1, f1=0|1
651     val = long(input->readLong(2));
652     if (val) f << "f" << i << "=" << val << ",";
653   }
654   for (int i=0; i<3; i++) { // fl3=0|1, fl4=0|1, fl5=1
655     val = long(input->readULong(1));
656     if (val) f << "fl" << i+3 << "=" << val << ",";
657   }
658   int pageDim[2];
659   for (auto &d : pageDim) d = static_cast<int>(input->readLong(2));
660   f << "dim=" << pageDim[1] << "x" << pageDim[0] << ",";
661   int dim[4];
662   for (int s=0; s<2; s++) {
663     for (auto &d: dim) d = static_cast<int>(input->readULong(2));
664     f << "pos" << s << "=" << dim[1] << "x" << dim[0]
665       << "<->" << dim[3] << "x" << dim[2] << ",";
666     if (s==1) break;
667 
668     int margins[4]= {dim[0], dim[1], pageDim[0]-dim[2], pageDim[1]-dim[3]};
669     if (margins[2] > 0 && 2*(margins[0]+margins[2]) < pageDim[0] &&
670         margins[3] > 0 && 2*(margins[1]+margins[3]) < pageDim[1]) {
671       getPageSpan().setMarginTop(double(margins[0])/72.0);
672       getPageSpan().setMarginBottom(double(margins[2])/72.0);
673       getPageSpan().setMarginLeft(double(margins[1])/72.0);
674       getPageSpan().setMarginRight(double(margins[3])/72.0);
675       getPageSpan().setFormLength(double(pageDim[0])/72.);
676       getPageSpan().setFormWidth(double(pageDim[1])/72.);
677       m_pageSpanSet = true;
678     }
679   }
680   m_state->m_numCol = static_cast<int>(input->readLong(2));
681   if (m_state->m_numCol > 1) f << "numCols=" << m_state->m_numCol << ",";
682   m_state->m_colSep = static_cast<int>(input->readLong(2));
683   if (m_state->m_colSep) f << "colSep=" << m_state->m_colSep << ",";
684 
685   for (int i=0; i<3; i++) { // gl0=3|3fff|4000|9001, gl1=3|4000|9001,gl2=d[12]|f[12]|1d2
686     val = long(input->readULong(2));
687     if (val) f << "gl" << i << "=" << std::hex << val << std::dec << ",";
688   }
689   ascFile.addPos(pos-4);
690   ascFile.addNote(f.str().c_str());
691   if (entry.length()==0x28)
692     return true;
693   m_textParser->readDocumentHF(entry);
694   return true;
695 }
696 
readLWSR2(MWAWEntry const & entry)697 bool LightWayTxtParser::readLWSR2(MWAWEntry const &entry)
698 {
699   if (entry.id() != 1002)
700     return false;
701   if (!entry.valid() || entry.length()%4) {
702     MWAW_DEBUG_MSG(("LightWayTxtParser::readLWSR2: the entry seems bad\n"));
703     return false;
704   }
705   auto N = int(entry.length()/4);
706   MWAWInputStreamPtr input = rsrcInput();
707   libmwaw::DebugFile &ascFile = rsrcAscii();
708   long pos = entry.begin();
709   input->seek(pos, librevenge::RVNG_SEEK_SET);
710 
711   libmwaw::DebugStream f;
712   f << "Entries(LWSR2):";
713   entry.setParsed(true);
714   f << "pos?=[" << std::hex;
715   for (int i = 0; i < N; i++)
716     f << input->readLong(4) << ",";
717   f << std::dec << "],";
718   ascFile.addPos(pos-4);
719   ascFile.addNote(f.str().c_str());
720   return true;
721 }
722 
readMPSR5(MWAWEntry const & entry)723 bool LightWayTxtParser::readMPSR5(MWAWEntry const &entry)
724 {
725   if (entry.id() != 1005)
726     return false;
727   if (!entry.valid() || entry.length() != 0x48) {
728     MWAW_DEBUG_MSG(("LightWayTxtParser::readMPSR5: the entry is bad\n"));
729     return false;
730   }
731   MWAWInputStreamPtr input = rsrcInput();
732   libmwaw::DebugFile &ascFile = rsrcAscii();
733   long pos = entry.begin();
734   input->seek(pos, librevenge::RVNG_SEEK_SET);
735 
736   libmwaw::DebugStream f;
737   f << "Entries(MPSR5):";
738   entry.setParsed(true);
739   long val = input->readLong(2); // a|c
740   if (val)
741     f << "f0=" << val << ",";
742   std::string name("");
743   for (int i = 0; i < 32; i++) {
744     auto c = char(input->readULong(1));
745     if (!c)
746       break;
747     name += c;
748   }
749   f << "defFont?=\"" << name << "\",";
750   input->seek(pos+34, librevenge::RVNG_SEEK_SET);
751   for (int i = 0; i < 2; i++) { // f1=3|4|6, f2=4
752     val = input->readLong(2);
753     if (val)
754       f << "f" << i+1 << "=" << val << ",";
755   }
756   int dim[4];
757   for (int s=0; s<2; s++) {
758     for (auto &d : dim) d = static_cast<int>(input->readLong(2));
759     f << "pos" << s << "=" << dim[1] << "x" << dim[0]
760       << "<->" << dim[3] << "x" << dim[2] << ",";
761   }
762   val = long(input->readULong(4)); // a very big number
763   if (val)
764     f << "unkn=" << std::hex << val << std::dec << ",";
765   long sel[2]; // checkme
766   for (long &i : sel)
767     i = input->readLong(4);
768   if (sel[0]==sel[1])
769     f << "sel?=" << std::hex << sel[0] << std::dec << ",";
770   else
771     f << "sel?=" << std::hex << sel[0] << "x" << sel[1] << std::dec << ",";
772   for (int i = 0; i < 2; i++) { // g1=0|6
773     val = input->readLong(2);
774     if (val)
775       f << "g" << i << "=" << val << ",";
776   }
777   for (int i = 0; i < 2; i++) { // fl0=0|1, fl1=0|1
778     val = long(input->readULong(1));
779     if (val)
780       f << "fl" << i << "=" << val << ",";
781   }
782 
783   ascFile.addPos(pos-4);
784   ascFile.addNote(f.str().c_str());
785   return true;
786 }
787 
788 ////////////////////////////////////////////////////////////
789 //
790 // Low level
791 //
792 ////////////////////////////////////////////////////////////
793 
794 ////////////////////////////////////////////////////////////
795 // read the header
796 ////////////////////////////////////////////////////////////
checkHeader(MWAWHeader * header,bool)797 bool LightWayTxtParser::checkHeader(MWAWHeader *header, bool /*strict*/)
798 {
799   *m_state = LightWayTxtParserInternal::State();
800   MWAWInputStreamPtr input = getInput();
801   if (!input || !getRSRCParser())
802     return false;
803   std::string type, creator;
804   if (input->getFinderInfo(type, creator) && type == "APPL")
805     m_state->m_isApplication=true;
806   MWAWEntry entry;
807   if (!m_state->m_isApplication) {
808     if (!input->hasDataFork())
809       return false;
810   }
811   else {
812     entry = getRSRCParser()->getEntry("TEXT", 128);
813     if (!entry.valid())
814       return false;
815   }
816   // check if the LWSR string exists
817   entry = getRSRCParser()->getEntry("LWSR", 1000);
818   if (!entry.valid()) {
819     MWAW_DEBUG_MSG(("LightWayTxtParser::checkHeader: can not find the LWSR[1000] resource, not a Mac File!!!\n"));
820     return false;
821   }
822   if (header)
823     header->reset(MWAWDocument::MWAW_T_LIGHTWAYTEXT, 1);
824 
825   return true;
826 }
827 
828 
829 // vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab:
830