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 <sstream>
39
40 #include <librevenge/librevenge.h>
41
42 #include "MWAWTextListener.hxx"
43 #include "MWAWDebug.hxx"
44 #include "MWAWFont.hxx"
45 #include "MWAWFontConverter.hxx"
46 #include "MWAWPageSpan.hxx"
47 #include "MWAWParagraph.hxx"
48 #include "MWAWPosition.hxx"
49 #include "MWAWRSRCParser.hxx"
50 #include "MWAWSection.hxx"
51 #include "MWAWSubDocument.hxx"
52
53 #include "NisusWrtParser.hxx"
54 #include "NisusWrtStruct.hxx"
55
56 #include "NisusWrtText.hxx"
57
58 /** Internal: the structures of a NisusWrtText */
59 namespace NisusWrtTextInternal
60 {
61 /** Internal: the fonts and many other data*/
62 struct Font {
63 //! the constructor
FontNisusWrtTextInternal::Font64 Font()
65 : m_font(-1,-1)
66 , m_pictureId(0)
67 , m_pictureWidth(0)
68 , m_markId(-1)
69 , m_variableId(0)
70 , m_format(0)
71 , m_format2(0)
72 , m_extra("")
73 {
74 }
isVariableNisusWrtTextInternal::Font75 bool isVariable() const
76 {
77 return (m_format2&0x20)==0x20;
78 }
79
80 //! operator<<
81 friend std::ostream &operator<<(std::ostream &o, Font const &font);
82
83 //! the font
84 MWAWFont m_font;
85 //! the picture id ( if this is for a picture )
86 int m_pictureId;
87 //! the picture width
88 int m_pictureWidth;
89 //! a mark id
90 int m_markId;
91 //! the variable id : in fact cst[unkn] + v_id
92 int m_variableId;
93 //! the main format ...
94 int m_format;
95 //! a series of flags
96 int m_format2;
97 //! two picture dim ( orig && file ?)
98 MWAWBox2i m_pictureDim[2];
99 //! extra data
100 std::string m_extra;
101 };
102
103
operator <<(std::ostream & o,Font const & font)104 std::ostream &operator<<(std::ostream &o, Font const &font)
105 {
106 if (font.m_pictureId) o << "pictId=" << font.m_pictureId << ",";
107 if (font.m_pictureWidth) o << "pictW=" << font.m_pictureWidth << ",";
108 if (font.m_markId >= 0) o << "markId=" << font.m_markId << ",";
109 if (font.m_variableId > 0) o << "variableId=" << font.m_variableId << ",";
110 if (font.m_format2&0x4) o << "index,";
111 if (font.m_format2&0x8) o << "TOC,";
112 if (font.m_format2&0x10) o << "samePage,";
113 if (font.m_format2&0x20) o << "variable,";
114 if (font.m_format2&0x40) o << "hyphenate,";
115 if (font.m_format2&0x83)
116 o << "#format2=" << std::hex << (font.m_format2 &0x83) << std::dec << ",";
117
118 if (font.m_format & 1) o << "noSpell,";
119 if (font.m_format & 0x10) o << "sameLine,";
120 if (font.m_format & 0x40) o << "endOfPage,"; // checkme
121 if (font.m_format & 0xA6)
122 o << "#fl=" << std::hex << (font.m_format & 0xA6) << std::dec << ",";
123 if (font.m_pictureDim[0].size()[0] || font.m_pictureDim[0].size()[1])
124 o << "pictDim=" << font.m_pictureDim[0] << ",";
125 if (font.m_pictureDim[0] != font.m_pictureDim[1] &&
126 (font.m_pictureDim[1].size()[0] || font.m_pictureDim[1].size()[1]))
127 o << "pictDim[crop]=" << font.m_pictureDim[1] << ",";
128 if (font.m_extra.length())
129 o << font.m_extra << ",";
130 return o;
131 }
132
133 /** Internal: class to store the paragraph properties */
134 struct Paragraph final : public MWAWParagraph {
135 //! Constructor
ParagraphNisusWrtTextInternal::Paragraph136 Paragraph()
137 : MWAWParagraph()
138 , m_name("")
139 {
140 }
141 Paragraph(Paragraph const &) = default;
142 //! destructor
143 ~Paragraph() final;
144 //! operator<<
operator <<(std::ostream & o,Paragraph const & ind)145 friend std::ostream &operator<<(std::ostream &o, Paragraph const &ind)
146 {
147 o << static_cast<MWAWParagraph const &>(ind);
148 if (ind.m_name.length()) o << "name=" << ind.m_name << ",";
149 return o;
150 }
151 //! the paragraph name
152 std::string m_name;
153 };
154
~Paragraph()155 Paragraph::~Paragraph()
156 {
157 }
158
159 /** Internal structure: use to store a header */
160 struct HeaderFooter {
161 //! Constructor
HeaderFooterNisusWrtTextInternal::HeaderFooter162 HeaderFooter()
163 : m_type(MWAWHeaderFooter::HEADER)
164 , m_occurrence(MWAWHeaderFooter::NEVER)
165 , m_page(0)
166 , m_textParagraph(-1)
167 , m_unknown(0)
168 , m_parsed(false)
169 , m_extra("")
170 {
171 for (auto &id : m_paragraph) id = -1;
172 }
173 //! operator<<
174 friend std::ostream &operator<<(std::ostream &o, HeaderFooter const &hf);
175 //! the header type
176 MWAWHeaderFooter::Type m_type;
177 //! the header occurrence
178 MWAWHeaderFooter::Occurrence m_occurrence;
179 //! the page
180 int m_page;
181 //! the paragraph position in the header zone (first and last)
182 long m_paragraph[2];
183 //! the text position
184 long m_textParagraph;
185 //! a unknown value
186 int m_unknown;
187 //! a flag to know if the footnote is parsed
188 mutable bool m_parsed;
189 //! some extra debuging information
190 std::string m_extra;
191 };
192
operator <<(std::ostream & o,HeaderFooter const & hf)193 std::ostream &operator<<(std::ostream &o, HeaderFooter const &hf)
194 {
195 if (hf.m_type==MWAWHeaderFooter::HEADER) o << "header,";
196 else o << "footer,";
197 switch (hf.m_occurrence) {
198 case MWAWHeaderFooter::NEVER:
199 o << "never,";
200 break;
201 case MWAWHeaderFooter::ODD:
202 o << "odd,";
203 break;
204 case MWAWHeaderFooter::EVEN:
205 o << "even,";
206 break;
207 case MWAWHeaderFooter::ALL:
208 o << "all,";
209 break;
210 #if !defined(__clang__)
211 default:
212 o << "#occurrence=" << int(hf.m_occurrence) << ",";
213 break;
214 #endif
215 }
216 o << "pos=" << hf.m_paragraph[0] << "<->" << hf.m_paragraph[1] << ",";
217 o << "pos[def]=" << hf.m_textParagraph << ",";
218 if (hf.m_unknown) o << "unkn=" << std::hex << hf.m_unknown << std::dec << ",";
219 o << hf.m_extra;
220 return o;
221 }
222
223 /** Internal structure: use to store a footnote */
224 struct Footnote {
225 //! Constructor
FootnoteNisusWrtTextInternal::Footnote226 Footnote()
227 : m_number(0)
228 , m_textPosition()
229 , m_textLabel("")
230 , m_noteLabel("")
231 , m_parsed(false)
232 , m_extra("")
233 {
234 for (auto &id : m_paragraph) id = -1;
235 }
236
237 //! returns a label corresponding to a note ( or nothing if we can use numbering note)
getTextLabelNisusWrtTextInternal::Footnote238 std::string getTextLabel(int actId) const
239 {
240 if (m_textLabel.length() == 0 || m_textLabel=="1")
241 return std::string("");
242 std::stringstream s;
243 for (char c : m_textLabel) {
244 if (c=='1')
245 s << actId;
246 else
247 s << c;
248 }
249 return s.str();
250 }
251
252 //! operator<<
253 friend std::ostream &operator<<(std::ostream &o, Footnote const &ft);
254 //! the note number
255 int m_number;
256 //! the paragraph position in the footnote zone (first and last)
257 int m_paragraph[2];
258 //! the text position
259 NisusWrtStruct::Position m_textPosition;
260 //! the label in the text
261 std::string m_textLabel;
262 //! the label in the note
263 std::string m_noteLabel;
264 //! a flag to know if the footnote is parsed
265 mutable bool m_parsed;
266 //! some extra debuging information
267 std::string m_extra;
268 };
269
operator <<(std::ostream & o,Footnote const & ft)270 std::ostream &operator<<(std::ostream &o, Footnote const &ft)
271 {
272 o << "pos=" << ft.m_textPosition << ",";
273 if (ft.m_paragraph[1] > ft.m_paragraph[0])
274 o << "paragraph[inNote]=" << ft.m_paragraph[0] << "<->" << ft.m_paragraph[1] << ",";
275 if (ft.m_number) o << "number=" << ft.m_number << ",";
276 if (ft.m_textLabel.length())
277 o << "textLabel=\"" << ft.m_textLabel << "\",";
278 if (ft.m_noteLabel.length())
279 o << "noteLabel=\"" << ft.m_noteLabel << "\",";
280 if (ft.m_extra.length())
281 o << ft.m_extra;
282 return o;
283 }
284
285 //! Internal: the picture data ( PICD )
286 struct PicturePara {
287 //! constructor
PictureParaNisusWrtTextInternal::PicturePara288 PicturePara()
289 : m_id(-1)
290 , m_paragraph(-1)
291 , m_position()
292 {
293 }
294 //! operator<<
295 friend std::ostream &operator<<(std::ostream &o, PicturePara const &pict);
296 //! the picture id
297 int m_id;
298 //! the paragraph position
299 int m_paragraph;
300 //! the position
301 MWAWBox2i m_position;
302 };
303
operator <<(std::ostream & o,PicturePara const & pict)304 std::ostream &operator<<(std::ostream &o, PicturePara const &pict)
305 {
306 if (pict.m_id > 0) o << "pictId=" << pict.m_id << ",";
307 if (pict.m_paragraph >= 0) o << "paragraph=" << pict.m_paragraph << ",";
308 if (pict.m_position.size()[0] || pict.m_position.size()[1])
309 o << "pos=" << pict.m_position << ",";
310 return o;
311 }
312
313 /** different types
314 *
315 * - Format: font properties
316 * - Ruler: new ruler
317 */
318 enum PLCType { P_Format=0, P_Ruler, P_Footnote, P_HeaderFooter, P_PicturePara, P_Unknown};
319
320 /** Internal: class to store the PLC: Pointer List Content ? */
321 struct DataPLC {
DataPLCNisusWrtTextInternal::DataPLC322 DataPLC()
323 : m_type(P_Format)
324 , m_id(-1)
325 , m_extra("")
326 {
327 }
328 //! operator<<
329 friend std::ostream &operator<<(std::ostream &o, DataPLC const &plc);
330 //! PLC type
331 PLCType m_type;
332 //! the id
333 int m_id;
334 //! an extra data to store message ( if needed )
335 std::string m_extra;
336 };
337 //! operator<< for DataPLC
operator <<(std::ostream & o,DataPLC const & plc)338 std::ostream &operator<<(std::ostream &o, DataPLC const &plc)
339 {
340 switch (plc.m_type) {
341 case P_Format:
342 o << "F";
343 break;
344 case P_Ruler:
345 o << "R";
346 break;
347 case P_Footnote:
348 o << "Fn";
349 break;
350 case P_HeaderFooter:
351 o << "HF";
352 break;
353 case P_PicturePara:
354 o << "Pict";
355 break;
356 case P_Unknown:
357 #if !defined(__clang__)
358 default:
359 #endif
360 o << "#type=" << int(plc.m_type) << ",";
361 }
362 if (plc.m_id >= 0) o << plc.m_id << ",";
363 else o << "_";
364 if (plc.m_extra.length()) o << plc.m_extra;
365 return o;
366 }
367
368 //! internal structure used to store zone data
369 struct Zone {
370 typedef std::multimap<NisusWrtStruct::Position,DataPLC,NisusWrtStruct::Position::Compare> PLCMap;
371
372 //! constructor
ZoneNisusWrtTextInternal::Zone373 Zone()
374 : m_entry()
375 , m_paragraphList()
376 , m_pictureParaList()
377 , m_plcMap()
378 {
379 }
380 //! the position of text in the rsrc file
381 MWAWEntry m_entry;
382 //! the list of paragraph
383 std::vector<Paragraph> m_paragraphList;
384 //! the list of paragraph
385 std::vector<PicturePara> m_pictureParaList;
386
387 //! the map pos -> format id
388 PLCMap m_plcMap;
389 };
390
391 ////////////////////////////////////////
392 //! Internal: the state of a NisusWrtText
393 struct State {
394 //! constructor
StateNisusWrtTextInternal::State395 State()
396 : m_version(-1)
397 , m_fontList()
398 , m_footnoteList()
399 , m_numPages(-1)
400 , m_actualPage(0)
401 , m_hfList()
402 , m_headersId()
403 , m_footersId()
404 {
405 }
406
407 //! the file version
408 mutable int m_version;
409
410 /** the font list */
411 std::vector<Font> m_fontList;
412 /** the list of footnote */
413 std::vector<Footnote> m_footnoteList;
414 /** the main zones : Main, Footnote, HeaderFooter */
415 Zone m_zones[3];
416
417 int m_numPages /* the number of pages */, m_actualPage /* the actual page */;
418 /** the list of header footer */
419 std::vector<HeaderFooter> m_hfList;
420 /** the list of header id which corresponds to each page */
421 std::vector<int> m_headersId;
422 /** the list of footer id which corresponds to each page */
423 std::vector<int> m_footersId;
424 };
425
426 ////////////////////////////////////////
427 //! Internal: the subdocument of a NisusWrtText
428 class SubDocument final : public MWAWSubDocument
429 {
430 public:
SubDocument(NisusWrtText & pars,MWAWInputStreamPtr const & input,int id,libmwaw::SubDocumentType type)431 SubDocument(NisusWrtText &pars, MWAWInputStreamPtr const &input, int id, libmwaw::SubDocumentType type)
432 : MWAWSubDocument(pars.m_mainParser, input, MWAWEntry())
433 , m_textParser(&pars)
434 , m_id(id)
435 , m_type(type)
436 {
437 }
438
439 //! destructor
~SubDocument()440 ~SubDocument() final {}
441
442 //! operator!=
443 bool operator!=(MWAWSubDocument const &doc) const final;
444
445 //! the parser function
446 void parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType type) final;
447
448 protected:
449 /** the text parser */
450 NisusWrtText *m_textParser;
451 //! the subdocument id
452 int m_id;
453 //! the subdocument type
454 libmwaw::SubDocumentType m_type;
455 private:
456 SubDocument(SubDocument const &orig) = delete;
457 SubDocument &operator=(SubDocument const &orig) = delete;
458 };
459
parse(MWAWListenerPtr & listener,libmwaw::SubDocumentType)460 void SubDocument::parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType /*type*/)
461 {
462 if (!listener.get()) {
463 MWAW_DEBUG_MSG(("NisusWrtTextInternal::SubDocument::parse: no listener\n"));
464 return;
465 }
466 if (!m_textParser) {
467 MWAW_DEBUG_MSG(("NisusWrtTextInternal::SubDocument::parse: no parser\n"));
468 return;
469 }
470 long pos = m_input->tell();
471 if (m_type == libmwaw::DOC_NOTE)
472 m_textParser->sendFootnote(m_id);
473 else if (m_type == libmwaw::DOC_HEADER_FOOTER)
474 m_textParser->sendHeaderFooter(m_id);
475 else {
476 MWAW_DEBUG_MSG(("NisusWrtTextInternal::SubDocument::parse: oops do not know how to send this kind of document\n"));
477 return;
478 }
479 m_input->seek(pos, librevenge::RVNG_SEEK_SET);
480 }
481
operator !=(MWAWSubDocument const & doc) const482 bool SubDocument::operator!=(MWAWSubDocument const &doc) const
483 {
484 if (MWAWSubDocument::operator!=(doc)) return true;
485 auto const *sDoc = dynamic_cast<SubDocument const *>(&doc);
486 if (!sDoc) return true;
487 if (m_textParser != sDoc->m_textParser) return true;
488 if (m_id != sDoc->m_id) return true;
489 if (m_type != sDoc->m_type) return true;
490 return false;
491 }
492 }
493
494 ////////////////////////////////////////////////////////////
495 // constructor/destructor, ...
496 ////////////////////////////////////////////////////////////
NisusWrtText(NisusWrtParser & parser)497 NisusWrtText::NisusWrtText(NisusWrtParser &parser)
498 : m_parserState(parser.getParserState())
499 , m_state(new NisusWrtTextInternal::State)
500 , m_mainParser(&parser)
501 {
502 }
503
~NisusWrtText()504 NisusWrtText::~NisusWrtText()
505 {
506 }
507
version() const508 int NisusWrtText::version() const
509 {
510 if (m_state->m_version < 0)
511 m_state->m_version = m_parserState->m_version;
512 return m_state->m_version;
513 }
514
numPages() const515 int NisusWrtText::numPages() const
516 {
517 if (m_state->m_numPages >= 0)
518 return m_state->m_numPages;
519 const_cast<NisusWrtText *>(this)->computePositions();
520 return m_state->m_numPages;
521 }
522
getHeader(int page,int & numSimilar)523 std::shared_ptr<MWAWSubDocument> NisusWrtText::getHeader(int page, int &numSimilar)
524 {
525 numSimilar=1;
526 std::shared_ptr<MWAWSubDocument> res;
527 auto numHeaders = int(m_state->m_headersId.size());
528 if (page < 1 || page-1 >= numHeaders) {
529 if (m_state->m_numPages>page)
530 numSimilar=m_state->m_numPages-page+1;
531 return res;
532 }
533 int hId = m_state->m_headersId[size_t(page-1)];
534 if (hId >= 0)
535 res.reset(new NisusWrtTextInternal::SubDocument(*this, m_mainParser->rsrcInput(), hId, libmwaw::DOC_HEADER_FOOTER));
536 while (page < numHeaders && m_state->m_headersId[size_t(page)]==hId) {
537 page++;
538 numSimilar++;
539 }
540 return res;
541 }
542
getFooter(int page,int & numSimilar)543 std::shared_ptr<MWAWSubDocument> NisusWrtText::getFooter(int page, int &numSimilar)
544 {
545 numSimilar=1;
546 std::shared_ptr<MWAWSubDocument> res;
547 auto numFooters = int(m_state->m_footersId.size());
548 if (page < 1 || page-1 >= numFooters) {
549 if (m_state->m_numPages>page)
550 numSimilar=m_state->m_numPages-page+1;
551 return res;
552 }
553 int fId = m_state->m_footersId[size_t(page-1)];
554 if (fId >= 0)
555 res.reset(new NisusWrtTextInternal::SubDocument(*this, m_mainParser->rsrcInput(), fId, libmwaw::DOC_HEADER_FOOTER));
556 while (page < numFooters && m_state->m_footersId[size_t(page)]==fId) {
557 page++;
558 numSimilar++;
559 }
560
561 return res;
562 }
563
computePositions()564 void NisusWrtText::computePositions()
565 {
566 // first compute the number of page and the number of paragraph by pages
567 int nPages = 1;
568 MWAWInputStreamPtr input = m_mainParser->getInput();
569 input->seek(0, librevenge::RVNG_SEEK_SET);
570 int paragraph=0;
571 std::vector<int> firstParagraphInPage;
572 firstParagraphInPage.push_back(0);
573 while (!input->isEnd()) {
574 auto c = char(input->readULong(1));
575 if (c==0xd)
576 paragraph++;
577 else if (c==0xc) {
578 nPages++;
579 firstParagraphInPage.push_back(paragraph);
580 }
581 }
582 m_state->m_actualPage = 1;
583 m_state->m_numPages = nPages;
584
585 // update the main page zone
586 m_state->m_zones[NisusWrtStruct::Z_Main].m_entry.setBegin(0);
587 m_state->m_zones[NisusWrtStruct::Z_Main].m_entry.setEnd(input->tell());
588 m_state->m_zones[NisusWrtStruct::Z_Main].m_entry.setId(NisusWrtStruct::Z_Main);
589 // compute the header/footer pages
590 int actPage = 1;
591 MWAWVec2i headerId(-1,-1), footerId(-1,-1);
592 m_state->m_headersId.resize(size_t(nPages), -1);
593 m_state->m_footersId.resize(size_t(nPages), -1);
594 for (size_t i = 0; i < m_state->m_hfList.size(); i++) {
595 auto &hf = m_state->m_hfList[i];
596 int page = 1;
597 long textPos = hf.m_textParagraph;
598 if (hf.m_type == MWAWHeaderFooter::FOOTER && textPos) textPos--;
599 for (size_t j = 0; j < firstParagraphInPage.size(); j++) {
600 if (textPos < firstParagraphInPage[j])
601 break;
602 page = int(j)+1;
603 }
604 //std::cerr << "find : page=" << page << " for hf" << int(i) << "\n";
605 for (int p = actPage; p < page; p++) {
606 m_state->m_headersId[size_t(p)-1] = (p%2) ? headerId[0] : headerId[1];
607 m_state->m_footersId[size_t(p)-1] = (p%2) ? footerId[0] : footerId[1];
608 }
609 actPage = hf.m_page = page;
610 MWAWVec2i &wh = hf.m_type == MWAWHeaderFooter::HEADER ? headerId : footerId;
611 switch (hf.m_occurrence) {
612 case MWAWHeaderFooter::ODD:
613 wh[0] = int(i);
614 break;
615 case MWAWHeaderFooter::EVEN:
616 wh[1] = int(i);
617 break;
618 case MWAWHeaderFooter::ALL:
619 wh[0] = wh[1] = int(i);
620 break;
621 case MWAWHeaderFooter::NEVER:
622 wh[0] = wh[1] = -1;
623 break;
624 #if !defined(__clang__)
625 default:
626 break;
627 #endif
628 }
629 }
630 for (int p = actPage; p <= nPages; p++) {
631 m_state->m_headersId[size_t(p)-1] = (p%2) ? headerId[0] : headerId[1];
632 m_state->m_footersId[size_t(p)-1] = (p%2) ? footerId[0] : footerId[1];
633 }
634 }
635
636 ////////////////////////////////////////////////////////////
637 // Intermediate level
638 ////////////////////////////////////////////////////////////
639
640 // find the different zones
createZones()641 bool NisusWrtText::createZones()
642 {
643 if (!m_mainParser->getRSRCParser()) {
644 MWAW_DEBUG_MSG(("NisusWrtText::createZones: can not find the entry map\n"));
645 return false;
646 }
647 auto &entryMap = m_mainParser->getRSRCParser()->getEntriesMap();
648
649 // footnote and headerFooter main zone
650 auto it = entryMap.lower_bound("HF ");
651 while (it != entryMap.end()) {
652 if (it->first != "HF ")
653 break;
654 MWAWEntry &entry = it++->second;
655 readHeaderFooter(entry);
656 }
657 it = entryMap.lower_bound("FOOT");
658 while (it != entryMap.end()) {
659 if (it->first != "FOOT")
660 break;
661 MWAWEntry &entry = it++->second;
662 readFootnotes(entry);
663 }
664
665 // fonts
666 it = entryMap.lower_bound("FLST");
667 while (it != entryMap.end()) {
668 if (it->first != "FLST")
669 break;
670 MWAWEntry &entry = it++->second;
671 readFontsList(entry);
672 }
673 it = entryMap.lower_bound("STYL");
674 while (it != entryMap.end()) {
675 if (it->first != "STYL")
676 break;
677 MWAWEntry &entry = it++->second;
678 readFonts(entry);
679 }
680 it = entryMap.lower_bound("FTAB");
681 while (it != entryMap.end()) {
682 if (it->first != "FTAB")
683 break;
684 MWAWEntry &entry = it++->second;
685 readFonts(entry);
686 }
687
688 // the font change
689 char const *posFontNames[] = { "FRMT", "FFRM", "HFRM" };
690 for (int z = 0; z < 3; z++) {
691 it = entryMap.lower_bound(posFontNames[z]);
692 while (it != entryMap.end()) {
693 if (it->first != posFontNames[z])
694 break;
695 MWAWEntry &entry = it++->second;
696 readPosToFont(entry, NisusWrtStruct::ZoneType(z));
697 }
698 }
699
700 // the paragraph: in mainZone 1004 means style paragraph
701 char const *paragNames[] = { "RULE", "FRUL", "HRUL" };
702 for (int z = 0; z < 3; z++) {
703 it = entryMap.lower_bound(paragNames[z]);
704 while (it != entryMap.end()) {
705 if (it->first != paragNames[z])
706 break;
707 MWAWEntry &entry = it++->second;
708 readParagraphs(entry, NisusWrtStruct::ZoneType(z));
709 }
710 }
711 // the picture associated to the paragraph
712 char const *pictDNames[] = { "PICD", "FPIC", "HPIC" };
713 for (int z = 0; z < 3; z++) {
714 it = entryMap.lower_bound(pictDNames[z]);
715 while (it != entryMap.end()) {
716 if (it->first != pictDNames[z])
717 break;
718 MWAWEntry &entry = it++->second;
719 readPICD(entry, NisusWrtStruct::ZoneType(z));
720 }
721 }
722
723 // End of the style zone
724
725 // style name ( can also contains some flags... )
726 it = entryMap.lower_bound("STNM");
727 while (it != entryMap.end()) {
728 if (it->first != "STNM")
729 break;
730 MWAWEntry &entry = it++->second;
731 std::vector<std::string> list;
732 m_mainParser->readStringsList(entry, list, false);
733 }
734 // style link to paragraph name
735 it = entryMap.lower_bound("STRL");
736 while (it != entryMap.end()) {
737 if (it->first != "STRL")
738 break;
739 MWAWEntry &entry = it++->second;
740 std::vector<std::string> list;
741 m_mainParser->readStringsList(entry, list, false);
742 }
743 // style next name
744 it = entryMap.lower_bound("STNX");
745 while (it != entryMap.end()) {
746 if (it->first != "STNX")
747 break;
748 MWAWEntry &entry = it++->second;
749 std::vector<std::string> list;
750 m_mainParser->readStringsList(entry, list, false);
751 }
752
753 // the text zone
754 char const *textNames[] = { "", "FNTX", "HFTX" };
755 for (int z = 1; z < 3; z++) {
756 it = entryMap.lower_bound(textNames[z]);
757 while (it != entryMap.end()) {
758 if (it->first != textNames[z])
759 break;
760 m_state->m_zones[z].m_entry = it++->second;
761 m_state->m_zones[z].m_entry.setId(z);
762 }
763 }
764 // now update the different data
765 computePositions();
766 return true;
767 }
768
769 ////////////////////////////////////////////////////////////
770 // Fonts
771 ////////////////////////////////////////////////////////////
772
773 // read a list of fonts
readFontsList(MWAWEntry const & entry)774 bool NisusWrtText::readFontsList(MWAWEntry const &entry)
775 {
776 if (!entry.valid() && entry.length()!=0) {
777 MWAW_DEBUG_MSG(("NisusWrtText::readFontsList: the entry is bad\n"));
778 return false;
779 }
780 entry.setParsed(true);
781 MWAWInputStreamPtr input = m_mainParser->rsrcInput();
782 if (!input || !input->checkPosition(entry.end())) {
783 MWAW_DEBUG_MSG(("NisusWrtText::readFontsList: the zone is too short\n"));
784 return false;
785 }
786 libmwaw::DebugFile &asciiFile = m_mainParser->rsrcAscii();
787 long pos = entry.begin();
788 input->seek(pos, librevenge::RVNG_SEEK_SET);
789
790 libmwaw::DebugStream f;
791 f << "Entries(FontNames)[" << entry.id() << "]:";
792 asciiFile.addPos(pos-4);
793 asciiFile.addNote(f.str().c_str());
794
795 int num=0;
796 while (!input->isEnd()) {
797 pos = input->tell();
798 if (pos == entry.end()) break;
799 if (pos+4 > entry.end()) {
800 asciiFile.addPos(pos);
801 asciiFile.addNote("FontNames###");
802
803 MWAW_DEBUG_MSG(("NisusWrtText::readFontsList: can not read flst\n"));
804 return false;
805 }
806 auto fId = static_cast<int>(input->readULong(2));
807 f.str("");
808 f << "FontNames" << num++ << ":fId=" << std::hex << fId << std::dec << ",";
809 auto pSz = static_cast<int>(input->readULong(1));
810
811 if (pSz+1+pos+2 > entry.end()) {
812 f << "###";
813 asciiFile.addPos(pos);
814 asciiFile.addNote(f.str().c_str());
815
816 MWAW_DEBUG_MSG(("NisusWrtText::readFontsList: can not read pSize\n"));
817 return false;
818 }
819 std::string name("");
820 for (int c=0; c < pSz; c++)
821 name += char(input->readULong(1));
822 m_parserState->m_fontConverter->setCorrespondance(fId, name);
823 f << name;
824 asciiFile.addPos(pos);
825 asciiFile.addNote(f.str().c_str());
826 if ((pSz%2)==0) input->seek(1,librevenge::RVNG_SEEK_CUR);
827 }
828 return true;
829 }
830
831 // read the FTAB/STYL resource: a font format ?
readFonts(MWAWEntry const & entry)832 bool NisusWrtText::readFonts(MWAWEntry const &entry)
833 {
834 bool isStyle = entry.type()=="STYL";
835 int const fSize = isStyle ? 58 : 98;
836 std::string name(isStyle ? "Style" : "Fonts");
837 if ((!entry.valid()&&entry.length()) || (entry.length()%fSize)) {
838 MWAW_DEBUG_MSG(("NisusWrtText::readFonts: the entry is bad\n"));
839 return false;
840 }
841 entry.setParsed(true);
842 MWAWInputStreamPtr input = m_mainParser->rsrcInput();
843 libmwaw::DebugFile &asciiFile = m_mainParser->rsrcAscii();
844 long pos = entry.begin();
845 input->seek(pos, librevenge::RVNG_SEEK_SET);
846
847 auto numElt = int(entry.length()/fSize);
848 libmwaw::DebugStream f;
849 f << "Entries(" << name << ")[" << entry.id() << "]:N=" << numElt;
850 asciiFile.addPos(pos-4);
851 asciiFile.addNote(f.str().c_str());
852
853 long val;
854 for (int i = 0; i < numElt; i++) {
855 NisusWrtTextInternal::Font font;
856 pos = input->tell();
857 f.str("");
858 if (!isStyle)
859 font.m_pictureId = static_cast<int>(input->readLong(2));
860
861 if (font.m_pictureId) {
862 // the two value seems to differ slightly for a picture
863 val = long(input->readULong(2));
864 if (val != 0xFF01) f << "#pictFlags0=" << std::hex << val << ",";
865 font.m_pictureWidth = static_cast<int>(input->readLong(2));
866 }
867 else {
868 val = long(input->readULong(2));
869 if (val != 0xFF00)
870 font.m_font.setId(int(val));
871 val = long(input->readULong(2));
872 if (val != 0xFF00)
873 font.m_font.setSize(float(val));
874 }
875
876 uint32_t flags=0;
877 auto flag = static_cast<int>(input->readULong(2));
878
879 if (flag&0x1) flags |= MWAWFont::boldBit;
880 if (flag&0x2) flags |= MWAWFont::italicBit;
881 if (flag&0x4) font.m_font.setUnderlineStyle(MWAWFont::Line::Simple);
882 if (flag&0x8) flags |= MWAWFont::embossBit;
883 if (flag&0x10) flags |= MWAWFont::shadowBit;
884 if (flag&0x20) font.m_font.setDeltaLetterSpacing(-1);
885 if (flag&0x40) font.m_font.setDeltaLetterSpacing(1);
886 if (flag &0xFF80)
887 f << "#flags0=" << std::hex << (flag &0xFF80) << std::dec << ",";
888 flag = static_cast<int>(input->readULong(2));
889 if (flag & 1) {
890 font.m_font.setUnderlineStyle(MWAWFont::Line::Simple);
891 f << "underline[lower],";
892 }
893 if (flag & 2) font.m_font.setUnderlineStyle(MWAWFont::Line::Dot);
894 if (flag & 4) font.m_font.setUnderlineWordFlag(true);
895 if (flag & 0x8) font.m_font.set(MWAWFont::Script::super());
896 if (flag & 0x10) font.m_font.set(MWAWFont::Script::sub());
897 if (flag & 0x20) font.m_font.setStrikeOutStyle(MWAWFont::Line::Simple);
898 if (flag & 0x40) font.m_font.setOverlineStyle(MWAWFont::Line::Simple);
899 if (flag & 0x80) flags |= MWAWFont::smallCapsBit;
900 if (flag & 0x100) flags |= MWAWFont::uppercaseBit;
901 if (flag & 0x200) flags |= MWAWFont::boxedBit;
902 if (flag & 0x400) flags |= MWAWFont::hiddenBit;
903 if (flag & 0x1000) font.m_font.set(MWAWFont::Script(40,librevenge::RVNG_PERCENT,58));
904 if (flag & 0x2000) font.m_font.set(MWAWFont::Script(-40,librevenge::RVNG_PERCENT,58));
905 if (flag & 0x4000) flags |= MWAWFont::reverseVideoBit;
906 if (flag & 0x8800)
907 f << "#flags1=" << std::hex << (flag & 0x8800) << std::dec << ",";
908 val = input->readLong(2);
909 if (val) f << "#f0=" << std::hex << val << ",";
910 font.m_format = static_cast<int>(input->readULong(1));
911 if (font.m_format & 8) {
912 font.m_format &= 0xF7;
913 flags |= MWAWFont::reverseWritingBit;
914 }
915 font.m_format2 = static_cast<int>(input->readULong(1));
916 font.m_font.setFlags(flags);
917
918 int color = 0;
919 // now data differs
920 if (isStyle) {
921 val = static_cast<int>(input->readULong(2)); // find [0-3] here
922 if (val) f << "unkn0=" << val << ",";
923 for (int j = 0; j < 6; j++) { // find s0=67, s1=a728
924 val = static_cast<int>(input->readULong(2));
925 if (val) f << "f" << j << "=" << std::hex << val << std::dec << ",";
926 }
927 color = static_cast<int>(input->readULong(2));
928 }
929 else {
930 color = static_cast<int>(input->readULong(2));
931 for (int j = 1; j < 6; j++) { // find always 0 here...
932 val = static_cast<int>(input->readULong(2));
933 if (val) f << "#f" << j << "=" << val << ",";
934 }
935 bool hasMark = false;
936 val = static_cast<int>(input->readULong(2));
937 if (val == 1) hasMark = true;
938 else if (val) f << "#hasMark=" << val << ",";
939 val = static_cast<int>(input->readULong(2));
940 if (hasMark) font.m_markId = int(val);
941 else if (val) f << "#markId=" << val << ",";
942 // f0=0|1 and if f0=1 then f1 is a small number between 1 and 20
943 for (int j = 0; j < 18; j++) {
944 val = static_cast<int>(input->readULong(2));
945 if (val) f << "g" << j << "=" << val << ",";
946 }
947 float expand=float(input->readLong(4))/65536.f;
948 if (expand < 0 || expand > 0)
949 font.m_font.setDeltaLetterSpacing(expand);
950 // 0, -1 or a small number related to the variable id : probably unknowncst+vId
951 font.m_variableId = static_cast<int>(input->readLong(4));
952 // the remaining seems to be 0 excepted for picture
953 for (int j = 0; j < 4; j++) { // find 0,0,[0|d5|f5|f8|ba], big number
954 val = static_cast<int>(input->readULong(2));
955 if (val) f << "h" << j << "=" << std::hex << val << std::dec << ",";
956 }
957 // two dim ?
958 for (auto &pictDim : font.m_pictureDim) {
959 int dim[4];
960 for (auto &d : dim) d = static_cast<int>(input->readLong(2));
961 pictDim=MWAWBox2i(MWAWVec2i(dim[1],dim[0]),MWAWVec2i(dim[3],dim[2]));
962 }
963 }
964
965 static const uint32_t colors[] =
966 { 0, 0xFF0000, 0x00FF00, 0x0000FF, 0x00FFFF, 0xFF00FF, 0xFFFF00, 0xFFFFFF };
967 if (color >= 0 && color < 8)
968 font.m_font.setColor(MWAWColor(colors[color]));
969 else if (color != 0xFF00)
970 f << "#color=" << color << ",";
971 font.m_extra = f.str();
972 if (!isStyle)
973 m_state->m_fontList.push_back(font);
974
975 f.str("");
976 f << name << i << ":" << font.m_font.getDebugString(m_parserState->m_fontConverter)
977 << font;
978 if (input->tell() != pos+fSize)
979 asciiFile.addDelimiter(input->tell(),'|');
980 asciiFile.addPos(pos);
981 asciiFile.addNote(f.str().c_str());
982 input->seek(pos+fSize, librevenge::RVNG_SEEK_SET);
983 }
984 return true;
985 }
986
987 // read the FRMT resource: filepos -> fonts
readPosToFont(MWAWEntry const & entry,NisusWrtStruct::ZoneType zoneId)988 bool NisusWrtText::readPosToFont(MWAWEntry const &entry, NisusWrtStruct::ZoneType zoneId)
989 {
990 if (!entry.valid() || (entry.length()%10)) {
991 MWAW_DEBUG_MSG(("NisusWrtText::readPosToFont: the entry is bad\n"));
992 return false;
993 }
994 if (zoneId >= 3) {
995 MWAW_DEBUG_MSG(("NisusWrtText::readPosToFont: find unexpected zoneId: %d\n", zoneId));
996 return false;
997 }
998 NisusWrtTextInternal::Zone &zone = m_state->m_zones[zoneId];
999 entry.setParsed(true);
1000 MWAWInputStreamPtr input = m_mainParser->rsrcInput();
1001 libmwaw::DebugFile &asciiFile = m_mainParser->rsrcAscii();
1002 long pos = entry.begin();
1003 input->seek(pos, librevenge::RVNG_SEEK_SET);
1004
1005 auto numElt = int(entry.length()/10);
1006 libmwaw::DebugStream f;
1007 f << "Entries(PosToFont)[" << zoneId << "]:N=" << numElt;
1008 asciiFile.addPos(pos-4);
1009 asciiFile.addNote(f.str().c_str());
1010
1011 NisusWrtStruct::Position position;
1012 NisusWrtTextInternal::DataPLC plc;
1013 plc.m_type = NisusWrtTextInternal::P_Format;
1014 for (int i = 0; i < numElt; i++) {
1015 pos = input->tell();
1016 f.str("");
1017 f << "PosToFont" << i << "[" << zoneId << "]:";
1018 position.m_paragraph = static_cast<int>(input->readULong(4)); // checkme or ??? m_paragraph
1019 position.m_word = static_cast<int>(input->readULong(2));
1020 position.m_char = static_cast<int>(input->readULong(2));
1021 f << "pos=" << position << ",";
1022 auto id = static_cast<int>(input->readLong(2));
1023 f << "F" << id << ",";
1024 plc.m_id = id;
1025 zone.m_plcMap.insert(NisusWrtTextInternal::Zone::PLCMap::value_type(position, plc));
1026 asciiFile.addPos(pos);
1027 asciiFile.addNote(f.str().c_str());
1028 input->seek(pos+10, librevenge::RVNG_SEEK_SET);
1029 }
1030 return true;
1031 }
1032
1033 ////////////////////////////////////////////////////////////
1034 // the paragraphs
1035 ////////////////////////////////////////////////////////////
1036
1037 // send the paragraph to the listener
setProperty(NisusWrtTextInternal::Paragraph const & para,int width)1038 void NisusWrtText::setProperty(NisusWrtTextInternal::Paragraph const ¶, int width)
1039 {
1040 if (!m_parserState->m_textListener) return;
1041 double origRMargin = para.m_margins[2].get();
1042 double rMargin=double(width)/72.-origRMargin;
1043 if (rMargin < 0.0) rMargin = 0;
1044 const_cast<NisusWrtTextInternal::Paragraph &>(para).m_margins[2] = rMargin;
1045 m_parserState->m_textListener->setParagraph(para);
1046 const_cast<NisusWrtTextInternal::Paragraph &>(para).m_margins[2] = origRMargin;
1047 }
1048
1049 // read the RULE resource: a list of rulers
readParagraphs(MWAWEntry const & entry,NisusWrtStruct::ZoneType zoneId)1050 bool NisusWrtText::readParagraphs(MWAWEntry const &entry, NisusWrtStruct::ZoneType zoneId)
1051 {
1052 if (!entry.valid() && entry.length() != 0) {
1053 MWAW_DEBUG_MSG(("NisusWrtText::readParagraphs: the entry is bad\n"));
1054 return false;
1055 }
1056 if (zoneId >= 3) {
1057 MWAW_DEBUG_MSG(("NisusWrtText::readParagraphs: find unexpected zoneId: %d\n", zoneId));
1058 return false;
1059 }
1060 auto &zone = m_state->m_zones[zoneId];
1061
1062 entry.setParsed(true);
1063 MWAWInputStreamPtr input = m_mainParser->rsrcInput();
1064 libmwaw::DebugFile &asciiFile = m_mainParser->rsrcAscii();
1065 long pos = entry.begin();
1066 input->seek(pos, librevenge::RVNG_SEEK_SET);
1067
1068 auto numElt = int(entry.length()/98);
1069 libmwaw::DebugStream f, f2;
1070 f << "Entries(RULE)[" << entry.type() << entry.id() << "]";
1071 if (entry.id()==1004) f << "[Styl]";
1072 else if (entry.id() != 1003) {
1073 MWAW_DEBUG_MSG(("NisusWrtText::readParagraphs: find unexpected entryId: %d\n", entry.id()));
1074 f << "###";
1075 }
1076 f << ":N=" << numElt;
1077 asciiFile.addPos(pos-4);
1078 asciiFile.addNote(f.str().c_str());
1079
1080 NisusWrtTextInternal::DataPLC plc;
1081 plc.m_type = NisusWrtTextInternal::P_Ruler;
1082
1083 long val;
1084 while (input->tell() != entry.end()) {
1085 int num = (entry.id() == 1003) ? static_cast<int>(zone.m_paragraphList.size()) : -1;
1086 pos = input->tell();
1087 f.str("");
1088 if (pos+8 > entry.end() || input->isEnd()) {
1089 f << "RULE" << num << "[" << zoneId << "]:###";
1090 asciiFile.addPos(pos);
1091 asciiFile.addNote(f.str().c_str());
1092
1093 MWAW_DEBUG_MSG(("NisusWrtText::readParagraphs: can not read end of zone\n"));
1094 return false;
1095 }
1096
1097 auto nPara = long(input->readULong(4));
1098 if (nPara == 0x7FFFFFFF) {
1099 input->seek(-4, librevenge::RVNG_SEEK_CUR);
1100 break;
1101 }
1102 NisusWrtStruct::Position textPosition;
1103 textPosition.m_paragraph = static_cast<int>(nPara); // checkme or ???? + para
1104
1105 auto sz = long(input->readULong(4));
1106 if (sz < 0x42 || pos+sz > entry.end()) {
1107 f << "RULE" << num << "[" << zoneId << "]:###";
1108 asciiFile.addPos(pos);
1109 asciiFile.addNote(f.str().c_str());
1110
1111 MWAW_DEBUG_MSG(("NisusWrtText::readParagraphs: can not read the size zone\n"));
1112 return false;
1113 }
1114 NisusWrtTextInternal::Paragraph para;
1115
1116 para.setInterline(double(input->readLong(4))/65536., librevenge::RVNG_POINT, MWAWParagraph::AtLeast);
1117 para.m_spacings[1] = double(input->readLong(4))/65536./72.;
1118 auto wh = int(input->readLong(2));
1119 switch (wh) {
1120 case 0:
1121 break; // left
1122 case 1:
1123 para.m_justify = MWAWParagraph::JustificationCenter;
1124 break;
1125 case 2:
1126 para.m_justify = MWAWParagraph::JustificationRight;
1127 break;
1128 case 3:
1129 para.m_justify = MWAWParagraph::JustificationFull;
1130 break;
1131 default:
1132 f << "#align=" << wh << ",";
1133 break;
1134 }
1135 val = input->readLong(2);
1136 if (val) f << "#f0=" << val << ",";
1137
1138 para.m_marginsUnit = librevenge::RVNG_INCH;
1139 para.m_margins[0] = double(input->readLong(4))/65536./72.;
1140 para.m_margins[1] = double(input->readLong(4))/65536./72.;
1141 para.m_margins[2] = double(input->readLong(4))/65536./72.;
1142 para.m_margins[0] =para.m_margins[0].get()-para.m_margins[1].get();
1143 wh = int(input->readULong(1));
1144 switch (wh) {
1145 case 0: // at least
1146 break;
1147 case 1:
1148 para.m_spacingsInterlineType = MWAWParagraph::Fixed;
1149 break;
1150 case 2:
1151 para.m_spacingsInterlineUnit = librevenge::RVNG_PERCENT;
1152 para.m_spacingsInterlineType = MWAWParagraph::Fixed;
1153 // before spacing is also in %, try to correct it
1154 para.m_spacings[1] = para.m_spacings[1].get()*12.0;
1155 break;
1156 default: // unknown, so...
1157 f << "#interline=" << (val&0xFC) << ",";
1158 para.setInterline(1.0, librevenge::RVNG_PERCENT);
1159 break;
1160 }
1161 val = input->readLong(1);
1162 if (val) f << "#f1=" << val << ",";
1163 for (int i = 0; i < 14; i++) {
1164 val = input->readLong(2);
1165 if (val) f << "g" << i << "=" << val << ",";
1166 }
1167 input->seek(pos+0x3E, librevenge::RVNG_SEEK_SET);
1168 long numTabs = input->readLong(2);
1169 bool ok = true;
1170 if (0x40+8*numTabs+2 > sz) {
1171 f << "###";
1172 MWAW_DEBUG_MSG(("NisusWrtText::readParagraphs: can not read the string\n"));
1173 ok = false;
1174 numTabs = 0;
1175 }
1176 for (long i = 0; i < numTabs; i++) {
1177 long tabPos = input->tell();
1178 MWAWTabStop tab;
1179
1180 f2.str("");
1181 tab.m_position = double(input->readLong(4))/72./65536.; // from left pos
1182 val = long(input->readULong(1));
1183 switch (val) {
1184 case 1:
1185 break;
1186 case 2:
1187 tab.m_alignment = MWAWTabStop::CENTER;
1188 break;
1189 case 3:
1190 tab.m_alignment = MWAWTabStop::RIGHT;
1191 break;
1192 case 4:
1193 tab.m_alignment = MWAWTabStop::DECIMAL;
1194 break;
1195 case 6: // a little old, look simillar to full justification
1196 f2 << "justify,";
1197 break;
1198 default:
1199 f2 << "#type=" << val << ",";
1200 break;
1201 }
1202 auto leader=static_cast<unsigned char>(input->readULong(1));
1203 if (leader) {
1204 int unicode= m_parserState->m_fontConverter->unicode(3, leader);
1205 if (unicode==-1)
1206 tab.m_leaderCharacter =static_cast<unsigned short>(leader);
1207 else
1208 tab.m_leaderCharacter =static_cast<unsigned short>(unicode);
1209 }
1210 val = long(input->readLong(2)); // unused ?
1211 if (val) f2 << "#unkn0=" << val << ",";
1212 para.m_tabs->push_back(tab);
1213 if (f2.str().length())
1214 f << "tab" << i << "=[" << f2.str() << "],";
1215 input->seek(tabPos+8, librevenge::RVNG_SEEK_SET);
1216 }
1217
1218 // ruler name
1219 long pSz = ok ? long(input->readULong(1)) : 0;
1220 if (pSz) {
1221 if (input->tell()+pSz != pos+sz && input->tell()+pSz+1 != pos+sz) {
1222 f << "name###";
1223 MWAW_DEBUG_MSG(("NisusWrtText::readParagraphs: can not read the ruler name\n"));
1224 asciiFile.addDelimiter(input->tell()-1,'#');
1225 }
1226 else {
1227 std::string str("");
1228 for (long i = 0; i < pSz; i++)
1229 str += char(input->readULong(1));
1230 para.m_name = str;
1231 }
1232 }
1233 plc.m_id = num;
1234 para.m_extra=f.str();
1235 if (entry.id() == 1003) {
1236 zone.m_paragraphList.push_back(para);
1237 zone.m_plcMap.insert(NisusWrtTextInternal::Zone::PLCMap::value_type(textPosition, plc));
1238 }
1239
1240 f.str("");
1241 f << "RULE" << num << "[" << zoneId << "]:";
1242 f << "paragraph=" << nPara << "," << para;
1243
1244 asciiFile.addPos(pos);
1245 asciiFile.addNote(f.str().c_str());
1246 input->seek(pos+sz, librevenge::RVNG_SEEK_SET);
1247 }
1248 pos = input->tell();
1249 f.str("");
1250 f << "RULE[" << zoneId << "](II):";
1251 if (pos+66 != entry.end() || input->readULong(4) != 0x7FFFFFFF) {
1252 f << "###";
1253 asciiFile.addPos(pos);
1254 asciiFile.addNote(f.str().c_str());
1255
1256 MWAW_DEBUG_MSG(("NisusWrtText::readParagraphs: find odd end\n"));
1257 return true;
1258 }
1259 for (int i = 0; i < 31; i++) { // only find 0 expected f12=0|100
1260 val = long(input->readLong(2));
1261 if (val) f << "f" << i << "=" << std::hex << val << std::dec << ",";
1262 }
1263 asciiFile.addPos(pos);
1264 asciiFile.addNote(f.str().c_str());
1265
1266 return true;
1267 }
1268
1269 ////////////////////////////////////////////////////////////
1270 // the zones header
1271 ////////////////////////////////////////////////////////////
1272
1273 // read the header/footer main entry
readHeaderFooter(MWAWEntry const & entry)1274 bool NisusWrtText::readHeaderFooter(MWAWEntry const &entry)
1275 {
1276 if (!entry.valid() || (entry.length()%32)) {
1277 MWAW_DEBUG_MSG(("NisusWrtText::readHeaderFooter: the entry is bad\n"));
1278 return false;
1279 }
1280 auto &zone = m_state->m_zones[NisusWrtStruct::Z_HeaderFooter];
1281 entry.setParsed(true);
1282 MWAWInputStreamPtr input = m_mainParser->rsrcInput();
1283 libmwaw::DebugFile &asciiFile = m_mainParser->rsrcAscii();
1284 long pos = entry.begin();
1285 input->seek(pos, librevenge::RVNG_SEEK_SET);
1286
1287 auto numElt = int(entry.length()/32);
1288 libmwaw::DebugStream f;
1289 f << "Entries(HeaderFooter)[" << entry.id() << "]:N=" << numElt;
1290 asciiFile.addPos(pos-4);
1291 asciiFile.addNote(f.str().c_str());
1292
1293 NisusWrtTextInternal::DataPLC plc;
1294 plc.m_type = NisusWrtTextInternal::P_HeaderFooter;
1295 long val;
1296 long lastPara = 0;
1297 for (int i = 0; i < numElt; i++) {
1298 pos = input->tell();
1299 f.str("");
1300 NisusWrtTextInternal::HeaderFooter hf;
1301 hf.m_textParagraph = input->readLong(4);
1302 hf.m_paragraph[0] = lastPara;
1303 hf.m_paragraph[1] = lastPara = input->readLong(4);
1304 auto what = static_cast<int>(input->readULong(2));
1305 switch ((what>>2)&0x3) {
1306 case 1:
1307 hf.m_type = MWAWHeaderFooter::HEADER;
1308 break;
1309 case 2:
1310 hf.m_type = MWAWHeaderFooter::FOOTER;
1311 break;
1312 default:
1313 f << "#what=" << ((what>>2)&0x3);
1314 break;
1315 }
1316 switch (what&0x3) {
1317 case 1:
1318 hf.m_occurrence = MWAWHeaderFooter::ODD;
1319 break;
1320 case 2:
1321 hf.m_occurrence = MWAWHeaderFooter::EVEN;
1322 break;
1323 case 3:
1324 hf.m_occurrence = MWAWHeaderFooter::ALL;
1325 break;
1326 default:
1327 f << "[#page],";
1328 break;
1329 }
1330 if (what&0xFFF0) f << "#flags=" << std::hex << (what&0xFFF0) << ",";
1331 // find 0|0x10|0x18|0x20|0x36|0x3a|0x40|0x4c|0x66 here
1332 hf.m_unknown = static_cast<int>(input->readLong(2));
1333 for (int j = 0; j < 10; j++) { // always 0 ?
1334 val = long(input->readLong(2));
1335 if (val) f << "g" << j << "=" << val << ",";
1336 }
1337 hf.m_extra = f.str();
1338 f.str("");
1339 f << "HeaderFooter" << i << ":" << hf;
1340
1341 m_state->m_hfList.push_back(hf);
1342 plc.m_id = i+1;
1343 NisusWrtStruct::Position hfPosition;
1344 hfPosition.m_paragraph=int(lastPara);
1345 zone.m_plcMap.insert(NisusWrtTextInternal::Zone::PLCMap::value_type(hfPosition, plc));
1346 asciiFile.addPos(pos);
1347 asciiFile.addNote(f.str().c_str());
1348 input->seek(pos+32, librevenge::RVNG_SEEK_SET);
1349 }
1350 return true;
1351 }
1352
1353 // read the footnote main entry
readFootnotes(MWAWEntry const & entry)1354 bool NisusWrtText::readFootnotes(MWAWEntry const &entry)
1355 {
1356 if (!entry.valid() || (entry.length()%36)) {
1357 MWAW_DEBUG_MSG(("NisusWrtText::readFootnotes: the entry is bad\n"));
1358 return false;
1359 }
1360 auto &mainZone = m_state->m_zones[NisusWrtStruct::Z_Main];
1361 auto &zone = m_state->m_zones[NisusWrtStruct::Z_Footnote];
1362 entry.setParsed(true);
1363 MWAWInputStreamPtr input = m_mainParser->rsrcInput();
1364 libmwaw::DebugFile &asciiFile = m_mainParser->rsrcAscii();
1365 long pos = entry.begin();
1366 input->seek(pos, librevenge::RVNG_SEEK_SET);
1367
1368 auto numElt = int(entry.length()/36);
1369 libmwaw::DebugStream f;
1370 f << "Entries(Footnotes)[" << entry.id() << "]:N=" << numElt;
1371 asciiFile.addPos(pos-4);
1372 asciiFile.addNote(f.str().c_str());
1373
1374 NisusWrtTextInternal::DataPLC plc;
1375 plc.m_type = NisusWrtTextInternal::P_Footnote;
1376 int lastParagraph = 0;
1377 long val;
1378 for (int i = 0; i < numElt; i++) {
1379 pos = input->tell();
1380 f.str("");
1381 NisusWrtTextInternal::Footnote footnote;
1382 footnote.m_textPosition.m_paragraph = static_cast<int>(input->readULong(4)); // checkme or ??? m_paragraph
1383 footnote.m_textPosition.m_word = static_cast<int>(input->readULong(2));
1384 footnote.m_textPosition.m_char = static_cast<int>(input->readULong(2));
1385 footnote.m_paragraph[0] = lastParagraph;
1386 lastParagraph = static_cast<int>(input->readULong(4)); // checkme or ??? m_paragraph
1387 footnote.m_paragraph[1] = lastParagraph;
1388 // find f0=0|55|6f, f1=15|16|26|27|39|3a
1389 for (int j = 0; j < 2; j++) {
1390 val = input->readLong(2);
1391 if (val) f << "f" << j << "=" << std::hex << val << std::dec << ",";
1392 }
1393 footnote.m_number = static_cast<int>(input->readLong(2));
1394 for (int j = 0; j < 3; j++) { // always 0 ?
1395 val = input->readLong(2);
1396 if (val) f << "g" << j << "=" << val << ",";
1397 }
1398 for (int wh = 0; wh < 2; wh++) {
1399 input->seek(pos+24+wh*6, librevenge::RVNG_SEEK_SET);
1400 std::string label("");
1401 for (int c = 0; c < 6; c++) {
1402 auto ch = char(input->readULong(1));
1403 if (ch == 0)
1404 break;
1405 label += ch;
1406 }
1407 if (wh==0) footnote.m_noteLabel = label;
1408 else footnote.m_textLabel = label;
1409 }
1410 footnote.m_extra = f.str();
1411 f.str("");
1412 f << "Footnotes" << i << ":" << footnote;
1413
1414 m_state->m_footnoteList.push_back(footnote);
1415 plc.m_id = i;
1416 mainZone.m_plcMap.insert(NisusWrtTextInternal::Zone::PLCMap::value_type(footnote.m_textPosition, plc));
1417 NisusWrtStruct::Position notePosition;
1418 notePosition.m_paragraph= footnote.m_paragraph[0];
1419 zone.m_plcMap.insert(NisusWrtTextInternal::Zone::PLCMap::value_type(notePosition, plc));
1420
1421 asciiFile.addPos(pos);
1422 asciiFile.addNote(f.str().c_str());
1423 input->seek(pos+36, librevenge::RVNG_SEEK_SET);
1424 }
1425 return true;
1426 }
1427
1428 // read the PICD zone ( a list of picture ? )
readPICD(MWAWEntry const & entry,NisusWrtStruct::ZoneType zoneId)1429 bool NisusWrtText::readPICD(MWAWEntry const &entry, NisusWrtStruct::ZoneType zoneId)
1430 {
1431 if ((!entry.valid()&&entry.length()) || (entry.length()%14)) {
1432 MWAW_DEBUG_MSG(("NisusWrtText::readPICD: the entry is bad\n"));
1433 return false;
1434 }
1435 if (zoneId >= 3) {
1436 MWAW_DEBUG_MSG(("NisusWrtText::readPICD: find unexpected zoneId: %d\n", zoneId));
1437 return false;
1438 }
1439 auto &zone = m_state->m_zones[zoneId];
1440 entry.setParsed(true);
1441 MWAWInputStreamPtr input = m_mainParser->rsrcInput();
1442 libmwaw::DebugFile &ascFile = m_mainParser->rsrcAscii();
1443 long pos = entry.begin();
1444 input->seek(pos, librevenge::RVNG_SEEK_SET);
1445
1446 auto numElt = int(entry.length()/14);
1447 libmwaw::DebugStream f;
1448 f << "Entries(PICD)[" << zoneId << "]:N=" << numElt;
1449 ascFile.addPos(pos-4);
1450 ascFile.addNote(f.str().c_str());
1451
1452 NisusWrtTextInternal::DataPLC plc;
1453 plc.m_type = NisusWrtTextInternal::P_PicturePara;
1454 for (int i = 0; i < numElt; i++) {
1455 pos = input->tell();
1456 f.str("");
1457 NisusWrtTextInternal::PicturePara pict;
1458 pict.m_paragraph = static_cast<int>(input->readLong(4));
1459 int dim[4];
1460 for (int &j : dim)
1461 j = static_cast<int>(input->readLong(2));
1462 pict.m_position = MWAWBox2i(MWAWVec2i(dim[1],dim[0]), MWAWVec2i(dim[3],dim[2]));
1463 pict.m_id = static_cast<int>(input->readULong(2));
1464 zone.m_pictureParaList.push_back(pict);
1465
1466 NisusWrtStruct::Position pictPosition;
1467 pictPosition.m_paragraph= pict.m_paragraph;
1468 plc.m_id = i;
1469 zone.m_plcMap.insert(NisusWrtTextInternal::Zone::PLCMap::value_type(pictPosition, plc));
1470
1471 f << "PICD" << i << ":" << pict;
1472 ascFile.addPos(pos);
1473 ascFile.addNote(f.str().c_str());
1474 input->seek(pos+14, librevenge::RVNG_SEEK_SET);
1475 }
1476 return true;
1477 }
1478
1479 ////////////////////////////////////////////////////////////
1480 //
1481 // Low level
1482 //
1483 ////////////////////////////////////////////////////////////
1484
1485 ////////////////////////////////////////////////////////////
findFilePos(NisusWrtStruct::ZoneType zoneId,NisusWrtStruct::Position const & pos)1486 long NisusWrtText::findFilePos(NisusWrtStruct::ZoneType zoneId, NisusWrtStruct::Position const &pos)
1487 {
1488 if (zoneId >= 3) {
1489 MWAW_DEBUG_MSG(("NisusWrtText::findFilePos: find unexpected zoneId: %d\n", zoneId));
1490 return -1;
1491 }
1492 auto &zone = m_state->m_zones[zoneId];
1493 MWAWEntry entry = zone.m_entry;
1494 if (!entry.valid()) {
1495 MWAW_DEBUG_MSG(("NisusWrtText::findFilePos: the entry is bad\n"));
1496 return -1;
1497 }
1498
1499 bool isMain = zoneId == NisusWrtStruct::Z_Main;
1500 MWAWInputStreamPtr input = isMain ?
1501 m_mainParser->getInput() : m_mainParser->rsrcInput();
1502 input->seek(entry.begin(), librevenge::RVNG_SEEK_SET);
1503
1504 NisusWrtStruct::Position actPos;
1505 for (long i = 0; i < entry.length(); i++) {
1506 if (input->isEnd())
1507 break;
1508 if (pos == actPos)
1509 return input->tell();
1510 auto c = static_cast<unsigned char>(input->readULong(1));
1511 // update the position
1512 switch (c) {
1513 case 0xd:
1514 actPos.m_paragraph++;
1515 actPos.m_word = actPos.m_char = 0;
1516 break;
1517 case '\t':
1518 case ' ':
1519 actPos.m_word++;
1520 actPos.m_char = 0;
1521 break;
1522 default:
1523 actPos.m_char++;
1524 break;
1525 }
1526 }
1527 if (pos == actPos)
1528 return input->tell();
1529 MWAW_DEBUG_MSG(("NisusWrtText::findFilePos: can not find the position\n"));
1530 return -1;
1531 }
1532
1533 ////////////////////////////////////////////////////////////
sendHeaderFooter(int hfId)1534 bool NisusWrtText::sendHeaderFooter(int hfId)
1535 {
1536 if (!m_parserState->m_textListener) {
1537 MWAW_DEBUG_MSG(("NisusWrtText::sendHeaderFooter: can not find the listener\n"));
1538 return false;
1539 }
1540 if (hfId >= int(m_state->m_hfList.size())) {
1541 MWAW_DEBUG_MSG(("NisusWrtText::sendHeaderFooter: can not find the headerFooter list\n"));
1542 return false;
1543 }
1544 if (hfId < 0)
1545 return true;
1546 auto const &hf = m_state->m_hfList[size_t(hfId)];
1547 hf.m_parsed = true;
1548
1549 MWAWEntry entry;
1550 entry.setId(NisusWrtStruct::Z_HeaderFooter);
1551 NisusWrtStruct::Position pos;
1552 pos.m_paragraph = static_cast<int>(hf.m_paragraph[0]);
1553 entry.setBegin(findFilePos(NisusWrtStruct::Z_HeaderFooter, pos));
1554 pos.m_paragraph = static_cast<int>(hf.m_paragraph[1]);
1555 entry.setEnd(findFilePos(NisusWrtStruct::Z_HeaderFooter, pos));
1556 if (entry.begin() < 0 || entry.length() < 0) {
1557 MWAW_DEBUG_MSG(("NisusWrtText::sendHeaderFooter: can not compute the headerFooter entry\n"));
1558 return false;
1559 }
1560 pos.m_paragraph = static_cast<int>(hf.m_paragraph[0]);
1561 sendText(entry, pos);
1562 return true;
1563 }
1564
1565 ////////////////////////////////////////////////////////////
sendFootnote(int footnoteId)1566 bool NisusWrtText::sendFootnote(int footnoteId)
1567 {
1568 if (!m_parserState->m_textListener) {
1569 MWAW_DEBUG_MSG(("NisusWrtText::sendFootnote: can not find the listener\n"));
1570 return false;
1571 }
1572 if (footnoteId >= int(m_state->m_footnoteList.size())) {
1573 MWAW_DEBUG_MSG(("NisusWrtText::sendFootnote: can not find the footnote list\n"));
1574 return false;
1575 }
1576 if (footnoteId < 0)
1577 return true;
1578 auto const &fnote = m_state->m_footnoteList[size_t(footnoteId)];
1579 fnote.m_parsed = true;
1580
1581 MWAWEntry entry;
1582 entry.setId(NisusWrtStruct::Z_Footnote);
1583 NisusWrtStruct::Position pos;
1584 pos.m_paragraph = fnote.m_paragraph[0];
1585 entry.setBegin(findFilePos(NisusWrtStruct::Z_Footnote, pos));
1586 pos.m_paragraph = fnote.m_paragraph[1];
1587 entry.setEnd(findFilePos(NisusWrtStruct::Z_Footnote, pos));
1588 if (entry.begin() < 0 || entry.length() < 0) {
1589 MWAW_DEBUG_MSG(("NisusWrtText::sendFootnote: can not compute the footnote entry\n"));
1590 return false;
1591 }
1592 pos.m_paragraph = fnote.m_paragraph[0];
1593 sendText(entry, pos);
1594 return true;
1595 }
1596
1597 ////////////////////////////////////////////////////////////
sendText(MWAWEntry const & entry,NisusWrtStruct::Position firstPos)1598 bool NisusWrtText::sendText(MWAWEntry const &entry, NisusWrtStruct::Position firstPos)
1599 {
1600 MWAWTextListenerPtr listener=m_parserState->m_textListener;
1601 if (!listener) {
1602 MWAW_DEBUG_MSG(("NisusWrtText::sendText: can not find the listener\n"));
1603 return false;
1604 }
1605 if (!entry.valid()) {
1606 MWAW_DEBUG_MSG(("NisusWrtText::sendText: the entry is bad\n"));
1607 return false;
1608 }
1609
1610 auto zoneId = static_cast<NisusWrtStruct::ZoneType>(entry.id());
1611 if (zoneId >= 3) {
1612 MWAW_DEBUG_MSG(("NisusWrtText::sendText: find unexpected zoneId: %d\n", zoneId));
1613 return false;
1614 }
1615 auto &zone = m_state->m_zones[zoneId];
1616 bool isMain = zoneId == NisusWrtStruct::Z_Main;
1617 auto width = int(72.0*m_mainParser->getPageWidth());
1618 if (isMain || zoneId == NisusWrtStruct::Z_Footnote) {
1619 float colSep = 0.5f;
1620 int nCol = 1;
1621 m_mainParser->getColumnInfo(nCol, colSep);
1622 if (nCol > 1)
1623 width /= nCol;
1624 if (isMain && nCol > 1) {
1625 if (listener->isSectionOpened())
1626 listener->closeSection();
1627
1628 MWAWSection sec;
1629 sec.setColumns(nCol, double(width), librevenge::RVNG_POINT);
1630 listener->openSection(sec);
1631 }
1632 }
1633 MWAWInputStreamPtr input
1634 = isMain ? m_mainParser->getInput() : m_mainParser->rsrcInput();
1635 libmwaw::DebugFile &ascFile =
1636 isMain ? m_mainParser->ascii() : m_mainParser->rsrcAscii();
1637 long pos = entry.begin();
1638 input->seek(pos, librevenge::RVNG_SEEK_SET);
1639
1640 libmwaw::DebugStream f;
1641 f << "Entries(TEXT)[" << zoneId << "]:";
1642 std::string str("");
1643 NisusWrtStruct::Position actPos(firstPos);
1644 auto it = zone.m_plcMap.begin();
1645 while (it != zone.m_plcMap.end() && it->first.cmp(actPos) < 0)
1646 ++it;
1647
1648 NisusWrtTextInternal::Font actFont;
1649 actFont.m_font = MWAWFont(3,12);
1650 listener->setFont(actFont.m_font);
1651 NisusWrtStruct::FootnoteInfo ftInfo;
1652 m_mainParser->getFootnoteInfo(ftInfo);
1653 bool lastCharFootnote = false;
1654 int noteId = 0, numVar=0, actVar=-1;
1655 std::vector<int> varValues;
1656 std::map<int,int> fontIdToVarIdMap;
1657 for (long i = 0; i <= entry.length(); i++) {
1658 if (i==entry.length() && !lastCharFootnote)
1659 break;
1660 while (it != zone.m_plcMap.end() && it->first.cmp(actPos) <= 0) {
1661 auto const &plcPos = it->first;
1662 auto const &plc = it++->second;
1663 f << str;
1664 str="";
1665 if (plcPos.cmp(actPos) < 0) {
1666 MWAW_DEBUG_MSG(("NisusWrtText::sendText: oops find unexpected position\n"));
1667 f << "###[" << plc << "]";
1668 continue;
1669 }
1670 f << "[" << plc << "]";
1671 switch (plc.m_type) {
1672 case NisusWrtTextInternal::P_Format: {
1673 if (plc.m_id < 0 || plc.m_id >= int(m_state->m_fontList.size())) {
1674 MWAW_DEBUG_MSG(("NisusWrtText::sendText: oops can not find the actual font\n"));
1675 f << "###";
1676 break;
1677 }
1678 auto const &font = m_state->m_fontList[size_t(plc.m_id)];
1679 actFont = font;
1680 if (font.m_pictureId <= 0)
1681 listener->setFont(font.m_font);
1682 if (!font.isVariable())
1683 break;
1684 if (fontIdToVarIdMap.find(plc.m_id) != fontIdToVarIdMap.end())
1685 actVar = fontIdToVarIdMap.find(plc.m_id)->second;
1686 else {
1687 actVar = numVar++;
1688 fontIdToVarIdMap[plc.m_id]=actVar;
1689 }
1690 break;
1691 }
1692 case NisusWrtTextInternal::P_Ruler: {
1693 if (plc.m_id < 0 || plc.m_id >= int(zone.m_paragraphList.size())) {
1694 MWAW_DEBUG_MSG(("NisusWrtText::sendText: oops can not find the actual ruler\n"));
1695 f << "###";
1696 break;
1697 }
1698 auto const ¶ = zone.m_paragraphList[size_t(plc.m_id)];
1699 setProperty(para, width);
1700 break;
1701 }
1702 case NisusWrtTextInternal::P_Footnote: {
1703 if (!isMain) break;
1704 if (!lastCharFootnote) {
1705 MWAW_DEBUG_MSG(("NisusWrtText::sendText: oops do not find the footnote symbol\n"));
1706 break;
1707 }
1708 if (plc.m_id < 0 || plc.m_id >= int(m_state->m_footnoteList.size())) {
1709 MWAW_DEBUG_MSG(("NisusWrtText::sendText: can not find the footnote\n"));
1710 MWAWSubDocumentPtr subdoc(new NisusWrtTextInternal::SubDocument(*this, input, -1, libmwaw::DOC_NOTE));
1711 listener->insertNote(MWAWNote(MWAWNote::FootNote), subdoc);
1712 break;
1713 }
1714 MWAWSubDocumentPtr subdoc(new NisusWrtTextInternal::SubDocument(*this, input, plc.m_id, libmwaw::DOC_NOTE));
1715 auto const &fnote = m_state->m_footnoteList[size_t(plc.m_id)];
1716 noteId++;
1717 if (fnote.m_number && noteId != fnote.m_number)
1718 noteId = fnote.m_number;
1719 MWAWNote note(ftInfo.endNotes() ? MWAWNote::EndNote : MWAWNote::FootNote);
1720 note.m_number=noteId;
1721 note.m_label=fnote.getTextLabel(noteId).c_str();
1722 listener->insertNote(note, subdoc);
1723 break;
1724 }
1725 case NisusWrtTextInternal::P_PicturePara: {
1726 if (plc.m_id < 0 || plc.m_id >= int(zone.m_pictureParaList.size())) {
1727 MWAW_DEBUG_MSG(("NisusWrtText::sendText: can not find the paragraph picture\n"));
1728 break;
1729 }
1730 auto &pict = zone.m_pictureParaList[size_t(plc.m_id)];
1731 MWAWPosition pictPos(MWAWVec2f(pict.m_position.min()), MWAWVec2f(pict.m_position.size()), librevenge::RVNG_POINT);
1732 pictPos.setRelativePosition(MWAWPosition::Paragraph);
1733 pictPos.m_wrapping = MWAWPosition::WBackground;
1734 m_mainParser->sendPicture(pict.m_id, pictPos);
1735 break;
1736 }
1737 case NisusWrtTextInternal::P_HeaderFooter:
1738 break;
1739 case NisusWrtTextInternal::P_Unknown:
1740 #if !defined(__clang__)
1741 default:
1742 #endif
1743 MWAW_DEBUG_MSG(("NisusWrtText::sendText: oops can not find unknown plc type\n"));
1744 f << "###";
1745 break;
1746 }
1747 }
1748
1749 if (input->isEnd())
1750 break;
1751 if (i==entry.length())
1752 break;
1753 auto c = static_cast<unsigned char>(input->readULong(1));
1754 str+=char(c);
1755 if (c==0xd) {
1756 f << str;
1757 ascFile.addPos(pos);
1758 ascFile.addNote(f.str().c_str());
1759
1760 str = "";
1761 pos = input->tell();
1762 f.str("");
1763 f << "TEXT" << zoneId << ":";
1764 }
1765
1766 // update the position
1767 switch (c) {
1768 case 0xd:
1769 actPos.m_paragraph++;
1770 actPos.m_word = actPos.m_char = 0;
1771 break;
1772 case '\t':
1773 case ' ':
1774 actPos.m_word++;
1775 actPos.m_char = 0;
1776 break;
1777 default:
1778 actPos.m_char++;
1779 break;
1780 }
1781
1782 // send char
1783 lastCharFootnote = false;
1784 switch (c) {
1785 case 0x1: {
1786 if (actFont.m_pictureId <= 0) {
1787 MWAW_DEBUG_MSG(("NisusWrtText::sendText: can not find pictureId for char 1\n"));
1788 f << "#";
1789 break;
1790 }
1791 MWAWPosition pictPos(MWAWVec2f(actFont.m_pictureDim[0].min()), MWAWVec2f(actFont.m_pictureDim[0].size()), librevenge::RVNG_POINT);
1792 pictPos.setRelativePosition(MWAWPosition::CharBaseLine);
1793 pictPos.setClippingPosition
1794 (MWAWVec2f(actFont.m_pictureDim[1].min()-actFont.m_pictureDim[0].min()),
1795 MWAWVec2f(actFont.m_pictureDim[0].max()-actFont.m_pictureDim[1].max()));
1796 m_mainParser->sendPicture(actFont.m_pictureId, pictPos);
1797 break;
1798 }
1799 case 0x3: // checkme: find in some file ( but seems to do nothing )
1800 break;
1801 case 0x9:
1802 listener->insertTab();
1803 break;
1804 case 0xb:
1805 listener->insertEOL(true);
1806 break;
1807 case 0xc:
1808 if (!isMain) break;
1809 m_mainParser->newPage(++m_state->m_actualPage);
1810 if (ftInfo.resetNumberOnNewPage()) noteId = 0;
1811 break;
1812 case 0xd:
1813 listener->insertEOL();
1814 break;
1815 case 0xf: {
1816 std::string format(m_mainParser->getDateFormat(zoneId, actVar));
1817 MWAWField field(MWAWField::Date);
1818 if (format.length())
1819 field.m_DTFormat = format;
1820 else
1821 f << "#";
1822 listener->insertField(field);
1823 break;
1824 }
1825 case 0x10: {
1826 MWAWField field(MWAWField::Time);
1827 field.m_DTFormat = "%H:%M";
1828 listener->insertField(field);
1829 break;
1830 }
1831 case 0x11:
1832 listener->insertField(MWAWField(MWAWField::Title));
1833 break;
1834 case 0x14: // mark separator ( ok to ignore )
1835 break;
1836 case 0x1c:
1837 if (isMain)
1838 lastCharFootnote = true;
1839 break;
1840 case 0x1d: {
1841 MWAWField::Type fType;
1842 std::string content;
1843 if (!m_mainParser->getReferenceData(zoneId, actVar, fType, content, varValues)) {
1844 listener->insertChar(' ');
1845 f << "#[ref]";
1846 break;
1847 }
1848 if (fType != MWAWField::None)
1849 listener->insertField(MWAWField(fType));
1850 else if (content.length())
1851 listener->insertUnicodeString(librevenge::RVNGString(content.c_str()));
1852 else
1853 f << "#[ref]";
1854 break;
1855 }
1856 // checkme: find also 0x8, 0x13, 0x15, 0x1e, 0x1f in glossary
1857 default:
1858 i+=listener->insertCharacter(static_cast<unsigned char>(c), input, entry.end());
1859 break;
1860 }
1861 }
1862 f << str;
1863 ascFile.addPos(pos);
1864 ascFile.addNote(f.str().c_str());
1865 return true;
1866 }
1867
1868 //! send data to the listener
sendMainText()1869 bool NisusWrtText::sendMainText()
1870 {
1871 if (!m_parserState->m_textListener) return true;
1872
1873 if (!m_state->m_zones[0].m_entry.valid()) {
1874 MWAW_DEBUG_MSG(("NisusWrtText::sendMainText: can not find the main text\n"));
1875 return false;
1876 }
1877 m_state->m_zones[0].m_entry.setParsed(true);
1878 sendText(m_state->m_zones[0].m_entry);
1879 return true;
1880 }
1881
1882
flushExtra()1883 void NisusWrtText::flushExtra()
1884 {
1885 if (!m_parserState->m_textListener) return;
1886 for (size_t f = 0; f < m_state->m_footnoteList.size(); f++) {
1887 if (m_state->m_footnoteList[f].m_parsed)
1888 continue;
1889 sendFootnote(int(f));
1890 }
1891 m_parserState->m_textListener->insertChar(' ');
1892 for (size_t hf = 0; hf < m_state->m_hfList.size(); hf++) {
1893 if (m_state->m_hfList[hf].m_parsed)
1894 continue;
1895 sendHeaderFooter(int(hf));
1896 }
1897 }
1898
1899 // vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab:
1900