/src/libmwaw/src/lib/LightWayTxtParser.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 <set> |
38 | | #include <sstream> |
39 | | |
40 | | #include <librevenge/librevenge.h> |
41 | | |
42 | | #include "MWAWTextListener.hxx" |
43 | | #include "MWAWFontConverter.hxx" |
44 | | #include "MWAWHeader.hxx" |
45 | | #include "MWAWPosition.hxx" |
46 | | #include "MWAWPrinter.hxx" |
47 | | #include "MWAWRSRCParser.hxx" |
48 | | #include "MWAWSubDocument.hxx" |
49 | | |
50 | | #include "LightWayTxtGraph.hxx" |
51 | | #include "LightWayTxtText.hxx" |
52 | | |
53 | | #include "LightWayTxtParser.hxx" |
54 | | |
55 | | /** Internal: the structures of a LightWayTxtParser */ |
56 | | namespace LightWayTxtParserInternal |
57 | | { |
58 | | //////////////////////////////////////// |
59 | | //! Internal: the state of a LightWayTxtParser |
60 | | struct State { |
61 | | //! constructor |
62 | | State() |
63 | 3.62k | : m_isApplication(false) |
64 | 3.62k | , m_actPage(0) |
65 | 3.62k | , m_numPages(0) |
66 | 3.62k | , m_numCol(1) |
67 | 3.62k | , m_colSep(0) |
68 | 3.62k | , m_headerHeight(0) |
69 | 3.62k | , m_footerHeight(0) |
70 | 3.62k | { |
71 | 3.62k | } |
72 | | |
73 | | /** true if we are parsing a application document */ |
74 | | bool m_isApplication; |
75 | | int m_actPage /** the actual page */, m_numPages /** the number of page of the final document */; |
76 | | |
77 | | int m_numCol /** the number of columns */, |
78 | | m_colSep /** the columns separator width in point */; |
79 | | int m_headerHeight /** the header height if known */, |
80 | | m_footerHeight /** the footer height if known */; |
81 | | }; |
82 | | |
83 | | //////////////////////////////////////// |
84 | | //! Internal: the subdocument of a LightWayTxtParser |
85 | | class SubDocument final : public MWAWSubDocument |
86 | | { |
87 | | public: |
88 | | SubDocument(LightWayTxtParser &pars, MWAWInputStreamPtr const &input, bool header) |
89 | 0 | : MWAWSubDocument(&pars, input, MWAWEntry()) |
90 | 0 | , m_isHeader(header) |
91 | 0 | { |
92 | 0 | } |
93 | | |
94 | | //! destructor |
95 | 0 | ~SubDocument() final {} |
96 | | |
97 | | //! operator!= |
98 | | bool operator!=(MWAWSubDocument const &doc) const final |
99 | 0 | { |
100 | 0 | if (MWAWSubDocument::operator!=(doc)) return true; |
101 | 0 | auto const *sDoc = dynamic_cast<SubDocument const *>(&doc); |
102 | 0 | if (!sDoc) return true; |
103 | 0 | if (m_isHeader != sDoc->m_isHeader) return true; |
104 | 0 | return false; |
105 | 0 | } |
106 | | |
107 | | //! the parser function |
108 | | void parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType type) final; |
109 | | |
110 | | protected: |
111 | | //! true if we need to send the parser |
112 | | int m_isHeader; |
113 | | }; |
114 | | |
115 | | void SubDocument::parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType /*type*/) |
116 | 0 | { |
117 | 0 | if (!listener.get()) { |
118 | 0 | MWAW_DEBUG_MSG(("LightWayTxtParserInternal::SubDocument::parse: no listener\n")); |
119 | 0 | return; |
120 | 0 | } |
121 | 0 | auto *parser=dynamic_cast<LightWayTxtParser *>(m_parser); |
122 | 0 | if (!parser) { |
123 | 0 | MWAW_DEBUG_MSG(("LightWayTxtParserInternal::SubDocument::parse: no parser\n")); |
124 | 0 | return; |
125 | 0 | } |
126 | | |
127 | 0 | parser->sendHeaderFooter(m_isHeader); |
128 | 0 | } |
129 | | } |
130 | | |
131 | | |
132 | | //////////////////////////////////////////////////////////// |
133 | | // constructor/destructor, ... |
134 | | //////////////////////////////////////////////////////////// |
135 | | LightWayTxtParser::LightWayTxtParser(MWAWInputStreamPtr const &input, MWAWRSRCParserPtr const &rsrcParser, MWAWHeader *header) |
136 | 1.59k | : MWAWTextParser(input, rsrcParser, header) |
137 | 1.59k | , m_state() |
138 | 1.59k | , m_pageSpanSet(false) |
139 | 1.59k | , m_graphParser() |
140 | 1.59k | , m_textParser() |
141 | 1.59k | { |
142 | 1.59k | init(); |
143 | 1.59k | } |
144 | | |
145 | | LightWayTxtParser::~LightWayTxtParser() |
146 | 1.59k | { |
147 | 1.59k | } |
148 | | |
149 | | void LightWayTxtParser::init() |
150 | 1.59k | { |
151 | 1.59k | resetTextListener(); |
152 | 1.59k | setAsciiName("main-1"); |
153 | | |
154 | 1.59k | m_state.reset(new LightWayTxtParserInternal::State); |
155 | | |
156 | | // reduce the margin (in case, the page is not defined) |
157 | 1.59k | getPageSpan().setMargins(0.1); |
158 | | |
159 | 1.59k | m_graphParser.reset(new LightWayTxtGraph(*this)); |
160 | 1.59k | m_textParser.reset(new LightWayTxtText(*this)); |
161 | 1.59k | } |
162 | | |
163 | | MWAWInputStreamPtr LightWayTxtParser::rsrcInput() |
164 | 1.15k | { |
165 | 1.15k | return getRSRCParser()->getInput(); |
166 | 1.15k | } |
167 | | |
168 | | libmwaw::DebugFile &LightWayTxtParser::rsrcAscii() |
169 | 1.15k | { |
170 | 1.15k | return getRSRCParser()->ascii(); |
171 | 1.15k | } |
172 | | |
173 | | bool LightWayTxtParser::textInDataFork() const |
174 | 432 | { |
175 | 432 | return !m_state->m_isApplication; |
176 | 432 | } |
177 | | |
178 | | //////////////////////////////////////////////////////////// |
179 | | // position and height |
180 | | //////////////////////////////////////////////////////////// |
181 | | MWAWVec2f LightWayTxtParser::getPageLeftTop() const |
182 | 0 | { |
183 | 0 | return MWAWVec2f(float(getPageSpan().getMarginLeft()), |
184 | 0 | float(getPageSpan().getMarginTop()+m_state->m_headerHeight/72.0)); |
185 | 0 | } |
186 | | |
187 | | //////////////////////////////////////////////////////////// |
188 | | // interface with the text parser |
189 | | //////////////////////////////////////////////////////////// |
190 | | bool LightWayTxtParser::getColumnInfo(int &numCols, int &colSep) const |
191 | 432 | { |
192 | 432 | if (m_state->m_numCol < 1) { |
193 | 162 | numCols = 1; |
194 | 162 | colSep = 0; |
195 | 162 | return false; |
196 | 162 | } |
197 | 270 | numCols = m_state->m_numCol; |
198 | 270 | colSep = m_state->m_colSep; |
199 | 270 | return true; |
200 | 432 | } |
201 | | |
202 | | bool LightWayTxtParser::sendHeaderFooter(bool header) |
203 | 0 | { |
204 | 0 | MWAWInputStreamPtr input = getInput(); |
205 | 0 | MWAWInputStreamPtr rsrc = rsrcInput(); |
206 | 0 | long pos = input->tell(), rsrcPos = rsrc ? rsrc->tell() : 0; |
207 | 0 | m_textParser->sendHeaderFooter(header); |
208 | 0 | input->seek(pos, librevenge::RVNG_SEEK_SET); |
209 | 0 | if (rsrc) |
210 | 0 | rsrc->seek(rsrcPos, librevenge::RVNG_SEEK_SET); |
211 | 0 | return true; |
212 | 0 | } |
213 | | |
214 | | //////////////////////////////////////////////////////////// |
215 | | // interface with the graph parser |
216 | | //////////////////////////////////////////////////////////// |
217 | | void LightWayTxtParser::sendGraphic(int graphId) |
218 | 0 | { |
219 | 0 | MWAWInputStreamPtr input = getInput(); |
220 | 0 | MWAWInputStreamPtr rsrc = rsrcInput(); |
221 | 0 | long pos = input->tell(), rsrcPos = rsrc ? rsrc->tell() : 0; |
222 | 0 | m_graphParser->send(graphId); |
223 | 0 | input->seek(pos, librevenge::RVNG_SEEK_SET); |
224 | 0 | if (rsrc) |
225 | 0 | rsrc->seek(rsrcPos, librevenge::RVNG_SEEK_SET); |
226 | 0 | } |
227 | | |
228 | | //////////////////////////////////////////////////////////// |
229 | | // new page |
230 | | //////////////////////////////////////////////////////////// |
231 | | void LightWayTxtParser::newPage(int number) |
232 | 0 | { |
233 | 0 | if (number <= m_state->m_actPage || number > m_state->m_numPages) |
234 | 0 | return; |
235 | | |
236 | 0 | while (m_state->m_actPage < number) { |
237 | 0 | m_state->m_actPage++; |
238 | 0 | if (!getTextListener() || m_state->m_actPage == 1) |
239 | 0 | continue; |
240 | 0 | getTextListener()->insertBreak(MWAWTextListener::PageBreak); |
241 | 0 | } |
242 | 0 | } |
243 | | |
244 | | //////////////////////////////////////////////////////////// |
245 | | // the parser |
246 | | //////////////////////////////////////////////////////////// |
247 | | void LightWayTxtParser::parse(librevenge::RVNGTextInterface *docInterface) |
248 | 432 | { |
249 | 432 | if (!getInput().get() || !getRSRCParser() || !checkHeader(nullptr)) throw(libmwaw::ParseException()); |
250 | 432 | bool ok = false; |
251 | 432 | try { |
252 | | // create the asciiFile |
253 | 432 | ascii().setStream(getInput()); |
254 | 432 | ascii().open(asciiName()); |
255 | 432 | checkHeader(nullptr); |
256 | 432 | ok = createZones(); |
257 | 432 | if (ok) { |
258 | 432 | createDocument(docInterface); |
259 | 432 | m_graphParser->sendPageGraphics(); |
260 | 432 | m_textParser->sendMainText(); |
261 | | #ifdef DEBUG |
262 | | m_graphParser->flushExtra(); |
263 | | m_textParser->flushExtra(); |
264 | | #endif |
265 | 432 | } |
266 | 432 | ascii().reset(); |
267 | 432 | } |
268 | 432 | catch (...) { |
269 | 0 | MWAW_DEBUG_MSG(("LightWayTxtParser::parse: exception catched when parsing\n")); |
270 | 0 | ok = false; |
271 | 0 | } |
272 | | |
273 | 432 | resetTextListener(); |
274 | 432 | if (!ok) throw(libmwaw::ParseException()); |
275 | 432 | } |
276 | | |
277 | | //////////////////////////////////////////////////////////// |
278 | | // create the document |
279 | | //////////////////////////////////////////////////////////// |
280 | | void LightWayTxtParser::createDocument(librevenge::RVNGTextInterface *documentInterface) |
281 | 432 | { |
282 | 432 | if (!documentInterface) return; |
283 | 432 | if (getTextListener()) { |
284 | 0 | MWAW_DEBUG_MSG(("LightWayTxtParser::createDocument: listener already exist\n")); |
285 | 0 | return; |
286 | 0 | } |
287 | | |
288 | | // update the page |
289 | 432 | m_state->m_actPage = 0; |
290 | | |
291 | | // create the page list |
292 | 432 | int numPages = 1; |
293 | 432 | if (m_graphParser->numPages() > numPages) |
294 | 0 | numPages = m_graphParser->numPages(); |
295 | 432 | if (m_textParser->numPages() > numPages) |
296 | 0 | numPages = m_textParser->numPages(); |
297 | 432 | m_state->m_numPages = numPages; |
298 | | |
299 | 432 | MWAWPageSpan ps(getPageSpan()); |
300 | 432 | if (m_textParser->hasHeaderFooter(true)) { |
301 | 0 | MWAWHeaderFooter header(MWAWHeaderFooter::HEADER, MWAWHeaderFooter::ALL); |
302 | 0 | header.m_subDocument.reset(new LightWayTxtParserInternal::SubDocument(*this, getInput(), true)); |
303 | 0 | ps.setHeaderFooter(header); |
304 | 0 | } |
305 | 432 | if (m_textParser->hasHeaderFooter(false)) { |
306 | 0 | MWAWHeaderFooter footer(MWAWHeaderFooter::FOOTER, MWAWHeaderFooter::ALL); |
307 | 0 | footer.m_subDocument.reset(new LightWayTxtParserInternal::SubDocument(*this, getInput(), false)); |
308 | 0 | ps.setHeaderFooter(footer); |
309 | 0 | } |
310 | 432 | ps.setPageSpan(m_state->m_numPages+1); |
311 | 432 | std::vector<MWAWPageSpan> pageList(1,ps); |
312 | 432 | MWAWTextListenerPtr listen(new MWAWTextListener(*getParserState(), pageList, documentInterface)); |
313 | 432 | setTextListener(listen); |
314 | 432 | listen->startDocument(); |
315 | 432 | } |
316 | | |
317 | | |
318 | | //////////////////////////////////////////////////////////// |
319 | | // |
320 | | // Intermediate level |
321 | | // |
322 | | //////////////////////////////////////////////////////////// |
323 | | bool LightWayTxtParser::createZones() |
324 | 432 | { |
325 | 432 | MWAWRSRCParserPtr rsrcParser = getRSRCParser(); |
326 | 432 | if (!rsrcParser) { |
327 | 0 | MWAW_DEBUG_MSG(("LightWayTxtParser::createZones: can not find the entry map\n")); |
328 | 0 | return false; |
329 | 0 | } |
330 | 432 | auto const &entryMap = rsrcParser->getEntriesMap(); |
331 | | |
332 | | // the different zones |
333 | 432 | auto it = entryMap.lower_bound("LWSR"); |
334 | 864 | while (it != entryMap.end()) { |
335 | 852 | if (it->first != "LWSR") |
336 | 420 | break; |
337 | | |
338 | 432 | MWAWEntry const &entry = it++->second; |
339 | 432 | switch (entry.id()) { |
340 | 432 | case 1000: |
341 | 432 | readDocument(entry); |
342 | 432 | break; |
343 | 0 | case 1001: |
344 | 0 | readPrintInfo(entry); |
345 | 0 | break; |
346 | 0 | case 1002: // a list of int ? |
347 | 0 | readLWSR2(entry); |
348 | 0 | break; |
349 | 0 | case 1003: |
350 | 0 | readDocInfo(entry); |
351 | 0 | break; |
352 | 0 | case 1007: |
353 | 0 | readTOCPage(entry); |
354 | 0 | break; |
355 | 0 | default: |
356 | 0 | break; |
357 | 432 | } |
358 | 432 | } |
359 | 432 | it = entryMap.lower_bound("MPSR"); |
360 | 820 | while (it != entryMap.end()) { |
361 | 734 | if (it->first != "MPSR") |
362 | 346 | break; |
363 | | |
364 | 388 | MWAWEntry const &entry = it++->second; |
365 | 388 | switch (entry.id()) { |
366 | 346 | case 1005: // a constant block which contains a default font? |
367 | 346 | readMPSR5(entry); |
368 | 346 | break; |
369 | 4 | case 1007: |
370 | 4 | readTOC(entry); |
371 | 4 | break; |
372 | 38 | default: |
373 | 38 | break; |
374 | 388 | } |
375 | 388 | } |
376 | 432 | if (!m_textParser->createZones()) |
377 | 0 | return false; |
378 | 432 | m_graphParser->createZones(); |
379 | 432 | return true; |
380 | 432 | } |
381 | | |
382 | | //////////////////////////////////////////////////////////// |
383 | | // read the doc/print info |
384 | | //////////////////////////////////////////////////////////// |
385 | | bool LightWayTxtParser::readDocInfo(MWAWEntry const &entry) |
386 | 0 | { |
387 | 0 | if (entry.id() != 1003) |
388 | 0 | return false; |
389 | 0 | if (!entry.valid() || (entry.length()%0x40)) { |
390 | 0 | MWAW_DEBUG_MSG(("LightWayTxtParser::readDocInfo: the entry seems bad\n")); |
391 | 0 | return false; |
392 | 0 | } |
393 | 0 | MWAWInputStreamPtr input = rsrcInput(); |
394 | 0 | libmwaw::DebugFile &ascFile = rsrcAscii(); |
395 | 0 | input->seek(entry.begin(), librevenge::RVNG_SEEK_SET); |
396 | 0 | entry.setParsed(true); |
397 | |
|
398 | 0 | auto N=int(entry.length()/0x40); |
399 | 0 | libmwaw::DebugStream f; |
400 | 0 | for (int n = 0; n < N; n++) { |
401 | 0 | long pos = input->tell(); |
402 | 0 | f.str(""); |
403 | 0 | if (n==0) |
404 | 0 | f << "Entries(DocInfo):"; |
405 | 0 | else |
406 | 0 | f << "DocInfo-" << n << ":"; |
407 | |
|
408 | 0 | auto fl=int(input->readULong(1)); // 0|28 |
409 | 0 | if (fl) f << "fl0=" << fl << ","; |
410 | 0 | long val=int(input->readULong(1)); // a small number less than 12 |
411 | 0 | if (val) f << "f0=" << val << ","; |
412 | 0 | val = input->readLong(2); // 0|3|4|c |
413 | 0 | if (val) f << "f1=" << val << ","; |
414 | 0 | int dim[2]; |
415 | 0 | for (auto &d : dim) d = int(input->readLong(2)); |
416 | 0 | f << "dim=" << dim[0] << "x" << dim[1] << ","; |
417 | 0 | int margins[4]; |
418 | 0 | f << "margins=["; |
419 | 0 | for (auto &margin : margins) { |
420 | 0 | margin = int(input->readLong(2)); |
421 | 0 | f << margin << ","; |
422 | 0 | } |
423 | 0 | f << "],"; |
424 | 0 | for (int i = 0; i < 6; i++) { // f2=0|1c, f3=7|9|f, f4=f6=f7=0|e, f5=0|e|54|78 |
425 | 0 | val = input->readLong(2); |
426 | 0 | if (val) f << "f" << i+2 << "=" << val << ","; |
427 | 0 | } |
428 | 0 | for (int i = 0; i < 6; i++) { // f1=0|1, f2=1, f3=0|1, f4=0|1, f5=0, f6=1 |
429 | 0 | val = static_cast<int>(input->readULong(1)); |
430 | 0 | if (val) f << "fl" << i+1 << "=" << val << ","; |
431 | 0 | } |
432 | 0 | for (int i = 0; i < 5; i++) { // g0=0|18, g1=0|14, g4=0|..|6 |
433 | 0 | val = input->readLong(2); |
434 | 0 | if (val) f << "g" << i << "=" << val << ","; |
435 | 0 | } |
436 | 0 | f << "col?=[" << std::hex; |
437 | 0 | for (int i = 0; i <3; i++) |
438 | 0 | f << input->readULong(2) << ","; |
439 | 0 | f << "]," << std::dec; |
440 | 0 | for (int i = 0; i < 6; i++) { // fl1=0|1, fl2=0|1, fl4=0|1, fl5=0|1 |
441 | 0 | val = static_cast<int>(input->readULong(1)); |
442 | 0 | if (val) f << "fl" << i << "(2)=" << val << ","; |
443 | 0 | } |
444 | 0 | for (int i = 0; i < 4; i++) { // alway 0? |
445 | 0 | val = input->readLong(2); |
446 | 0 | if (val) f << "h" << i << "=" << val << ","; |
447 | 0 | } |
448 | |
|
449 | 0 | ascFile.addPos(n==0 ? pos-4 : pos); |
450 | 0 | ascFile.addNote(f.str().c_str()); |
451 | 0 | input->seek(pos+0x40, librevenge::RVNG_SEEK_SET); |
452 | 0 | } |
453 | 0 | return true; |
454 | 0 | } |
455 | | |
456 | | bool LightWayTxtParser::readPrintInfo(MWAWEntry const &entry) |
457 | 0 | { |
458 | 0 | if (!entry.valid() || entry.length() < 0x78) { |
459 | 0 | MWAW_DEBUG_MSG(("LightWayTxtParser::readPrintInfo: the entry is bad\n")); |
460 | 0 | return false; |
461 | 0 | } |
462 | 0 | if (entry.id() != 1001) { |
463 | 0 | MWAW_DEBUG_MSG(("LightWayTxtParser::readPrintInfo: the entry id %d is odd\n", entry.id())); |
464 | 0 | } |
465 | 0 | entry.setParsed(true); |
466 | 0 | MWAWInputStreamPtr input = rsrcInput(); |
467 | 0 | long pos = entry.begin(); |
468 | 0 | input->seek(pos, librevenge::RVNG_SEEK_SET); |
469 | |
|
470 | 0 | libmwaw::DebugStream f; |
471 | | // print info |
472 | 0 | libmwaw::PrinterInfo info; |
473 | 0 | if (!info.read(input)) return false; |
474 | 0 | if (entry.id() != 1001) |
475 | 0 | f << "Entries(PrintInfo)[#" << entry.id() << "]:" << info; |
476 | 0 | else |
477 | 0 | f << "Entries(PrintInfo):" << info; |
478 | 0 | if (entry.length() != 0x78) |
479 | 0 | f << "###size=" << entry.length() << ","; |
480 | 0 | rsrcAscii().addPos(pos-4); |
481 | 0 | rsrcAscii().addNote(f.str().c_str()); |
482 | 0 | if (m_pageSpanSet) |
483 | 0 | return true; |
484 | | |
485 | 0 | MWAWVec2i paperSize = info.paper().size(); |
486 | 0 | MWAWVec2i pageSize = info.page().size(); |
487 | 0 | if (pageSize.x() <= 0 || pageSize.y() <= 0 || |
488 | 0 | paperSize.x() <= 0 || paperSize.y() <= 0) return false; |
489 | | |
490 | | // define margin from print info |
491 | 0 | MWAWVec2i lTopMargin= -1 * info.paper().pos(0); |
492 | 0 | MWAWVec2i rBotMargin=info.paper().pos(1) - info.page().pos(1); |
493 | | |
494 | | // move margin left | top |
495 | 0 | int decalX = lTopMargin.x() > 14 ? lTopMargin.x()-14 : 0; |
496 | 0 | int decalY = lTopMargin.y() > 14 ? lTopMargin.y()-14 : 0; |
497 | 0 | lTopMargin -= MWAWVec2i(decalX, decalY); |
498 | 0 | rBotMargin += MWAWVec2i(decalX, decalY); |
499 | | |
500 | | // decrease right | bottom |
501 | 0 | int rightMarg = rBotMargin.x() -10; |
502 | 0 | if (rightMarg < 0) rightMarg=0; |
503 | 0 | int botMarg = rBotMargin.y() -50; |
504 | 0 | if (botMarg < 0) botMarg=0; |
505 | |
|
506 | 0 | getPageSpan().setMarginTop(lTopMargin.y()/72.0); |
507 | 0 | getPageSpan().setMarginBottom(botMarg/72.0); |
508 | 0 | getPageSpan().setMarginLeft(lTopMargin.x()/72.0); |
509 | 0 | getPageSpan().setMarginRight(rightMarg/72.0); |
510 | 0 | getPageSpan().setFormLength(paperSize.y()/72.); |
511 | 0 | getPageSpan().setFormWidth(paperSize.x()/72.); |
512 | |
|
513 | 0 | return true; |
514 | 0 | } |
515 | | |
516 | | //////////////////////////////////////////////////////////// |
517 | | // read the TOC data |
518 | | //////////////////////////////////////////////////////////// |
519 | | bool LightWayTxtParser::readTOCPage(MWAWEntry const &entry) |
520 | 0 | { |
521 | 0 | if (entry.id() != 1007) |
522 | 0 | return false; |
523 | 0 | if (!entry.valid() || entry.length()<0x24) { |
524 | 0 | MWAW_DEBUG_MSG(("LightWayTxtParser::readTOCPage: the entry is bad\n")); |
525 | 0 | return false; |
526 | 0 | } |
527 | 0 | MWAWInputStreamPtr input = rsrcInput(); |
528 | 0 | libmwaw::DebugFile &ascFile = rsrcAscii(); |
529 | 0 | long pos = entry.begin(); |
530 | 0 | input->seek(pos, librevenge::RVNG_SEEK_SET); |
531 | |
|
532 | 0 | libmwaw::DebugStream f; |
533 | 0 | f << "Entries(TOCpage)[" << entry.id() << "]:"; |
534 | 0 | entry.setParsed(true); |
535 | 0 | int dim[4]; |
536 | 0 | for (auto &d : dim) d = static_cast<int>(input->readLong(4)); |
537 | 0 | f << "dim?=" << dim[0] << "x" << dim[1] |
538 | 0 | << "<->" << dim[2] << "x" << dim[3] << ","; |
539 | 0 | for (int i = 0; i < 9; i++) { // f5=1|2|21, f8=256 |
540 | 0 | auto val = static_cast<int>(input->readLong(2)); |
541 | 0 | if (val) f << "f" << i << "=" << val << ","; |
542 | 0 | } |
543 | 0 | auto N = static_cast<int>(input->readLong(2)); |
544 | 0 | f << "N=" << N << ","; |
545 | 0 | if (input->tell()+N>entry.end()) { |
546 | 0 | MWAW_DEBUG_MSG(("LightWayTxtParser::readTOCPage: the page seems bead\n")); |
547 | 0 | f << "###"; |
548 | 0 | ascFile.addPos(pos-4); |
549 | 0 | ascFile.addNote(f.str().c_str()); |
550 | 0 | return false; |
551 | 0 | } |
552 | 0 | f << "pages=["; |
553 | 0 | for (int i = 0; i < N; i++) |
554 | 0 | f << static_cast<int>(input->readULong(1)) << ","; |
555 | 0 | f << "],"; |
556 | 0 | ascFile.addPos(pos-4); |
557 | 0 | ascFile.addNote(f.str().c_str()); |
558 | 0 | return true; |
559 | 0 | } |
560 | | |
561 | | bool LightWayTxtParser::readTOC(MWAWEntry const &entry) |
562 | 4 | { |
563 | 4 | if (entry.id() != 1007) |
564 | 0 | return false; |
565 | 4 | if (!entry.valid() || entry.length()<2) { |
566 | 4 | MWAW_DEBUG_MSG(("LightWayTxtParser::readTOC: the entry is bad\n")); |
567 | 4 | return false; |
568 | 4 | } |
569 | 0 | MWAWInputStreamPtr input = rsrcInput(); |
570 | 0 | libmwaw::DebugFile &ascFile = rsrcAscii(); |
571 | 0 | long pos = entry.begin(); |
572 | 0 | input->seek(pos, librevenge::RVNG_SEEK_SET); |
573 | |
|
574 | 0 | libmwaw::DebugStream f; |
575 | 0 | f << "Entries(TOCdata)[" << entry.id() << "]:"; |
576 | 0 | entry.setParsed(true); |
577 | 0 | auto N=static_cast<int>(input->readULong(2)); |
578 | 0 | f << "N=" << N << ","; |
579 | 0 | if (long(N*9+2) > entry.length()) { |
580 | 0 | MWAW_DEBUG_MSG(("LightWayTxtParser::readTOC: the number of entry seems bad\n")); |
581 | 0 | f << "###"; |
582 | 0 | ascFile.addPos(pos-4); |
583 | 0 | ascFile.addNote(f.str().c_str()); |
584 | 0 | return false; |
585 | 0 | } |
586 | 0 | ascFile.addPos(pos-4); |
587 | 0 | ascFile.addNote(f.str().c_str()); |
588 | |
|
589 | 0 | bool ok = true; |
590 | 0 | for (int i = 0; i < N; i++) { |
591 | 0 | pos = input->tell(); |
592 | 0 | if (pos+9 > entry.end()) { |
593 | 0 | ok = false; |
594 | 0 | break; |
595 | 0 | } |
596 | 0 | f.str(""); |
597 | 0 | f << "TOCdata-" << i << ":"; |
598 | 0 | long cPos[2]; |
599 | 0 | for (auto &c : cPos) c = long(input->readULong(4)); |
600 | 0 | f << "cpos?=" << cPos[0] << "<->" << cPos[1] << ","; |
601 | 0 | auto nC = static_cast<int>(input->readULong(1)); |
602 | 0 | if (pos+9+nC > entry.end()) { |
603 | 0 | ok = false; |
604 | 0 | break; |
605 | 0 | } |
606 | 0 | std::string name(""); |
607 | 0 | for (int c = 0; c < nC; c++) |
608 | 0 | name += char(input->readULong(1)); |
609 | 0 | f << name; |
610 | 0 | ascFile.addPos(pos); |
611 | 0 | ascFile.addNote(f.str().c_str()); |
612 | 0 | f.str(""); |
613 | 0 | f << "[TOC" << i << "]"; |
614 | 0 | ascii().addPos(cPos[0]); |
615 | 0 | ascii().addNote(f.str().c_str()); |
616 | 0 | } |
617 | 0 | if (!ok) { |
618 | 0 | f << "###"; |
619 | 0 | MWAW_DEBUG_MSG(("LightWayTxtParser::readTOC: can not read end\n")); |
620 | 0 | ascFile.addPos(pos); |
621 | 0 | ascFile.addNote(f.str().c_str()); |
622 | 0 | } |
623 | 0 | return true; |
624 | 0 | } |
625 | | |
626 | | //////////////////////////////////////////////////////////// |
627 | | // read the main document information data then unknown data |
628 | | //////////////////////////////////////////////////////////// |
629 | | bool LightWayTxtParser::readDocument(MWAWEntry const &entry) |
630 | 432 | { |
631 | 432 | if (entry.id() != 1000) |
632 | 0 | return false; |
633 | 432 | if (!entry.valid() || entry.length()<0x28) { |
634 | 11 | MWAW_DEBUG_MSG(("LightWayTxtParser::readDocument: the entry seems bad\n")); |
635 | 11 | return false; |
636 | 11 | } |
637 | 421 | MWAWInputStreamPtr input = rsrcInput(); |
638 | 421 | libmwaw::DebugFile &ascFile = rsrcAscii(); |
639 | 421 | long pos = entry.begin(); |
640 | 421 | input->seek(pos, librevenge::RVNG_SEEK_SET); |
641 | | |
642 | 421 | libmwaw::DebugStream f; |
643 | 421 | f << "Entries(Document):"; |
644 | 421 | entry.setParsed(true); |
645 | 421 | long val; |
646 | 1.68k | for (int i=0; i<3; i++) { // fl1=0|2|6, fl2=0|80 |
647 | 1.26k | val = long(input->readULong(1)); |
648 | 1.26k | if (val) f << "fl" << i << std::hex << "=" << val << std::dec << ","; |
649 | 1.26k | } |
650 | 1.26k | for (int i=0; i<2; i++) { // f0=0|1, f1=0|1 |
651 | 842 | val = long(input->readLong(2)); |
652 | 842 | if (val) f << "f" << i << "=" << val << ","; |
653 | 842 | } |
654 | 1.68k | for (int i=0; i<3; i++) { // fl3=0|1, fl4=0|1, fl5=1 |
655 | 1.26k | val = long(input->readULong(1)); |
656 | 1.26k | if (val) f << "fl" << i+3 << "=" << val << ","; |
657 | 1.26k | } |
658 | 421 | int pageDim[2]; |
659 | 842 | for (auto &d : pageDim) d = static_cast<int>(input->readLong(2)); |
660 | 421 | f << "dim=" << pageDim[1] << "x" << pageDim[0] << ","; |
661 | 421 | int dim[4]; |
662 | 842 | for (int s=0; s<2; s++) { |
663 | 3.36k | for (auto &d: dim) d = static_cast<int>(input->readULong(2)); |
664 | 842 | f << "pos" << s << "=" << dim[1] << "x" << dim[0] |
665 | 842 | << "<->" << dim[3] << "x" << dim[2] << ","; |
666 | 842 | if (s==1) break; |
667 | | |
668 | 421 | int margins[4]= {dim[0], dim[1], pageDim[0]-dim[2], pageDim[1]-dim[3]}; |
669 | 421 | if (margins[2] > 0 && 2*(margins[0]+margins[2]) < pageDim[0] && |
670 | 156 | margins[3] > 0 && 2*(margins[1]+margins[3]) < pageDim[1]) { |
671 | 148 | getPageSpan().setMarginTop(double(margins[0])/72.0); |
672 | 148 | getPageSpan().setMarginBottom(double(margins[2])/72.0); |
673 | 148 | getPageSpan().setMarginLeft(double(margins[1])/72.0); |
674 | 148 | getPageSpan().setMarginRight(double(margins[3])/72.0); |
675 | 148 | getPageSpan().setFormLength(double(pageDim[0])/72.); |
676 | 148 | getPageSpan().setFormWidth(double(pageDim[1])/72.); |
677 | 148 | m_pageSpanSet = true; |
678 | 148 | } |
679 | 421 | } |
680 | 421 | m_state->m_numCol = static_cast<int>(input->readLong(2)); |
681 | 421 | if (m_state->m_numCol > 1) f << "numCols=" << m_state->m_numCol << ","; |
682 | 421 | m_state->m_colSep = static_cast<int>(input->readLong(2)); |
683 | 421 | if (m_state->m_colSep) f << "colSep=" << m_state->m_colSep << ","; |
684 | | |
685 | 1.68k | for (int i=0; i<3; i++) { // gl0=3|3fff|4000|9001, gl1=3|4000|9001,gl2=d[12]|f[12]|1d2 |
686 | 1.26k | val = long(input->readULong(2)); |
687 | 1.26k | if (val) f << "gl" << i << "=" << std::hex << val << std::dec << ","; |
688 | 1.26k | } |
689 | 421 | ascFile.addPos(pos-4); |
690 | 421 | ascFile.addNote(f.str().c_str()); |
691 | 421 | if (entry.length()==0x28) |
692 | 238 | return true; |
693 | 183 | m_textParser->readDocumentHF(entry); |
694 | 183 | return true; |
695 | 421 | } |
696 | | |
697 | | bool LightWayTxtParser::readLWSR2(MWAWEntry const &entry) |
698 | 0 | { |
699 | 0 | if (entry.id() != 1002) |
700 | 0 | return false; |
701 | 0 | if (!entry.valid() || entry.length()%4) { |
702 | 0 | MWAW_DEBUG_MSG(("LightWayTxtParser::readLWSR2: the entry seems bad\n")); |
703 | 0 | return false; |
704 | 0 | } |
705 | 0 | auto N = int(entry.length()/4); |
706 | 0 | MWAWInputStreamPtr input = rsrcInput(); |
707 | 0 | libmwaw::DebugFile &ascFile = rsrcAscii(); |
708 | 0 | long pos = entry.begin(); |
709 | 0 | input->seek(pos, librevenge::RVNG_SEEK_SET); |
710 | |
|
711 | 0 | libmwaw::DebugStream f; |
712 | 0 | f << "Entries(LWSR2):"; |
713 | 0 | entry.setParsed(true); |
714 | 0 | f << "pos?=[" << std::hex; |
715 | 0 | for (int i = 0; i < N; i++) |
716 | 0 | f << input->readLong(4) << ","; |
717 | 0 | f << std::dec << "],"; |
718 | 0 | ascFile.addPos(pos-4); |
719 | 0 | ascFile.addNote(f.str().c_str()); |
720 | 0 | return true; |
721 | 0 | } |
722 | | |
723 | | bool LightWayTxtParser::readMPSR5(MWAWEntry const &entry) |
724 | 346 | { |
725 | 346 | if (entry.id() != 1005) |
726 | 0 | return false; |
727 | 346 | if (!entry.valid() || entry.length() != 0x48) { |
728 | 61 | MWAW_DEBUG_MSG(("LightWayTxtParser::readMPSR5: the entry is bad\n")); |
729 | 61 | return false; |
730 | 61 | } |
731 | 285 | MWAWInputStreamPtr input = rsrcInput(); |
732 | 285 | libmwaw::DebugFile &ascFile = rsrcAscii(); |
733 | 285 | long pos = entry.begin(); |
734 | 285 | input->seek(pos, librevenge::RVNG_SEEK_SET); |
735 | | |
736 | 285 | libmwaw::DebugStream f; |
737 | 285 | f << "Entries(MPSR5):"; |
738 | 285 | entry.setParsed(true); |
739 | 285 | long val = input->readLong(2); // a|c |
740 | 285 | if (val) |
741 | 285 | f << "f0=" << val << ","; |
742 | 285 | std::string name(""); |
743 | 2.81k | for (int i = 0; i < 32; i++) { |
744 | 2.78k | auto c = char(input->readULong(1)); |
745 | 2.78k | if (!c) |
746 | 253 | break; |
747 | 2.53k | name += c; |
748 | 2.53k | } |
749 | 285 | f << "defFont?=\"" << name << "\","; |
750 | 285 | input->seek(pos+34, librevenge::RVNG_SEEK_SET); |
751 | 855 | for (int i = 0; i < 2; i++) { // f1=3|4|6, f2=4 |
752 | 570 | val = input->readLong(2); |
753 | 570 | if (val) |
754 | 488 | f << "f" << i+1 << "=" << val << ","; |
755 | 570 | } |
756 | 285 | int dim[4]; |
757 | 855 | for (int s=0; s<2; s++) { |
758 | 2.28k | for (auto &d : dim) d = static_cast<int>(input->readLong(2)); |
759 | 570 | f << "pos" << s << "=" << dim[1] << "x" << dim[0] |
760 | 570 | << "<->" << dim[3] << "x" << dim[2] << ","; |
761 | 570 | } |
762 | 285 | val = long(input->readULong(4)); // a very big number |
763 | 285 | if (val) |
764 | 285 | f << "unkn=" << std::hex << val << std::dec << ","; |
765 | 285 | long sel[2]; // checkme |
766 | 285 | for (long &i : sel) |
767 | 570 | i = input->readLong(4); |
768 | 285 | if (sel[0]==sel[1]) |
769 | 197 | f << "sel?=" << std::hex << sel[0] << std::dec << ","; |
770 | 88 | else |
771 | 88 | f << "sel?=" << std::hex << sel[0] << "x" << sel[1] << std::dec << ","; |
772 | 855 | for (int i = 0; i < 2; i++) { // g1=0|6 |
773 | 570 | val = input->readLong(2); |
774 | 570 | if (val) |
775 | 162 | f << "g" << i << "=" << val << ","; |
776 | 570 | } |
777 | 855 | for (int i = 0; i < 2; i++) { // fl0=0|1, fl1=0|1 |
778 | 570 | val = long(input->readULong(1)); |
779 | 570 | if (val) |
780 | 121 | f << "fl" << i << "=" << val << ","; |
781 | 570 | } |
782 | | |
783 | 285 | ascFile.addPos(pos-4); |
784 | 285 | ascFile.addNote(f.str().c_str()); |
785 | 285 | return true; |
786 | 346 | } |
787 | | |
788 | | //////////////////////////////////////////////////////////// |
789 | | // |
790 | | // Low level |
791 | | // |
792 | | //////////////////////////////////////////////////////////// |
793 | | |
794 | | //////////////////////////////////////////////////////////// |
795 | | // read the header |
796 | | //////////////////////////////////////////////////////////// |
797 | | bool LightWayTxtParser::checkHeader(MWAWHeader *header, bool /*strict*/) |
798 | 2.02k | { |
799 | 2.02k | *m_state = LightWayTxtParserInternal::State(); |
800 | 2.02k | MWAWInputStreamPtr input = getInput(); |
801 | 2.02k | if (!input || !getRSRCParser()) |
802 | 112 | return false; |
803 | 1.91k | std::string type, creator; |
804 | 1.91k | if (input->getFinderInfo(type, creator) && type == "APPL") |
805 | 0 | m_state->m_isApplication=true; |
806 | 1.91k | MWAWEntry entry; |
807 | 1.91k | if (!m_state->m_isApplication) { |
808 | 1.91k | if (!input->hasDataFork()) |
809 | 47 | return false; |
810 | 1.91k | } |
811 | 0 | else { |
812 | 0 | entry = getRSRCParser()->getEntry("TEXT", 128); |
813 | 0 | if (!entry.valid()) |
814 | 0 | return false; |
815 | 0 | } |
816 | | // check if the LWSR string exists |
817 | 1.86k | entry = getRSRCParser()->getEntry("LWSR", 1000); |
818 | 1.86k | if (!entry.valid()) { |
819 | 511 | MWAW_DEBUG_MSG(("LightWayTxtParser::checkHeader: can not find the LWSR[1000] resource, not a Mac File!!!\n")); |
820 | 511 | return false; |
821 | 511 | } |
822 | 1.35k | if (header) |
823 | 492 | header->reset(MWAWDocument::MWAW_T_LIGHTWAYTEXT, 1); |
824 | | |
825 | 1.35k | return true; |
826 | 1.86k | } |
827 | | |
828 | | |
829 | | // vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: |