/src/libmwaw/src/lib/MsWrd1Parser.cxx
Line | Count | Source |
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 <sstream> |
38 | | |
39 | | #include <librevenge/librevenge.h> |
40 | | |
41 | | #include "MWAWTextListener.hxx" |
42 | | #include "MWAWFont.hxx" |
43 | | #include "MWAWFontConverter.hxx" |
44 | | #include "MWAWHeader.hxx" |
45 | | #include "MWAWParagraph.hxx" |
46 | | #include "MWAWPictMac.hxx" |
47 | | #include "MWAWPosition.hxx" |
48 | | #include "MWAWPrinter.hxx" |
49 | | #include "MWAWSection.hxx" |
50 | | #include "MWAWSubDocument.hxx" |
51 | | |
52 | | #include "MsWrd1Parser.hxx" |
53 | | |
54 | | /** Internal: the structures of a MsWrd1Parser */ |
55 | | namespace MsWrd1ParserInternal |
56 | | { |
57 | | /** different types |
58 | | * |
59 | | * - FONT: font |
60 | | * - RULER: ruler |
61 | | * - PAGE: page break |
62 | | * - FOOTNOTE: footnote marker |
63 | | * - ZONE: unknown(zone4) |
64 | | */ |
65 | | enum PLCType { FONT=0, RULER, FOOTNOTE, PAGE, ZONE, UNKNOWN}; |
66 | | |
67 | | /** Internal: class to store the PLC: Pointer List Content ? */ |
68 | | struct PLC { |
69 | | //! constructor |
70 | | explicit PLC(PLCType type=UNKNOWN) |
71 | 16.4k | : m_type(type) |
72 | 16.4k | , m_id(-1) |
73 | 16.4k | , m_extras("") |
74 | 16.4k | { |
75 | 16.4k | } |
76 | | //! operator<< |
77 | | friend std::ostream &operator<<(std::ostream &o, PLC const &plc); |
78 | | //! the type |
79 | | PLCType m_type; |
80 | | //! the id |
81 | | int m_id; |
82 | | //! a string used to store the parsing extrass |
83 | | std::string m_extras; |
84 | | }; |
85 | | |
86 | | std::ostream &operator<<(std::ostream &o, PLC const &plc) |
87 | 0 | { |
88 | 0 | switch (plc.m_type) { |
89 | 0 | case FONT: |
90 | 0 | o << "F"; |
91 | 0 | break; |
92 | 0 | case RULER: |
93 | 0 | o << "P"; |
94 | 0 | break; |
95 | 0 | case FOOTNOTE: |
96 | 0 | o << "Fn"; |
97 | 0 | break; |
98 | 0 | case PAGE: |
99 | 0 | o << "Page"; |
100 | 0 | break; |
101 | 0 | case ZONE: |
102 | 0 | o << "Z"; |
103 | 0 | break; |
104 | 0 | case UNKNOWN: |
105 | | #if !defined(__clang__) |
106 | | default: |
107 | | #endif |
108 | 0 | o << "#type" << int(plc.m_type); |
109 | 0 | break; |
110 | 0 | } |
111 | 0 | if (plc.m_id != -1) o << plc.m_id; |
112 | 0 | else o << "_"; |
113 | 0 | if (!plc.m_extras.empty()) o << ":" << plc.m_extras; |
114 | 0 | return o; |
115 | 0 | } |
116 | | |
117 | | //////////////////////////////////////// |
118 | | //! Internal: the font of a MsWrd1Parser |
119 | | struct Font { |
120 | | //! constructor |
121 | | Font() |
122 | 332k | : m_font() |
123 | 332k | , m_type(0) |
124 | 332k | , m_extras("") |
125 | 332k | { |
126 | 332k | } |
127 | | //! operator<< |
128 | | friend std::ostream &operator<<(std::ostream &o, Font const &ft); |
129 | | //! the basic font property |
130 | | MWAWFont m_font; |
131 | | //! a unknown int, maybe 0x80 means defined font |
132 | | int m_type; |
133 | | //! a string used to store the parsing extrass |
134 | | std::string m_extras; |
135 | | }; |
136 | | |
137 | | std::ostream &operator<<(std::ostream &o, Font const &ft) |
138 | 0 | { |
139 | 0 | if (ft.m_type) o << "type=" << std::hex << ft.m_type << std::dec << ","; |
140 | 0 | if (!ft.m_extras.empty()) o << ft.m_extras; |
141 | 0 | return o; |
142 | 0 | } |
143 | | |
144 | | //////////////////////////////////////// |
145 | | //! Internal: the paragraph of a MsWrd1Parser |
146 | | struct Paragraph final : public MWAWParagraph { |
147 | | //! constructor |
148 | | Paragraph() |
149 | 215k | : MWAWParagraph() |
150 | 215k | , m_type(0) |
151 | 215k | , m_type2(0) |
152 | 215k | { |
153 | 215k | } |
154 | 123k | Paragraph(Paragraph const &)=default; |
155 | | Paragraph &operator=(Paragraph const &)=default; |
156 | 62.3k | Paragraph &operator=(Paragraph &&)=default; |
157 | | //! destructor |
158 | | ~Paragraph() final; |
159 | | //! operator<< |
160 | | friend std::ostream &operator<<(std::ostream &o, Paragraph const &ft); |
161 | | //! the initial type |
162 | | int m_type; |
163 | | //! another type |
164 | | int m_type2; |
165 | | }; |
166 | | |
167 | | Paragraph::~Paragraph() |
168 | 339k | { |
169 | 339k | } |
170 | | |
171 | | std::ostream &operator<<(std::ostream &o, Paragraph const ¶) |
172 | 0 | { |
173 | 0 | o << static_cast<MWAWParagraph const &>(para); |
174 | | // 0|80 frequent: means redefine paragraph? find also a7 in a footnote |
175 | 0 | if (para.m_type) o << "type=" << std::hex << para.m_type << std::dec << ","; |
176 | |
|
177 | 0 | if (para.m_type2 & 0xF0) { |
178 | 0 | bool foot = (para.m_type2 & 0x10); |
179 | 0 | if (foot) o << "footer/footnote["; |
180 | 0 | else o << "header["; |
181 | 0 | if (para.m_type2 & 0x20) o << (foot ? "even," : "odd,"); |
182 | 0 | if (para.m_type2 & 0x40) o << (foot ? "odd," : "even,"); |
183 | 0 | if (para.m_type2 & 0x80) o << "first,"; |
184 | 0 | o << "]"; |
185 | 0 | } |
186 | 0 | if (para.m_type2 & 0xF) |
187 | 0 | o << "#type2=" << std::hex << (para.m_type2 & 0xF) << std::dec << ","; |
188 | |
|
189 | 0 | return o; |
190 | 0 | } |
191 | | |
192 | | //////////////////////////////////////// |
193 | | //! Internal: the state of a MsWrd1Parser |
194 | | struct State { |
195 | | //! constructor |
196 | | State() |
197 | 83.3k | : m_eot(-1) |
198 | 83.3k | , m_numColumns(1) |
199 | 83.3k | , m_columnsSep(0) |
200 | 83.3k | , m_textZonesList() |
201 | 83.3k | , m_mainTextZonesList() |
202 | 83.3k | , m_fontsList() |
203 | 83.3k | , m_paragraphsList() |
204 | 83.3k | , m_endNote(false) |
205 | 83.3k | , m_footnotesList() |
206 | 83.3k | , m_plcMap() |
207 | 83.3k | , m_actPage(0) |
208 | 83.3k | , m_numPages(1) |
209 | 83.3k | , m_headersId() |
210 | 83.3k | , m_footersId() |
211 | 83.3k | { |
212 | 583k | for (auto &limit : m_fileZonesLimit) limit = -1; |
213 | 83.3k | } |
214 | | |
215 | | //! end of text |
216 | | long m_eot; |
217 | | //! the number of columns |
218 | | int m_numColumns; |
219 | | //! the column separator |
220 | | float m_columnsSep; |
221 | | //! the zones limits |
222 | | int m_fileZonesLimit[7]; |
223 | | //! the list of text zones |
224 | | std::vector<MWAWVec2l> m_textZonesList; |
225 | | //! the list of main text zones |
226 | | std::vector<int> m_mainTextZonesList; |
227 | | //! the list of fonts |
228 | | std::vector<Font> m_fontsList; |
229 | | //! the list of paragraph |
230 | | std::vector<Paragraph> m_paragraphsList; |
231 | | //! a flag to know if we send endnote or footnote |
232 | | bool m_endNote; |
233 | | //! the footnote positions ( list of beginPos, endPos) |
234 | | std::vector<MWAWVec2l> m_footnotesList; |
235 | | //! the text correspondance zone ( filepos, plc ) |
236 | | std::multimap<long, PLC> m_plcMap; |
237 | | |
238 | | int m_actPage /** the actual page */, m_numPages /** the number of page of the final document */; |
239 | | /** the list of header id which corresponds to each page */ |
240 | | std::vector<int> m_headersId; |
241 | | /** the list of footer id which corresponds to each page */ |
242 | | std::vector<int> m_footersId; |
243 | | }; |
244 | | |
245 | | //////////////////////////////////////// |
246 | | //! Internal: the subdocument of a MsWrdParser |
247 | | class SubDocument final : public MWAWSubDocument |
248 | | { |
249 | | public: |
250 | | //! constructor for footnote, header |
251 | | SubDocument(MsWrd1Parser &pars, MWAWInputStreamPtr const &input, MWAWEntry const &position) |
252 | 92.0k | : MWAWSubDocument(&pars, input, position) |
253 | 92.0k | { |
254 | 92.0k | } |
255 | | |
256 | | //! destructor |
257 | 0 | ~SubDocument() final {} |
258 | | |
259 | | //! operator!= |
260 | | bool operator!=(MWAWSubDocument const &doc) const final |
261 | 0 | { |
262 | 0 | return MWAWSubDocument::operator!=(doc); |
263 | 0 | } |
264 | | |
265 | | //! the parser function |
266 | | void parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType type) final; |
267 | | |
268 | | protected: |
269 | | }; |
270 | | |
271 | | void SubDocument::parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType) |
272 | 91.3k | { |
273 | 91.3k | if (!listener.get()) { |
274 | 0 | MWAW_DEBUG_MSG(("MsWrd1ParserInternal::SubDocument::parse: no listener\n")); |
275 | 0 | return; |
276 | 0 | } |
277 | 91.3k | auto *parser=dynamic_cast<MsWrd1Parser *>(m_parser); |
278 | 91.3k | if (!parser) { |
279 | 0 | MWAW_DEBUG_MSG(("MsWrd1ParserInternal::SubDocument::parse: no parser\n")); |
280 | 0 | return; |
281 | 0 | } |
282 | | |
283 | 91.3k | if (!m_zone.valid()) { |
284 | 14.1k | listener->insertChar(' '); |
285 | 14.1k | return; |
286 | 14.1k | } |
287 | 77.1k | long pos = m_input->tell(); |
288 | 77.1k | parser->sendText(m_zone); |
289 | 77.1k | m_input->seek(pos, librevenge::RVNG_SEEK_SET); |
290 | 77.1k | } |
291 | | } |
292 | | |
293 | | |
294 | | //////////////////////////////////////////////////////////// |
295 | | // constructor/destructor, ... |
296 | | //////////////////////////////////////////////////////////// |
297 | | MsWrd1Parser::MsWrd1Parser(MWAWInputStreamPtr const &input, MWAWRSRCParserPtr const &rsrcParser, MWAWHeader *header) |
298 | 36.2k | : MWAWTextParser(input, rsrcParser, header) |
299 | 36.2k | , m_state() |
300 | 36.2k | { |
301 | 36.2k | init(); |
302 | 36.2k | } |
303 | | |
304 | | MsWrd1Parser::~MsWrd1Parser() |
305 | 36.2k | { |
306 | 36.2k | } |
307 | | |
308 | | void MsWrd1Parser::init() |
309 | 36.2k | { |
310 | 36.2k | resetTextListener(); |
311 | 36.2k | setAsciiName("main-1"); |
312 | | |
313 | 36.2k | m_state.reset(new MsWrd1ParserInternal::State); |
314 | | |
315 | | // reduce the margin (in case, the page is not defined) |
316 | 36.2k | getPageSpan().setMargins(0.1); |
317 | 36.2k | } |
318 | | |
319 | | //////////////////////////////////////////////////////////// |
320 | | // new page |
321 | | //////////////////////////////////////////////////////////// |
322 | | void MsWrd1Parser::newPage(int number) |
323 | 172k | { |
324 | 172k | if (number <= m_state->m_actPage || number > m_state->m_numPages) |
325 | 145k | return; |
326 | | |
327 | 55.5k | while (m_state->m_actPage < number) { |
328 | 28.4k | m_state->m_actPage++; |
329 | 28.4k | if (!getTextListener() || m_state->m_actPage == 1) |
330 | 1.63k | continue; |
331 | 26.7k | getTextListener()->insertBreak(MWAWTextListener::PageBreak); |
332 | 26.7k | } |
333 | 27.1k | } |
334 | | |
335 | | void MsWrd1Parser::removeLastCharIfEOL(MWAWEntry &entry) |
336 | 92.9k | { |
337 | 92.9k | if (!entry.valid()) return; |
338 | 78.9k | MWAWInputStreamPtr input = getInput(); |
339 | 78.9k | long actPos = input->tell(); |
340 | 78.9k | input->seek(entry.end()-1, librevenge::RVNG_SEEK_SET); |
341 | 78.9k | if (input->readLong(1)==0xd) |
342 | 8.74k | entry.setLength(entry.length()-1); |
343 | 78.9k | input->seek(actPos, librevenge::RVNG_SEEK_SET); |
344 | 78.9k | } |
345 | | //////////////////////////////////////////////////////////// |
346 | | // the parser |
347 | | //////////////////////////////////////////////////////////// |
348 | | void MsWrd1Parser::parse(librevenge::RVNGTextInterface *docInterface) |
349 | 10.8k | { |
350 | 10.8k | if (!getInput().get() || !checkHeader(nullptr)) throw(libmwaw::ParseException()); |
351 | 10.8k | bool ok = true; |
352 | 10.8k | try { |
353 | | // create the asciiFile |
354 | 10.8k | ascii().setStream(getInput()); |
355 | 10.8k | ascii().open(asciiName()); |
356 | 10.8k | checkHeader(nullptr); |
357 | 10.8k | ok = createZones(); |
358 | 10.8k | if (ok) { |
359 | 10.8k | createDocument(docInterface); |
360 | 10.8k | sendMain(); |
361 | 10.8k | } |
362 | | |
363 | 10.8k | ascii().reset(); |
364 | 10.8k | } |
365 | 10.8k | catch (...) { |
366 | 0 | MWAW_DEBUG_MSG(("MsWrd1Parser::parse: exception catched when parsing\n")); |
367 | 0 | ok = false; |
368 | 0 | } |
369 | | |
370 | 10.8k | resetTextListener(); |
371 | 10.8k | if (!ok) throw(libmwaw::ParseException()); |
372 | 10.8k | } |
373 | | |
374 | | //////////////////////////////////////////////////////////// |
375 | | // send the main zone |
376 | | //////////////////////////////////////////////////////////// |
377 | | void MsWrd1Parser::sendMain() |
378 | 10.8k | { |
379 | 14.2k | for (auto id : m_state->m_mainTextZonesList) { |
380 | 14.2k | if (id < 0 || id >= int(m_state->m_textZonesList.size())) |
381 | 0 | continue; |
382 | 14.2k | MWAWEntry entry; |
383 | 14.2k | entry.setBegin(m_state->m_textZonesList[size_t(id)][0]); |
384 | 14.2k | entry.setEnd(m_state->m_textZonesList[size_t(id)][1]); |
385 | 14.2k | sendText(entry, true); |
386 | 14.2k | } |
387 | | // maybe need if we have no text ; if not, nobody will see it |
388 | 10.8k | if (getTextListener()) |
389 | 10.8k | getTextListener()->insertChar(' '); |
390 | 10.8k | } |
391 | | |
392 | | //////////////////////////////////////////////////////////// |
393 | | // create the document |
394 | | //////////////////////////////////////////////////////////// |
395 | | void MsWrd1Parser::createDocument(librevenge::RVNGTextInterface *documentInterface) |
396 | 10.8k | { |
397 | 10.8k | if (!documentInterface) return; |
398 | 10.8k | if (getTextListener()) { |
399 | 0 | MWAW_DEBUG_MSG(("MsWrd1Parser::createDocument: listener already exist\n")); |
400 | 0 | return; |
401 | 0 | } |
402 | | |
403 | | // update the page |
404 | 10.8k | m_state->m_actPage = 0; |
405 | | // create the page list |
406 | 10.8k | std::vector<MWAWPageSpan> pageList; |
407 | 10.8k | auto numHeaders=int(m_state->m_headersId.size()); |
408 | 10.8k | auto numFooters=int(m_state->m_footersId.size()); |
409 | 60.0k | for (int i = 0; i <= m_state->m_numPages;) { |
410 | 49.2k | int numSim[2]= {1,1}; |
411 | 49.2k | MWAWPageSpan ps(getPageSpan()); |
412 | 49.2k | while (i < numHeaders) { |
413 | 38.3k | int id = m_state->m_headersId[size_t(i)]; |
414 | 38.3k | if (id < 0 || id >= int(m_state->m_textZonesList.size())) |
415 | 28.7k | break; |
416 | 9.62k | MWAWEntry entry; |
417 | 9.62k | entry.setBegin(m_state->m_textZonesList[size_t(id)][0]); |
418 | 9.62k | entry.setEnd(m_state->m_textZonesList[size_t(id)][1]); |
419 | 9.62k | removeLastCharIfEOL(entry); |
420 | 9.62k | if (!entry.valid()) break; |
421 | 9.20k | MWAWHeaderFooter header(MWAWHeaderFooter::HEADER, MWAWHeaderFooter::ALL); |
422 | 9.20k | header.m_subDocument.reset |
423 | 9.20k | (new MsWrd1ParserInternal::SubDocument(*this, getInput(), entry)); |
424 | 9.20k | ps.setHeaderFooter(header); |
425 | 9.20k | int j = i+1; |
426 | 87.8k | while (j < numHeaders && m_state->m_headersId[size_t(j)]==id) { |
427 | 78.6k | numSim[0]++; |
428 | 78.6k | j++; |
429 | 78.6k | } |
430 | 9.20k | break; |
431 | 9.62k | } |
432 | 49.2k | while (i < int(numFooters)) { |
433 | 38.3k | int id = m_state->m_footersId[size_t(i)]; |
434 | 38.3k | if (id < 0 || id >= int(m_state->m_textZonesList.size())) |
435 | 27.6k | break; |
436 | 10.7k | MWAWEntry entry; |
437 | 10.7k | entry.setBegin(m_state->m_textZonesList[size_t(id)][0]); |
438 | 10.7k | entry.setEnd(m_state->m_textZonesList[size_t(id)][1]); |
439 | 10.7k | removeLastCharIfEOL(entry); |
440 | 10.7k | if (!entry.valid()) break; |
441 | 10.3k | MWAWHeaderFooter footer(MWAWHeaderFooter::FOOTER, MWAWHeaderFooter::ALL); |
442 | 10.3k | footer.m_subDocument.reset |
443 | 10.3k | (new MsWrd1ParserInternal::SubDocument(*this, getInput(), entry)); |
444 | 10.3k | ps.setHeaderFooter(footer); |
445 | 10.3k | int j = i+1; |
446 | 163k | while (j < numFooters && m_state->m_footersId[size_t(j)]==id) { |
447 | 153k | numSim[1]++; |
448 | 153k | j++; |
449 | 153k | } |
450 | 10.3k | break; |
451 | 10.7k | } |
452 | 49.2k | if (numSim[1] < numSim[0]) numSim[0]=numSim[1]; |
453 | 49.2k | if (numSim[0] < 1) numSim[0]=1; |
454 | 49.2k | ps.setPageSpan(numSim[0]); |
455 | 49.2k | i+=numSim[0]; |
456 | 49.2k | pageList.push_back(ps); |
457 | 49.2k | } |
458 | | |
459 | | // |
460 | 10.8k | MWAWTextListenerPtr listen(new MWAWTextListener(*getParserState(), pageList, documentInterface)); |
461 | 10.8k | setTextListener(listen); |
462 | 10.8k | listen->startDocument(); |
463 | 10.8k | } |
464 | | |
465 | | |
466 | | //////////////////////////////////////////////////////////// |
467 | | // Intermediate level |
468 | | //////////////////////////////////////////////////////////// |
469 | | |
470 | | // create the different zones |
471 | | bool MsWrd1Parser::createZones() |
472 | 10.8k | { |
473 | 10.8k | libmwaw::DebugStream f; |
474 | 10.8k | if (m_state->m_eot < 0x80) return false; |
475 | | |
476 | 10.8k | ascii().addPos(0x80); |
477 | 10.8k | ascii().addNote("TextContent"); |
478 | | |
479 | 10.8k | ascii().addPos(m_state->m_eot); |
480 | 10.8k | ascii().addNote("_"); |
481 | | |
482 | 10.8k | MWAWInputStreamPtr input = getInput(); |
483 | 67.4k | for (int z = 5; z >= 0; z--) { |
484 | 59.0k | if (m_state->m_fileZonesLimit[z] == m_state->m_fileZonesLimit[z+1]) |
485 | 37.0k | continue; |
486 | 21.9k | if (!input->checkPosition(m_state->m_fileZonesLimit[z+1]*0x80) || |
487 | 19.5k | m_state->m_fileZonesLimit[z] > m_state->m_fileZonesLimit[z+1]) { |
488 | 2.44k | f.str(""); |
489 | 2.44k | f << "Entries(Zone" << z << "):###"; |
490 | 2.44k | MWAW_DEBUG_MSG(("MsWrd1Parser::createZones: zone %d is too long\n",z)); |
491 | 2.44k | ascii().addPos(m_state->m_fileZonesLimit[z]*0x80); |
492 | 2.44k | ascii().addNote(f.str().c_str()); |
493 | 2.44k | break; |
494 | 2.44k | } |
495 | 19.5k | MWAWVec2i limit(m_state->m_fileZonesLimit[z],m_state->m_fileZonesLimit[z+1]); |
496 | 19.5k | bool done = false; |
497 | 19.5k | switch (z) { |
498 | 4.35k | case 0: |
499 | 8.83k | case 1: |
500 | 8.83k | done = readPLC(limit,z); |
501 | 8.83k | break; |
502 | 3.14k | case 2: |
503 | 3.14k | done = readFootnoteCorrespondance(limit); |
504 | 3.14k | break; |
505 | 2.13k | case 3: |
506 | 2.13k | done = readDocInfo(limit); |
507 | 2.13k | break; |
508 | 2.69k | case 4: |
509 | 2.69k | done = readZones(limit); |
510 | 2.69k | break; |
511 | 2.72k | case 5: |
512 | 2.72k | done = readPageBreak(limit); |
513 | 2.72k | break; |
514 | 0 | default: |
515 | 0 | break; |
516 | 19.5k | } |
517 | 19.5k | if (done) continue; |
518 | 22.6k | for (int p = m_state->m_fileZonesLimit[z], i=0; p < m_state->m_fileZonesLimit[z+1]; p++, i++) { |
519 | 17.6k | f.str(""); |
520 | 17.6k | f << "Entries(Zone" << z << ")[" << i << "]:"; |
521 | 17.6k | ascii().addPos(p*0x80); |
522 | 17.6k | ascii().addNote(f.str().c_str()); |
523 | 17.6k | } |
524 | 5.01k | ascii().addPos(m_state->m_fileZonesLimit[z+1]*0x80); |
525 | 5.01k | ascii().addNote("_"); |
526 | 5.01k | } |
527 | 10.8k | prepareTextZones(); |
528 | 10.8k | return true; |
529 | 10.8k | } |
530 | | |
531 | | // try to read retrieve the header/footer zones ... |
532 | | bool MsWrd1Parser::prepareTextZones() |
533 | 10.8k | { |
534 | 10.8k | m_state->m_numPages = 1; |
535 | 10.8k | m_state->m_textZonesList.resize(0); |
536 | 10.8k | m_state->m_mainTextZonesList.resize(0); |
537 | 10.8k | m_state->m_headersId.resize(0); |
538 | 10.8k | m_state->m_footersId.resize(0); |
539 | 10.8k | long endMain = m_state->m_eot; |
540 | 10.8k | for (auto const &footnote : m_state->m_footnotesList) { |
541 | 9.71k | long pos = footnote[0]; |
542 | 9.71k | if (pos >= 0x80 && pos < endMain) |
543 | 1.93k | endMain = pos; |
544 | 9.71k | } |
545 | 10.8k | if (endMain < 0x80) { |
546 | 0 | MWAW_DEBUG_MSG(("MsWrd1Parser::sendText: oops problem computing the limit of the main section")); |
547 | 0 | m_state->m_textZonesList.push_back(MWAWVec2l(0x80, m_state->m_eot)); |
548 | 0 | m_state->m_mainTextZonesList.push_back(0); |
549 | 0 | return false; |
550 | 0 | } |
551 | | |
552 | 10.8k | auto plcIt = m_state->m_plcMap.begin(); |
553 | 10.8k | long pos = 0x80, prevMainPos=pos; |
554 | 10.8k | int actPage = 1; |
555 | 10.8k | int actType = 0; |
556 | 10.8k | MWAWVec2i headerId(-1, -1), footerId(-1, -1); |
557 | 10.8k | int firstHeaderId=-1, firstFooterId=-1; |
558 | 749k | while (pos < endMain) { |
559 | 738k | int newType = 0; |
560 | 738k | if (plcIt == m_state->m_plcMap.end() || plcIt->first>=endMain) { |
561 | 9.28k | pos = endMain; |
562 | 9.28k | newType = -1; |
563 | 9.28k | } |
564 | 729k | else { |
565 | 729k | pos = plcIt->first; |
566 | 729k | MsWrd1ParserInternal::PLC const &plc = plcIt++->second; |
567 | 729k | if (plc.m_type==MsWrd1ParserInternal::PAGE && pos!=0x80) { |
568 | 27.7k | if (actPage> int(m_state->m_headersId.size())) { |
569 | 26.7k | m_state->m_headersId.resize(size_t(actPage), -1); |
570 | 26.7k | m_state->m_headersId[size_t(actPage)-1] = headerId[(actPage%2)]; |
571 | 26.7k | } |
572 | 27.7k | if (actPage> int(m_state->m_footersId.size())) { |
573 | 26.9k | m_state->m_footersId.resize(size_t(actPage), -1); |
574 | 26.9k | m_state->m_footersId[size_t(actPage)-1] = footerId[(actPage%2)]; |
575 | 26.9k | } |
576 | 27.7k | actPage++; |
577 | 27.7k | } |
578 | 729k | if (plc.m_type!=MsWrd1ParserInternal::RULER) continue; |
579 | 165k | if (plc.m_id >= 0 && plc.m_id < int(m_state->m_paragraphsList.size())) |
580 | 33.8k | newType = (m_state->m_paragraphsList[size_t(plc.m_id)].m_type2>>4); |
581 | 165k | if (newType == actType) |
582 | 148k | continue; |
583 | 165k | } |
584 | 25.7k | if (pos==prevMainPos) { |
585 | 3.69k | actType = newType; |
586 | 3.69k | continue; |
587 | 3.69k | } |
588 | | |
589 | 22.0k | auto id = int(m_state->m_textZonesList.size()); |
590 | 22.0k | m_state->m_textZonesList.push_back(MWAWVec2l(prevMainPos, pos)); |
591 | 22.0k | prevMainPos=pos; |
592 | 22.0k | if (actType==0) { |
593 | 14.2k | m_state->m_mainTextZonesList.push_back(id); |
594 | 14.2k | actType = newType; |
595 | 14.2k | continue; |
596 | 14.2k | } |
597 | 7.83k | if (actType&1) { |
598 | 3.06k | if (actType&2) footerId[1]=id; |
599 | 3.06k | if (actType&4) footerId[0]=id; |
600 | 3.06k | if (actType&8) firstFooterId=id; |
601 | 3.06k | m_state->m_footersId.resize(size_t(actPage), -1); |
602 | 3.06k | m_state->m_footersId[size_t(actPage)-1] = |
603 | 3.06k | (actPage==1 && firstFooterId >= 0) ? firstFooterId : |
604 | 3.06k | (actPage%2) ? footerId[1] : footerId[0]; |
605 | 3.06k | } |
606 | 4.76k | else { |
607 | 4.76k | if (actType&2) headerId[0]=id; |
608 | 4.76k | if (actType&4) headerId[1]=id; |
609 | 4.76k | if (actType&8) firstHeaderId=id; |
610 | 4.76k | m_state->m_headersId.resize(size_t(actPage), -1); |
611 | 4.76k | m_state->m_headersId[size_t(actPage)-1] = |
612 | 4.76k | (actPage==1 && firstHeaderId >= 0) ? firstHeaderId : |
613 | 4.76k | (actPage%2) ? headerId[1] : headerId[0]; |
614 | 4.76k | } |
615 | 7.83k | actType = newType; |
616 | 7.83k | } |
617 | 10.8k | if (actPage> int(m_state->m_headersId.size())) { |
618 | 9.80k | m_state->m_headersId.resize(size_t(actPage), -1); |
619 | 9.80k | m_state->m_headersId[size_t(actPage)-1] = headerId[(actPage%2)]; |
620 | 9.80k | } |
621 | 10.8k | if (actPage> int(m_state->m_footersId.size())) { |
622 | 9.83k | m_state->m_footersId.resize(size_t(actPage), -1); |
623 | 9.83k | m_state->m_footersId[size_t(actPage)-1] = footerId[(actPage%2)]; |
624 | 9.83k | } |
625 | 10.8k | m_state->m_numPages = actPage; |
626 | 10.8k | return true; |
627 | 10.8k | } |
628 | | |
629 | | //////////////////////////////////////////////////////////// |
630 | | // try to read the different zones |
631 | | //////////////////////////////////////////////////////////// |
632 | | |
633 | | // read the character property |
634 | | bool MsWrd1Parser::readFont(long fPos, MsWrd1ParserInternal::Font &font) |
635 | 75.5k | { |
636 | 75.5k | font = MsWrd1ParserInternal::Font(); |
637 | 75.5k | libmwaw::DebugStream f; |
638 | 75.5k | MWAWInputStreamPtr input = getInput(); |
639 | 75.5k | input->seek(fPos, librevenge::RVNG_SEEK_SET); |
640 | 75.5k | auto sz = static_cast<int>(input->readLong(1)); |
641 | 75.5k | if (sz < 1 || sz > 0x7f || !input->checkPosition(fPos+1+sz)) { |
642 | 19.6k | MWAW_DEBUG_MSG(("MsWrd1Parser::readFont: the zone size seems bad\n")); |
643 | 19.6k | return false; |
644 | 19.6k | } |
645 | 55.8k | font.m_type = static_cast<int>(input->readULong(1)); |
646 | 55.8k | int val; |
647 | 55.8k | uint32_t flags=0; |
648 | 55.8k | if (sz >= 2) { |
649 | 49.2k | val = static_cast<int>(input->readULong(1)); |
650 | 49.2k | if (val & 0x80) flags |= MWAWFont::boldBit; |
651 | 49.2k | if (val & 0x40) flags |= MWAWFont::italicBit; |
652 | 49.2k | if (val & 0x3f) |
653 | 46.1k | font.m_font.setId((val & 0x3f)); |
654 | 49.2k | } |
655 | 55.8k | if (sz >= 3) { |
656 | 41.5k | val = static_cast<int>(input->readULong(1)); |
657 | 41.5k | if (val) font.m_font.setSize(float(val)/2.f); |
658 | 41.5k | } |
659 | 55.8k | if (sz >= 4) { |
660 | 39.1k | val = static_cast<int>(input->readULong(1)); |
661 | 39.1k | if (val & 0x80) font.m_font.setUnderlineStyle(MWAWFont::Line::Simple); |
662 | 39.1k | switch ((val&0xc)>>2) { |
663 | 26.0k | case 0: |
664 | 26.0k | break; |
665 | 3.26k | case 3: |
666 | 3.26k | flags |= MWAWFont::uppercaseBit; |
667 | 3.26k | break; |
668 | 9.87k | default: |
669 | 9.87k | f << "#capBits=" << int((val&0xc)>>2) << ","; |
670 | 39.1k | } |
671 | | // find also &2 for footnote |
672 | 39.1k | if (val & 0x73) |
673 | 24.7k | f << "#flags1=" << std::hex << (val & 0x73) << std::dec << ","; |
674 | 39.1k | } |
675 | 55.8k | if (sz >= 5) { |
676 | 35.5k | val = static_cast<int>(input->readULong(1)); |
677 | 35.5k | if (val & 0x10) flags |= MWAWFont::embossBit; |
678 | 35.5k | if (val & 0x8) flags |= MWAWFont::shadowBit; |
679 | 35.5k | if (val & 0xe7) |
680 | 11.9k | f << "#flags2=" << std::hex << (val & 0xe7) << std::dec << ","; |
681 | 35.5k | } |
682 | 55.8k | if (sz >= 6) { // vdepl |
683 | 32.1k | val = static_cast<int>(input->readLong(1)); |
684 | 32.1k | if (val > 0) font.m_font.set(MWAWFont::Script::super100()); |
685 | 5.96k | else if (val < 0) font.m_font.set(MWAWFont::Script::sub100()); |
686 | 32.1k | } |
687 | 55.8k | if (sz >= 7) { |
688 | 23.9k | f << "###"; |
689 | 23.9k | ascii().addDelimiter(input->tell(),'|'); |
690 | 23.9k | } |
691 | 55.8k | font.m_font.setFlags(flags); |
692 | 55.8k | font.m_extras = f.str(); |
693 | | |
694 | 55.8k | return true; |
695 | 55.8k | } |
696 | | |
697 | | /* read the paragraph property */ |
698 | | bool MsWrd1Parser::readParagraph(long fPos, MsWrd1ParserInternal::Paragraph ¶) |
699 | 62.3k | { |
700 | 62.3k | para = MsWrd1ParserInternal::Paragraph(); |
701 | 62.3k | libmwaw::DebugStream f; |
702 | 62.3k | MWAWInputStreamPtr input = getInput(); |
703 | 62.3k | input->seek(fPos, librevenge::RVNG_SEEK_SET); |
704 | 62.3k | auto sz = static_cast<int>(input->readLong(1)); |
705 | 62.3k | if (sz < 1 || sz > 0x7f || !input->checkPosition(fPos+1+sz)) { |
706 | 9.93k | MWAW_DEBUG_MSG(("MsWrd1Parser::readParagraph: the zone size seems bad\n")); |
707 | 9.93k | return false; |
708 | 9.93k | } |
709 | 52.4k | para.m_type = static_cast<int>(input->readULong(1)); |
710 | 52.4k | int val; |
711 | 52.4k | if (sz >= 2) { |
712 | 50.6k | val = static_cast<int>(input->readULong(1)); |
713 | 50.6k | switch (val>>6) { |
714 | 32.8k | case 0: |
715 | 32.8k | break; // left |
716 | 8.08k | case 1: |
717 | 8.08k | para.m_justify = MWAWParagraph::JustificationCenter; |
718 | 8.08k | break; |
719 | 1.99k | case 2: |
720 | 1.99k | para.m_justify = MWAWParagraph::JustificationRight; |
721 | 1.99k | break; |
722 | 7.66k | case 3: |
723 | 7.66k | para.m_justify = MWAWParagraph::JustificationFull; |
724 | 7.66k | break; |
725 | 0 | default: |
726 | 0 | break; |
727 | 50.6k | } |
728 | 50.6k | if (val & 0x10) f << "dontbreak[para],"; |
729 | 50.6k | if (val & 0x20) f << "dontbreak[line],"; |
730 | 50.6k | if (val & 0xf) |
731 | 20.4k | f << "#justify=" << std::hex << (val & 0xf) << std::dec << ","; |
732 | 50.6k | } |
733 | 52.4k | if (sz >= 4) { // find always 0 here |
734 | 41.7k | val = static_cast<int>(input->readLong(2)); |
735 | 41.7k | if (val) f << "#f0=" << val << ","; |
736 | 41.7k | } |
737 | 52.4k | if (sz >= 6) { |
738 | 39.8k | val = static_cast<int>(input->readLong(2)); |
739 | 39.8k | if (val) |
740 | 34.8k | para.m_margins[2] = double(val)/1440.0; |
741 | 39.8k | } |
742 | 52.4k | if (sz >= 8) { |
743 | 37.6k | val = static_cast<int>(input->readLong(2)); |
744 | 37.6k | if (val) |
745 | 32.5k | para.m_margins[0] = double(val)/1440.0; |
746 | 37.6k | } |
747 | 52.4k | if (sz >= 10) { |
748 | 34.2k | val = static_cast<int>(input->readLong(2)); |
749 | 34.2k | if (val && !para.m_margins[0].isSet()) |
750 | 599 | para.m_margins[1] = double(val)/1440.0; |
751 | 33.6k | else if (val) |
752 | 24.1k | para.m_margins[1] = para.m_margins[0].get()+double(val)/1440.0; |
753 | 34.2k | } |
754 | 52.4k | if (sz >= 12) { |
755 | 34.1k | val = static_cast<int>(input->readLong(2)); |
756 | 34.1k | if (val) |
757 | 25.3k | para.setInterline(double(val)/1440.0, librevenge::RVNG_INCH); |
758 | 34.1k | } |
759 | 52.4k | if (sz >= 14) { |
760 | 31.7k | val = static_cast<int>(input->readLong(2)); |
761 | 31.7k | if (val) |
762 | 24.2k | para.m_spacings[1] = double(val)/1440.0; |
763 | 31.7k | } |
764 | 52.4k | if (sz >= 16) { |
765 | 30.7k | val = static_cast<int>(input->readLong(2)); |
766 | 30.7k | if (val) |
767 | 23.9k | para.m_spacings[2] = double(val)/1440.0; |
768 | 30.7k | } |
769 | 52.4k | if (sz >= 17) |
770 | 16.6k | para.m_type2 = static_cast<int>(input->readULong(1)); |
771 | | // checkme: not sure what is the exact decomposition of the following |
772 | 52.4k | if (sz >= 22) { // find always 0 here |
773 | 65.4k | for (int i = 0; i < 5; i++) { |
774 | 54.5k | val = static_cast<int>(input->readLong(1)); |
775 | 54.5k | if (val) f << "#f" << i+1 << "=" << val << ","; |
776 | 54.5k | } |
777 | 10.9k | } |
778 | 52.4k | if (sz >= 26) { |
779 | 10.5k | int numTabs = (sz-26)/4; |
780 | 153k | for (int i = 0; i < numTabs; i++) { |
781 | 142k | MWAWTabStop newTab; |
782 | 142k | newTab.m_position = double(input->readLong(2))/1440.; |
783 | 142k | auto flags = static_cast<int>(input->readULong(1)); |
784 | 142k | switch ((flags>>5)&3) { |
785 | 83.8k | case 0: |
786 | 83.8k | break; |
787 | 15.6k | case 1: |
788 | 15.6k | newTab.m_alignment = MWAWTabStop::CENTER; |
789 | 15.6k | break; |
790 | 8.17k | case 2: |
791 | 8.17k | newTab.m_alignment = MWAWTabStop::RIGHT; |
792 | 8.17k | break; |
793 | 35.0k | case 3: |
794 | 35.0k | newTab.m_alignment = MWAWTabStop::DECIMAL; |
795 | 35.0k | break; |
796 | 0 | default: |
797 | 0 | break; |
798 | 142k | } |
799 | 142k | switch ((flags>>2)&3) { |
800 | 71.8k | case 0: |
801 | 71.8k | break; |
802 | 20.6k | case 1: |
803 | 20.6k | newTab.m_leaderCharacter = '.'; |
804 | 20.6k | break; |
805 | 16.6k | case 2: |
806 | 16.6k | newTab.m_leaderCharacter = '-'; |
807 | 16.6k | break; |
808 | 33.6k | case 3: |
809 | 33.6k | newTab.m_leaderCharacter = '_'; |
810 | 33.6k | break; |
811 | 0 | default: |
812 | 0 | break; |
813 | 142k | } |
814 | 142k | if (flags & 0x93) |
815 | 93.5k | f << "#tabs" << i << "[fl1=" << std::hex << (flags & 0x93) << std::dec << ","; |
816 | 142k | val = static_cast<int>(input->readULong(1)); |
817 | 142k | if (val) |
818 | 104k | f << "#tabs" << i << "[fl2=" << std::hex << val << std::dec << ","; |
819 | 142k | para.m_tabs->push_back(newTab); |
820 | 142k | } |
821 | 10.5k | } |
822 | 52.4k | if (input->tell() != fPos+1+sz) |
823 | 17.2k | ascii().addDelimiter(input->tell(), '|'); |
824 | 52.4k | para.m_extra = f.str(); |
825 | 52.4k | return true; |
826 | 52.4k | } |
827 | | |
828 | | /* read the page break separation */ |
829 | | bool MsWrd1Parser::readPageBreak(MWAWVec2i limits) |
830 | 2.72k | { |
831 | 2.72k | MWAWInputStreamPtr input = getInput(); |
832 | 2.72k | if (limits[1] <= limits[0] || !input->checkPosition(limits[1]*0x80)) { |
833 | 0 | MWAW_DEBUG_MSG(("MsWrd1Parser::readPageBreak: the zone is not well defined\n")); |
834 | 0 | return false; |
835 | 0 | } |
836 | 2.72k | libmwaw::DebugStream f; |
837 | 2.72k | long pos = limits[0]*0x80; |
838 | 2.72k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
839 | 2.72k | f << "Entries(PageBreak):"; |
840 | 2.72k | auto N = static_cast<int>(input->readULong(2)); |
841 | 2.72k | f << "N=" << N << ","; |
842 | 2.72k | if (N==0 || 4+6*N > (limits[1]-limits[0])*0x80) { |
843 | 906 | MWAW_DEBUG_MSG(("MsWrd1Parser::readPageBreak: the number of element seems odds\n")); |
844 | 906 | f << "###"; |
845 | 906 | ascii().addPos(pos); |
846 | 906 | ascii().addNote(f.str().c_str()); |
847 | 906 | return false; |
848 | 906 | } |
849 | 1.81k | long val = static_cast<int>(input->readULong(2)); // 1|a |
850 | 1.81k | f << "unkn=" << val << ","; |
851 | 1.81k | MsWrd1ParserInternal::PLC plc(MsWrd1ParserInternal::PAGE); |
852 | 663k | for (int i = 0; i < N; i++) { |
853 | 661k | auto pg = static_cast<int>(input->readULong(2)); |
854 | 661k | long textPos = long(input->readULong(4))+0x80; |
855 | 661k | f << "Page" << i << "=" << std::hex << textPos << std::dec; |
856 | 661k | if (pg != i+1) f << "[page=" << pg << "]"; |
857 | 661k | if (textPos < m_state->m_eot) { |
858 | 175k | plc.m_id = pg; |
859 | 175k | m_state->m_plcMap.insert |
860 | 175k | (std::multimap<long, MsWrd1ParserInternal::PLC>::value_type(textPos, plc)); |
861 | 175k | } |
862 | 486k | else if (i != N-1) |
863 | 485k | f << "###"; |
864 | 661k | f << ","; |
865 | 661k | } |
866 | 1.81k | if (input->tell() != limits[1]*0x80) |
867 | 1.81k | ascii().addDelimiter(input->tell(),'|'); |
868 | 1.81k | ascii().addPos(pos); |
869 | 1.81k | ascii().addNote(f.str().c_str()); |
870 | 1.81k | return true; |
871 | 2.72k | } |
872 | | |
873 | | /* read the footnote zone */ |
874 | | bool MsWrd1Parser::readFootnoteCorrespondance(MWAWVec2i limits) |
875 | 3.14k | { |
876 | 3.14k | MWAWInputStreamPtr input = getInput(); |
877 | 3.14k | if (limits[1] <= limits[0] || !input->checkPosition(limits[1]*0x80)) { |
878 | 0 | MWAW_DEBUG_MSG(("MsWrd1Parser::readFootnoteCorrespondance: the zone is not well defined\n")); |
879 | 0 | return false; |
880 | 0 | } |
881 | 3.14k | libmwaw::DebugStream f; |
882 | | |
883 | 3.14k | long textEnd = m_state->m_eot; |
884 | 3.14k | MsWrd1ParserInternal::PLC plc(MsWrd1ParserInternal::FOOTNOTE); |
885 | 3.14k | long pos = limits[0]*0x80; |
886 | 3.14k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
887 | 3.14k | f << "Entries(Footnote):"; |
888 | 3.14k | auto N = static_cast<int>(input->readULong(2)); |
889 | 3.14k | auto N1 = static_cast<int>(input->readULong(2)); |
890 | 3.14k | f << "N=" << N << ","; |
891 | 3.14k | if (N!=N1) f << "N1=" << N1 << ","; |
892 | 3.14k | if (N!=N1 || N==0 || 4+8*N > (limits[1]-limits[0])*0x80) { |
893 | 1.96k | MWAW_DEBUG_MSG(("MsWrd1Parser::readFootnoteCorrespondance: the number of element seems odds\n")); |
894 | 1.96k | f << "###"; |
895 | 1.96k | ascii().addPos(pos); |
896 | 1.96k | ascii().addNote(f.str().c_str()); |
897 | 1.96k | return false; |
898 | 1.96k | } |
899 | 1.18k | std::map<long, int> footnoteMap; |
900 | 207k | for (int i = 0; i < N; i++) { |
901 | 207k | long textPos = long(input->readULong(4))+0x80; |
902 | 207k | long notePos = long(input->readULong(4))+0x80; |
903 | 207k | bool ok = textPos <= textEnd && notePos <= textEnd; |
904 | 207k | f << "Fn" << i << ":" << std::hex << textPos << "<->" << notePos << std::dec << ","; |
905 | 207k | if (!ok) { |
906 | 143k | if (i==N-1) break; |
907 | 142k | f << "###"; |
908 | 142k | continue; |
909 | 143k | } |
910 | 63.5k | plc.m_id = int(footnoteMap.size()); |
911 | 63.5k | footnoteMap[notePos]=plc.m_id; |
912 | 63.5k | m_state->m_plcMap.insert |
913 | 63.5k | (std::multimap<long, MsWrd1ParserInternal::PLC>::value_type(textPos, plc)); |
914 | 63.5k | m_state->m_plcMap.insert |
915 | 63.5k | (std::multimap<long, MsWrd1ParserInternal::PLC>::value_type(notePos, plc)); |
916 | 63.5k | } |
917 | 1.18k | m_state->m_footnotesList.resize(footnoteMap.size(),MWAWVec2l(0,0)); |
918 | 10.3k | for (auto fIt=footnoteMap.begin(); fIt!=footnoteMap.end();) { |
919 | 9.20k | MWAWVec2l fPos; |
920 | 9.20k | fPos[0] = fIt->first; |
921 | 9.20k | int id = fIt++->second; |
922 | 9.20k | fPos[1] = fIt==footnoteMap.end() ? m_state->m_eot : fIt->first; |
923 | 9.20k | if (id >= int(m_state->m_footnotesList.size())) |
924 | 510 | m_state->m_footnotesList.resize(size_t(id)+1,MWAWVec2l(0,0)); |
925 | 9.20k | m_state->m_footnotesList[size_t(id)]=fPos; |
926 | 9.20k | } |
927 | 1.18k | ascii().addDelimiter(input->tell(),'|'); |
928 | 1.18k | ascii().addPos(pos); |
929 | 1.18k | ascii().addNote(f.str().c_str()); |
930 | | |
931 | 1.18k | return true; |
932 | 3.14k | } |
933 | | |
934 | | /* read the zone4: a list of main zone ( headers, footers ) ? */ |
935 | | bool MsWrd1Parser::readZones(MWAWVec2i limits) |
936 | 2.69k | { |
937 | 2.69k | MWAWInputStreamPtr input = getInput(); |
938 | 2.69k | if (limits[1] <= limits[0] || !input->checkPosition(limits[1]*0x80)) { |
939 | 0 | MWAW_DEBUG_MSG(("MsWrd1Parser::readZones: the zone is not well defined\n")); |
940 | 0 | return false; |
941 | 0 | } |
942 | 2.69k | libmwaw::DebugStream f; |
943 | | |
944 | 2.69k | MsWrd1ParserInternal::PLC plc(MsWrd1ParserInternal::ZONE); |
945 | 2.69k | long pos = limits[0]*0x80; |
946 | 2.69k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
947 | 2.69k | f << "Entries(Zones):"; |
948 | 2.69k | auto N = static_cast<int>(input->readULong(2)); |
949 | 2.69k | auto N1 = static_cast<int>(input->readULong(2)); |
950 | 2.69k | f << "N=" << N << ","; |
951 | 2.69k | if (N!=N1) f << "N1=" << N1 << ","; |
952 | 2.69k | if (N!=N1 || N==0 || 4+10*N > (limits[1]-limits[0])*0x80) { |
953 | 2.08k | MWAW_DEBUG_MSG(("MsWrd1Parser::readZones: the number of element seems odds\n")); |
954 | 2.08k | f << "###"; |
955 | 2.08k | ascii().addPos(pos); |
956 | 2.08k | ascii().addNote(f.str().c_str()); |
957 | 2.08k | return false; |
958 | 2.08k | } |
959 | 51.6k | for (int i = 0; i < N; i++) { |
960 | 50.9k | long textPos = long(input->readULong(4))+0x80; |
961 | 50.9k | f << std::hex << textPos << std::dec; |
962 | 50.9k | f << ":f0=" << input->readLong(2); // find 1|2|3 |
963 | 50.9k | auto val = static_cast<int>(input->readLong(4)); // find -1, 0x900, 0xa00 |
964 | 50.9k | if (val!=-1) f << ":f1=" << std::hex << val << std::dec; |
965 | 50.9k | if (textPos < m_state->m_eot) { |
966 | 17.5k | plc.m_id = i; |
967 | 17.5k | m_state->m_plcMap.insert |
968 | 17.5k | (std::multimap<long, MsWrd1ParserInternal::PLC>::value_type(textPos, plc)); |
969 | 17.5k | } |
970 | 33.4k | else if (textPos != m_state->m_eot && i != N-1) |
971 | 32.9k | f << "###"; |
972 | 50.9k | f << ","; |
973 | 50.9k | } |
974 | 609 | ascii().addDelimiter(input->tell(),'|'); |
975 | 609 | ascii().addPos(pos); |
976 | 609 | ascii().addNote(f.str().c_str()); |
977 | | |
978 | 609 | return true; |
979 | 2.69k | } |
980 | | |
981 | | /* read the document information */ |
982 | | bool MsWrd1Parser::readDocInfo(MWAWVec2i limits) |
983 | 2.13k | { |
984 | 2.13k | MWAWInputStreamPtr input = getInput(); |
985 | 2.13k | if (limits[1] != limits[0]+1 || !input->checkPosition(limits[1]*0x80)) { |
986 | 60 | MWAW_DEBUG_MSG(("MsWrd1Parser::readDocInfo: the zone is not well defined\n")); |
987 | 60 | return false; |
988 | 60 | } |
989 | | |
990 | 2.07k | libmwaw::DebugStream f; |
991 | 2.07k | long pos = limits[0]*0x80; |
992 | 2.07k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
993 | 2.07k | f << "Entries(DocInfo):"; |
994 | 2.07k | int val; |
995 | 6.21k | for (int i=0; i < 2; i++) { // find 66|0 |
996 | 4.14k | val = static_cast<int>(input->readULong(1)); |
997 | 4.14k | if (val) |
998 | 2.74k | f << "f" << i << "=" << std::hex << val << std::dec << ","; |
999 | 4.14k | } |
1000 | 2.07k | auto flags = static_cast<int>(input->readULong(1)); |
1001 | 2.07k | switch (flags>>5) { |
1002 | 1.09k | case 0: |
1003 | 1.09k | f << "division=no,"; |
1004 | 1.09k | break; |
1005 | 90 | case 1: |
1006 | 90 | f << "division=columns,"; |
1007 | 90 | break; |
1008 | 361 | case 2: |
1009 | 361 | f << "division=page,"; |
1010 | 361 | break; // default |
1011 | 237 | case 3: |
1012 | 237 | f << "division=evenpage,"; |
1013 | 237 | break; |
1014 | 37 | case 4: |
1015 | 37 | f << "division=oddpage,"; |
1016 | 37 | break; |
1017 | 257 | default: |
1018 | 257 | f << "#division=" << (flags>>5) << ","; |
1019 | 257 | break; |
1020 | 2.07k | } |
1021 | 2.07k | switch ((flags>>2)&7) { |
1022 | 919 | case 0: // default (numeric) |
1023 | 919 | break; |
1024 | 419 | case 1: |
1025 | 419 | f << "numbering=roman[upper],"; |
1026 | 419 | break; |
1027 | 62 | case 2: |
1028 | 62 | f << "numbering=roman[lower],"; |
1029 | 62 | break; |
1030 | 270 | case 3: |
1031 | 270 | f << "numbering=alpha[upper],"; |
1032 | 270 | break; |
1033 | 97 | case 4: |
1034 | 97 | f << "numbering=alpha[lower],"; |
1035 | 97 | break; |
1036 | 306 | default: |
1037 | 306 | f << "#numbering[type]=" << ((flags>>2)&7) << ","; |
1038 | 306 | break; |
1039 | 2.07k | } |
1040 | 2.07k | if (flags&3) f << "flags=" << (flags&3) << ","; |
1041 | | |
1042 | 2.07k | float pageDim[2]; |
1043 | 4.14k | for (auto &d : pageDim) d = float(input->readULong(2))/1440.f; |
1044 | 2.07k | f << "dim=[" << pageDim[1] << "x" << pageDim[0] << "],"; |
1045 | 2.07k | val = static_cast<int>(input->readLong(2)); |
1046 | 2.07k | if (val != -1) f << "firstPage=" << val << ","; |
1047 | | // check me |
1048 | 2.07k | float pagePos[2][2]; // [Y|X][header|size] |
1049 | 2.07k | char const *wh[] = {"TopMargin", "Y[page]", "LeftMargin", "X[page]" }; |
1050 | 6.21k | for (int i = 0; i < 2; i++) { |
1051 | 12.4k | for (int j = 0; j < 2; j++) { |
1052 | 8.29k | pagePos[i][j] = float(input->readULong(2))/1440.f; |
1053 | 8.29k | f << wh[i*2+j] << "=" << pagePos[i][j] << ","; |
1054 | 8.29k | } |
1055 | 4.14k | } |
1056 | 2.07k | flags = static_cast<int>(input->readULong(1)); |
1057 | 2.07k | bool endNote = false; |
1058 | 2.07k | if (flags&1) { |
1059 | 702 | f << "endnote,"; |
1060 | 702 | endNote = true; |
1061 | 702 | } |
1062 | 2.07k | if (flags&2) |
1063 | 537 | f << "autonumbering,"; |
1064 | 2.07k | if (flags&0xFC) |
1065 | 951 | f << "flags2=" << std::hex << (flags&0xFC) << std::dec << ","; |
1066 | 2.07k | ascii().addPos(pos); |
1067 | 2.07k | ascii().addNote(f.str().c_str()); |
1068 | | |
1069 | 2.07k | pos = input->tell(); |
1070 | 2.07k | f.str(""); |
1071 | 2.07k | f << "DocInfo(II):"; |
1072 | 2.07k | auto numCols = static_cast<int>(input->readULong(1)); |
1073 | 2.07k | if (numCols != 1) { |
1074 | 2.00k | f << "nCols=" << numCols << ","; |
1075 | 2.00k | if (numCols < 1 || numCols > 6) { |
1076 | 1.48k | f << "###"; |
1077 | 1.48k | numCols = 1; |
1078 | 1.48k | } |
1079 | 2.00k | } |
1080 | 2.07k | float hfLength[2]; |
1081 | 4.14k | for (auto &hf : hfLength) hf = float(input->readULong(2))/1440.f; |
1082 | 2.07k | hfLength[1]=pageDim[0]-hfLength[1]; |
1083 | | |
1084 | 2.07k | f << "headerLength=" << hfLength[0] << ","; |
1085 | 2.07k | f << "footerLength=" << hfLength[1] << ","; |
1086 | 2.07k | float colSep = float(input->readULong(2))/1440.f; |
1087 | 2.07k | f << "colSep=" << colSep << ","; |
1088 | 2.07k | val = static_cast<int>(input->readLong(2)); |
1089 | 2.07k | if (val) |
1090 | 1.47k | f << "f3=" << val << ","; |
1091 | 2.07k | f << "distToHeader=" << float(input->readULong(2))/1440.f << ","; |
1092 | 2.07k | f << "distToNote=" << float(input->readULong(2))/1440.f << ","; |
1093 | | // probably follows by other distance |
1094 | | |
1095 | 2.07k | if (pageDim[0] > 0 && pageDim[1] > 0 && |
1096 | 1.58k | pagePos[0][0]>=0 && pagePos[0][1]>=0 && pageDim[0] >= pagePos[0][0]+pagePos[0][1] && |
1097 | 743 | pagePos[1][0]>=0 && pagePos[1][1]>=0 && pageDim[1] >= pagePos[1][0]+pagePos[1][1] && |
1098 | 391 | pageDim[1] >= float(numCols)*pagePos[1][1]) { |
1099 | 370 | getPageSpan().setMarginTop(double(pagePos[0][0])); |
1100 | 370 | getPageSpan().setMarginLeft(double(pagePos[1][0])); |
1101 | 370 | getPageSpan().setFormLength(double(pageDim[0])); |
1102 | 370 | getPageSpan().setFormWidth(double(pageDim[1])); |
1103 | 370 | m_state->m_endNote = endNote; |
1104 | 370 | m_state->m_numColumns = numCols; |
1105 | 370 | m_state->m_columnsSep = colSep; |
1106 | 370 | } |
1107 | 1.70k | else { |
1108 | 1.70k | MWAW_DEBUG_MSG(("MsWrd1Parser::readDocInfo: some dimension do not look good\n")); |
1109 | 1.70k | } |
1110 | 2.07k | ascii().addDelimiter(input->tell(),'|'); |
1111 | 2.07k | ascii().addPos(pos); |
1112 | 2.07k | ascii().addNote(f.str().c_str()); |
1113 | 2.07k | ascii().addPos(pos+53); |
1114 | 2.07k | ascii().addNote("DocInfo(III)"); |
1115 | 2.07k | return true; |
1116 | 2.07k | } |
1117 | | |
1118 | | // read a plc zone (char or paragraph properties ) |
1119 | | bool MsWrd1Parser::readPLC(MWAWVec2i limits, int wh) |
1120 | 8.83k | { |
1121 | 8.83k | MWAWInputStreamPtr input = getInput(); |
1122 | 8.83k | if (limits[1] <= limits[0] || !input->checkPosition(limits[1]*0x80)) { |
1123 | 0 | MWAW_DEBUG_MSG(("MsWrd1Parser::readPLC: the zone is not well defined\n")); |
1124 | 0 | return false; |
1125 | 0 | } |
1126 | 8.83k | libmwaw::DebugStream f, f2; |
1127 | | |
1128 | 8.83k | std::map<long, int> posIdMap; |
1129 | 8.83k | MsWrd1ParserInternal::PLC plc(wh==0 ? MsWrd1ParserInternal::FONT : |
1130 | 8.83k | MsWrd1ParserInternal::RULER); |
1131 | 8.83k | char const *what = wh==0 ? "Char" : "Para"; |
1132 | | |
1133 | 1.25M | for (int z = limits[0], n=0; z < limits[1]; z++, n++) { |
1134 | 1.24M | f.str(""); |
1135 | 1.24M | f << "Entries(" << what << ")[" << n << "]:"; |
1136 | 1.24M | long pos = z*0x80; |
1137 | 1.24M | input->seek(pos+0x7f, librevenge::RVNG_SEEK_SET); |
1138 | 1.24M | auto N = static_cast<int>(input->readULong(1)); |
1139 | 1.24M | f << "N=" << N << ","; |
1140 | 1.24M | if (4+N*6 > 0x7f) { |
1141 | 389k | f << "###"; |
1142 | 389k | MWAW_DEBUG_MSG(("MsWrd1Parser::readPLC: the number of element seems to big\n")); |
1143 | 389k | ascii().addDelimiter(input->tell(),'|'); |
1144 | 389k | ascii().addPos(pos); |
1145 | 389k | ascii().addNote(f.str().c_str()); |
1146 | 389k | continue; |
1147 | 389k | } |
1148 | 860k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
1149 | 860k | auto fPos = long(input->readULong(4)); |
1150 | | |
1151 | 2.48M | for (int i = 0; i < N; i++) { |
1152 | 1.62M | f << "fPos=" << std::hex << fPos; |
1153 | 1.62M | auto newPos = long(input->readULong(4)); |
1154 | 1.62M | f << "->" << newPos << std::dec; |
1155 | | |
1156 | 1.62M | auto depl = static_cast<int>(input->readLong(2)); |
1157 | 1.62M | if (depl == -1) |
1158 | 136k | plc.m_id = -1; |
1159 | 1.48M | else if (depl < N*6 || 4+depl >= 0x7f) { |
1160 | 1.34M | f << "[###pos=" << std::hex << depl << std::dec << "]"; |
1161 | 1.34M | plc.m_id = -1; |
1162 | 1.34M | } |
1163 | 144k | else { |
1164 | 144k | long dataPos = pos+depl+4; |
1165 | 144k | long actPos = input->tell(); |
1166 | 144k | if (posIdMap.find(dataPos) == posIdMap.end()) { |
1167 | 137k | f2.str(""); |
1168 | 137k | f2 << what << "-"; |
1169 | 137k | if (wh == 0) { |
1170 | 75.5k | MsWrd1ParserInternal::Font font; |
1171 | 75.5k | if (readFont(dataPos, font)) { |
1172 | 55.8k | plc.m_id=int(m_state->m_fontsList.size()); |
1173 | 55.8k | m_state->m_fontsList.push_back(font); |
1174 | 55.8k | f2 << plc.m_id << ":"; |
1175 | | #ifdef DEBUG |
1176 | | f2 << font.m_font.getDebugString(getFontConverter()) << font; |
1177 | | #endif |
1178 | 55.8k | } |
1179 | 19.6k | else { |
1180 | 19.6k | plc.m_id = -1; |
1181 | 19.6k | f2 << "###"; |
1182 | 19.6k | } |
1183 | 75.5k | ascii().addPos(dataPos); |
1184 | 75.5k | ascii().addNote(f2.str().c_str()); |
1185 | 75.5k | } |
1186 | 62.3k | else { |
1187 | 62.3k | MsWrd1ParserInternal::Paragraph para; |
1188 | 62.3k | if (readParagraph(dataPos, para)) { |
1189 | 52.4k | plc.m_id=int(m_state->m_paragraphsList.size()); |
1190 | 52.4k | m_state->m_paragraphsList.push_back(para); |
1191 | 52.4k | f2 << plc.m_id << ":" << para; |
1192 | 52.4k | } |
1193 | 9.93k | else { |
1194 | 9.93k | plc.m_id = -1; |
1195 | 9.93k | f2 << "###"; |
1196 | 9.93k | } |
1197 | 62.3k | ascii().addPos(dataPos); |
1198 | 62.3k | ascii().addNote(f2.str().c_str()); |
1199 | 62.3k | } |
1200 | 137k | posIdMap[dataPos] = plc.m_id; |
1201 | 137k | } |
1202 | 6.14k | else |
1203 | 6.14k | plc.m_id = posIdMap.find(dataPos)->second; |
1204 | 144k | input->seek(actPos, librevenge::RVNG_SEEK_SET); |
1205 | 144k | } |
1206 | 1.62M | m_state->m_plcMap.insert |
1207 | 1.62M | (std::multimap<long, MsWrd1ParserInternal::PLC>::value_type(fPos, plc)); |
1208 | 1.62M | fPos = newPos; |
1209 | 1.62M | f << ":" << plc << ","; |
1210 | 1.62M | } |
1211 | 860k | ascii().addDelimiter(input->tell(),'|'); |
1212 | 860k | ascii().addPos(pos); |
1213 | 860k | ascii().addNote(f.str().c_str()); |
1214 | 860k | } |
1215 | | |
1216 | 8.83k | return true; |
1217 | 8.83k | } |
1218 | | |
1219 | | //////////////////////////////////////////////////////////// |
1220 | | // try to read a text entry |
1221 | | //////////////////////////////////////////////////////////// |
1222 | | bool MsWrd1Parser::sendText(MWAWEntry const &textEntry, bool isMain) |
1223 | 91.4k | { |
1224 | 91.4k | if (!textEntry.valid()) return false; |
1225 | 90.7k | if (!getTextListener()) { |
1226 | 0 | MWAW_DEBUG_MSG(("MsWrd1Parser::sendText: can not find a listener!")); |
1227 | 0 | return true; |
1228 | 0 | } |
1229 | 90.7k | if (isMain) { |
1230 | 13.5k | int numCols = m_state->m_numColumns; |
1231 | 13.5k | if (numCols > 1 && !getTextListener()->isSectionOpened()) { |
1232 | 248 | MWAWSection sec; |
1233 | 248 | sec.setColumns(numCols, getPageWidth()/double(numCols), librevenge::RVNG_INCH, double(m_state->m_columnsSep)); |
1234 | 248 | getTextListener()->openSection(sec); |
1235 | 248 | } |
1236 | 13.5k | } |
1237 | 90.7k | long pos = textEntry.begin(); |
1238 | 90.7k | MWAWInputStreamPtr input = getInput(); |
1239 | | |
1240 | 90.7k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
1241 | 90.7k | libmwaw::DebugStream f; |
1242 | 90.7k | f << "TextContent:"; |
1243 | 90.7k | int actFId=-1, actRId = -1, actPage=0; |
1244 | 90.7k | auto plcIt = m_state->m_plcMap.begin(); |
1245 | 26.3M | while (plcIt != m_state->m_plcMap.end() && plcIt->first < pos) { |
1246 | 26.2M | MsWrd1ParserInternal::PLC const &plc = plcIt++->second; |
1247 | 26.2M | if (plc.m_type == MsWrd1ParserInternal::FONT) |
1248 | 419k | actFId = plc.m_id; |
1249 | 25.8M | else if (plc.m_type == MsWrd1ParserInternal::RULER) |
1250 | 441k | actRId = plc.m_id; |
1251 | 25.3M | else if (plc.m_type == MsWrd1ParserInternal::PAGE) |
1252 | 391k | actPage++; |
1253 | 26.2M | } |
1254 | | // new page can be in header, ..., so sometimes we must force a new page... |
1255 | 90.7k | if (isMain && actPage > m_state->m_actPage) |
1256 | 855 | newPage(actPage); |
1257 | 90.7k | MsWrd1ParserInternal::Font actFont, defFont; |
1258 | 90.7k | defFont.m_font = MWAWFont(3,12); |
1259 | 90.7k | if (actFId>=0 && actFId < int(m_state->m_fontsList.size())) |
1260 | 8.10k | actFont = m_state->m_fontsList[size_t(actFId)]; |
1261 | 82.5k | else |
1262 | 82.5k | actFont = defFont; |
1263 | 90.7k | bool rulerNotSent = actRId != -1, fontNotSent = true; |
1264 | 13.4M | while (!input->isEnd() && input->tell() < textEntry.end()) { |
1265 | 13.3M | long actPos = input->tell(); |
1266 | 13.3M | bool firstPlc = true; |
1267 | 14.0M | while (plcIt != m_state->m_plcMap.end() && plcIt->first <= actPos) { |
1268 | 637k | if (firstPlc) { |
1269 | 285k | ascii().addPos(pos); |
1270 | 285k | ascii().addNote(f.str().c_str()); |
1271 | 285k | pos = actPos; |
1272 | 285k | f.str(""); |
1273 | 285k | f << "TextContent:"; |
1274 | 285k | firstPlc = false; |
1275 | 285k | } |
1276 | | |
1277 | 637k | auto const &plc = plcIt++->second; |
1278 | 637k | switch (plc.m_type) { |
1279 | 59.3k | case MsWrd1ParserInternal::FONT: |
1280 | 59.3k | if (plc.m_id >= 0 && plc.m_id < int(m_state->m_fontsList.size())) |
1281 | 34.9k | getTextListener()->setFont(m_state->m_fontsList[size_t(plc.m_id)].m_font); |
1282 | 24.4k | else |
1283 | 24.4k | getTextListener()->setFont(defFont.m_font); |
1284 | 59.3k | actFont.m_font = getTextListener()->getFont(); |
1285 | 59.3k | fontNotSent = false; |
1286 | 59.3k | break; |
1287 | 145k | case MsWrd1ParserInternal::RULER: |
1288 | 145k | actRId = plc.m_id; |
1289 | 145k | rulerNotSent = true; |
1290 | 145k | break; |
1291 | 202k | case MsWrd1ParserInternal::PAGE: |
1292 | 202k | if (isMain) newPage(++actPage); |
1293 | 202k | break; |
1294 | 212k | case MsWrd1ParserInternal::FOOTNOTE: { |
1295 | 212k | if (!isMain) break; |
1296 | 72.4k | if (plc.m_id < 0 || plc.m_id >= int(m_state->m_footnotesList.size())) { |
1297 | 0 | MWAW_DEBUG_MSG(("MsWrd1Parser::sendText: oops, can not find a footnote!\n")); |
1298 | 0 | break; |
1299 | 0 | } |
1300 | 72.4k | MWAWEntry entry; |
1301 | 72.4k | entry.setBegin(m_state->m_footnotesList[size_t(plc.m_id)][0]); |
1302 | 72.4k | entry.setEnd(m_state->m_footnotesList[size_t(plc.m_id)][1]); |
1303 | 72.4k | removeLastCharIfEOL(entry); |
1304 | 72.4k | std::shared_ptr<MWAWSubDocument> subdoc |
1305 | 72.4k | (new MsWrd1ParserInternal::SubDocument(*this, getInput(), entry)); |
1306 | 72.4k | getTextListener()->insertNote(MWAWNote(m_state->m_endNote ? MWAWNote::EndNote : MWAWNote::FootNote), subdoc); |
1307 | 72.4k | break; |
1308 | 72.4k | } |
1309 | 17.5k | case MsWrd1ParserInternal::ZONE: |
1310 | 17.5k | case MsWrd1ParserInternal::UNKNOWN: |
1311 | | #if !defined(__clang__) |
1312 | | default: |
1313 | | #endif |
1314 | 17.5k | break; |
1315 | 637k | } |
1316 | 637k | f << "[" << plc << "]"; |
1317 | 637k | } |
1318 | 13.3M | if (rulerNotSent) { |
1319 | 127k | if (actRId >= 0 && actRId < int(m_state->m_paragraphsList.size())) |
1320 | 36.7k | setProperty(m_state->m_paragraphsList[size_t(actRId)]); |
1321 | 90.8k | else |
1322 | 90.8k | setProperty(MsWrd1ParserInternal::Paragraph()); |
1323 | 127k | rulerNotSent = false; |
1324 | 127k | } |
1325 | 13.3M | if (fontNotSent) getTextListener()->setFont(actFont.m_font); |
1326 | 13.3M | auto c = static_cast<unsigned char>(input->readULong(1)); |
1327 | 13.3M | f << char(c); |
1328 | 13.3M | switch (c) { |
1329 | 772k | case 1: |
1330 | 772k | getTextListener()->insertUnicodeString(librevenge::RVNGString("(picture)")); |
1331 | 772k | break; |
1332 | 60.5k | case 5: // footnote mark |
1333 | 93.8k | case 0xc: // end of file |
1334 | 93.8k | break; |
1335 | 135k | case 0x9: |
1336 | 135k | getTextListener()->insertTab(); |
1337 | 135k | break; |
1338 | 570k | case 0xd: |
1339 | 570k | getTextListener()->insertEOL(); |
1340 | 570k | break; |
1341 | 11.8M | default: |
1342 | 11.8M | getTextListener()->insertCharacter(static_cast<unsigned char>(c), input, textEntry.end()); |
1343 | 11.8M | break; |
1344 | 13.3M | } |
1345 | 13.3M | } |
1346 | 90.7k | ascii().addPos(pos); |
1347 | 90.7k | ascii().addNote(f.str().c_str()); |
1348 | 90.7k | return true; |
1349 | 90.7k | } |
1350 | | |
1351 | | // send the ruler properties |
1352 | | void MsWrd1Parser::setProperty(MsWrd1ParserInternal::Paragraph const ¶) |
1353 | 127k | { |
1354 | 127k | if (!getTextListener()) return; |
1355 | 127k | getTextListener()->setParagraph(para); |
1356 | 127k | } |
1357 | | |
1358 | | //////////////////////////////////////////////////////////// |
1359 | | // Low level |
1360 | | //////////////////////////////////////////////////////////// |
1361 | | |
1362 | | // read the header |
1363 | | bool MsWrd1Parser::checkHeader(MWAWHeader *header, bool strict) |
1364 | 47.0k | { |
1365 | 47.0k | *m_state = MsWrd1ParserInternal::State(); |
1366 | 47.0k | MWAWInputStreamPtr input = getInput(); |
1367 | 47.0k | if (!input || !input->hasDataFork()) |
1368 | 0 | return false; |
1369 | | |
1370 | 47.0k | libmwaw::DebugStream f; |
1371 | 47.0k | if (!input->checkPosition(0x80)) { |
1372 | 341 | MWAW_DEBUG_MSG(("MsWrd1Parser::checkHeader: file is too short\n")); |
1373 | 341 | return false; |
1374 | 341 | } |
1375 | 46.7k | long pos = 0; |
1376 | 46.7k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
1377 | 46.7k | auto val = static_cast<int>(input->readULong(2)); |
1378 | 46.7k | switch (val) { |
1379 | 46.5k | case 0xfe32: |
1380 | 46.5k | switch (input->readULong(2)) { |
1381 | 46.5k | case 0x0: |
1382 | 46.5k | setVersion(1); |
1383 | 46.5k | break; |
1384 | 0 | default: |
1385 | 0 | return false; |
1386 | 46.5k | } |
1387 | 46.5k | break; |
1388 | 46.5k | default: |
1389 | 156 | return false; |
1390 | 46.7k | } |
1391 | | |
1392 | 46.5k | f << "FileHeader:"; |
1393 | 46.5k | val = static_cast<int>(input->readULong(1)); // v1: ab other 0 ? |
1394 | 46.5k | if (val) f << "f0=" << val << ","; |
1395 | 139k | for (int i = 1; i < 3; i++) { // always 0 |
1396 | 93.1k | val = static_cast<int>(input->readLong(2)); |
1397 | 93.1k | if (val) f << "f" << i << "=" << val << ","; |
1398 | 93.1k | } |
1399 | 279k | for (int i = 0; i < 5; i++) { // always 0 ? |
1400 | 232k | val = static_cast<int>(input->readLong(1)); |
1401 | 232k | if (val) f << "g" << i << "=" << val << ","; |
1402 | 232k | } |
1403 | | |
1404 | 46.5k | m_state->m_eot = long(input->readULong(4)); |
1405 | 46.5k | f << "text=" << std::hex << 0x80 << "<->" << m_state->m_eot << ","; |
1406 | 46.5k | if (0x80 > m_state->m_eot || !input->checkPosition(m_state->m_eot)) { |
1407 | 1.55k | MWAW_DEBUG_MSG(("MsWrd1Parser::checkHeader: problem with text position must stop\n")); |
1408 | 1.55k | return false; |
1409 | 1.55k | } |
1410 | | |
1411 | 45.0k | m_state->m_fileZonesLimit[0] = int((m_state->m_eot+0x7f)/0x80); |
1412 | 45.0k | f << "zonesPos=[" << std::hex; |
1413 | 260k | for (int i = 0; i < 6; i++) { |
1414 | 226k | m_state->m_fileZonesLimit[i+1] = static_cast<int>(input->readLong(2)); |
1415 | 226k | if (m_state->m_fileZonesLimit[i]==m_state->m_fileZonesLimit[i+1]) { |
1416 | 8.43k | f << "_,"; |
1417 | 8.43k | continue; |
1418 | 8.43k | } |
1419 | 217k | if (m_state->m_fileZonesLimit[i]<m_state->m_fileZonesLimit[i+1]) { |
1420 | 86.5k | f << m_state->m_fileZonesLimit[i]*0x80 << "<->" |
1421 | 86.5k | << m_state->m_fileZonesLimit[i+1]*0x80 << ","; |
1422 | 86.5k | continue; |
1423 | 86.5k | } |
1424 | 131k | MWAW_DEBUG_MSG(("MsWrd1Parser::checkHeader: problem reading the zones positions\n")); |
1425 | 131k | if (strict) return false; |
1426 | 120k | f << "###" << m_state->m_fileZonesLimit[i+1]*0x80 << ","; |
1427 | 120k | m_state->m_fileZonesLimit[i+1] = m_state->m_fileZonesLimit[i]; |
1428 | 120k | } |
1429 | 34.7k | f << std::dec << "],"; |
1430 | 34.7k | ascii().addPos(pos); |
1431 | 34.7k | ascii().addNote(f.str().c_str()); |
1432 | 34.7k | pos = input->tell(); |
1433 | 34.7k | f.str(""); |
1434 | 34.7k | f << "FileHeader[A]:"; |
1435 | 625k | for (int i = 0; i < 17; i++) { |
1436 | 591k | val = static_cast<int>(input->readLong(2)); |
1437 | 591k | if (val) f << "f" << i << "=" << val << ","; |
1438 | 591k | } |
1439 | 34.7k | ascii().addPos(pos); |
1440 | 34.7k | ascii().addNote(f.str().c_str()); |
1441 | | |
1442 | 34.7k | long textSize[2]; |
1443 | 69.5k | for (auto &tSize : textSize) tSize = input->readLong(4); |
1444 | 34.7k | if (textSize[0] != textSize[1] || 0x80+textSize[0] != m_state->m_eot) { |
1445 | 28.7k | MWAW_DEBUG_MSG(("MsWrd1Parser::checkHeader: problem with text position length\n")); |
1446 | 28.7k | if (strict) return false; |
1447 | 28.2k | f << "##textSize=" << std::hex << textSize[0] << ":" << textSize[1] << std::dec << ","; |
1448 | 28.2k | if (textSize[1] > textSize[0]) textSize[0] = textSize[1]; |
1449 | 28.2k | if (0x80+textSize[0] > m_state->m_eot && input->checkPosition(0x80+textSize[0])) |
1450 | 3.11k | m_state->m_eot = 0x80+textSize[0]; |
1451 | 28.2k | } |
1452 | 34.2k | pos=input->tell(); |
1453 | 34.2k | f.str(""); |
1454 | 34.2k | f << "FileHeader[B]:"; |
1455 | 993k | for (int i = 0; i < 28; i++) { // always 0 |
1456 | 959k | val = static_cast<int>(input->readLong(2)); |
1457 | 959k | if (val) f << "f" << i << "=" << val << ","; |
1458 | 959k | } |
1459 | 34.2k | ascii().addPos(pos); |
1460 | 34.2k | ascii().addNote(f.str().c_str()); |
1461 | 34.2k | if (header) |
1462 | 12.6k | header->reset(MWAWDocument::MWAW_T_MICROSOFTWORD, 1); |
1463 | 34.2k | return true; |
1464 | 34.7k | } |
1465 | | |
1466 | | // vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: |