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 <cstring>
35 #include <iomanip>
36 #include <iostream>
37 #include <limits>
38 #include <map>
39 #include <set>
40 #include <sstream>
41
42 #include <librevenge/librevenge.h>
43
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 "MWAWSubDocument.hxx"
52
53 #include "MsWrdParser.hxx"
54
55 #include "MsWrdText.hxx"
56
57 /** Internal: the structures of a MsWrdParser */
58 namespace MsWrdParserInternal
59 {
60 ////////////////////////////////////////
61 //! Internal: the object of MsWrdParser
62 struct Object {
ObjectMsWrdParserInternal::Object63 Object()
64 : m_textPos(-1)
65 , m_pos()
66 , m_name("")
67 , m_id(-1)
68 , m_annotation()
69 , m_extra("")
70 {
71 for (auto &id : m_ids) id=-1;
72 for (auto &idFlag : m_idsFlag) idFlag=0;
73 for (auto &flag : m_flags) flag=0;
74 }
75
getEntryMsWrdParserInternal::Object76 MsWrdEntry getEntry() const
77 {
78 MsWrdEntry res;
79 res.setBegin(m_pos.begin());
80 res.setEnd(m_pos.end());
81 res.setType("ObjectData");
82 res.setId(m_id);
83 return res;
84 }
85
86 //! operator<<
operator <<(std::ostream & o,Object const & obj)87 friend std::ostream &operator<<(std::ostream &o, Object const &obj)
88 {
89 if (obj.m_textPos >= 0)
90 o << std::hex << "textPos?=" << obj.m_textPos << std::dec << ",";
91 if (obj.m_id >= 0) o << "Obj" << obj.m_id << ",";
92 if (obj.m_name.length()) o << obj.m_name << ",";
93 for (int st = 0; st < 2; st++) {
94 if (obj.m_ids[st] == -1 && obj.m_idsFlag[st] == 0) continue;
95 o << "id" << st << "=" << obj.m_ids[st];
96 if (obj.m_idsFlag[st]) o << ":" << std::hex << obj.m_idsFlag[st] << std::dec << ",";
97 }
98 for (int st = 0; st < 2; st++) {
99 if (obj.m_flags[st])
100 o << "fl" << st << "=" << std::hex << obj.m_flags[st] << std::dec << ",";
101 }
102
103 if (obj.m_extra.length()) o << "extras=[" << obj.m_extra << "],";
104 return o;
105 }
106 //! the text position
107 long m_textPos;
108
109 //! the object entry
110 MWAWEntry m_pos;
111
112 //! the object name
113 std::string m_name;
114
115 //! the id
116 int m_id;
117
118 //! some others id?
119 int m_ids[2];
120
121 //! some flags link to m_ids
122 int m_idsFlag[2];
123
124 //! some flags
125 int m_flags[2];
126
127 //! the annotation entry
128 MWAWEntry m_annotation;
129
130 //! some extra data
131 std::string m_extra;
132 };
133
134 ////////////////////////////////////////
135 //! Internal: the picture of a MsWrdParser
136 struct Picture {
137 struct Zone;
PictureMsWrdParserInternal::Picture138 Picture()
139 : m_dim()
140 , m_picturesList()
141 , m_flag(0)
142 {
143 }
144 //! operator<<
operator <<(std::ostream & o,Picture const & pict)145 friend std::ostream &operator<<(std::ostream &o, Picture const &pict)
146 {
147 o << "dim=" << pict.m_dim << ",";
148 if (pict.m_flag) o << "f0=" << std::hex << pict.m_flag << std::dec << ",";
149 return o;
150 }
151
152 //! the dimension
153 MWAWBox2i m_dim;
154 //! the list of picture
155 std::vector<Zone> m_picturesList;
156 //! an unknown flag
157 int m_flag;
158
159 // ! a small zone
160 struct Zone {
ZoneMsWrdParserInternal::Picture::Zone161 Zone()
162 : m_pos()
163 , m_dim()
164 {
165 for (auto &fl : m_flags) fl=0;
166 }
167 //! operator<<
operator <<MsWrdParserInternal::Picture168 friend std::ostream &operator<<(std::ostream &o, Zone const &pict)
169 {
170 o << "dim=" << pict.m_dim << ",";
171 if (pict.m_flags[0] != 8) o << "f0=" << pict.m_flags[0] << ",";
172 if (pict.m_flags[1]) o << "f1=" << pict.m_flags[1] << ",";
173 if (pict.m_flags[2] != 1) o << "f2=" << pict.m_flags[2] << ","; // or 0
174 return o;
175 }
176 //! the position in file
177 MWAWEntry m_pos;
178 //! the dimension
179 MWAWBox2i m_dim;
180 //! three unknown flags
181 int m_flags[3];
182 };
183
184 };
185
186 ////////////////////////////////////////
187 //! Internal: the state of a MsWrdParser
188 struct State {
189 //! constructor
StateMsWrdParserInternal::State190 State()
191 : m_bot(-1)
192 , m_eot(-1)
193 , m_endNote(false)
194 , m_picturesMap()
195 , m_posToCommentMap()
196 , m_actPage(0)
197 , m_numPages(0)
198 , m_headersId()
199 , m_footersId()
200 , m_metaData()
201 {
202 }
203
204 //! the begin of the text
205 long m_bot;
206 //! end of the text
207 long m_eot;
208 //! a flag to know if we must place the note at the end or in the foot part
209 bool m_endNote;
210 //! the map filePos -> Picture
211 std::map<long, Picture> m_picturesMap;
212 //! the map textPos -> comment entry
213 std::map<long,MWAWEntry> m_posToCommentMap;
214
215 //! the list of object ( mainZone, other zone)
216 std::vector<Object> m_objectList[2];
217
218 int m_actPage /** the actual page */, m_numPages /** the number of page of the final document */;
219
220 /** the list of header id which corresponds to each page */
221 std::vector<int> m_headersId;
222 /** the list of footer id which corresponds to each page */
223 std::vector<int> m_footersId;
224 /** the meta data */
225 librevenge::RVNGPropertyList m_metaData;
226 };
227
228 ////////////////////////////////////////
229 //! Internal: the subdocument of a MsWrdParser
230 class SubDocument final : public MWAWSubDocument
231 {
232 public:
233 //! constructor for footnote, comment
SubDocument(MsWrdParser & pars,MWAWInputStreamPtr const & input,int id,libmwaw::SubDocumentType type)234 SubDocument(MsWrdParser &pars, MWAWInputStreamPtr const &input, int id, libmwaw::SubDocumentType type)
235 : MWAWSubDocument(&pars, input, MWAWEntry())
236 , m_id(id)
237 , m_type(type)
238 , m_pictFPos(-1)
239 , m_pictCPos(-1)
240 {
241 }
242 //! constructor for header/footer
SubDocument(MsWrdParser & pars,MWAWInputStreamPtr const & input,MWAWEntry const & entry,libmwaw::SubDocumentType type)243 SubDocument(MsWrdParser &pars, MWAWInputStreamPtr const &input, MWAWEntry const &entry, libmwaw::SubDocumentType type)
244 : MWAWSubDocument(&pars, input, entry)
245 , m_id(-1)
246 , m_type(type)
247 , m_pictFPos(-1)
248 , m_pictCPos(-1)
249 {
250 }
251 //! constructor for picture
SubDocument(MsWrdParser & pars,MWAWInputStreamPtr const & input,long fPos,int cPos)252 SubDocument(MsWrdParser &pars, MWAWInputStreamPtr const &input, long fPos, int cPos)
253 : MWAWSubDocument(&pars, input, MWAWEntry())
254 , m_id(-1)
255 , m_type(libmwaw::DOC_NONE)
256 , m_pictFPos(fPos)
257 , m_pictCPos(cPos)
258 {
259 }
260
261 //! destructor
~SubDocument()262 ~SubDocument() final {}
263
264 //! operator!=
265 bool operator!=(MWAWSubDocument const &doc) const final;
266
267 //! the parser function
268 void parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType type) final;
269
270 protected:
271 //! the subdocument id
272 int m_id;
273 //! the subdocument type
274 libmwaw::SubDocumentType m_type;
275 //! the picture file position
276 long m_pictFPos;
277 //! the picture char position
278 int m_pictCPos;
279 };
280
parse(MWAWListenerPtr & listener,libmwaw::SubDocumentType type)281 void SubDocument::parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType type)
282 {
283 if (!listener.get()) {
284 MWAW_DEBUG_MSG(("MsWrdParserInternal::SubDocument::parse: no listener\n"));
285 return;
286 }
287 auto *parser=dynamic_cast<MsWrdParser *>(m_parser);
288 if (!parser) {
289 MWAW_DEBUG_MSG(("MsWrdParserInternal::SubDocument::parse: no parser\n"));
290 return;
291 }
292
293 long pos = m_input->tell();
294 if (m_type == libmwaw::DOC_NONE && m_pictCPos >= 0 && m_pictFPos > 0)
295 parser->sendPicture(m_pictFPos, m_pictCPos, MWAWPosition::Frame);
296 else if (m_type == libmwaw::DOC_HEADER_FOOTER)
297 parser->send(m_zone);
298 else if (m_type == libmwaw::DOC_COMMENT_ANNOTATION)
299 parser->sendSimpleTextZone(listener, m_zone);
300 else
301 parser->send(m_id, type);
302 m_input->seek(pos, librevenge::RVNG_SEEK_SET);
303 }
304
operator !=(MWAWSubDocument const & doc) const305 bool SubDocument::operator!=(MWAWSubDocument const &doc) const
306 {
307 if (MWAWSubDocument::operator!=(doc)) return true;
308 auto const *sDoc = dynamic_cast<SubDocument const *>(&doc);
309 if (!sDoc) return true;
310 if (m_id != sDoc->m_id) return true;
311 if (m_type != sDoc->m_type) return true;
312 if (m_pictFPos != sDoc->m_pictFPos) return true;
313 if (m_pictCPos != sDoc->m_pictCPos) return true;
314 return false;
315 }
316 }
317
318 ////////////////////////////////////////////////////////////
319 // MsWrdEntry
320 ////////////////////////////////////////////////////////////
~MsWrdEntry()321 MsWrdEntry::~MsWrdEntry()
322 {
323 }
324
operator <<(std::ostream & o,MsWrdEntry const & entry)325 std::ostream &operator<<(std::ostream &o, MsWrdEntry const &entry)
326 {
327 if (entry.type().length()) {
328 o << entry.type();
329 if (entry.m_id >= 0) o << "[" << entry.m_id << "]";
330 o << "=";
331 }
332 return o;
333 }
334
335 ////////////////////////////////////////////////////////////
336 // constructor/destructor, ...
337 ////////////////////////////////////////////////////////////
MsWrdParser(MWAWInputStreamPtr const & input,MWAWRSRCParserPtr const & rsrcParser,MWAWHeader * header)338 MsWrdParser::MsWrdParser(MWAWInputStreamPtr const &input, MWAWRSRCParserPtr const &rsrcParser, MWAWHeader *header)
339 : MWAWTextParser(input, rsrcParser, header)
340 , m_state()
341 , m_entryMap()
342 , m_textParser()
343 {
344 init();
345 }
346
~MsWrdParser()347 MsWrdParser::~MsWrdParser()
348 {
349 }
350
init()351 void MsWrdParser::init()
352 {
353 resetTextListener();
354 setAsciiName("main-1");
355
356 m_state.reset(new MsWrdParserInternal::State);
357
358 // reduce the margin (in case, the page is not defined)
359 getPageSpan().setMargins(0.1);
360
361 m_textParser.reset(new MsWrdText(*this));
362 }
363
364 ////////////////////////////////////////////////////////////
365 // new page and color
366 ////////////////////////////////////////////////////////////
newPage(int number)367 void MsWrdParser::newPage(int number)
368 {
369 if (number <= m_state->m_actPage || number > m_state->m_numPages)
370 return;
371
372 while (m_state->m_actPage < number) {
373 m_state->m_actPage++;
374 if (!getTextListener() || m_state->m_actPage == 1)
375 continue;
376 getTextListener()->insertBreak(MWAWTextListener::PageBreak);
377 }
378 }
379
getColor(int id,MWAWColor & col) const380 bool MsWrdParser::getColor(int id, MWAWColor &col) const
381 {
382 switch (id) {
383 case 0:
384 col=MWAWColor(0,0,0);
385 break; // black
386 case 1:
387 col=MWAWColor(0,0,255);
388 break; // blue
389 case 2:
390 col=MWAWColor(0, 255,255);
391 break; // cyan
392 case 3:
393 col=MWAWColor(0,255,0);
394 break; // green
395 case 4:
396 col=MWAWColor(255,0,255);
397 break; // magenta
398 case 5:
399 col=MWAWColor(255,0,0);
400 break; // red
401 case 6:
402 col=MWAWColor(255,255,0);
403 break; // yellow
404 case 7:
405 col=MWAWColor(255,255,255);
406 break; // white
407 default:
408 MWAW_DEBUG_MSG(("MsWrdParser::getColor: unknown color=%d\n", id));
409 return false;
410 }
411 return true;
412 }
413
sendSimpleTextZone(MWAWListenerPtr & listener,MWAWEntry const & entry)414 void MsWrdParser::sendSimpleTextZone(MWAWListenerPtr &listener, MWAWEntry const &entry)
415 {
416 if (!listener || !entry.valid()) return;
417 auto input=getInput();
418 if (input->size()<entry.end()) {
419 MWAW_DEBUG_MSG(("MsWrdParser::sendSimpleTextZone: entry seems bad\n"));
420 return;
421 }
422 long pos=input->tell();
423
424 input->seek(entry.begin(), librevenge::RVNG_SEEK_SET);
425 for (long i=0; i<entry.length(); ++i) {
426 char c=char(input->readULong(1));
427 switch (c) {
428 case 0x9:
429 listener->insertTab();
430 break;
431 case 0xd: // line break hard
432 if (i+1!=entry.length())
433 listener->insertEOL();
434 break;
435 default: // asume basic caracter, ie. will not works if Chinese, ...
436 listener->insertCharacter(static_cast<unsigned char>(c));
437 break;
438 }
439 }
440 input->seek(pos, librevenge::RVNG_SEEK_SET);
441 }
442
sendFootnote(int id)443 void MsWrdParser::sendFootnote(int id)
444 {
445 if (!getTextListener()) return;
446
447 MWAWSubDocumentPtr subdoc(new MsWrdParserInternal::SubDocument(*this, getInput(), id, libmwaw::DOC_NOTE));
448 getTextListener()->insertNote
449 (MWAWNote(m_state->m_endNote ? MWAWNote::EndNote : MWAWNote::FootNote), subdoc);
450 }
451
sendFieldComment(int id)452 void MsWrdParser::sendFieldComment(int id)
453 {
454 if (!getTextListener()) return;
455
456 MWAWSubDocumentPtr subdoc(new MsWrdParserInternal::SubDocument(*this, getInput(), id, libmwaw::DOC_COMMENT_ANNOTATION));
457 getTextListener()->insertComment(subdoc);
458 }
459
send(MWAWEntry const & entry)460 void MsWrdParser::send(MWAWEntry const &entry)
461 {
462 m_textParser->sendText(entry, false);
463 }
464
send(int id,libmwaw::SubDocumentType type)465 void MsWrdParser::send(int id, libmwaw::SubDocumentType type)
466 {
467 if (type==libmwaw::DOC_COMMENT_ANNOTATION)
468 m_textParser->sendFieldComment(id);
469 else if (type==libmwaw::DOC_NOTE)
470 m_textParser->sendFootnote(id);
471 else {
472 MWAW_DEBUG_MSG(("MsWrdParser::send: find unexpected type\n"));
473 }
474 }
475
476 ////////////////////////////////////////////////////////////
477 // the parser
478 ////////////////////////////////////////////////////////////
parse(librevenge::RVNGTextInterface * docInterface)479 void MsWrdParser::parse(librevenge::RVNGTextInterface *docInterface)
480 {
481 if (!getInput().get() || !checkHeader(nullptr)) throw(libmwaw::ParseException());
482 bool ok = true;
483 try {
484 // create the asciiFile
485 ascii().setStream(getInput());
486 ascii().open(asciiName());
487
488 checkHeader(nullptr);
489 ascii().addPos(getInput()->tell());
490 ascii().addNote("_");
491
492 ok = createZones();
493 if (ok) {
494 createDocument(docInterface);
495 m_textParser->sendMainText();
496
497 m_textParser->flushExtra();
498 }
499
500 ascii().reset();
501 }
502 catch (...) {
503 MWAW_DEBUG_MSG(("MsWrdParser::parse: exception catched when parsing\n"));
504 ok = false;
505 }
506
507 resetTextListener();
508 if (!ok) throw(libmwaw::ParseException());
509 }
510
511 ////////////////////////////////////////////////////////////
512 // create the document
513 ////////////////////////////////////////////////////////////
createDocument(librevenge::RVNGTextInterface * documentInterface)514 void MsWrdParser::createDocument(librevenge::RVNGTextInterface *documentInterface)
515 {
516 if (!documentInterface) return;
517 if (getTextListener()) {
518 MWAW_DEBUG_MSG(("MsWrdParser::createDocument: listener already exist\n"));
519 return;
520 }
521
522 // update the page
523 m_state->m_actPage = 0;
524
525 // create the page list
526 MWAWPageSpan ps(getPageSpan());
527 MWAWEntry entry = m_textParser->getHeader();
528 if (entry.valid()) {
529 MWAWHeaderFooter header(MWAWHeaderFooter::HEADER, MWAWHeaderFooter::ALL);
530 header.m_subDocument.reset
531 (new MsWrdParserInternal::SubDocument(*this, getInput(), entry, libmwaw::DOC_HEADER_FOOTER));
532 ps.setHeaderFooter(header);
533 }
534 entry = m_textParser->getFooter();
535 if (entry.valid()) {
536 MWAWHeaderFooter footer(MWAWHeaderFooter::FOOTER, MWAWHeaderFooter::ALL);
537 footer.m_subDocument.reset
538 (new MsWrdParserInternal::SubDocument(*this, getInput(), entry, libmwaw::DOC_HEADER_FOOTER));
539 ps.setHeaderFooter(footer);
540 }
541 int numPage = 1;
542 if (m_textParser->numPages() > numPage)
543 numPage = m_textParser->numPages();
544 m_state->m_numPages = numPage;
545
546 ps.setPageSpan(m_state->m_numPages+1);
547 std::vector<MWAWPageSpan> pageList(1,ps);
548 //
549 MWAWTextListenerPtr listen(new MWAWTextListener(*getParserState(), pageList, documentInterface));
550 setTextListener(listen);
551 if (!m_state->m_metaData.empty())
552 listen->setDocumentMetaData(m_state->m_metaData);
553 listen->startDocument();
554 }
555
556
557 ////////////////////////////////////////////////////////////
558 //
559 // Intermediate level
560 //
561 ////////////////////////////////////////////////////////////
562
563 ////////////////////////////////////////////////////////////
564 // try to find the different zone
565 ////////////////////////////////////////////////////////////
createZones()566 bool MsWrdParser::createZones()
567 {
568 if (!readZoneList()) return false;
569 MWAWInputStreamPtr input = getInput();
570 long pos = input->tell();
571 if (pos != m_state->m_bot) {
572 ascii().addPos(pos);
573 ascii().addNote("_");
574 }
575 libmwaw::DebugStream f;
576 ascii().addPos(m_state->m_eot);
577 ascii().addNote("_");
578
579 auto it = m_entryMap.find("PrintInfo");
580 if (it != m_entryMap.end())
581 readPrintInfo(it->second);
582
583 it = m_entryMap.find("DocSum");
584 if (it != m_entryMap.end())
585 readDocSum(it->second);
586
587 it = m_entryMap.find("Printer");
588 if (it != m_entryMap.end())
589 readPrinter(it->second);
590
591 readObjects();
592
593 bool ok = m_textParser->createZones(m_state->m_bot);
594
595 it = m_entryMap.find("DocumentInfo");
596 if (it != m_entryMap.end())
597 readDocumentInfo(it->second);
598
599 it = m_entryMap.find("Zone17");
600 if (it != m_entryMap.end())
601 readZone17(it->second);
602
603 it = m_entryMap.find("Picture");
604 while (it != m_entryMap.end()) {
605 if (!it->second.hasType("Picture")) break;
606 MsWrdEntry &entry=it++->second;
607 readPicture(entry);
608 }
609
610 for (auto fIt : m_entryMap) {
611 MsWrdEntry const &entry = fIt.second;
612 if (entry.isParsed()) continue;
613 ascii().addPos(entry.begin());
614 f.str("");
615 f << entry;
616 ascii().addNote(f.str().c_str());
617 ascii().addPos(entry.end());
618 ascii().addNote("_");
619
620 }
621 return ok;
622 }
623
624 ////////////////////////////////////////////////////////////
625 // read the zone list ( FIB )
626 ////////////////////////////////////////////////////////////
readZoneList()627 bool MsWrdParser::readZoneList()
628 {
629 MWAWInputStreamPtr input = getInput();
630 int const vers = version();
631 getInput()->seek(vers <= 3 ? 30 : 64, librevenge::RVNG_SEEK_SET);
632 int numData = vers <= 3 ? 15: 20;
633 std::stringstream s;
634 for (int i = 0; i < numData; i++) {
635 switch (i) {
636 // the first two zone are often simillar : even/odd header/footer ?
637 case 0: // original styles zone, often invalid
638 readEntry("Styles", 0);
639 break;
640 case 1: // STSH
641 readEntry("Styles", 1);
642 break;
643 case 2: // FFNDRef
644 readEntry("FootnotePos");
645 break;
646 case 3: // FFNDText
647 readEntry("FootnoteDef");
648 break;
649 case 4: // SED
650 readEntry("Section");
651 break;
652 case 5: //
653 readEntry("PageBreak");
654 break;
655 case 6: // fandRef
656 readEntry("FieldName");
657 break;
658 case 7: // fandText
659 readEntry("FieldPos");
660 break;
661 case 8: // Hdd
662 readEntry("HeaderFooter");
663 break;
664 case 9: // BteChpx
665 readEntry("CharList", 0);
666 break;
667 case 10: // BtePapx
668 readEntry("ParagList", 1);
669 break;
670 case 12: // SttbfFfn
671 readEntry("FontIds");
672 break;
673 case 13: // PrDrvr: checkme: is it ok also for v3 file ?
674 readEntry("PrintInfo");
675 break;
676 case 14: // Clx/Phe
677 readEntry(vers <= 3 ? "TextStruct" : "ParaInfo");
678 break;
679 case 15: // Dop?
680 readEntry("DocumentInfo");
681 break;
682 case 16:
683 readEntry("Printer");
684 break;
685 case 18: // Clx (ie. a list of Pcd )
686 readEntry("TextStruct");
687 break;
688 case 19:
689 readEntry("FootnoteData");
690 break;
691 default:
692 s.str("");
693 s << "Zone" << i;
694 if (i < 4) s << "_";
695 readEntry(s.str());
696 break;
697 }
698 }
699
700 if (vers <= 3) return true;
701 long pos = input->tell();
702 libmwaw::DebugStream f;
703 f << "Entries(ListZoneData)[0]:";
704 for (int i = 0; i < 2; i++) // two small int
705 f << "f" << i << "=" << input->readLong(2) << ",";
706
707 ascii().addPos(pos);
708 ascii().addNote(f.str().c_str());
709 if (vers <= 4) return true;
710
711 // main
712 readEntry("ObjectName",0);
713 readEntry("FontNames");
714 readEntry("ObjectList",0);
715 readEntry("ObjectFlags",0);
716 readEntry("DocSum",0);
717 for (int i = 25; i < 31; i++) {
718 /* check me: Zone25, Zone26, Zone27: also some object name, list, flags ? */
719 // header/footer
720 if (i==28) readEntry("ObjectName",1);
721 else if (i==29) readEntry("ObjectList",1);
722 else if (i==30) readEntry("ObjectFlags",1);
723 else {
724 s.str("");
725 s << "Zone" << i;
726 readEntry(s.str());
727 }
728 }
729
730 pos = input->tell();
731 f.str("");
732 f << "ListZoneData[1]:";
733
734 long val = input->readLong(2);
735 if (val) f << "unkn=" << val << ",";
736 ascii().addPos(pos);
737 ascii().addNote(f.str().c_str());
738
739 if (input->isEnd()) {
740 MWAW_DEBUG_MSG(("MsWrdParser::readZoneList: can not read list zone\n"));
741 return false;
742 }
743 return true;
744 }
745
746 ////////////////////////////////////////////////////////////
747 //
748 // Low level
749 //
750 ////////////////////////////////////////////////////////////
751
752
753
754 ////////////////////////////////////////////////////////////
755 // read the header
756 ////////////////////////////////////////////////////////////
checkHeader(MWAWHeader * header,bool strict)757 bool MsWrdParser::checkHeader(MWAWHeader *header, bool strict)
758 {
759 *m_state = MsWrdParserInternal::State();
760
761 MWAWInputStreamPtr input = getInput();
762 if (!input || !input->hasDataFork())
763 return false;
764
765 libmwaw::DebugStream f;
766 int headerSize=64;
767 if (!input->checkPosition(0x88)) {
768 MWAW_DEBUG_MSG(("MsWrdParser::checkHeader: file is too short\n"));
769 return false;
770 }
771 long pos = 0;
772 input->seek(pos, librevenge::RVNG_SEEK_SET);
773 auto val = static_cast<int>(input->readULong(2));
774 switch (val) {
775 case 0xfe34:
776 switch (input->readULong(2)) {
777 case 0x0:
778 headerSize = 30;
779 setVersion(3);
780 break;
781 default:
782 return false;
783 }
784 break;
785 case 0xfe37:
786 switch (input->readULong(2)) {
787 case 0x1c:
788 setVersion(4);
789 break;
790 case 0x23:
791 setVersion(5);
792 break;
793 default:
794 return false;
795 }
796 break;
797 default:
798 return false;
799 }
800
801 int const vers = version();
802 f << "FileHeader:";
803 val = static_cast<int>(input->readULong(1)); // v1: ab other 0 ?
804 if (val) f << "f0=" << val << ",";
805 for (int i = 1; i < 3; i++) { // always 0
806 val = static_cast<int>(input->readLong(2));
807 if (val) f << "f" << i << "=" << val << ",";
808 }
809 if (vers > 3) {
810 // find 4, 8, c, 24, 2c
811 val = static_cast<int>(input->readLong(2));
812 if (val)
813 f << "unkn=" << std::hex << val << std::dec << ",";
814 // 0,0,0x19,0
815 for (int i = 4; i < 8; i++) {
816 val = static_cast<int>(input->readLong(1));
817 if (val) f << "f" << i << "=" << val << ",";
818 }
819 }
820
821 for (int i = 0; i < 5; i++) { // always 0 ?
822 val = static_cast<int>(input->readLong(1));
823 if (val) f << "g" << i << "=" << val << ",";
824 }
825
826 m_state->m_bot = vers <= 3 ? 0x100 : long(input->readULong(4));
827 m_state->m_eot = long(input->readULong(4));
828 f << "text=" << std::hex << m_state->m_bot << "<->" << m_state->m_eot << ",";
829 if (m_state->m_bot > m_state->m_eot) {
830 f << "#text,";
831 if (0x100 <= m_state->m_eot) {
832 MWAW_DEBUG_MSG(("MsWrdParser::checkHeader: problem with text position: reset begin to default\n"));
833 m_state->m_bot = 0x100;
834 }
835 else {
836 MWAW_DEBUG_MSG(("MsWrdParser::checkHeader: problem with text position: reset to empty\n"));
837 m_state->m_bot = m_state->m_eot = 0x100;
838 }
839 }
840
841 if (vers <= 3) { // always 0
842 for (int i = 0; i < 6; i++) {
843 val = static_cast<int>(input->readLong(2));
844 if (val) f << "h" << i << "=" << val << ",";
845 }
846 ascii().addPos(pos);
847 ascii().addNote(f.str().c_str());
848 if (!readHeaderEndV3())
849 return false;
850 if (header)
851 header->reset(MWAWDocument::MWAW_T_MICROSOFTWORD, vers);
852 return true;
853 }
854
855 auto endOfData = long(input->readULong(4));
856 f << "eof=" << std::hex << endOfData << std::dec << ",";
857 if (endOfData < 100 || !input->checkPosition(endOfData)) {
858 MWAW_DEBUG_MSG(("MsWrdParser::checkHeader: end of file pos is too small\n"));
859 if (endOfData < m_state->m_eot || strict)
860 return false;
861 f << "#endOfData,";
862 }
863 ascii().addPos(endOfData);
864 ascii().addNote("Entries(End)");
865
866 val = static_cast<int>(input->readLong(4)); // always 0 ?
867 if (val) f << "unkn2=" << val << ",";
868 ascii().addPos(pos);
869 ascii().addNote(f.str().c_str());
870
871 if (!m_textParser->readHeaderTextLength())
872 return false;
873
874 pos = input->tell();
875 f.str("");
876 f << "FileHeader[A]:";
877 for (int i = 0; i < 8; i++) {
878 val = static_cast<int>(input->readLong(2));
879 if (val) f << "f" << i << "=" << val << ",";
880 }
881
882 // ok, we can finish initialization
883 if (header)
884 header->reset(MWAWDocument::MWAW_T_MICROSOFTWORD, vers);
885
886 if (long(input->tell()) != headerSize)
887 ascii().addDelimiter(input->tell(), '|');
888
889 ascii().addPos(pos);
890 ascii().addNote(f.str().c_str());
891
892 return true;
893 }
894
895 ////////////////////////////////////////////////////////////
896 // try to the end of the header
897 ////////////////////////////////////////////////////////////
readHeaderEndV3()898 bool MsWrdParser::readHeaderEndV3()
899 {
900 MWAWInputStreamPtr input = getInput();
901 if (!input->checkPosition(0xb8))
902 return false;
903 libmwaw::DebugStream f;
904 input->seek(0x78, librevenge::RVNG_SEEK_SET);
905 long pos = input->tell();
906 long val = input->readLong(4); // normally 0x100
907 if (val != 0x100)
908 f << "FileHeader[A]:" << std::hex << val << std::dec << ",";
909 else
910 f << "_";
911 ascii().addPos(pos);
912 ascii().addNote(f.str().c_str());
913 if (!m_textParser->readHeaderTextLength())
914 return false;
915 pos = input->tell();
916 f << "FileHeader[B]:";
917 for (int i = 0; i < 18; i++) { // always 0 ?
918 val = input->readLong(2);
919 if (val)
920 f << "f" << i << "=" << val << ",";
921 }
922 float dim[6]; // H, W+margin T, L, B, R
923 for (auto &d : dim) d = float(input->readLong(2))/1440.0f;
924
925 f << "page=" << dim[1] << "x" << dim[0] << ",";
926 f << "margins=" << dim[3] << "x" << dim[2] << "-" << dim[5] << "x" << dim[4] << ",";
927 bool dimOk = true;
928 if (dim[0]>0 && dim[1]>0) {
929 for (int i = 2; i < 6; i++)
930 if (dim[i] < 0) dimOk = false;
931 if (2*(dim[3]+dim[5]) > dim[1] || 2*(dim[2]+dim[4]) > dim[0]) dimOk = false;
932 if (!dimOk) {
933 f << "###";
934 MWAW_DEBUG_MSG(("MsWrdParser::readHeaderEndV3: page dimensions seem bad\n"));
935 }
936 else {
937 getPageSpan().setMarginTop(double(dim[2]));
938 getPageSpan().setMarginLeft(double(dim[3]));
939 getPageSpan().setMarginBottom((dim[4]< 0.5f) ? 0.0 : double(dim[4])-0.5);
940 getPageSpan().setMarginRight((dim[5]< 0.5f) ? 0.0 : double(dim[5])-0.5);
941 getPageSpan().setFormLength(double(dim[0]));
942 getPageSpan().setFormWidth(double(dim[1]));
943 }
944 }
945 else
946 dimOk = false;
947 ascii().addPos(pos);
948 ascii().addNote(f.str().c_str());
949
950 pos = input->tell();
951 f.str("");
952 f << "FileHeader[C]:";
953 val = input->readLong(2); // always 0 ?
954 if (val)
955 f << "margins[binding]=" << float(val)/1440.f << ",";
956 val = input->readLong(2);
957 f << "defTabs=" << float(val)/1440.f << ",";
958 auto flags = static_cast<int>(input->readULong(1));
959 if (flags & 0x80) // page vis a vis
960 f << "facingpage,";
961 if (flags & 0x40) // ligne creuse
962 f << "defTabs[emptyline],";
963 switch ((flags>>1) & 0x3) {
964 case 0:
965 if (dimOk) m_state->m_endNote = true;
966 f << "endnote,";
967 break;
968 case 1:
969 f << "footnote,";
970 break;
971 case 2:
972 f << "footnote[undertext],";
973 break;
974 default:
975 f << "#notepos=3,";
976 break;
977 }
978 if (flags&1) {
979 f << "landscape,";
980 if (dimOk)
981 getPageSpan().setFormOrientation(MWAWPageSpan::LANDSCAPE);
982 }
983 flags &= 0x38;
984 if (flags)
985 f << "#flags=" << std::hex << flags << std::dec << ",";
986 flags = static_cast<int>(input->readULong(1));
987 if (flags) // always 1
988 f << "fl1=" << std::hex << flags << std::dec << ",";
989 char const *wh[] = { "note", "line", "page" };
990 for (auto const *what : wh) {
991 val = long(input->readULong(2));
992 if (val == 1) continue;
993 if (val & 0x8000)
994 f << what << "[firstNumber]=" << (val&0x7FFF) << "[auto],";
995 else
996 f << what << "[firstNumber]=" << val << ",";
997 }
998 for (int i = 0; i < 2; i++) { // first flags often 0x40, second?
999 flags = static_cast<int>(input->readULong(1));
1000 if (flags) // always 1
1001 f << "fl" << 2+i << "=" << std::hex << flags << std::dec << ",";
1002 }
1003 for (int i = 0; i < 13; i++) { // always 0?
1004 val = input->readLong(2);
1005 if (val)
1006 f << "f" << i << "=" << val << ",";
1007 }
1008 ascii().addPos(pos);
1009 ascii().addNote(f.str().c_str());
1010
1011 pos = input->tell();
1012 f.str("");
1013 f << "FileHeader[D]:";
1014 auto sz = static_cast<int>(input->readULong(1));
1015 if (sz == 0) {
1016 ascii().addPos(pos);
1017 ascii().addNote("_");
1018 return true;
1019 }
1020 if (sz > 31) {
1021 f << "###";
1022 MWAW_DEBUG_MSG(("MsWrdParser::readHeaderEndV3: next filename seems bad\n"));
1023 }
1024 else {
1025 std::string fName("");
1026 for (int i = 0; i < sz; i++)
1027 fName += char(input->readULong(1));
1028 f << "nextFile=" << fName;
1029 }
1030 ascii().addPos(pos);
1031 ascii().addNote(f.str().c_str());
1032 input->seek(0x100, librevenge::RVNG_SEEK_SET);
1033 return true;
1034 }
1035
1036 ////////////////////////////////////////////////////////////
1037 // try to read an entry
1038 ////////////////////////////////////////////////////////////
readEntry(std::string type,int id)1039 MsWrdEntry MsWrdParser::readEntry(std::string type, int id)
1040 {
1041 MWAWInputStreamPtr input = getInput();
1042 MsWrdEntry entry;
1043 entry.setType(type);
1044 entry.setId(id);
1045 long pos = input->tell();
1046 libmwaw::DebugStream f;
1047
1048 auto debPos = long(input->readULong(4));
1049 auto sz = long(input->readULong(2));
1050 if (id >= 0) f << "Entries(" << type << ")[" << id << "]:";
1051 else f << "Entries(" << type << "):";
1052 if (sz == 0) {
1053 ascii().addPos(pos);
1054 ascii().addNote("_");
1055 return entry;
1056 }
1057 if (!input->checkPosition(debPos+sz)) {
1058 MWAW_DEBUG_MSG(("MsWrdParser::readEntry: problem reading entry: %s\n", type.c_str()));
1059 f << "#";
1060 ascii().addPos(pos);
1061 ascii().addNote(f.str().c_str());
1062 return entry;
1063 }
1064
1065 entry.setBegin(debPos);
1066 entry.setLength(sz);
1067 m_entryMap.insert
1068 (std::multimap<std::string, MsWrdEntry>::value_type(type, entry));
1069
1070 f << std::hex << debPos << "[" << sz << "],";
1071 ascii().addPos(pos);
1072 ascii().addNote(f.str().c_str());
1073
1074 return entry;
1075 }
1076
1077 ////////////////////////////////////////////////////////////
1078 // read the document information
1079 ////////////////////////////////////////////////////////////
readDocumentInfo(MsWrdEntry & entry)1080 bool MsWrdParser::readDocumentInfo(MsWrdEntry &entry)
1081 {
1082 if (entry.length() != 0x20) {
1083 MWAW_DEBUG_MSG(("MsWrdParser::readDocumentInfo: the zone size seems odd\n"));
1084 return false;
1085 }
1086 MWAWInputStreamPtr input = getInput();
1087 long pos = entry.begin();
1088 entry.setParsed(true);
1089 input->seek(pos, librevenge::RVNG_SEEK_SET);
1090 libmwaw::DebugStream f;
1091 f << "DocumentInfo:";
1092
1093 float dim[2];
1094 for (float &i : dim) i = float(input->readLong(2))/1440.f;
1095 f << "dim?=" << dim[1] << "x" << dim[0] << ",";
1096
1097 float margin[4];
1098 f << ",marg=["; // top, left?, bottom, right?
1099 for (auto &marg : margin) {
1100 marg = float(input->readLong(2))/1440.f;
1101 f << marg << ",";
1102 if (marg < 0) marg *= -1.0f;
1103 }
1104 f << "],";
1105
1106 if (dim[0] > margin[0]+margin[2] && dim[1] > margin[1]+margin[3]) {
1107 getPageSpan().setMarginTop(double(margin[0]));
1108 getPageSpan().setMarginLeft(double(margin[1]));
1109 /* decrease a little the right/bottom margin to allow fonts discrepancy*/
1110 getPageSpan().setMarginBottom((margin[2]< 0.5f) ? 0.0 : double(margin[2])-0.5);
1111 getPageSpan().setMarginRight((margin[3]< 0.5f) ? 0.0 : double(margin[3])-0.5);
1112
1113 getPageSpan().setFormLength(double(dim[0]));
1114 getPageSpan().setFormWidth(double(dim[1]));
1115 }
1116 else {
1117 MWAW_DEBUG_MSG(("MsWrdParser::readDocumentInfo: the page dimensions seems odd\n"));
1118 }
1119
1120 auto val = static_cast<int>(input->readLong(2)); // always 0 ?
1121 if (val) f << "unkn=" << val << ",";
1122 val = static_cast<int>(input->readLong(2)); // 0x2c5 or 0x2d0?
1123 f << "f0=" << val << ",";
1124 for (int i = 0; i < 4; i++) { //[a|12|40|42|4a|52|54|d2],0,0|80,1
1125 val = static_cast<int>(input->readULong(1));
1126 if (val) f << "fl" << i << "=" << std::hex << val << std::dec << ",";
1127 }
1128 val = static_cast<int>(input->readLong(2)); // always 1 ?
1129 if (val != 1) f << "f1=" << val << ",";
1130 // a small number between 0 and 77
1131 f << "f2=" << static_cast<int>(input->readLong(2)) << ",";
1132 for (int i = 0; i < 4; i++) { //[0|2|40|42|44|46|48|58],0|64,0|10|80,[0|2|5]
1133 val = static_cast<int>(input->readULong(1));
1134 if (val) f << "flA" << i << "=" << std::hex << val << std::dec << ",";
1135 }
1136 val = static_cast<int>(input->readLong(2)); // always 0 ?
1137 if (val != 1) f << "f3=" << val << ",";
1138 val = static_cast<int>(input->readLong(2)); // 0, 48, 50
1139 if (val) f << "f4=" << val << ",";
1140
1141 ascii().addPos(entry.begin());
1142 ascii().addNote(f.str().c_str());
1143 ascii().addPos(entry.end());
1144 ascii().addNote("_");
1145 return true;
1146 }
1147
1148 ////////////////////////////////////////////////////////////
1149 // read the zone 17
1150 ////////////////////////////////////////////////////////////
readZone17(MsWrdEntry & entry)1151 bool MsWrdParser::readZone17(MsWrdEntry &entry)
1152 {
1153 if (entry.length() != 0x2a) {
1154 MWAW_DEBUG_MSG(("MsWrdParser::readZone17: the zone size seems odd\n"));
1155 return false;
1156 }
1157 MWAWInputStreamPtr input = getInput();
1158 long pos = entry.begin();
1159 entry.setParsed(true);
1160 input->seek(pos, librevenge::RVNG_SEEK_SET);
1161 libmwaw::DebugStream f;
1162 f << "Zone17:";
1163 if (version() < 5) {
1164 f << "bdbox?=[";
1165 for (int i = 0; i < 4; i++)
1166 f << input->readLong(2) << ",";
1167 f << "],";
1168 f << "bdbox2?=[";
1169 for (int i = 0; i < 4; i++)
1170 f << input->readLong(2) << ",";
1171 f << "],";
1172 }
1173
1174 /*
1175 f0=0, 80, 82, 84, b0, b4, c2, c4, f0, f2 : type and ?
1176 f1=0|1|8|34|88 */
1177 int val;
1178 for (int i = 0; i < 2; i++) {
1179 val = static_cast<int>(input->readULong(1));
1180 if (val) f << "f" << i << "=" << std::hex << val << std::dec << ",";
1181 }
1182 // 0 or 1, followed by 0
1183 for (int i = 2; i < 4; i++) {
1184 val = static_cast<int>(input->readLong(1));
1185 if (val) f << "f" << i << "=" << val << ",";
1186 }
1187 auto ptr = long(input->readULong(4)); // a text ptr ( often near to textLength )
1188 f << "textPos[sel?]=" << std::hex << ptr << std::dec << ",";
1189 val = static_cast<int>(input->readULong(4)); // almost always ptr
1190 if (val != ptr)
1191 f << "textPos1=" << std::hex << val << std::dec << ",";
1192 // a small int between 6 and b
1193 val = static_cast<int>(input->readLong(2));
1194 if (val) f << "f4=" << val << ",";
1195
1196 for (int i = 5; i < 7; i++) { // 0,0 or 3,5 or 8000, 8000
1197 val = static_cast<int>(input->readULong(2));
1198 if (val) f << "f" << i << "=" << std::hex << val << std::dec << ",";
1199 }
1200 val = static_cast<int>(input->readULong(4)); // almost always ptr
1201 if (val != ptr)
1202 f << "textPos2=" << std::hex << val << std::dec << ",";
1203 /* g0=[0,1,5,c], g1=[0,1,3,4] */
1204 for (int i = 0; i < 2; i++) {
1205 val = static_cast<int>(input->readLong(2));
1206 if (val) f << "g" << i << "=" << val << ",";
1207 }
1208 if (version() == 5) {
1209 f << "bdbox?=[";
1210 for (int i = 0; i < 4; i++)
1211 f << input->readLong(2) << ",";
1212 f << "],";
1213 f << "bdbox2?=[";
1214 for (int i = 0; i < 4; i++)
1215 f << input->readLong(2) << ",";
1216 f << "],";
1217 }
1218 ascii().addPos(pos);
1219 ascii().addNote(f.str().c_str());
1220 ascii().addPos(entry.end());
1221 ascii().addNote("_");
1222 return true;
1223 }
1224
1225 ////////////////////////////////////////////////////////////
1226 // read the printer name
1227 ////////////////////////////////////////////////////////////
readPrinter(MsWrdEntry & entry)1228 bool MsWrdParser::readPrinter(MsWrdEntry &entry)
1229 {
1230 if (entry.length() < 2) {
1231 MWAW_DEBUG_MSG(("MsWrdParser::readPrinter: the zone seems to short\n"));
1232 return false;
1233 }
1234
1235 MWAWInputStreamPtr input = getInput();
1236 long pos = entry.begin();
1237 input->seek(pos, librevenge::RVNG_SEEK_SET);
1238 libmwaw::DebugStream f;
1239 f << "Printer:";
1240 auto sz = static_cast<int>(input->readULong(2));
1241 if (sz > entry.length()) {
1242 MWAW_DEBUG_MSG(("MsWrdParser::readPrinter: the zone seems to short\n"));
1243 return false;
1244 }
1245 auto strSz = static_cast<int>(input->readULong(1));
1246 if (strSz+2> sz) {
1247 MWAW_DEBUG_MSG(("MsWrdParser::readPrinter: name seems to big\n"));
1248 return false;
1249 }
1250 std::string name("");
1251 for (int i = 0; i < strSz; i++)
1252 name+=char(input->readLong(1));
1253 f << name << ",";
1254 int i= 0;
1255 while (long(input->tell())+2 <= entry.end()) { // almost always a,0,0
1256 auto val = static_cast<int>(input->readLong(2));
1257 if (val) f << "f" << i << "=" << val << ",";
1258 i++;
1259 }
1260 if (long(input->tell()) != entry.end())
1261 ascii().addDelimiter(input->tell(), '|');
1262
1263 entry.setParsed(true);
1264 ascii().addPos(pos);
1265 ascii().addNote(f.str().c_str());
1266
1267 ascii().addPos(entry.end());
1268 ascii().addNote("_");
1269 return true;
1270 }
1271
1272 ////////////////////////////////////////////////////////////
1273 // read the document summary
1274 ////////////////////////////////////////////////////////////
readDocSum(MsWrdEntry & entry)1275 bool MsWrdParser::readDocSum(MsWrdEntry &entry)
1276 {
1277 MWAWInputStreamPtr input = getInput();
1278 if (entry.length() < 8 || !input->checkPosition(entry.end())) {
1279 MWAW_DEBUG_MSG(("MsWrdParser::readDocSum: the zone seems to short\n"));
1280 return false;
1281 }
1282
1283 long pos = entry.begin();
1284 input->seek(pos, librevenge::RVNG_SEEK_SET);
1285 libmwaw::DebugStream f;
1286 f << "DocSum:";
1287 auto sz = static_cast<int>(input->readULong(2));
1288 if (sz > entry.length()) {
1289 MWAW_DEBUG_MSG(("MsWrdParser::readDocSum: the zone seems to short\n"));
1290 return false;
1291 }
1292 entry.setParsed(true);
1293
1294 if (sz != entry.length()) f << "#";
1295 char const *what[] = { "title", "subject","author","version","keyword",
1296 "creator", "author1", "author2" // unsure why there are 4 authors...
1297 };
1298 char const *attribNames[] = { "dc:title", "dc:subject", "meta:initial-creator", nullptr,
1299 "meta:keywords", "dc:creator", nullptr, nullptr
1300 };
1301 auto fontConverter = getFontConverter();
1302 for (int i = 0; i < 8; i++) {
1303 long actPos = input->tell();
1304 if (actPos == entry.end()) break;
1305
1306 sz = static_cast<int>(input->readULong(1));
1307 if (sz == 0 || sz == 0xFF) continue;
1308
1309 if (actPos+1+sz > entry.end()) {
1310 MWAW_DEBUG_MSG(("MsWrdParser::readDocSum: string %d to short...\n", i));
1311 f << "#";
1312 input->seek(actPos, librevenge::RVNG_SEEK_SET);
1313 break;
1314 }
1315 librevenge::RVNGString s;
1316 for (int j = 0; j < sz; j++) {
1317 auto c= static_cast<unsigned char>(input->readULong(1));
1318 // assume standart encoding here
1319 int unicode = fontConverter ? fontConverter->unicode(3, c) : -1;
1320 if (unicode!=-1)
1321 libmwaw::appendUnicode(uint32_t(unicode), s);
1322 else if (c<0x20)
1323 f << "##" << int(c);
1324 else
1325 s.append(char(c));
1326 }
1327 if (!s.empty() && attribNames[i]!=nullptr)
1328 m_state->m_metaData.insert(attribNames[i],s);
1329 f << what[i] << "=" << s.cstr() << ",";
1330 }
1331
1332 ascii().addPos(pos);
1333 ascii().addNote(f.str().c_str());
1334
1335 if (long(input->tell()) != entry.end())
1336 ascii().addDelimiter(input->tell(), '|');
1337
1338 ascii().addPos(entry.end());
1339 ascii().addNote("_");
1340 return true;
1341 }
1342
1343 ////////////////////////////////////////////////////////////
1344 // read a list of strings zone
1345 ////////////////////////////////////////////////////////////
readStringsZone(MsWrdEntry & entry,std::vector<std::string> & list)1346 bool MsWrdParser::readStringsZone(MsWrdEntry &entry, std::vector<std::string> &list)
1347 {
1348 list.resize(0);
1349 MWAWInputStreamPtr input = getInput();
1350 if (entry.length() < 2 || !input->checkPosition(entry.end())) {
1351 MWAW_DEBUG_MSG(("MsWrdParser::readStringsZone: the zone seems to short\n"));
1352 return false;
1353 }
1354
1355 long pos = entry.begin();
1356 input->seek(pos, librevenge::RVNG_SEEK_SET);
1357 libmwaw::DebugStream f;
1358 f << entry;
1359 auto sz = static_cast<int>(input->readULong(2));
1360 if (sz > entry.length()) {
1361 MWAW_DEBUG_MSG(("MsWrdParser::readStringsZone: the zone seems to short\n"));
1362 return false;
1363 }
1364 ascii().addPos(entry.begin());
1365 ascii().addNote(f.str().c_str());
1366
1367 int id = 0;
1368 while (long(input->tell()) != entry.end()) {
1369 pos = input->tell();
1370 auto strSz = static_cast<int>(input->readULong(1));
1371 if (pos+strSz+1> entry.end()) {
1372 MWAW_DEBUG_MSG(("MsWrdParser::readStringsZone: a string seems to big\n"));
1373 f << "#";
1374 break;
1375 }
1376 std::string name("");
1377 for (int i = 0; i < strSz; i++)
1378 name+=char(input->readLong(1));
1379 list.push_back(name);
1380 f.str("");
1381 f << entry << "id" << id++ << "," << name << ",";
1382 ascii().addPos(pos);
1383 ascii().addNote(f.str().c_str());
1384 }
1385
1386 if (long(input->tell()) != entry.end()) {
1387 ascii().addPos(input->tell());
1388 f.str("");
1389 f << entry << "#";
1390 ascii().addNote(f.str().c_str());
1391 }
1392
1393 entry.setParsed(true);
1394
1395 ascii().addPos(entry.end());
1396 ascii().addNote("_");
1397 return true;
1398 }
1399
1400 ////////////////////////////////////////////////////////////
1401 // read the objects
1402 ////////////////////////////////////////////////////////////
readObjects()1403 bool MsWrdParser::readObjects()
1404 {
1405 MWAWInputStreamPtr input = getInput();
1406
1407 auto it = m_entryMap.find("ObjectList");
1408 while (it != m_entryMap.end()) {
1409 if (!it->second.hasType("ObjectList")) break;
1410 MsWrdEntry &entry=it++->second;
1411 readObjectList(entry);
1412 }
1413
1414 it = m_entryMap.find("ObjectFlags");
1415 while (it != m_entryMap.end()) {
1416 if (!it->second.hasType("ObjectFlags")) break;
1417 MsWrdEntry &entry=it++->second;
1418 readObjectFlags(entry);
1419 }
1420
1421 it = m_entryMap.find("ObjectName");
1422 while (it != m_entryMap.end()) {
1423 if (!it->second.hasType("ObjectName")) break;
1424 MsWrdEntry &entry=it++->second;
1425 std::vector<std::string> list;
1426 readStringsZone(entry, list);
1427
1428 if (entry.id() < 0 || entry.id() > 1) {
1429 MWAW_DEBUG_MSG(("MsWrdParser::readObjects: unexpected entry id: %d\n", entry.id()));
1430 continue;
1431 }
1432 auto &listObject = m_state->m_objectList[entry.id()];
1433 size_t numObjects = listObject.size();
1434 if (list.size() != numObjects) {
1435 MWAW_DEBUG_MSG(("MsWrdParser::readObjects: unexpected number of name\n"));
1436 if (list.size() < numObjects) numObjects = list.size();
1437 }
1438 for (size_t i = 0; i < numObjects; i++)
1439 listObject[i].m_name = list[i];
1440 }
1441
1442 std::map<long,MWAWEntry> posToComments;
1443 for (auto &listObject : m_state->m_objectList) {
1444 for (auto &obj : listObject) {
1445 readObject(obj);
1446 if (obj.m_annotation.valid() && obj.m_textPos>=0)
1447 posToComments[obj.m_textPos]=obj.m_annotation;
1448 }
1449 }
1450 m_state->m_posToCommentMap=posToComments;
1451 return true;
1452 }
1453
readObjectList(MsWrdEntry & entry)1454 bool MsWrdParser::readObjectList(MsWrdEntry &entry)
1455 {
1456 if (entry.id() < 0 || entry.id() > 1) {
1457 MWAW_DEBUG_MSG(("MsWrdParser::readObjectList: unexpected entry id: %d\n", entry.id()));
1458 return false;
1459 }
1460 std::vector<MsWrdParserInternal::Object> &listObject = m_state->m_objectList[entry.id()];
1461 listObject.resize(0);
1462 if (entry.length() < 4 || (entry.length()%18) != 4) {
1463 MWAW_DEBUG_MSG(("MsWrdParser::readObjectList: the zone size seems odd\n"));
1464 return false;
1465 }
1466 MWAWInputStreamPtr input = getInput();
1467 long pos = entry.begin();
1468 entry.setParsed(true);
1469 input->seek(pos, librevenge::RVNG_SEEK_SET);
1470 libmwaw::DebugStream f;
1471 f << "ObjectList[" << entry.id() << "]:";
1472 auto N=int(entry.length()/18);
1473
1474 auto &plcMap=m_textParser->getTextPLCMap();
1475 MsWrdText::PLC plc(MsWrdText::PLC::Object);
1476 std::vector<long> textPos; // checkme
1477 textPos.resize(size_t(N)+1);
1478 f << "[";
1479 for (int i = 0; i < N+1; i++) {
1480 auto tPos = long(input->readULong(4));
1481 textPos[size_t(i)] = tPos;
1482 f << std::hex << tPos << std::dec << ",";
1483 if (i == N)
1484 break;
1485 plc.m_id = i;
1486 plcMap.insert(std::multimap<long, MsWrdText::PLC>::value_type(tPos,plc));
1487 }
1488 f << "],";
1489 ascii().addPos(pos);
1490 ascii().addNote(f.str().c_str());
1491
1492 for (int i = 0; i < N; i++) {
1493 MsWrdParserInternal::Object object;
1494 object.m_textPos = textPos[size_t(i)];
1495 pos = input->tell();
1496 f.str("");
1497 object.m_id = static_cast<int>(input->readLong(2));
1498 // id0=<small number>:[8|48], id1: <small number>:60->normal, :7c?, 0->annotation ?
1499 for (int st = 0; st < 2; st++) {
1500 object.m_ids[st] = static_cast<int>(input->readLong(2));
1501 object.m_idsFlag[st] = static_cast<int>(input->readULong(1));
1502 }
1503
1504 object.m_pos.setBegin(long(input->readULong(4)));
1505 auto val = static_cast<int>(input->readLong(2)); // always 0 ?
1506 if (val) f << "#f1=" << val << ",";
1507 object.m_extra = f.str();
1508 f.str("");
1509 f << "ObjectList-" << i << ":" << object;
1510 if (!input->checkPosition(object.m_pos.begin())) {
1511 MWAW_DEBUG_MSG(("MsWrdParser::readObjectList: pb with ptr\n"));
1512 f << "#ptr=" << std::hex << object.m_pos.begin() << std::dec << ",";
1513 object.m_pos.setBegin(0);
1514 }
1515
1516 listObject.push_back(object);
1517 ascii().addPos(pos);
1518 ascii().addNote(f.str().c_str());
1519 }
1520
1521 ascii().addPos(entry.end());
1522 ascii().addNote("_");
1523 return true;
1524
1525 }
1526
readObjectFlags(MsWrdEntry & entry)1527 bool MsWrdParser::readObjectFlags(MsWrdEntry &entry)
1528 {
1529 if (entry.id() < 0 || entry.id() > 1) {
1530 MWAW_DEBUG_MSG(("MsWrdParser::readObjectFlags: unexpected entry id: %d\n", entry.id()));
1531 return false;
1532 }
1533 std::vector<MsWrdParserInternal::Object> &listObject = m_state->m_objectList[entry.id()];
1534 auto numObject = static_cast<int>(listObject.size());
1535 if (entry.length() < 4 || (entry.length()%6) != 4) {
1536 MWAW_DEBUG_MSG(("MsWrdParser::readObjectFlags: the zone size seems odd\n"));
1537 return false;
1538 }
1539 MWAWInputStreamPtr input = getInput();
1540 long pos = entry.begin();
1541 entry.setParsed(true);
1542 input->seek(pos, librevenge::RVNG_SEEK_SET);
1543 libmwaw::DebugStream f;
1544 f << "ObjectFlags[" << entry.id() << "]:";
1545 auto N=int(entry.length()/6);
1546 if (N != numObject) {
1547 MWAW_DEBUG_MSG(("MsWrdParser::readObjectFlags: unexpected number of object\n"));
1548 }
1549
1550 f << "[";
1551 for (int i = 0; i < N+1; i++) {
1552 auto textPos = long(input->readULong(4));
1553 if (i < numObject && textPos != listObject[size_t(i)].m_textPos && textPos != listObject[size_t(i)].m_textPos+1)
1554 f << "#";
1555 f << std::hex << textPos << std::dec << ",";
1556 }
1557 f << "],";
1558 ascii().addPos(pos);
1559 ascii().addNote(f.str().c_str());
1560
1561 for (int i = 0; i < N; i++) {
1562 pos = input->tell();
1563 int flags[2];
1564 for (auto &flag : flags) flag = static_cast<int>(input->readULong(1));
1565 f.str("");
1566 f << "ObjectFlags-" << i << ":";
1567 if (i < numObject) {
1568 for (int st = 0; st < 2; st++) listObject[size_t(i)].m_flags[st] = flags[st];
1569 f << "Obj" << listObject[size_t(i)].m_id << ",";
1570 }
1571 // indentical to ObjectList id0[low] ?
1572 if (flags[0] != 0x48) f << "fl0=" << std::hex << flags[0] << std::dec << ",";
1573 if (flags[1]) f << "fl1=" << std::hex << flags[1] << std::dec << ",";
1574 ascii().addPos(pos);
1575 ascii().addNote(f.str().c_str());
1576 }
1577
1578 ascii().addPos(entry.end());
1579 ascii().addNote("_");
1580 return true;
1581
1582 }
1583
readObject(MsWrdParserInternal::Object & obj)1584 bool MsWrdParser::readObject(MsWrdParserInternal::Object &obj)
1585 {
1586 MWAWInputStreamPtr input = getInput();
1587 libmwaw::DebugStream f;
1588
1589 long pos = obj.m_pos.begin(), beginPos = pos;
1590 if (!pos) return false;
1591
1592 input->seek(pos, librevenge::RVNG_SEEK_SET);
1593 auto sz = static_cast<int>(input->readULong(4));
1594
1595 f << "Entries(ObjectData):Obj" << obj.m_id << ",";
1596 if (!input->checkPosition(pos+sz) || sz < 6) {
1597 MWAW_DEBUG_MSG(("MsWrdParser::readObject: pb finding object data sz\n"));
1598 f << "#";
1599 ascii().addPos(beginPos);
1600 ascii().addNote(f.str().c_str());
1601 return false;
1602 }
1603 obj.m_pos.setLength(sz);
1604 long endPos = obj.m_pos.end();
1605 ascii().addPos(endPos);
1606 ascii().addNote("_");
1607
1608 auto fSz = static_cast<int>(input->readULong(2));
1609 if (fSz < 0 || fSz+6 > sz) {
1610 MWAW_DEBUG_MSG(("MsWrdParser::readObject: pb reading the name\n"));
1611 f << "#";
1612 ascii().addPos(beginPos);
1613 ascii().addNote(f.str().c_str());
1614 return false;
1615 }
1616 MsWrdEntry fileEntry = obj.getEntry();
1617 fileEntry.setParsed(true);
1618 m_entryMap.insert
1619 (std::multimap<std::string, MsWrdEntry>::value_type(fileEntry.type(), fileEntry));
1620
1621 long zoneEnd = pos+6+fSz;
1622 std::string name(""); // first equation, second "" or Equation Word?
1623 while (long(input->tell()) != zoneEnd) {
1624 auto c = static_cast<int>(input->readULong(1));
1625 if (c == 0) {
1626 if (name.length()) f << name << ",";
1627 name = "";
1628 continue;
1629 }
1630 name += char(c);
1631 }
1632 if (name.length()) f << name << ",";
1633
1634 pos = input->tell();
1635 // Equation Word? : often contains not other data
1636 if (pos==endPos) {
1637 ascii().addPos(beginPos);
1638 ascii().addNote(f.str().c_str());
1639 return true;
1640 }
1641
1642 // 0 or a small size c for annotation an equivalent of file type?
1643 fSz = static_cast<int>(input->readULong(1));
1644 if (pos+fSz+1 > endPos) {
1645 MWAW_DEBUG_MSG(("MsWrdParser::readObject: pb reading the second field zone\n"));
1646 f << "#fSz=" << fSz;
1647 ascii().addPos(beginPos);
1648 ascii().addNote(f.str().c_str());
1649 return false;
1650 }
1651 int val;
1652 bool isAnnotation=false;
1653 if (fSz==12) { // possible annotation
1654 f << "type=[";
1655 for (int i = 0; i < 4; i++) { // f0=f1=f2=0, f3=0x100
1656 val = static_cast<int>(input->readLong(2));
1657 if (val) f << "g0=" << std::hex << val << std::dec << ",";
1658 }
1659 std::string type("");
1660 for (int i = 0; i < 4; i++)
1661 type += char(input->readULong(1));
1662 f << type << "],";
1663 isAnnotation=type=="ANOT";
1664 }
1665 else if (fSz) {
1666 f << "##data2[sz]=" << fSz << ",";
1667 ascii().addDelimiter(input->tell(),'|');
1668 input->seek(pos+fSz+1, librevenge::RVNG_SEEK_SET);
1669 ascii().addDelimiter(input->tell(),'|');
1670 }
1671 pos = input->tell();
1672 if (pos+2>endPos) {
1673 if (pos!= endPos)
1674 f << "###";
1675 ascii().addPos(beginPos);
1676 ascii().addNote(f.str().c_str());
1677 return true;
1678 }
1679 val = static_cast<int>(input->readLong(2));
1680 if (val) f << "#f0=" << val << ",";
1681
1682 pos = input->tell();
1683 if (pos+4>endPos) {
1684 if (pos!= endPos)
1685 f << "##";
1686 ascii().addPos(beginPos);
1687 ascii().addNote(f.str().c_str());
1688 return true;
1689 }
1690 auto dataSz = long(input->readULong(4));
1691 pos = input->tell();
1692 if (pos+dataSz > endPos) {
1693 MWAW_DEBUG_MSG(("MsWrdParser::readObject: pb reading the last field size zone\n"));
1694 f << "#fSz[last]=" << dataSz;
1695 ascii().addPos(beginPos);
1696 ascii().addNote(f.str().c_str());
1697 return false;
1698 }
1699 if (isAnnotation && dataSz>9) {
1700 f << "annot=[";
1701 for (int i = 0; i < 3; i++) { // h0=1|2, h1,h2: big numbers
1702 val = static_cast<int>(input->readULong(2));
1703 if (val)
1704 f << "h" << i << "=" << std::hex << val << std::dec << ",";
1705 }
1706 fSz = static_cast<int>(input->readULong(1));
1707 bool ok=true;
1708 if (fSz+7 > dataSz) {
1709 MWAW_DEBUG_MSG(("MsWrdParser::readObject: can not read the annotation string\n"));
1710 f << "###";
1711 ok = false;
1712 }
1713 else {
1714 std::string annotation("");
1715 for (int i = 0; i < fSz; i++)
1716 annotation += char(input->readULong(1));
1717 if (!annotation.empty())
1718 f << "annot[inText]=" << annotation << ",";
1719 }
1720
1721 if (ok) {
1722 val = static_cast<int>(input->readULong(1)); // always 0
1723 if (val)
1724 f << "h3=" << std::hex << val << std::dec << ",";
1725 fSz = static_cast<int>(input->readULong(1));
1726 }
1727 if (!ok) {
1728 }
1729 else if (fSz+9 > dataSz) {
1730 MWAW_DEBUG_MSG(("MsWrdParser::readObject: can not read the annotation comment\n"));
1731 f << "###";
1732 }
1733 else {
1734 // store the comment
1735 obj.m_annotation.setBegin(input->tell());
1736 obj.m_annotation.setLength(fSz);
1737 std::string annotation("");
1738 for (int i = 0; i < fSz; i++)
1739 annotation += char(input->readULong(1));
1740 if (!annotation.empty())
1741 f << "annot[comment]=" << annotation << ",";
1742 }
1743 }
1744 else if (dataSz)
1745 ascii().addDelimiter(pos, '|');
1746 input->seek(pos+dataSz, librevenge::RVNG_SEEK_SET);
1747
1748 pos = input->tell();
1749 ascii().addPos(beginPos);
1750 ascii().addNote(f.str().c_str());
1751 if (pos != endPos)
1752 ascii().addDelimiter(pos, '#');
1753
1754 return true;
1755 }
1756
1757 ////////////////////////////////////////////////////////////
1758 // check if a zone is a picture/read a picture
1759 ////////////////////////////////////////////////////////////
checkPicturePos(long pos,int type)1760 bool MsWrdParser::checkPicturePos(long pos, int type)
1761 {
1762 MWAWInputStreamPtr input = getInput();
1763 if (pos < 0x100 || !input->checkPosition(pos))
1764 return false;
1765
1766 input->seek(pos, librevenge::RVNG_SEEK_SET);
1767 auto sz = long(input->readULong(4));
1768 long endPos = pos+sz;
1769 if (sz < 14 || !input->checkPosition(sz+pos)) return false;
1770 auto num = static_cast<int>(input->readLong(1));
1771 if (num < 0 || num > 4) return false;
1772 input->seek(pos+14, librevenge::RVNG_SEEK_SET);
1773 for (int n = 0; n < num; n++) {
1774 long actPos = input->tell();
1775 auto pSz = long(input->readULong(4));
1776 if (pSz+actPos > endPos) return false;
1777 input->seek(pSz+actPos, librevenge::RVNG_SEEK_SET);
1778 }
1779 if (input->tell() != endPos)
1780 return false;
1781
1782 static int id = 0;
1783 MsWrdEntry entry;
1784 entry.setBegin(pos);
1785 entry.setEnd(endPos);
1786 entry.setType("Picture");
1787 entry.setPictType(type);
1788 entry.setId(id++);
1789 m_entryMap.insert
1790 (std::multimap<std::string, MsWrdEntry>::value_type(entry.type(), entry));
1791
1792 return true;
1793 }
1794
readPicture(MsWrdEntry & entry)1795 bool MsWrdParser::readPicture(MsWrdEntry &entry)
1796 {
1797 if (m_state->m_picturesMap.find(entry.begin())!=m_state->m_picturesMap.end())
1798 return true;
1799 if (entry.length() < 30 && entry.length() != 14) {
1800 MWAW_DEBUG_MSG(("MsWrdParser::readPicture: the zone seems too short\n"));
1801 return false;
1802 }
1803 MWAWInputStreamPtr input = getInput();
1804 long pos = entry.begin();
1805 entry.setParsed(true);
1806 input->seek(pos, librevenge::RVNG_SEEK_SET);
1807 libmwaw::DebugStream f;
1808 f << "Entries(Picture)[" << entry.pictType() << "-" << entry.id() << "]:";
1809 auto sz = long(input->readULong(4));
1810 if (sz > entry.length()) {
1811 MWAW_DEBUG_MSG(("MsWrdParser::readPicture: the zone size seems too big\n"));
1812 return false;
1813 }
1814 auto N = static_cast<int>(input->readULong(1));
1815 f << "N=" << N << ",";
1816 MsWrdParserInternal::Picture pict;
1817 pict.m_flag = static_cast<int>(input->readULong(1)); // find 0 or 0x80
1818 int dim[4];
1819 for (auto &d : dim) d = static_cast<int>(input->readLong(2));
1820 pict.m_dim=MWAWBox2i(MWAWVec2i(dim[1],dim[0]), MWAWVec2i(dim[3],dim[2]));
1821 f << pict;
1822 ascii().addPos(pos);
1823 ascii().addNote(f.str().c_str());
1824
1825 for (int n=0; n < N; n++) {
1826 MsWrdParserInternal::Picture::Zone zone;
1827 pos = input->tell();
1828 f.str("");
1829 f << "Picture-" << n << "[" << entry.pictType() << "-" << entry.id() << "]:";
1830 sz = long(input->readULong(4));
1831 if (sz < 16 || sz+pos > entry.end()) {
1832 MWAW_DEBUG_MSG(("MsWrdParser::readPicture: pb with the picture size\n"));
1833 f << "#";
1834 ascii().addPos(pos);
1835 ascii().addNote(f.str().c_str());
1836 return false;
1837 }
1838 for (int i = 0; i < 3; ++i) zone.m_flags[i] = static_cast<int>(input->readULong((i==2) ? 2 : 1));
1839 for (auto &d : dim) d = static_cast<int>(input->readLong(2));
1840 zone.m_dim=MWAWBox2i(MWAWVec2i(dim[1],dim[0]), MWAWVec2i(dim[3],dim[2]));
1841 zone.m_pos.setBegin(pos+16);
1842 zone.m_pos.setLength(sz-16);
1843 f << zone;
1844 ascii().addPos(pos);
1845 ascii().addNote(f.str().c_str());
1846 if (sz <= 16)
1847 continue;
1848 pict.m_picturesList.push_back(zone);
1849 #ifdef DEBUG_WITH_FILES
1850 ascii().skipZone(pos+16, pos+sz-1);
1851 librevenge::RVNGBinaryData file;
1852 input->seek(pos+16, librevenge::RVNG_SEEK_SET);
1853 input->readDataBlock(sz-16, file);
1854 static int volatile pictName = 0;
1855 libmwaw::DebugStream f2;
1856 f2 << "PICT-" << ++pictName << ".pct";
1857 libmwaw::Debug::dumpFile(file, f2.str().c_str());
1858 #endif
1859
1860 input->seek(pos+sz, librevenge::RVNG_SEEK_SET);
1861 }
1862 m_state->m_picturesMap[entry.begin()]=pict;
1863 pos = input->tell();
1864 if (pos != entry.end())
1865 ascii().addDelimiter(pos, '|');
1866 ascii().addPos(entry.end());
1867 ascii().addNote("_");
1868 return true;
1869 }
1870
sendPicture(long fPos,int cPos,MWAWPosition::AnchorTo anchor)1871 void MsWrdParser::sendPicture(long fPos, int cPos, MWAWPosition::AnchorTo anchor)
1872 {
1873 if (!getTextListener()) {
1874 MWAW_DEBUG_MSG(("MsWrdParser::sendPicture: listener is not set\n"));
1875 return;
1876 }
1877 if ((anchor == MWAWPosition::Char || anchor == MWAWPosition::CharBaseLine) &&
1878 m_state->m_posToCommentMap.find(long(cPos-1))!=m_state->m_posToCommentMap.end()) {
1879 MWAWInputStreamPtr input = getInput();
1880 std::shared_ptr<MWAWSubDocument> subdoc=std::make_shared<MsWrdParserInternal::SubDocument>(*this, input, m_state->m_posToCommentMap.find(long(cPos-1))->second, libmwaw::DOC_COMMENT_ANNOTATION);
1881 getTextListener()->insertComment(subdoc);
1882 return;
1883 }
1884 if (m_state->m_picturesMap.find(fPos)==m_state->m_picturesMap.end()) {
1885 MWAW_DEBUG_MSG(("MsWrdParser::sendPicture: can not find picture for pos %lx\n", static_cast<long unsigned int>(fPos)));
1886 return;
1887 }
1888 auto const &pict= m_state->m_picturesMap.find(fPos)->second;
1889 MWAWInputStreamPtr input = getInput();
1890 if (pict.m_picturesList.size()!=1 &&
1891 (anchor == MWAWPosition::Char || anchor == MWAWPosition::CharBaseLine)) {
1892 std::shared_ptr<MsWrdParserInternal::SubDocument> subdoc
1893 (new MsWrdParserInternal::SubDocument(*this, input, fPos, cPos));
1894 MWAWPosition pictPos(MWAWVec2f(pict.m_dim.min()), MWAWVec2f(pict.m_dim.size()), librevenge::RVNG_POINT);
1895 pictPos.setRelativePosition(MWAWPosition::Char,
1896 MWAWPosition::XLeft, MWAWPosition::YTop);
1897 pictPos.m_wrapping = MWAWPosition::WBackground;
1898 getTextListener()->insertTextBox(pictPos, subdoc);
1899 return;
1900 }
1901 MWAWPosition basicPos(MWAWVec2f(0.,0.), MWAWVec2f(100.,100.), librevenge::RVNG_POINT);
1902 if (anchor != MWAWPosition::Page && anchor != MWAWPosition::Frame) {
1903 basicPos.setRelativePosition(anchor, MWAWPosition::XLeft, MWAWPosition::YCenter);
1904 basicPos.m_wrapping = MWAWPosition::WBackground;
1905 }
1906 else
1907 basicPos.setRelativePosition(anchor);
1908
1909 long actPos = input->tell();
1910 MWAWBox2f naturalBox;
1911 int n=0;
1912 for (auto const &zone : pict.m_picturesList) {
1913 n++;
1914 if (!zone.m_pos.valid()) continue;
1915 MWAWPosition pos(basicPos);
1916 pos.setOrigin(pos.origin()+MWAWVec2f(zone.m_dim.min()));
1917 pos.setSize(MWAWVec2f(zone.m_dim.size()));
1918
1919 input->seek(zone.m_pos.begin(), librevenge::RVNG_SEEK_SET);
1920 MWAWPict::ReadResult res = MWAWPictData::check(input, static_cast<int>(zone.m_pos.length()), naturalBox);
1921 if (res == MWAWPict::MWAW_R_BAD) {
1922 MWAW_DEBUG_MSG(("MsWrdParser::sendPicture: can not find the picture %d\n", int(n-1)));
1923 continue;
1924 }
1925
1926 input->seek(zone.m_pos.begin(), librevenge::RVNG_SEEK_SET);
1927 std::shared_ptr<MWAWPict> thePict(MWAWPictData::get(input, static_cast<int>(zone.m_pos.length())));
1928 if (!thePict) continue;
1929 MWAWEmbeddedObject picture;
1930 if (thePict->getBinary(picture))
1931 getTextListener()->insertPicture(pos, picture);
1932 }
1933 input->seek(actPos, librevenge::RVNG_SEEK_SET);
1934 }
1935
1936 ////////////////////////////////////////////////////////////
1937 // read the print info
1938 ////////////////////////////////////////////////////////////
readPrintInfo(MsWrdEntry & entry)1939 bool MsWrdParser::readPrintInfo(MsWrdEntry &entry)
1940 {
1941 if (entry.length() < 0x78) {
1942 MWAW_DEBUG_MSG(("MsWrdParser::readPrintInfo: the zone seems to short\n"));
1943 return false;
1944 }
1945 MWAWInputStreamPtr input = getInput();
1946 long pos = entry.begin();
1947 entry.setParsed(true);
1948 input->seek(pos, librevenge::RVNG_SEEK_SET);
1949 libmwaw::DebugStream f;
1950 // print info
1951 libmwaw::PrinterInfo info;
1952 if (!info.read(input)) return false;
1953 f << "PrintInfo:"<< info;
1954
1955 MWAWVec2i paperSize = info.paper().size();
1956 MWAWVec2i pageSize = info.page().size();
1957 if (pageSize.x() <= 0 || pageSize.y() <= 0 ||
1958 paperSize.x() <= 0 || paperSize.y() <= 0) return false;
1959
1960 // define margin from print info
1961 MWAWVec2i lTopMargin= -1 * info.paper().pos(0);
1962 MWAWVec2i rBotMargin=info.paper().size() - info.page().size();
1963
1964 // move margin left | top
1965 int decalX = lTopMargin.x() > 14 ? lTopMargin.x()-14 : 0;
1966 int decalY = lTopMargin.y() > 14 ? lTopMargin.y()-14 : 0;
1967 lTopMargin -= MWAWVec2i(decalX, decalY);
1968 rBotMargin += MWAWVec2i(decalX, decalY);
1969
1970 int leftMargin = lTopMargin.x();
1971 int topMargin = lTopMargin.y();
1972
1973 // decrease right | bottom
1974 int rightMarg = rBotMargin.x() -50;
1975 if (rightMarg < 0) {
1976 leftMargin -= (-rightMarg);
1977 if (leftMargin < 0) leftMargin=0;
1978 rightMarg=0;
1979 }
1980 int botMarg = rBotMargin.y() -50;
1981 if (botMarg < 0) {
1982 topMargin -= (-botMarg);
1983 if (topMargin < 0) topMargin=0;
1984 botMarg=0;
1985 }
1986
1987 getPageSpan().setFormOrientation(MWAWPageSpan::PORTRAIT);
1988 getPageSpan().setMarginTop(topMargin/72.0);
1989 getPageSpan().setMarginBottom(botMarg/72.0);
1990 getPageSpan().setMarginLeft(leftMargin/72.0);
1991 getPageSpan().setMarginRight(rightMarg/72.0);
1992 getPageSpan().setFormLength(paperSize.y()/72.);
1993 getPageSpan().setFormWidth(paperSize.x()/72.);
1994
1995 ascii().addPos(pos);
1996 ascii().addNote(f.str().c_str());
1997
1998 if (long(input->tell()) != entry.end())
1999 ascii().addDelimiter(input->tell(), '|');
2000
2001 ascii().addPos(entry.end());
2002 ascii().addNote("_");
2003
2004 return true;
2005 }
2006
2007 // vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab:
2008