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