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 <map>
38 #include <set>
39 #include <sstream>
40
41 #include <librevenge/librevenge.h>
42
43 #include "MWAWCell.hxx"
44 #include "MWAWTextListener.hxx"
45 #include "MWAWFont.hxx"
46 #include "MWAWFontConverter.hxx"
47 #include "MWAWHeader.hxx"
48 #include "MWAWPosition.hxx"
49 #include "MWAWPictMac.hxx"
50 #include "MWAWPrinter.hxx"
51 #include "MWAWRSRCParser.hxx"
52 #include "MWAWSubDocument.hxx"
53
54 #include "FullWrtGraph.hxx"
55 #include "FullWrtStruct.hxx"
56 #include "FullWrtText.hxx"
57
58 #include "FullWrtParser.hxx"
59
60 /** Internal: the structures of a FullWrtParser */
61 namespace FullWrtParserInternal
62 {
63 //! Internal and low level: a structure used to define the list of zone in Zone 0 data of a FullWrite file
64 struct DocZoneStruct {
65 //! constructor
DocZoneStructFullWrtParserInternal::DocZoneStruct66 DocZoneStruct()
67 : m_pos(-1)
68 , m_structType(0)
69 , m_type(-1)
70 , m_nextId(0)
71 , m_fatherId(-1)
72 , m_childList() {}
73 //! the operator<<
operator <<(std::ostream & o,DocZoneStruct const & dt)74 friend std::ostream &operator<<(std::ostream &o, DocZoneStruct const &dt)
75 {
76 switch (dt.m_structType) {
77 case 0:
78 o << "empty,";
79 break;
80 case 1: // normal
81 break;
82 case 4: // hidden?
83 o << "hidden,";
84 break;
85 default:
86 o << "#structType=" << dt.m_structType << ",";
87 break;
88 }
89 if (dt.m_type!=-1)
90 o << FullWrtStruct::getTypeName(dt.m_type);
91 if (dt.m_nextId) o << "nId=" << dt.m_nextId << ",";
92 if (dt.m_fatherId>=0) o << "fId=" << dt.m_fatherId << ",";
93 if (!dt.m_childList.empty()) {
94 o << "childs=[";
95 for (auto id : dt.m_childList)
96 o << id << ",";
97 o << "],";
98 }
99 return o;
100 }
101 //! the file position
102 long m_pos;
103 //! the struct type
104 int m_structType;
105 //! the type
106 int m_type;
107 //! the next id
108 int m_nextId;
109 //! the father id
110 int m_fatherId;
111 //! the list of child id
112 std::vector<int> m_childList;
113 };
114
115 ////////////////////////////////////////
116 //! Internal: the sidebar of a FullWrtParser
117 struct SideBar final : public FullWrtStruct::ZoneHeader {
118 //! constructor
SideBarFullWrtParserInternal::SideBar119 explicit SideBar(FullWrtStruct::ZoneHeader &)
120 : m_box()
121 , m_page(0)
122 {
123 }
124 //! destructor
125 ~SideBar() final;
126 //! the position (in point)
127 MWAWBox2f m_box;
128 //! the page
129 int m_page;
130 };
131
~SideBar()132 SideBar::~SideBar()
133 {
134 }
135
136 ////////////////////////////////////////
137 //! Internal: the reference data call of a FullWrtParser
138 struct ReferenceCalledData {
139 // constructor
ReferenceCalledDataFullWrtParserInternal::ReferenceCalledData140 ReferenceCalledData()
141 : m_id(-1)
142 {
143 for (auto &val : m_values) val=0;
144 }
145 //! the operator<<
operator <<(std::ostream & o,ReferenceCalledData const & dt)146 friend std::ostream &operator<<(std::ostream &o, ReferenceCalledData const &dt)
147 {
148 if (dt.m_id >= 0) o << "refId=" << dt.m_id << ",";
149 for (int i = 0; i < 5; i++) {
150 if (dt.m_values[i])
151 o << "f" << i << "=" << dt.m_values[i] << ",";
152 }
153 return o;
154 }
155 //! the reference id
156 int m_id;
157 //! some unknown values
158 int m_values[5];
159 };
160
161 ////////////////////////////////////////
162 //! Internal: the state of a FullWrtParser
163 struct State {
164 //! constructor
StateFullWrtParserInternal::State165 State()
166 : m_pageSpanSet(false)
167 , m_fileZoneList()
168 , m_fileZoneFlagsList()
169 , m_docZoneList()
170 , m_docFileIdMap()
171 , m_fileDocIdMap()
172 , m_biblioId(-1)
173 , m_entryMap()
174 , m_variableRedirectMap()
175 , m_referenceRedirectMap()
176 , m_actPage(0)
177 , m_numPages(0)
178 , m_headerHeight(0)
179 , m_footerHeight(0)
180 {
181 for (auto &fl : m_zoneFlagsId) fl = -1;
182 }
183
184 //! insert a docId fileId in the correspondance map
addCorrespondanceFullWrtParserInternal::State185 bool addCorrespondance(int docId, int fileId)
186 {
187 if (m_docFileIdMap.find(docId) != m_docFileIdMap.end() ||
188 m_fileDocIdMap.find(fileId) != m_fileDocIdMap.end()) {
189 MWAW_DEBUG_MSG(("FullWrtParserInternal::State::addCorrespondance can not insert %d<->%d\n", docId, fileId));
190 return false;
191 }
192 m_fileDocIdMap[fileId]=docId;
193 m_docFileIdMap[docId]=fileId;
194 // update the zone type ( if possible )
195 if (docId >= 0 && docId < int(m_docZoneList.size()) &&
196 m_entryMap.find(fileId) != m_entryMap.end() &&
197 m_entryMap.find(fileId)->second)
198 m_entryMap.find(fileId)->second->m_fileType = m_docZoneList[size_t(docId)].m_type;
199 else {
200 MWAW_DEBUG_MSG(("FullWrtParserInternal::State::addCorrespondance can not update the zone type for %d<->%d\n", docId, fileId));
201 }
202 return true;
203 }
204 //! return the file zone id ( if found or -1)
getFileZoneIdFullWrtParserInternal::State205 int getFileZoneId(int docId) const
206 {
207 auto it = m_docFileIdMap.find(docId);
208 if (it == m_docFileIdMap.end()) {
209 MWAW_DEBUG_MSG(("FullWrtParserInternal::State::getFileZoneId can not find %d\n", docId));
210 return -1;
211 }
212 return it->second;
213 }
214 //! a flag to know if the page span has been filled
215 bool m_pageSpanSet;
216 //! the list of main zone flags id
217 int m_zoneFlagsId[3];
218
219 //! the list of file zone position
220 FullWrtStruct::EntryPtr m_fileZoneList;
221
222 //! the list of file zone flags
223 FullWrtStruct::EntryPtr m_fileZoneFlagsList;
224
225 //! the list of the documents zone list
226 std::vector<DocZoneStruct> m_docZoneList;
227
228 //! the correspondance doc id -> file id
229 std::map<int,int> m_docFileIdMap;
230
231 //! the correspondance file id -> doc id
232 std::map<int,int> m_fileDocIdMap;
233
234 //! the bibliography id
235 int m_biblioId;
236
237 //! zoneId -> entry
238 std::multimap<int, FullWrtStruct::EntryPtr > m_entryMap;
239
240 //! redirection docId -> variable docId
241 std::map<int,int> m_variableRedirectMap;
242
243 //! redirection docId -> reference docId
244 std::map<int,ReferenceCalledData> m_referenceRedirectMap;
245
246 int m_actPage /** the actual page */, m_numPages /** the number of page of the final document */;
247
248 int m_headerHeight /** the header height if known */,
249 m_footerHeight /** the footer height if known */;
250 };
251
252 ////////////////////////////////////////
253 //! Internal: the subdocument of a FullWrtParser
254 class SubDocument final : public MWAWSubDocument
255 {
256 public:
SubDocument(FullWrtParser & pars,MWAWInputStreamPtr const & input,int zoneId)257 SubDocument(FullWrtParser &pars, MWAWInputStreamPtr const &input, int zoneId)
258 : MWAWSubDocument(&pars, input, MWAWEntry())
259 , m_id(zoneId) {}
260
261 //! destructor
~SubDocument()262 ~SubDocument() final {}
263
264 //! operator!=
operator !=(MWAWSubDocument const & doc) const265 bool operator!=(MWAWSubDocument const &doc) const final
266 {
267 if (MWAWSubDocument::operator!=(doc)) return true;
268 auto const *sDoc = dynamic_cast<SubDocument const *>(&doc);
269 if (!sDoc) return true;
270 if (m_id != sDoc->m_id) return true;
271 return false;
272 }
273
274 //! the parser function
275 void parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType type) final;
276
277 protected:
278 //! the subdocument id
279 int m_id;
280 };
281
parse(MWAWListenerPtr & listener,libmwaw::SubDocumentType)282 void SubDocument::parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType /*type*/)
283 {
284 if (!listener.get()) {
285 MWAW_DEBUG_MSG(("FullWrtParserInternall::SubDocument::parse: no listener\n"));
286 return;
287 }
288 auto *parser=dynamic_cast<FullWrtParser *>(m_parser);
289 if (!parser) {
290 MWAW_DEBUG_MSG(("FullWrtParserInternall::SubDocument::parse: no parser\n"));
291 return;
292 }
293
294 long pos = m_input->tell();
295 parser->send(m_id);
296 m_input->seek(pos, librevenge::RVNG_SEEK_SET);
297 }
298 }
299
300 ////////////////////////////////////////////////////////////
301 // constructor/destructor, ...
302 ////////////////////////////////////////////////////////////
FullWrtParser(MWAWInputStreamPtr const & input,MWAWRSRCParserPtr const & rsrcParser,MWAWHeader * header)303 FullWrtParser::FullWrtParser(MWAWInputStreamPtr const &input, MWAWRSRCParserPtr const &rsrcParser, MWAWHeader *header)
304 : MWAWTextParser(input, rsrcParser, header)
305 , m_state()
306 , m_graphParser()
307 , m_textParser()
308 {
309 init();
310 }
311
~FullWrtParser()312 FullWrtParser::~FullWrtParser()
313 {
314 for (auto it : m_state->m_entryMap) {
315 FullWrtStruct::EntryPtr zone = it.second;
316 if (zone) zone->closeDebugFile();
317 }
318 }
319
init()320 void FullWrtParser::init()
321 {
322 resetTextListener();
323 setAsciiName("main-1");
324
325 m_state.reset(new FullWrtParserInternal::State);
326
327 // reduce the margin (in case, the page is not defined)
328 getPageSpan().setMargins(0.1);
329
330 m_graphParser.reset(new FullWrtGraph(*this));
331 m_textParser.reset(new FullWrtText(*this));
332 }
333
334 ////////////////////////////////////////////////////////////
335 // new page, interface function
336 ////////////////////////////////////////////////////////////
newPage(int number)337 void FullWrtParser::newPage(int number)
338 {
339 if (number <= m_state->m_actPage || number > m_state->m_numPages)
340 return;
341
342 while (m_state->m_actPage < number) {
343 m_state->m_actPage++;
344 if (!getTextListener() || m_state->m_actPage == 1)
345 continue;
346 getTextListener()->insertBreak(MWAWTextListener::PageBreak);
347 }
348 }
349
getPageLeftTop() const350 MWAWVec2f FullWrtParser::getPageLeftTop() const
351 {
352 return MWAWVec2f(float(getPageSpan().getMarginLeft()),
353 float(getPageSpan().getMarginTop()+m_state->m_headerHeight/72.0));
354 }
355
getBorder(int bId,FullWrtStruct::Border & border) const356 bool FullWrtParser::getBorder(int bId, FullWrtStruct::Border &border) const
357 {
358 return m_graphParser->getBorder(bId, border);
359 }
360
getNumDocZoneStruct() const361 int FullWrtParser::getNumDocZoneStruct() const
362 {
363 return int(m_state->m_docZoneList.size());
364 }
365
getDocumentTypeName(int id) const366 std::string FullWrtParser::getDocumentTypeName(int id) const
367 {
368 if (id<0||id >= int(m_state->m_docZoneList.size()))
369 return "";
370 return FullWrtStruct::getTypeName(m_state->m_docZoneList[size_t(id)].m_type);
371 }
372
sendGraphic(int id)373 void FullWrtParser::sendGraphic(int id)
374 {
375 if (id < 0 || id >= int(m_state->m_docZoneList.size())) {
376 MWAW_DEBUG_MSG(("FullWrtParser::sendGraphic: can not find graphic data for zone %d\n", id));
377 }
378 else {
379 auto const &data = m_state->m_docZoneList[size_t(id)];
380 if (data.m_type != 0x15) {
381 MWAW_DEBUG_MSG(("FullWrtParser::sendGraphic: call for zone[%x]\n", static_cast<unsigned int>(data.m_type)));
382 }
383 }
384 m_graphParser->sendGraphic(m_state->getFileZoneId(id));
385 }
386
send(int fileId,MWAWColor fontColor)387 bool FullWrtParser::send(int fileId, MWAWColor fontColor)
388 {
389 if (fileId < 0) {
390 if (getTextListener()) getTextListener()->insertChar(' ');
391 return true;
392 }
393 return m_textParser->send(fileId, fontColor);
394 }
395
396 ////////////////////////////////////////////////////////////
397 // the parser
398 ////////////////////////////////////////////////////////////
parse(librevenge::RVNGTextInterface * docInterface)399 void FullWrtParser::parse(librevenge::RVNGTextInterface *docInterface)
400 {
401 if (!getInput().get() || !checkHeader(nullptr)) throw(libmwaw::ParseException());
402 bool ok = true;
403 try {
404 #ifdef DEBUG
405 // just test if a rsrc exists
406 if (getRSRCParser()) {
407 MWAW_DEBUG_MSG(("FullWrtParser::parse: find a ressource fork\n"));
408 getRSRCParser()->getEntry("STR ", 700);
409 }
410 #endif
411 // create the asciiFile
412 ascii().setStream(getInput());
413 ascii().open(asciiName());
414
415 checkHeader(nullptr);
416 ok = createZones();
417 if (ok) {
418 createDocument(docInterface);
419 m_graphParser->sendPageGraphics();
420 m_textParser->sendMainText();
421 m_graphParser->flushExtra();
422 #ifdef DEBUG
423 m_textParser->flushExtra();
424 #endif
425 }
426 bool first = true;
427 libmwaw::DebugStream f;
428 for (auto it : m_state->m_entryMap) {
429 FullWrtStruct::EntryPtr zone = it.second;
430 if (!zone || !zone->valid() || zone->isParsed()) continue;
431 f.str("");
432 if (zone->hasType("UnknownZone"))
433 f << "Entries(NotParsed)";
434 else
435 f << "Entries(" << zone->type() << ")";
436 if (zone->hasType("Biblio")) {
437 MWAW_DEBUG_MSG(("FullWrtParser::parse: find some biblio zone unparsed!!!\n"));
438 }
439 else if (first) {
440 f << "###";
441 first = false;
442 MWAW_DEBUG_MSG(("FullWrtParser::parse: find some unparsed zone!!!\n"));
443 }
444 if (zone->m_nextId != -2) f << "[" << zone->m_nextId << "]";
445 f << "|" << *zone << ":";
446 libmwaw::DebugFile &asciiFile = zone->getAsciiFile();
447
448 asciiFile.addPos(zone->begin());
449 asciiFile.addNote(f.str().c_str());
450 asciiFile.addPos(zone->end());
451 asciiFile.addNote("_");
452
453 zone->closeDebugFile();
454 }
455
456 ascii().reset();
457 }
458 catch (...) {
459 MWAW_DEBUG_MSG(("FullWrtParser::parse: exception catched when parsing\n"));
460 ok = false;
461 }
462
463 resetTextListener();
464 if (!ok) throw(libmwaw::ParseException());
465 }
466
467 ////////////////////////////////////////////////////////////
468 // create the document
469 ////////////////////////////////////////////////////////////
createDocument(librevenge::RVNGTextInterface * documentInterface)470 void FullWrtParser::createDocument(librevenge::RVNGTextInterface *documentInterface)
471 {
472 if (!documentInterface) return;
473 if (getTextListener()) {
474 MWAW_DEBUG_MSG(("FullWrtParser::createDocument: listener already exist\n"));
475 return;
476 }
477
478 // update the page
479 m_state->m_actPage = 0;
480 int numPage = m_textParser->numPages();
481 if (m_graphParser->numPages()>numPage)
482 numPage=m_graphParser->numPages();
483 m_state->m_numPages = numPage;
484
485 // create the page list
486 int actHeaderId = -1, actFooterId = -1;
487 std::shared_ptr<FullWrtParserInternal::SubDocument> headerSubdoc, footerSubdoc;
488 std::vector<MWAWPageSpan> pageList;
489 for (int i = 0; i < m_state->m_numPages;) {
490 int numSim[2]= {1,1};
491 int headerId = m_textParser->getHeaderFooterId(true,i+1, numSim[0]);
492 if (headerId != actHeaderId) {
493 actHeaderId = headerId;
494 if (actHeaderId == -1)
495 headerSubdoc.reset();
496 else
497 headerSubdoc.reset
498 (new FullWrtParserInternal::SubDocument(*this, getInput(), headerId));
499 }
500 int footerId = m_textParser->getHeaderFooterId(false, i+1, numSim[1]);
501 if (footerId != actFooterId) {
502 actFooterId = footerId;
503 if (actFooterId == -1)
504 footerSubdoc.reset();
505 else
506 footerSubdoc.reset
507 (new FullWrtParserInternal::SubDocument(*this, getInput(), footerId));
508 }
509
510 MWAWPageSpan ps(getPageSpan());
511 if (headerSubdoc) {
512 MWAWHeaderFooter header(MWAWHeaderFooter::HEADER, MWAWHeaderFooter::ALL);
513 header.m_subDocument=headerSubdoc;
514 ps.setHeaderFooter(header);
515 }
516 if (footerSubdoc) {
517 MWAWHeaderFooter footer(MWAWHeaderFooter::FOOTER, MWAWHeaderFooter::ALL);
518 footer.m_subDocument=footerSubdoc;
519 ps.setHeaderFooter(footer);
520 }
521 if (numSim[1] < numSim[0]) numSim[0]=numSim[1];
522 if (numSim[0] < 1) numSim[0]=1;
523 ps.setPageSpan(numSim[0]);
524 i+=numSim[0];
525 pageList.push_back(ps);
526 }
527
528 // retrieve the header/footer
529 MWAWTextListenerPtr listen(new MWAWTextListener(*getParserState(), pageList, documentInterface));
530 setTextListener(listen);
531 listen->startDocument();
532 }
533
534
535 ////////////////////////////////////////////////////////////
536 //
537 // Intermediate level
538 //
539 ////////////////////////////////////////////////////////////
createFileZones()540 bool FullWrtParser::createFileZones()
541 {
542 /* FileZonePos: define a list of zone in the file and a link between these zone
543 FileZoneFlags: define the list of contents zone and link each to the first file zone
544 */
545
546 // first creates the zone (entry are mapped by number of the zones in the file)
547 if (m_state->m_fileZoneList)
548 readFileZonePos(m_state->m_fileZoneList);
549 // update each main filezone, ie. move appart the 3 main zone and sets their final ids
550 if (m_state->m_fileZoneFlagsList)
551 readFileZoneFlags(m_state->m_fileZoneFlagsList);
552
553 // finally, remapped the enry by fId
554 std::vector<FullWrtStruct::EntryPtr > listZones;
555 for (auto it : m_state->m_entryMap)
556 listZones.push_back(it.second);
557 m_state->m_entryMap.clear();
558 for (auto &entry : listZones) {
559 if (!entry->valid() || entry->isParsed()) continue;
560 int fId = entry->id();
561 if (entry->m_typeId == -1) fId=-fId-1;
562 if (m_state->m_entryMap.find(fId) != m_state->m_entryMap.end()) {
563 MWAW_DEBUG_MSG(("FullWrtParser::createFileZones: can not find generic zone id %d\n",fId));
564 }
565 else
566 m_state->m_entryMap.insert
567 (std::multimap<int, FullWrtStruct::EntryPtr >::value_type(fId, entry));
568 }
569 return true;
570 }
571
createZones()572 bool FullWrtParser::createZones()
573 {
574 createFileZones();
575
576 // first treat the main zones
577 std::vector<FullWrtStruct::EntryPtr > mainZones;
578 mainZones.resize(3);
579 for (auto it : m_state->m_entryMap) {
580 FullWrtStruct::EntryPtr &zone = it.second;
581 if (!zone || !zone->valid() || zone->isParsed()) continue;
582 if (zone->m_typeId != -1 || zone->id() < 0 || zone->id() >= 3)
583 continue;
584 auto zId = size_t(zone->id());
585 if (mainZones[size_t(zId)]) {
586 MWAW_DEBUG_MSG(("FullWrtParser::createZones: Oops main zone %d already founded\n", int(zId)));
587 continue;
588 }
589 mainZones[zId] = zone;
590 }
591 if (!mainZones[1] || !readDocZoneStruct(mainZones[1])) {
592 MWAW_DEBUG_MSG(("FullWrtParser::createZones: can not read the docZoneStruct zone\n"));
593 }
594 if (!mainZones[0] || !readDocZoneData(mainZones[0])) {
595 MWAW_DEBUG_MSG(("FullWrtParser::createZones: can not read the docZoneData zone\n"));
596 }
597 if (!mainZones[2] || !readDocInfo(mainZones[2])) {
598 MWAW_DEBUG_MSG(("FullWrtParser::createZones: can not read the document information zone\n"));
599 }
600
601 // now treat the other zones
602 for (auto it : m_state->m_entryMap) {
603 FullWrtStruct::EntryPtr &zone = it.second;
604 if (!zone || !zone->valid() || zone->isParsed()) continue;
605 if (zone->m_typeId >= 0) {
606 // first use the zone type
607 bool done = false;
608 switch (zone->m_fileType) {
609 case 0x15:
610 done = m_graphParser->readGraphic(zone);
611 break;
612 case 0xa:
613 case 0xb:
614 case 0xc:
615 case 0xd:
616 case 0xe:
617 case 0xf:
618 case 0x10:
619 case 0x11:
620 case 0x12:
621 case 0x13:
622 case 0x14:
623 case 0x18:
624 done = m_textParser->readTextData(zone);
625 break;
626 default:
627 break;
628 }
629 if (done) continue;
630
631 // unknown, so try all possibilities
632 if (m_graphParser->readGraphic(zone)) continue;
633 if (m_textParser->readTextData(zone)) continue;
634 }
635 else if (zone->m_typeId == -1) {
636 if (zone->id()>=0 && zone->id()< 3) {
637 MWAW_DEBUG_MSG(("FullWrtParser::createZones: Oops find an unparsed main zone %d\n", zone->id()));
638 }
639 else if (zone->hasType("Biblio")) {
640 MWAW_DEBUG_MSG(("FullWrtParser::createZones: find a bibliography zone: unparsed\n"));
641 }
642 else {
643 MWAW_DEBUG_MSG(("FullWrtParser::createZones: find unexpected general zone\n"));
644 }
645 }
646 }
647 m_textParser->prepareData();
648 return true;
649 }
650
651 ////////////////////////////////////////////////////////////
652 //
653 // Low level
654 //
655 ////////////////////////////////////////////////////////////
656
657 ////////////////////////////////////////////////////////////
658 // read the header
659 ////////////////////////////////////////////////////////////
checkHeader(MWAWHeader * header,bool)660 bool FullWrtParser::checkHeader(MWAWHeader *header, bool /*strict*/)
661 {
662 *m_state = FullWrtParserInternal::State();
663
664 MWAWInputStreamPtr input = getInput();
665 if (!input || !input->hasDataFork())
666 return false;
667
668 int const minSize=50;
669 input->seek(minSize,librevenge::RVNG_SEEK_SET);
670 if (int(input->tell()) != minSize) {
671 MWAW_DEBUG_MSG(("FullWrtParser::checkHeader: file is too short\n"));
672 return false;
673 }
674
675 if (!readDocPosition())
676 return false;
677
678 input->seek(0,librevenge::RVNG_SEEK_SET);
679
680 if (header)
681 header->reset(MWAWDocument::MWAW_T_FULLWRITE, 1);
682
683 return true;
684 }
685
readDocInfo(FullWrtStruct::EntryPtr zone)686 bool FullWrtParser::readDocInfo(FullWrtStruct::EntryPtr zone)
687 {
688 if (zone->length() < 0x4b2)
689 return false;
690 MWAWInputStreamPtr input = zone->m_input;
691 libmwaw::DebugFile &asciiFile = zone->getAsciiFile();
692 libmwaw::DebugStream f;
693
694 long pos = zone->begin();
695 input->seek(pos, librevenge::RVNG_SEEK_SET);
696 auto N = static_cast<int>(input->readLong(2));
697 if (!N) return false;
698 input->seek(4, librevenge::RVNG_SEEK_CUR);
699 auto val = static_cast<int>(input->readLong(2));
700 if (N < val-2 || N > val+2) return false;
701 input->seek(2, librevenge::RVNG_SEEK_CUR);
702 auto nC = static_cast<int>(input->readULong(1));
703 if (!nC || nC > 70) return false;
704 for (int i = 0; i < nC; i++) {
705 auto c = static_cast<int>(input->readULong(1));
706 if (c < 0x20) return false;
707 }
708
709 zone->setParsed(true);
710 input->seek(pos+2, librevenge::RVNG_SEEK_SET);
711 f << "Entries(DocInfo)|" << *zone << ":";
712 f << "N0=" << N << ",";
713 f << "unkn0=" << std::hex << input->readULong(2) << std::dec << ","; // big number
714 for (int i = 0; i < 2; i++) { // 0|1|a7|ff followed by a small number
715 val = static_cast<int>(input->readULong(1));
716 if (val) f << "f" << i << "=" << std::hex << val << std::dec << ",";
717 }
718 val = static_cast<int>(input->readLong(2)); // almost always N
719 if (val != N) f << "N1=" << val << ",";
720 f << "unkn1=" << std::hex << input->readULong(2) << std::dec << ","; // big number
721 std::string title("");
722 nC = static_cast<int>(input->readULong(1));
723 for (int i = 0; i < nC; i++)
724 title += char(input->readLong(1));
725 f << "title=" << title << ",";
726 asciiFile.addDelimiter(input->tell(),'|');
727 asciiFile.addPos(pos);
728 asciiFile.addNote(f.str().c_str());
729
730 pos += 10+70; // checkme
731 input->seek(pos, librevenge::RVNG_SEEK_SET);
732 f.str("");
733 f << "DocInfo-A:";
734 for (int i = 0; i < 4; i++) { // 0, 1, 2, 80
735 val = static_cast<int>(input->readULong(1));
736 if (val)
737 f << "fl" << i << "=" << std::hex << val << std::dec << ",";
738 }
739 val = static_cast<int>(input->readLong(2)); // almost always 0, but find also 53, 64, ba, f4
740 if (val) f << "f0=" << val << ",";
741 f << "unkn=["; // 2 big number which seems realted
742 for (int i = 0; i < 2; i++)
743 f << std::hex << input->readULong(4) << std::dec << ",";
744 f << "],";
745 for (int i = 4; i < 6; i++) { // always 1, 0 ?
746 val = static_cast<int>(input->readULong(1));
747 if (val!=5-i) f << "fl" << i << "=" << std::hex << val << std::dec << ",";
748 }
749 // 5 relative big number : multiple of 4
750 auto ptr = long(input->readULong(4));
751 f << "unkn2=[" << std::hex << ptr << "," << std::dec;
752 for (int i = 0; i < 4; i++)
753 f << long(input->readULong(4))-ptr << ",";
754 f << "],";
755 val = static_cast<int>(input->readLong(2)); // almost always -2, but find also 6
756 if (val != -2)
757 f << "f1=" << val << ",";
758 for (int i = 0; i < 2; i++) { // always 0,0
759 val = static_cast<int>(input->readULong(2));
760 if (val) f << "f" << i+2 << "=" << std::hex << val << std::dec << ",";
761 }
762 for (int st=0; st < 2; st++) {
763 long actPos = input->tell();
764 val = static_cast<int>(input->readULong(2)); // big number
765 if (val) f << "g" << st << "=" << std::hex << val << std::dec << ",";
766
767 nC = static_cast<int>(input->readULong(1));
768 if (nC > 32) {
769 MWAW_DEBUG_MSG(("FullWrtParser::readDocInfo: can not read user name\n"));
770 nC = 0;
771 }
772 std::string s("");
773 for (int i = 0; i < nC; i++) s+=char(input->readLong(1));
774 if (nC)
775 f << "Username" << st << "=" << s << ",";
776 input->seek(actPos+36, librevenge::RVNG_SEEK_SET);
777 }
778
779 asciiFile.addPos(pos);
780 asciiFile.addNote(f.str().c_str());
781 pos = input->tell();
782 asciiFile.addPos(pos);
783 asciiFile.addNote("DocInfo-B");
784 pos+=196;
785 input->seek(pos, librevenge::RVNG_SEEK_SET);
786 for (int i = 0; i < 6; i++) {
787 pos = input->tell();
788 f.str("");
789 f << "DocInfo-C" << i << ":" << input->readLong(2);
790
791 asciiFile.addPos(pos);
792 asciiFile.addNote(f.str().c_str());
793 input->seek(pos+48, librevenge::RVNG_SEEK_SET);
794 }
795 for (int i = 0; i < 9; i++) {
796 pos = input->tell();
797 f.str("");
798 f << "DocInfo-D" << i << ":";
799
800 asciiFile.addPos(pos);
801 asciiFile.addNote(f.str().c_str());
802 input->seek(pos+38, librevenge::RVNG_SEEK_SET);
803 }
804 pos = input->tell();
805 asciiFile.addPos(pos);
806 asciiFile.addNote("DocInfo-E");
807 input->seek(pos+182, librevenge::RVNG_SEEK_SET);
808
809 // this part in v1 and v2
810 pos = input->tell();
811 f.str("");
812 f << "DocInfo-F:";
813 bool ok = true;
814 if (version()==2) {
815 asciiFile.addPos(pos);
816 asciiFile.addNote(f.str().c_str());
817 input->seek(pos+436, librevenge::RVNG_SEEK_SET);
818 pos = input->tell();
819 if (!readEndDocInfo(zone)) {
820 asciiFile.addPos(pos);
821 asciiFile.addNote("DocInfoII#");
822 ok = false;
823 }
824 }
825 else {
826 if (pos+18 < zone->end()) {
827 val = static_cast<int>(input->readLong(2)); // always 0
828 if (val) f << "f0=" << val << ",";
829 val = static_cast<int>(input->readLong(4)); // can be a big number (often neg )
830 if (val) f << "f1=" << val << ",";
831 // always 0 except one time g0=a,g1=1d,g5=50fe
832 for (int i = 0; i < 6; i++) {
833 val = static_cast<int>(input->readULong(2));
834 if (val) f << "g" << i << "=" << std::hex << val << std::dec << ",";
835 }
836 }
837 else {
838 ok = false;
839 f << "#";
840 }
841 asciiFile.addPos(pos);
842 asciiFile.addNote(f.str().c_str());
843 }
844
845 if (ok) {
846 pos=input->tell();
847 f.str("");
848 f << "DocInfo-G:";
849 auto type=static_cast<int>(input->readULong(2));
850 f << "f0=" << std::hex << type << std::dec << ",";
851 int dim[4];
852 for (auto &d : dim) d=static_cast<int>(input->readLong(2));
853 f << "dim=" << dim[1] << "x" << dim[0] << "<->"
854 << dim[3] << "x" << dim[2] << ",";
855 // checkme: 3: followed by 2 int, 6-b: followed by 3 int, e-f: by 4, other?
856 int num=(type&0xF000)>=0xE000 ? 4:(type&0xF000)>0x3000 ? 3:2;
857 for (int i=0; i< num; ++i) { // f1=0x100, f3=3
858 val=static_cast<int>(input->readLong(2));
859 if (val) f << "f" << i+1 << "=" << val << ",";
860 }
861 for (int st=0; st<2; ++st) { // probably left/right page
862 int margins[4];
863 for (auto &margin : margins) margin=static_cast<int>(input->readLong(2));
864 f << "pageDim" << st << "=" << margins[1] << "x" << margins[0] << "<->"
865 << margins[3] << "x" << margins[2] << ",";
866 if (st==1)
867 break;
868 if (margins[0]<margins[2] && margins[2]<dim[2] && 2*(margins[2]-margins[0]) > dim[2] &&
869 margins[1]<margins[3] && margins[3]<dim[3] && 2*(margins[3]-margins[1]) > dim[3] &&
870 dim[2]>100 && dim[2]<2000 && dim[3]>100 && dim[3]<2000) {
871 getPageSpan().setMarginTop(double(margins[0])/72.0);
872 getPageSpan().setMarginBottom(double(dim[2]-margins[2])/72.0);
873 getPageSpan().setMarginLeft(double(margins[1])/72.0);
874 getPageSpan().setMarginRight(double(dim[3]-margins[3])/72.0);
875 getPageSpan().setFormLength(double(dim[2])/72.);
876 getPageSpan().setFormWidth(double(dim[3])/72.);
877 m_state->m_pageSpanSet=true;
878 }
879 else {
880 MWAW_DEBUG_MSG(("FullWrtParser::readDocInfo:can not read document margins!\n"));
881 }
882 }
883 asciiFile.addDelimiter(input->tell(),'|');
884
885 asciiFile.addPos(pos);
886 asciiFile.addNote(f.str().c_str());
887 /* seems to end with
888 00000009000043686f6f73657200
889 000000100000436f6e74726f6c2050616e656c7300
890 0000000b000046696e642046696c6500
891 0000001500004772617068696e672043616c63756c61746f7200
892 0000000f00004a69677361772050757a7a6c6500
893 0000000a00004b6579204361707300
894 0000000a00004e6f74652050616400
895 0000001500000000000000000000000000006361000000000000
896 */
897 }
898 // try to retrieve the last part: printInfo+3 int
899 input->seek(zone->end()-130, librevenge::RVNG_SEEK_SET);
900 if (readPrintInfo(zone)) {
901 pos = input->tell();
902 f.str("");
903 f << "DocInfo-End:";
904 if (pos == zone->end()-6) {
905 // f0=0, f1=0|1(in v2) but can also be a big number in v1, f2=0|1a
906 for (int i = 0; i < 3; i++) {
907 val = static_cast<int>(input->readLong(2));
908 if (val) f << "f" << i << "=" << val << ",";
909 }
910 }
911 else
912 f << "#";
913 asciiFile.addPos(pos);
914 asciiFile.addNote(f.str().c_str());
915 }
916 else {
917 MWAW_DEBUG_MSG(("FullWrtParser::readDocInfo: can not find print info\n"));
918 asciiFile.addPos(zone->end()-130);
919 asciiFile.addNote("DocInfo-G#");
920 }
921
922 zone->closeDebugFile();
923 return true;
924 }
925
926 ////////////////////////////////////////////////////////////
927 // read the end of the zone data
readEndDocInfo(FullWrtStruct::EntryPtr zone)928 bool FullWrtParser::readEndDocInfo(FullWrtStruct::EntryPtr zone)
929 {
930 if (version() < 2)
931 return false;
932
933 MWAWInputStreamPtr input = zone->m_input;
934 libmwaw::DebugFile &asciiFile = zone->getAsciiFile();
935 libmwaw::DebugStream f;
936
937 // at least 4 possible zones, maybe more...
938 for (int i = 0; i < 5; i++) {
939 long pos = input->tell();
940 bool ok = true;
941 std::string name("");
942 for (int j = 0; j < 4; j++) {
943 auto val=int(input->readULong(1));
944 if (val < 9) {
945 ok = false;
946 break;
947 }
948 name+=char(val);
949 }
950 if (!ok || input->readULong(1)) {
951 input->seek(pos, librevenge::RVNG_SEEK_SET);
952 break;
953 }
954 input->seek(pos, librevenge::RVNG_SEEK_SET);
955 ok = false;
956 if (name=="font") // block0 : unseen
957 ;
958 else if (name=="bord")
959 ok = m_graphParser->readBorderDocInfo(zone);
960 else if (name=="extr")
961 ok = m_textParser->readParaModDocInfo(zone);
962 else if (name=="cite") // block3
963 ok = readCitationDocInfo(zone);
964
965 if (ok)
966 continue;
967
968 MWAW_DEBUG_MSG(("FullWrtParser::readEndDocInfo: can not read block %s\n", name.c_str()));
969 input->seek(pos+5, librevenge::RVNG_SEEK_SET);
970 long blckSz = input->readLong(4);
971 if (blckSz < 2 || pos+8+blckSz > zone->end()) {
972 input->seek(pos, librevenge::RVNG_SEEK_SET);
973 break;
974 }
975 auto num=int(input->readULong(2));
976 f.str("");
977 f << "Entries(Doc" << name << "):N=" << num << ",###";
978 asciiFile.addPos(pos);
979 asciiFile.addNote(f.str().c_str());
980 input->seek(pos+9+blckSz, librevenge::RVNG_SEEK_SET);
981 }
982 return true;
983 }
984
readCitationDocInfo(FullWrtStruct::EntryPtr zone)985 bool FullWrtParser::readCitationDocInfo(FullWrtStruct::EntryPtr zone)
986 {
987 MWAWInputStreamPtr input = zone->m_input;
988 libmwaw::DebugFile &asciiFile = zone->getAsciiFile();
989 libmwaw::DebugStream f;
990 long pos = input->tell();
991 if (input->readULong(4)!=0x63697465 || input->readULong(1)) {
992 input->seek(pos, librevenge::RVNG_SEEK_SET);
993 return false;
994 }
995
996 long blckSz = input->readLong(4);
997 long endData = pos+9+blckSz;
998 int num = static_cast<int>(input->readULong(2)), val;
999 f << "Entries(RefValues):N=" << num << ",";
1000 if (blckSz <= 2 || endData > zone->end() || pos+num > endData) {
1001 MWAW_DEBUG_MSG(("FullWrtParser::readCitationDocInfo: problem reading the data block or the number of data\n"));
1002 f << "###";
1003 asciiFile.addPos(pos);
1004 asciiFile.addNote(f.str().c_str());
1005 if (endData <= zone->end()) {
1006 input->seek(endData, librevenge::RVNG_SEEK_SET);
1007 return true;
1008 }
1009 input->seek(pos, librevenge::RVNG_SEEK_SET);
1010 return false;
1011 }
1012
1013 asciiFile.addPos(pos);
1014 asciiFile.addNote(f.str().c_str());
1015 for (int i = 0; i < num; i++) {
1016 f.str("");
1017 f << "RefValues-" << i << ",";
1018 pos = input->tell();
1019 auto sz = int(input->readULong(1));
1020 if (input->tell()+sz > endData)
1021 break;
1022 std::string name("");
1023 bool ok = true;
1024 for (int j = 0; j < sz; j++) {
1025 val = int(input->readULong(1));
1026 if (val < 0x9) {
1027 ok = false;
1028 break;
1029 }
1030 name+=char(val);
1031 }
1032 if (!ok) break;
1033 f << "\"" << name << "\",";
1034 asciiFile.addPos(pos);
1035 asciiFile.addNote(f.str().c_str());
1036 }
1037 if (input->tell() != endData) {
1038 f.str("");
1039 f << "RefValues-##";
1040 asciiFile.addPos(pos);
1041 asciiFile.addNote(f.str().c_str());
1042 input->seek(endData, librevenge::RVNG_SEEK_SET);
1043 }
1044 return true;
1045 }
1046
1047 ////////////////////////////////////////////////////////////
1048 // read the print info
1049 ////////////////////////////////////////////////////////////
readPrintInfo(FullWrtStruct::EntryPtr zone)1050 bool FullWrtParser::readPrintInfo(FullWrtStruct::EntryPtr zone)
1051 {
1052 MWAWInputStreamPtr input = zone->m_input;
1053 libmwaw::DebugFile &asciiFile = zone->getAsciiFile();
1054
1055 long pos = input->tell();
1056 if (input->readULong(2) != 0) return false;
1057 auto sz = long(input->readULong(2));
1058 if (sz != 0x78)
1059 return false;
1060 long endPos = pos+4+sz;
1061 input->seek(endPos, librevenge::RVNG_SEEK_SET);
1062 if (long(input->tell()) != endPos) {
1063 MWAW_DEBUG_MSG(("FullWrtParser::readPrintInfo: file is too short\n"));
1064 return false;
1065 }
1066 input->seek(pos+4, librevenge::RVNG_SEEK_SET);
1067
1068 libmwaw::DebugStream f;
1069 // print info
1070 libmwaw::PrinterInfo info;
1071 if (!info.read(input)) {
1072 // we know that the size is ok, so let try to continue
1073 asciiFile.addPos(pos);
1074 asciiFile.addNote("Entries(PrintInfo):##");
1075 input->seek(endPos, librevenge::RVNG_SEEK_SET);
1076 MWAW_DEBUG_MSG(("FullWrtParser::readPrintInfo: can not read print info, continue\n"));
1077 return true;
1078 }
1079 f << "Entries(PrintInfo):"<< info;
1080
1081 MWAWVec2i paperSize = info.paper().size();
1082 MWAWVec2i pageSize = info.page().size();
1083 if (pageSize.x() <= 0 || pageSize.y() <= 0 ||
1084 paperSize.x() <= 0 || paperSize.y() <= 0) return false;
1085
1086 if (!m_state->m_pageSpanSet) {
1087 // define margin from print info
1088 MWAWVec2i lTopMargin= -1 * info.paper().pos(0);
1089 MWAWVec2i rBotMargin=info.paper().size() - info.page().size();
1090
1091 // move margin left | top
1092 int decalX = lTopMargin.x() > 14 ? lTopMargin.x()-14 : 0;
1093 int decalY = lTopMargin.y() > 14 ? lTopMargin.y()-14 : 0;
1094 lTopMargin -= MWAWVec2i(decalX, decalY);
1095 rBotMargin += MWAWVec2i(decalX, decalY);
1096
1097 // decrease right | bottom
1098 int rightMarg = rBotMargin.x() -50;
1099 if (rightMarg < 0) rightMarg=0;
1100 int botMarg = rBotMargin.y() -50;
1101 if (botMarg < 0) botMarg=0;
1102
1103 getPageSpan().setMarginTop(lTopMargin.y()/72.0);
1104 getPageSpan().setMarginBottom(botMarg/72.0);
1105 getPageSpan().setMarginLeft(lTopMargin.x()/72.0);
1106 getPageSpan().setMarginRight(rightMarg/72.0);
1107 getPageSpan().setFormLength(paperSize.y()/72.);
1108 getPageSpan().setFormWidth(paperSize.x()/72.);
1109 }
1110 if (long(input->tell()) !=endPos) {
1111 input->seek(endPos, librevenge::RVNG_SEEK_SET);
1112 f << ", #endPos";
1113 asciiFile.addDelimiter(input->tell(), '|');
1114 }
1115
1116 asciiFile.addPos(pos);
1117 asciiFile.addNote(f.str().c_str());
1118
1119 return true;
1120 }
1121
1122 ////////////////////////////////////////////////////////////
1123 // read the document zone data
readDocZoneData(FullWrtStruct::EntryPtr zone)1124 bool FullWrtParser::readDocZoneData(FullWrtStruct::EntryPtr zone)
1125 {
1126 MWAWInputStreamPtr input = zone->m_input;
1127 libmwaw::DebugFile &asciiFile = zone->getAsciiFile();
1128 libmwaw::DebugStream f;
1129 // int vers = version();
1130
1131 long pos = zone->begin();
1132 input->seek(pos, librevenge::RVNG_SEEK_SET);
1133 zone->setParsed(true);
1134 f << "Entries(DZoneData)|" << *zone << ":";
1135 asciiFile.addPos(pos);
1136 asciiFile.addNote(f.str().c_str());
1137
1138 int val, prevTypeOk=-1;
1139 // first try to read normally the zone
1140 size_t numDocTypes = m_state->m_docZoneList.size();
1141 for (size_t z = 1; z < m_state->m_docZoneList.size(); z++) {
1142 FullWrtParserInternal::DocZoneStruct const &doc = m_state->m_docZoneList[z];
1143 if (doc.m_type < 0) continue;
1144
1145 pos = input->tell();
1146 if (pos+2 > zone->end()) break;
1147
1148 bool done = false;
1149 for (int st = 0; st < 4; st++) {
1150 input->seek(pos+st, librevenge::RVNG_SEEK_SET);
1151 FullWrtStruct::ZoneHeader docData;
1152 std::shared_ptr<FullWrtStruct::ZoneHeader> res;
1153 docData.m_type = doc.m_type;
1154 switch (doc.m_type) {
1155 case 0:
1156 done = m_textParser->readColumns(zone);
1157 break;
1158 case 1:
1159 done = m_textParser->readParagraphTabs(zone, int(z));
1160 break;
1161 case 2:
1162 done = m_textParser->readItem(zone, int(z), doc.m_structType==4);
1163 break;
1164 case 3:
1165 done = m_textParser->readStyle(zone);
1166 break;
1167 case 4: {
1168 if (pos+st+4> zone->end()) break;
1169 f.str("");
1170 f << "Entries(DZone4):";
1171 int numOk = 0;
1172 for (int j = 0; j < 2; j++) { // always 0|0
1173 val = int(input->readLong(2));
1174 if (val >= -2 && val <= 0) numOk++;
1175 if (val) f << "f" << j << "=" << val << ",";
1176 }
1177 if (!numOk) break;
1178 asciiFile.addPos(pos+st);
1179 asciiFile.addNote(f.str().c_str());
1180 done = true;
1181 break;
1182 }
1183 case 6:
1184 if (pos+st+2> zone->end()) break;
1185 val = int(input->readULong(2));
1186 if (!val || val > 0x200) break;
1187 f.str("");
1188 f << "Entries(DZone6):" << doc << ",v=" << val;
1189 asciiFile.addPos(pos+st);
1190 asciiFile.addNote(f.str().c_str());
1191 done = true;
1192 break;
1193 case 0x13:
1194 case 0x14:
1195 res=m_graphParser->readSideBar(zone, docData);
1196 break;
1197 case 0x15:
1198 res=m_graphParser->readGraphicData(zone, docData);
1199 break;
1200 case 0x19: // reference data?
1201 done=readReferenceData(zone);
1202 break;
1203 case 0x1a: {
1204 if (pos+st+12> zone->end()) break;
1205 FullWrtParserInternal::ReferenceCalledData refData;
1206 refData.m_id = int(input->readULong(2));
1207 if (refData.m_id < 0 || refData.m_id >= int(numDocTypes) ||
1208 m_state->m_docZoneList[size_t(refData.m_id)].m_type != 0x19)
1209 break;
1210 // two small number and then f0=first id in refData, f1=RefValueId?
1211 // after 0 except one time f2=0x71
1212 for (auto &data : refData.m_values) data = int(input->readULong(2));
1213
1214 f.str("");
1215 f << "Entries(RefCalled):docId=" << refData;
1216 if (m_state->m_referenceRedirectMap.find(int(z)) == m_state->m_referenceRedirectMap.end())
1217 m_state->m_referenceRedirectMap[int(z)]=refData;
1218 else {
1219 MWAW_DEBUG_MSG(("FullWrtParser::readDocZoneData: oops, reference redirection already exists for docId=%d\n", int(z)));
1220 }
1221 asciiFile.addPos(pos+st);
1222 asciiFile.addNote(f.str().c_str());
1223 input->seek(pos+st+12, librevenge::RVNG_SEEK_SET);
1224 done = true;
1225 break;
1226 }
1227 case 0x1e:
1228 if (pos+st+2> zone->end()) break;
1229 val = int(input->readULong(2));
1230 if (val<=0 || val >= int(numDocTypes)) break;
1231
1232 f.str("");
1233 // normally a type 15 or 18 zone
1234 f << "Entries(VariableData):docId=" << val
1235 << "[" << std::hex << m_state->m_docZoneList[size_t(val)].m_type
1236 << std::dec << "],";
1237 if (m_state->m_variableRedirectMap.find(int(z)) == m_state->m_variableRedirectMap.end())
1238 m_state->m_variableRedirectMap[int(z)]=val;
1239 else {
1240 MWAW_DEBUG_MSG(("FullWrtParser::readDocZoneData: oops, variable redirection already exists for docId=%d\n", int(z)));
1241 }
1242 asciiFile.addPos(pos+st);
1243 asciiFile.addNote(f.str().c_str());
1244 done = true;
1245 break;
1246 case 0x1f:
1247 done = m_textParser->readDataMod(zone, int(z));
1248 break;
1249 default:
1250 done=doc.m_type<=0x18 && readGenericDocData(zone, docData);
1251 break;
1252 }
1253 if (res)
1254 done=true;
1255 if (done) {
1256 int docId=res ? res->m_docId : docData.m_docId;
1257 if (docId >= 0 && docId != int(z)) {
1258 MWAW_DEBUG_MSG(("FullWrtParser::readDocZoneData: unexpected id %d != %d\n", docId, int(z)));
1259 done = false;
1260 }
1261 else {
1262 if (res)
1263 m_state->addCorrespondance(res->m_docId, res->m_fileId);
1264 break;
1265 }
1266 }
1267 input->seek(pos+st, librevenge::RVNG_SEEK_SET);
1268 if (input->readLong(1)) break;
1269 }
1270 if (done) {
1271 prevTypeOk = doc.m_type;
1272 continue;
1273 }
1274
1275 f.str("");
1276 f << "Entries(DZoneData)##:" << doc;
1277 asciiFile.addPos(pos);
1278 asciiFile.addNote(f.str().c_str());
1279
1280 MWAW_DEBUG_MSG(("FullWrtParser::readDocZoneData: loose reading at zone %d[%d:%d]\n", int(z), doc.m_type, prevTypeOk));
1281 if (prevTypeOk != -1) prevTypeOk = -1;
1282 //
1283 input->seek(pos+4, librevenge::RVNG_SEEK_SET);
1284 bool lastOk = false;
1285 while (input->tell()+4 < zone->end()) {
1286 bool prevLastOk = lastOk;
1287 lastOk = true;
1288 pos = input->tell();
1289 done=m_textParser->readParagraphTabs(zone)||m_textParser->readColumns(zone);
1290 if (done) continue;
1291 FullWrtStruct::ZoneHeader docData;
1292 done=docData.read(zone);
1293 if (done) {
1294 if (docData.m_docId >int(z) && docData.m_docId < int(m_state->m_docZoneList.size())) {
1295 z = size_t(docData.m_docId-1);
1296 input->seek(pos, librevenge::RVNG_SEEK_SET);
1297 MWAW_DEBUG_MSG(("FullWrtParser::readDocZoneData: continue reading at zone %d\n", docData.m_docId));
1298 break;
1299 }
1300 continue;
1301 }
1302 if (prevLastOk) {
1303 asciiFile.addPos(pos);
1304 asciiFile.addNote("DZoneData##:");
1305 }
1306 lastOk = false;
1307 input->seek(pos+1, librevenge::RVNG_SEEK_SET);
1308 }
1309 }
1310
1311 return true;
1312 }
1313
readDocZoneStruct(FullWrtStruct::EntryPtr zone)1314 bool FullWrtParser::readDocZoneStruct(FullWrtStruct::EntryPtr zone)
1315 {
1316 MWAWInputStreamPtr input = zone->m_input;
1317 libmwaw::DebugFile &asciiFile = zone->getAsciiFile();
1318 libmwaw::DebugStream f;
1319
1320 long pos = zone->begin();
1321 input->seek(pos, librevenge::RVNG_SEEK_SET);
1322 auto N = static_cast<int>(input->readLong(2));
1323 if ((N & 0xF)||N<=0) return false;
1324 input->seek(pos+6, librevenge::RVNG_SEEK_SET);
1325 for (int i = 0; i < N-1; i++) {
1326 if (input->tell() >= zone->end())
1327 return false;
1328 long v = input->readLong(1);
1329 if (v==0) continue;
1330 if (v!=1 && v!=4) {
1331 if (2*i > N) {
1332 MWAW_DEBUG_MSG(("FullWrtParser::readDocZoneStruct: find only %d/%d entries\n", i, N));
1333 break;
1334 }
1335 return false;
1336 }
1337 input->seek(4+v, librevenge::RVNG_SEEK_CUR);
1338 }
1339 if (input->tell() > zone->end())
1340 return false;
1341
1342 zone->setParsed(true);
1343 f << "Entries(DZoneStruct)|" << *zone <<":";
1344 if (N%16) { // always a multiple of 16?
1345 MWAW_DEBUG_MSG(("FullWrtParser::readDocZoneStruct: N(%d) seems odd\n", N));
1346 f << "###";
1347 }
1348 f << "N=" << N << ",";
1349 input->seek(pos+2, librevenge::RVNG_SEEK_SET);
1350 f << "unkn=" << std::hex << input->readULong(4) << std::dec << ",";
1351 asciiFile.addPos(pos);
1352 asciiFile.addNote(f.str().c_str());
1353 std::set<int> seenSet;
1354 auto &zoneList = m_state->m_docZoneList;
1355 zoneList.resize(size_t(N)+1);
1356 for (int i = 0; i < N-1; i++) {
1357 pos = input->tell();
1358 auto type = static_cast<int>(input->readULong(1));
1359 if (type > 1 && type!=4) {
1360 asciiFile.addPos(pos);
1361 asciiFile.addNote("DZoneStruct-###");
1362 break;
1363 }
1364
1365 FullWrtParserInternal::DocZoneStruct dt;
1366 dt.m_structType = type;
1367 dt.m_pos = pos;
1368 f.str("");
1369 f << "DZoneStruct-" << i+1 << ":";
1370 if (type) {
1371 dt.m_type = static_cast<int>(input->readULong(1)); // small number between 0 and 1f
1372 dt.m_nextId = static_cast<int>(input->readLong(2));
1373 dt.m_fatherId = static_cast<int>(input->readLong(2));
1374 if (dt.m_nextId < 0 || dt.m_nextId > N) {
1375 f << "#nId=" << dt.m_nextId <<",";
1376 dt.m_nextId = 0;
1377 }
1378 if (dt.m_fatherId < 0 || dt.m_fatherId > N) {
1379 f << "#fId=" << dt.m_fatherId <<",";
1380 dt.m_fatherId = -1;
1381 }
1382 if (dt.m_nextId) {
1383 if (seenSet.find(dt.m_nextId) != seenSet.end()) {
1384 f << "##nId=" << dt.m_nextId << ",";
1385 dt.m_nextId = 0;
1386 }
1387 else
1388 seenSet.insert(dt.m_nextId);
1389 }
1390 if (type==4) {
1391 asciiFile.addDelimiter(input->tell(),'|');
1392 input->seek(3, librevenge::RVNG_SEEK_CUR);
1393 }
1394 f << dt;
1395 }
1396 zoneList[size_t(i)+1]=dt;
1397 asciiFile.addPos(pos);
1398 asciiFile.addNote(f.str().c_str());
1399 }
1400 if (input->tell() != zone->end()) {
1401 MWAW_DEBUG_MSG(("FullWrtParser::readDocZoneStruct: end seems odd\n"));
1402 }
1403 // build child list
1404 for (size_t i = 0; i <= size_t(N); i++) {
1405 int fId = zoneList[i].m_fatherId;
1406 int nId = zoneList[i].m_nextId;
1407 if (nId && zoneList[size_t(nId)].m_fatherId != fId) {
1408 MWAW_DEBUG_MSG(("FullWrtParser::readDocZoneStruct: find incoherent children: %d and %d\n", int(i), nId));
1409 continue;
1410 }
1411 auto cId = int(i);
1412 if (seenSet.find(int(cId))!=seenSet.end() || fId < 0) continue;
1413 // insert the child and its siblings
1414 while (cId > 0 && cId <= N) {
1415 zoneList[size_t(fId)].m_childList.push_back(cId);
1416 cId = zoneList[size_t(cId)].m_nextId;
1417 }
1418 }
1419 // check that we have no dag or cycle
1420 seenSet.clear();
1421 std::vector<int> toDoList;
1422 toDoList.push_back(0);
1423 seenSet.insert(0);
1424 while (toDoList.size()) {
1425 int id = toDoList.back();
1426 toDoList.pop_back();
1427
1428 auto &nd = zoneList[size_t(id)];
1429 size_t c = 0;
1430 while (c < nd.m_childList.size()) {
1431 int cId = nd.m_childList[c++];
1432 if (seenSet.find(cId)==seenSet.end()) {
1433 seenSet.insert(cId);
1434 toDoList.push_back(cId);
1435 continue;
1436 }
1437 MWAW_DEBUG_MSG(("FullWrtParser::readDocZoneStruct: oops, find a unexpected dag or cycle\n"));
1438 c--;
1439 nd.m_childList.erase(nd.m_childList.begin()+int(c));
1440 }
1441 }
1442 for (auto const &nd : zoneList) {
1443 if (nd.m_childList.empty()) continue;
1444 f.str("");
1445 f << "childs=[";
1446 for (auto id : nd.m_childList)
1447 f << id << ",";
1448 f << "],";
1449 asciiFile.addPos(nd.m_pos >= 0 ? nd.m_pos : zone->begin());
1450 asciiFile.addNote(f.str().c_str());
1451 }
1452 zone->closeDebugFile();
1453 return true;
1454 }
1455
1456 ////////////////////////////////////////////////////////////
1457 // read the correspondance data
readGenericDocData(FullWrtStruct::EntryPtr zone,FullWrtStruct::ZoneHeader & doc)1458 bool FullWrtParser::readGenericDocData(FullWrtStruct::EntryPtr zone, FullWrtStruct::ZoneHeader &doc)
1459 {
1460 MWAWInputStreamPtr input = zone->m_input;
1461 long pos = input->tell();
1462 if (!doc.read(zone)) {
1463 input->seek(pos, librevenge::RVNG_SEEK_SET);
1464 return false;
1465 }
1466
1467 int const vers = version();
1468 libmwaw::DebugFile &asciiFile = zone->getAsciiFile();
1469 libmwaw::DebugStream f;
1470
1471 int val;
1472 int numSzFollowBlock = 0;
1473 switch (doc.m_type) {
1474 case 0xc:
1475 case 0xd:
1476 case 0xf:
1477 case 0x11:
1478 case 0x12:
1479 case 0x15:
1480 break;
1481 case 0xa:
1482 case 0xb:
1483 case 0xe:
1484 case 0x10:
1485 case 0x18:
1486 numSzFollowBlock = 1;
1487 break;
1488 case 0x13:
1489 numSzFollowBlock = 3;
1490 break;
1491 default:
1492 MWAW_DEBUG_MSG(("FullWrtParser::readGenericDocData: called with type=%d\n",doc.m_type));
1493 break;
1494 case -1:
1495 break;
1496 }
1497 if (input->tell()+1 > zone->end()) {
1498 input->seek(pos, librevenge::RVNG_SEEK_SET);
1499 return false;
1500 }
1501
1502 f.str("");
1503 if (doc.m_type > 0)
1504 f << "Entries(DZone" << std::hex << doc.m_type << std::dec << "):";
1505 else
1506 f << "Entries(DZoneUnkn" << "):";
1507 f << doc;
1508 if (!m_state->addCorrespondance(doc.m_docId, doc.m_fileId))
1509 f << "#";
1510
1511 asciiFile.addPos(pos);
1512 asciiFile.addNote(f.str().c_str());
1513
1514 for (int i = 0; i < numSzFollowBlock; i++) {
1515 f.str("");
1516 f << "DZone" << std::hex << doc.m_type << std::dec << "[" << i << "]:";
1517 pos = input->tell();
1518 auto sz = long(input->readULong(4));
1519 if (sz < 0 || pos+sz+4 > zone->end()) {
1520 input->seek(pos, librevenge::RVNG_SEEK_SET);
1521 f << "#";
1522 asciiFile.addPos(pos);
1523 asciiFile.addNote(f.str().c_str());
1524 return true;
1525 }
1526 asciiFile.addPos(pos);
1527 asciiFile.addNote(f.str().c_str());
1528 if (sz) input->seek(sz, librevenge::RVNG_SEEK_CUR);
1529 }
1530
1531 if (doc.m_type==0xa) {
1532 asciiFile.addPos(input->tell());
1533 asciiFile.addNote("DZonea[1]#");
1534 input->seek(vers==2 ? 8 : 66, librevenge::RVNG_SEEK_CUR);
1535 }
1536
1537 val = int(input->readLong(1));
1538 if (doc.m_type==0xa) ;
1539 else if (val==1) {
1540 pos = input->tell();
1541 auto sz = long(input->readULong(4));
1542 if (sz && input->tell()+sz <= zone->end()) {
1543 f.str("");
1544 f << "DZone" << std::hex << doc.m_type << std::dec << "[end]:";
1545 asciiFile.addPos(pos);
1546 asciiFile.addNote(f.str().c_str());
1547 input->seek(sz, librevenge::RVNG_SEEK_CUR);
1548 }
1549 else {
1550 MWAW_DEBUG_MSG(("FullWrtParser::readGenericDocData: find bad end data\n"));
1551 input->seek(pos, librevenge::RVNG_SEEK_SET);
1552 }
1553 }
1554 else if (val) {
1555 MWAW_DEBUG_MSG(("FullWrtParser::readGenericDocData: find bad end data(II)\n"));
1556 }
1557 return true;
1558 }
1559
readReferenceData(FullWrtStruct::EntryPtr zone)1560 bool FullWrtParser::readReferenceData(FullWrtStruct::EntryPtr zone)
1561 {
1562 MWAWInputStreamPtr input = zone->m_input;
1563 long pos = input->tell();
1564 if (pos+22 > zone->end()) {
1565 input->seek(pos, librevenge::RVNG_SEEK_SET);
1566 return false;
1567 }
1568
1569 libmwaw::DebugFile &asciiFile = zone->getAsciiFile();
1570 libmwaw::DebugStream f;
1571 f.str("");
1572 f << "Entries(RefData):";
1573 long val = int(input->readULong(2));
1574 int numOk = 0;
1575 if (val == 0xa || val == 0xc) numOk++;
1576 f << "type?=" << val << ",";
1577
1578 f << "unkn=["; // 3 small number and 0, f0 or f2 is probably an Id, f1=0|1|2
1579 for (int i = 0; i < 4; i++) {
1580 val = long(input->readULong(2));
1581 if (val)
1582 f << val << ",";
1583 else
1584 f << "_,";
1585 if (i==3) break;
1586 if (val>0 && val < 0x100) numOk++;
1587 }
1588 f << "],";
1589 if (numOk <= 2) {
1590 input->seek(pos, librevenge::RVNG_SEEK_SET);
1591 return false;
1592 }
1593 f << "ptr=" << std::hex << input->readULong(4) << std::dec << ",";
1594 for (int i = 0; i < 2; i++) { // always 0 ?
1595 val = long(input->readULong(2));
1596 if (val)
1597 f << "f" << i << "=" << val << ",";
1598 }
1599
1600 long sz = input->readLong(4);
1601 if (sz < 0 || pos+22+sz > zone->end()) {
1602 input->seek(pos, librevenge::RVNG_SEEK_SET);
1603 return false;
1604 }
1605 auto numZones=int(m_state->m_docZoneList.size());
1606 f << "callerId=["; // normally zone of type 0x1a
1607 for (long i = 0; i < sz/2; i++) {
1608 auto id = int(input->readLong(2));
1609 if (id < 0 || id >= numZones ||
1610 m_state->m_docZoneList[size_t(id)].m_type != 0x1a)
1611 f << "#";
1612 f << id << ",";
1613 }
1614 f << "],";
1615 input->seek(pos+22+sz, librevenge::RVNG_SEEK_SET);
1616 asciiFile.addPos(pos);
1617 asciiFile.addNote(f.str().c_str());
1618 return true;
1619 }
1620
1621 ////////////////////////////////////////////////////////////
1622 // read the zone flag and positions
1623 ////////////////////////////////////////////////////////////
readFileZoneFlags(FullWrtStruct::EntryPtr zone)1624 bool FullWrtParser::readFileZoneFlags(FullWrtStruct::EntryPtr zone)
1625 {
1626 int vers = version();
1627 int dataSz = vers==1 ? 22 : 16;
1628 if (!zone || zone->length()%dataSz) {
1629 MWAW_DEBUG_MSG(("FullWrtParser::readFileZoneFlags: size seems odd\n"));
1630 return false;
1631 }
1632 zone->setParsed(true);
1633 MWAWInputStreamPtr input = zone->m_input;
1634 libmwaw::DebugFile &asciiFile = zone->getAsciiFile();
1635
1636 libmwaw::DebugStream f;
1637 long numElt = zone->length()/dataSz;
1638 input->seek(zone->begin(), librevenge::RVNG_SEEK_SET);
1639 std::multimap<int, FullWrtStruct::EntryPtr >::iterator it;
1640 int numNegZone=3;
1641 for (long i = 0; i < numElt; i++) {
1642 long pos = input->tell();
1643 auto id = static_cast<int>(input->readLong(2));
1644 it = m_state->m_entryMap.find(id);
1645 FullWrtStruct::EntryPtr entry;
1646 f.str("");
1647 if (it == m_state->m_entryMap.end()) {
1648 if (id != -2) {
1649 MWAW_DEBUG_MSG(("FullWrtParser::readFileZoneFlags: can not find entry %d\n",id));
1650 f << "###";
1651 }
1652 entry.reset(new FullWrtStruct::Entry(input));
1653 entry->setId(1000+id); // false id
1654 }
1655 else
1656 entry = it->second;
1657 entry->setType("UnknownZone");
1658 auto val = static_cast<int>(input->readLong(2)); // always -2 ?
1659 if (val != -2) f << "g0=" << val << ",";
1660 val = static_cast<int>(input->readLong(2)); // always 0 ?
1661 if (val) f << "g1=" << val << ",";
1662 // a small number between 1 and 0x100
1663 entry->m_values[0] = static_cast<int>(input->readLong(2));
1664 for (int j = 0; j < 2; j++) { // always 0
1665 val = static_cast<int>(input->readLong(2));
1666 if (val) f << "g" << j+2 << "=" << val << ",";
1667 }
1668 /** -1: generic, -2: null, other fId */
1669 entry->m_typeId = static_cast<int>(input->readLong(2));
1670 if (entry->m_typeId == -2) ;
1671 else if (entry->m_typeId != -1)
1672 entry->setId(int(i));
1673 else {
1674 bool find = false;
1675 for (int j = 0; j < 3; j++) {
1676 if (i!=m_state->m_zoneFlagsId[j]) continue;
1677 find = true;
1678 entry->setId(j);
1679 break;
1680 }
1681 if (!find) {
1682 MWAW_DEBUG_MSG(("FullWrtParser::readFileZoneFlags: can not find generic zone id %ld\n",i));
1683 f << "#";
1684 entry->setId(numNegZone);
1685 }
1686 numNegZone++;
1687 }
1688 // v2: always 0|0x14, v1 two small number or 0x7FFF
1689 entry->m_values[1] = static_cast<int>(input->readLong(1));
1690 entry->m_values[2] = static_cast<int>(input->readLong(1));
1691 if (vers == 1) {
1692 for (int j = 0; j < 3; j++) { // always 0, -2|0, 0 ?
1693 val = static_cast<int>(input->readLong(2));
1694 if ((j==1 && val !=-2) || (j!=1 && val))
1695 f << "g" << j+4 << "=" << val << ",";
1696 }
1697 }
1698
1699 std::string extra = f.str();
1700 f.str("");
1701 if (i==0) f << "Entries(FZoneFlags):";
1702 else f << "FZoneFlags-" << i << ":";
1703 f << *entry << ",";
1704 f << extra;
1705
1706 if (entry->id() < 0) {
1707 if (entry->m_typeId != -2) {
1708 MWAW_DEBUG_MSG(("FullWrtParser::readFileZoneFlags: find a null zone with unexpected type\n"));
1709 }
1710 }
1711
1712 input->seek(pos+dataSz, librevenge::RVNG_SEEK_SET);
1713 asciiFile.addPos(pos);
1714 asciiFile.addNote(f.str().c_str());
1715 }
1716 asciiFile.addPos(zone->end());
1717 asciiFile.addNote("Entries(ZoneAfter)");
1718 return true;
1719 }
1720
readFileZonePos(FullWrtStruct::EntryPtr zone)1721 bool FullWrtParser::readFileZonePos(FullWrtStruct::EntryPtr zone)
1722 {
1723 int vers = version();
1724 int dataSz = vers==1 ? 10 : 8;
1725 if (zone->length()%dataSz) {
1726 MWAW_DEBUG_MSG(("FullWrtParser::readFileZonePos: size seems odd\n"));
1727 return false;
1728 }
1729 zone->setParsed(true);
1730 MWAWInputStreamPtr input = zone->m_input;
1731 libmwaw::DebugFile &asciiFile = zone->getAsciiFile();
1732
1733 libmwaw::DebugStream f;
1734 auto numElt = int(zone->length()/dataSz);
1735 input->seek(zone->begin(), librevenge::RVNG_SEEK_SET);
1736 int val;
1737
1738 // read data
1739 std::set<long> filePositions;
1740 std::vector<FullWrtStruct::EntryPtr > listEntry;
1741 if (numElt>0)
1742 listEntry.resize(size_t(numElt));
1743 for (int i = 0; i < numElt; i++) {
1744 long pos = input->tell();
1745 long fPos = input->readLong(4);
1746
1747 FullWrtStruct::EntryPtr entry(new FullWrtStruct::Entry(input));
1748 if (i == m_state->m_biblioId)
1749 entry->setType("Biblio");
1750 else
1751 entry->setType("Unknown");
1752 entry->m_nextId = static_cast<int>(input->readLong(2));
1753 auto id = static_cast<int>(input->readLong(2));
1754 f << "realId=" << id << ",";
1755 entry->setId(i);
1756 if (fPos >= 0) {
1757 filePositions.insert(fPos);
1758 entry->setBegin(fPos);
1759 }
1760 f.str("");
1761
1762 if (entry->begin()>=0)
1763 f << "pos=" << std::hex << entry->begin() << std::dec << ",";
1764 if (entry->m_nextId != -2) f << "nextId=" << entry->m_nextId << ",";
1765 if (vers==1) {
1766 val = static_cast<int>(input->readLong(2));
1767 if (val) f << "f0=" << val << ",";
1768 }
1769
1770 input->seek(pos+dataSz, librevenge::RVNG_SEEK_SET);
1771
1772 entry->setExtra(f.str());
1773 f.str("");
1774 if (i == 0) f << "Entries(FZonePos):";
1775 else f << "FZonePos" << i << ":";
1776 f << *entry;
1777
1778 asciiFile.addPos(pos);
1779 asciiFile.addNote(f.str().c_str());
1780
1781 if (id != -2 && (id < 1 || id >= numElt)) {
1782 MWAW_DEBUG_MSG(("FullWrtParser::readFileZonePos: entry id seems bad\n"));
1783 }
1784 listEntry[size_t(i)] = entry;
1785 }
1786 filePositions.insert(zone->begin());
1787
1788 // compute end of each entry
1789 for (auto entry : listEntry) {
1790 if (!entry || entry->begin() < 0)
1791 continue;
1792 auto it=filePositions.find(entry->begin());
1793 if (it == filePositions.end()) {
1794 MWAW_DEBUG_MSG(("FullWrtParser::readFileZonePos: can not find my entry\n"));
1795 continue;
1796 }
1797 if (++it == filePositions.end()) {
1798 MWAW_DEBUG_MSG(("FullWrtParser::readFileZonePos: can not find my entry\n"));
1799 continue;
1800 }
1801
1802 entry->setEnd(*it);
1803 if (entry->m_nextId < 0) continue;
1804 if (entry->m_nextId >= numElt) {
1805 entry->m_nextId = -1;
1806 MWAW_DEBUG_MSG(("FullWrtParser::readFileZonePos: can not find the next entry\n"));
1807 continue;
1808 }
1809 if (!listEntry[size_t(entry->m_nextId)] || listEntry[size_t(entry->m_nextId)]->isParsed()) {
1810 entry->m_nextId = -1;
1811 MWAW_DEBUG_MSG(("FullWrtParser::readFileZonePos: next entry %d is already used\n",
1812 entry->m_nextId));
1813 continue;
1814 }
1815 listEntry[size_t(entry->m_nextId)]->setParsed(true);
1816 }
1817
1818 for (int i = 0; i < numElt; i++) {
1819 auto entry = listEntry[size_t(i)];
1820 if (!entry || !entry->valid() || entry->isParsed()) continue;
1821
1822 m_state->m_entryMap.insert
1823 (std::multimap<int, FullWrtStruct::EntryPtr >::value_type(i, entry));
1824
1825 if (entry->m_nextId < 0) {
1826 entry->m_input = input;
1827 entry->m_asciiFile = std::shared_ptr<libmwaw::DebugFile>
1828 (&asciiFile, MWAW_shared_ptr_noop_deleter<libmwaw::DebugFile>());
1829 continue;
1830 }
1831 // ok we must reconstruct a file
1832 FullWrtStruct::EntryPtr actEnt = entry;
1833 librevenge::RVNGBinaryData &data = entry->m_data;
1834 while (1) {
1835 if (!actEnt->valid()) break;
1836 input->seek(actEnt->begin(), librevenge::RVNG_SEEK_SET);
1837 unsigned long read;
1838 const unsigned char *dt = input->read(size_t(actEnt->length()), read);
1839 data.append(dt, read);
1840 asciiFile.skipZone(actEnt->begin(), actEnt->end()-1);
1841 if (actEnt->m_nextId < 0) break;
1842 actEnt = listEntry[size_t(actEnt->m_nextId)];
1843 if (actEnt) actEnt->setParsed(true);
1844 }
1845 entry->update();
1846 }
1847
1848 asciiFile.addPos(zone->end());
1849 asciiFile.addNote("_");
1850 return true;
1851 }
1852
1853 ////////////////////////////////////////////////////////////
1854 // read the document header
1855 ////////////////////////////////////////////////////////////
readDocPosition()1856 bool FullWrtParser::readDocPosition()
1857 {
1858 MWAWInputStreamPtr input = getInput();
1859 if (!input->checkPosition(48))
1860 return false;
1861
1862 libmwaw::DebugStream f;
1863 input->seek(-48, librevenge::RVNG_SEEK_END);
1864 long pos = input->tell();
1865 f << "Entries(DocPosition):";
1866
1867 long val;
1868 m_state->m_biblioId = static_cast<int>(input->readLong(2));
1869 if (m_state->m_biblioId != -2)
1870 f << "bibId=" << m_state->m_biblioId << ",";
1871 for (int i = 0; i < 4; i++) { // always 0?
1872 val = input->readLong(2);
1873 if (val) f << "f" << i << "=" << val <<",";
1874 }
1875 long sz[2];
1876 for (int i = 0; i < 2; i++) {
1877 FullWrtStruct::EntryPtr zone(new FullWrtStruct::Entry(input));
1878 zone->m_asciiFile = std::shared_ptr<libmwaw::DebugFile>
1879 (&ascii(), MWAW_shared_ptr_noop_deleter<libmwaw::DebugFile>());
1880 zone->setBegin(long(input->readULong(4)));
1881 zone->setLength((sz[i]=long(input->readULong(4))));
1882 if (!input->checkPosition(zone->end()) || !zone->valid())
1883 return false;
1884 if (i == 1) m_state->m_fileZoneList = zone;
1885 else m_state->m_fileZoneFlagsList = zone;
1886 }
1887 f << "flZones=[";
1888 for (int i = 0; i < 3; i++) {
1889 m_state->m_zoneFlagsId[2-i] = static_cast<int>(input->readLong(2));
1890 f << m_state->m_zoneFlagsId[2-i] << ",";
1891 }
1892 f << "],";
1893 val = input->readLong(2); // always 0 ?
1894 if (val) f << "g0=" << val << ",";
1895 // a big number
1896 f << std::hex << "unkn=" << input->readULong(2) << std::dec << ",";
1897 val = long(input->readULong(4));
1898 if (val != 1 && val != 0xbeecf54L) // always 1 in v1 and 0xbeecf54L in v2 ?
1899 f << std::hex << "unkn2=" << val << std::dec << ",";
1900 // always 1 ?
1901 val = long(input->readULong(4));
1902 if (val != 1) // always 1 in v1
1903 f << "g1=" << val << ",";
1904 val = long(input->readULong(4));
1905 if (val==0x46575254L) {
1906 if ((sz[0]%16)==0 && (sz[1]%8)==0)
1907 setVersion(2);
1908 else if ((sz[0]%22)==0 && (sz[1]%10)==0)
1909 setVersion(1);
1910 else
1911 return false;
1912 }
1913 else {
1914 if (val != 1) f << "g2=" << val << ",";
1915 if ((sz[0]%22)==0 && (sz[1]%10)==0)
1916 setVersion(1);
1917 else
1918 return false;
1919 }
1920 ascii().addPos(pos);
1921 ascii().addNote(f.str().c_str());
1922
1923 return true;
1924 }
1925
1926 ////////////////////////////////////////////////////////////
1927 // the variable part
1928 ////////////////////////////////////////////////////////////
sendReference(int id)1929 void FullWrtParser::sendReference(int id)
1930 {
1931 if (!getTextListener()) return;
1932
1933 if (id < 0 || id >= int(m_state->m_docZoneList.size())) {
1934 MWAW_DEBUG_MSG(("FullWrtParser::sendReference: can not find data for id=%d\n", id));
1935 return;
1936 }
1937 if (m_state->m_docZoneList[size_t(id)].m_type != 0x1a) {
1938 MWAW_DEBUG_MSG(("FullWrtParser::sendReference: find unexpected type for fieldDataRedirect=%x\n", static_cast<unsigned int>(m_state->m_docZoneList[size_t(id)].m_type)));
1939 return;
1940 }
1941 if (m_state->m_referenceRedirectMap.find(id) == m_state->m_referenceRedirectMap.end())
1942 return; // ok, we have not read the reference
1943 int docId = m_state->m_referenceRedirectMap.find(id)->second.m_id;
1944 if (docId < 0 || docId >= int(m_state->m_docZoneList.size()) ||
1945 m_state->m_docZoneList[size_t(docId)].m_type != 0x19) {
1946 MWAW_DEBUG_MSG(("FullWrtParser::sendReference: find unexpected redirection id[%d] for reference %d\n", docId, id));
1947 return;
1948 }
1949 static bool first = true;
1950 if (first) {
1951 first = false;
1952 MWAW_DEBUG_MSG(("FullWrtParser::sendReference: sorry, this function is not implemented\n"));
1953 }
1954 }
1955
1956 ////////////////////////////////////////////////////////////
1957 // the variable part
1958 ////////////////////////////////////////////////////////////
sendVariable(int id)1959 void FullWrtParser::sendVariable(int id)
1960 {
1961 if (!getTextListener()) return;
1962
1963 if (id < 0 || id >= int(m_state->m_docZoneList.size())) {
1964 MWAW_DEBUG_MSG(("FullWrtParser::sendVariable: can not find data for id=%d\n", id));
1965 return;
1966 }
1967 if (m_state->m_docZoneList[size_t(id)].m_type != 0x1e) {
1968 MWAW_DEBUG_MSG(("FullWrtParser::sendVariable: find unexpected type for fieldDataRedirect=%x\n", static_cast<unsigned int>(m_state->m_docZoneList[size_t(id)].m_type)));
1969 return;
1970 }
1971 if (m_state->m_variableRedirectMap.find(id) == m_state->m_variableRedirectMap.end()) {
1972 MWAW_DEBUG_MSG(("FullWrtParser::sendVariable: can not find redirection for id=%d\n", id));
1973 return;
1974 }
1975 int docId = m_state->m_variableRedirectMap.find(id)->second;
1976 if (docId < 0 || docId >= int(m_state->m_docZoneList.size())) {
1977 MWAW_DEBUG_MSG(("FullWrtParser::sendVariable: find unexpected redirection id[%d] for variable %d\n", docId, id));
1978 return;
1979 }
1980 auto const &data = m_state->m_docZoneList[size_t(docId)];
1981 if (data.m_type==0x15)
1982 sendGraphic(docId);
1983 else if (data.m_type == 0x18) {
1984 /** in this case, the content seems to be a textbox which contains the field display,
1985 but as in general this zone is not read correctly (ie. the field is not found ) and
1986 as sending textbox is not implemented, better to stop here...
1987 */
1988 static bool first = true;
1989 if (first) {
1990 first = false;
1991 MWAW_DEBUG_MSG(("FullWrtParser::sendVariable: sorry, send text/field variable is not implemented\n"));
1992 }
1993 }
1994 else {
1995 MWAW_DEBUG_MSG(("FullWrtParser::sendVariable: find unexpected redirection type[%x] for variable %d\n", static_cast<unsigned int>(data.m_type), id));
1996 }
1997 }
1998
1999 ////////////////////////////////////////////////////////////
2000 // send a text zone
2001 ////////////////////////////////////////////////////////////
sendText(int id,libmwaw::SubDocumentType type,MWAWNote::Type wh)2002 void FullWrtParser::sendText(int id, libmwaw::SubDocumentType type, MWAWNote::Type wh)
2003 {
2004 if (!getTextListener()) return;
2005
2006 if (id >= 0 && id < int(m_state->m_docZoneList.size())) {
2007 auto const &data = m_state->m_docZoneList[size_t(id)];
2008 int docType = data.m_type;
2009 if (type==libmwaw::DOC_NOTE && (docType==0xc|| docType==0xd)) ;
2010 else if (type == libmwaw::DOC_COMMENT_ANNOTATION && docType == 0xb) ;
2011 else {
2012 MWAW_DEBUG_MSG(("FullWrtParser::sendText: call with %d[%x]\n", int(type),static_cast<unsigned int>(docType)));
2013 }
2014 }
2015 else {
2016 MWAW_DEBUG_MSG(("FullWrtParser::sendText: can not find data for id=%d\n", id));
2017 }
2018 int fId = m_state->getFileZoneId(id);
2019 MWAWSubDocumentPtr subdoc(new FullWrtParserInternal::SubDocument(*this, getInput(), fId));
2020 if (type==libmwaw::DOC_NOTE)
2021 getTextListener()->insertNote(MWAWNote(wh), subdoc);
2022 else if (type==libmwaw::DOC_COMMENT_ANNOTATION)
2023 getTextListener()->insertComment(subdoc);
2024 else {
2025 MWAW_DEBUG_MSG(("FullWrtParser::sendText: unexpected type\n"));
2026 }
2027 }
2028
2029 // vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab:
2030