/src/libmwaw/src/lib/HanMacWrdKParser.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 <map> |
38 | | #include <set> |
39 | | #include <sstream> |
40 | | #include <string> |
41 | | |
42 | | #include <librevenge/librevenge.h> |
43 | | |
44 | | #include "MWAWCell.hxx" |
45 | | #include "MWAWTextListener.hxx" |
46 | | #include "MWAWFont.hxx" |
47 | | #include "MWAWFontConverter.hxx" |
48 | | #include "MWAWHeader.hxx" |
49 | | #include "MWAWList.hxx" |
50 | | #include "MWAWParagraph.hxx" |
51 | | #include "MWAWPosition.hxx" |
52 | | #include "MWAWPictMac.hxx" |
53 | | #include "MWAWPrinter.hxx" |
54 | | #include "MWAWSubDocument.hxx" |
55 | | |
56 | | #include "HanMacWrdKGraph.hxx" |
57 | | #include "HanMacWrdKText.hxx" |
58 | | |
59 | | #include "HanMacWrdKParser.hxx" |
60 | | |
61 | | /** Internal: the structures of a HanMacWrdKParser */ |
62 | | namespace HanMacWrdKParserInternal |
63 | | { |
64 | | //////////////////////////////////////// |
65 | | //! Internal: the state of a HanMacWrdKParser |
66 | | struct State { |
67 | | //! constructor |
68 | | State() |
69 | 22.0k | : m_zonesListBegin(-1) |
70 | 22.0k | , m_zonesMap() |
71 | 22.0k | , m_actPage(0) |
72 | 22.0k | , m_numPages(0) |
73 | 22.0k | , m_headerHeight(0) |
74 | 22.0k | , m_footerHeight(0) |
75 | 22.0k | { |
76 | 22.0k | } |
77 | | |
78 | | //! the list of zone begin |
79 | | long m_zonesListBegin; |
80 | | //! a map of entry: zoneId->zone |
81 | | std::multimap<long,std::shared_ptr<HanMacWrdKZone> > m_zonesMap; |
82 | | |
83 | | int m_actPage /** the actual page */, m_numPages /** the number of page of the final document */; |
84 | | int m_headerHeight /** the header height if known */, |
85 | | m_footerHeight /** the footer height if known */; |
86 | | }; |
87 | | |
88 | | //////////////////////////////////////// |
89 | | //! Internal: the subdocument of a HanMacWrdKParser |
90 | | class SubDocument final : public MWAWSubDocument |
91 | | { |
92 | | public: |
93 | | SubDocument(HanMacWrdKParser &pars, MWAWInputStreamPtr const &input, long zoneId) |
94 | 4.89k | : MWAWSubDocument(&pars, input, MWAWEntry()) |
95 | 4.89k | , m_id(zoneId) {} |
96 | | |
97 | | //! destructor |
98 | 0 | ~SubDocument() final {} |
99 | | |
100 | | //! operator!= |
101 | | bool operator!=(MWAWSubDocument const &doc) const final |
102 | 0 | { |
103 | 0 | if (MWAWSubDocument::operator!=(doc)) return true; |
104 | 0 | auto const *sDoc = dynamic_cast<SubDocument const *>(&doc); |
105 | 0 | if (!sDoc) return true; |
106 | 0 | if (m_id != sDoc->m_id) return true; |
107 | 0 | return false; |
108 | 0 | } |
109 | | |
110 | | //! the parser function |
111 | | void parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType type) final; |
112 | | |
113 | | protected: |
114 | | //! the subdocument id |
115 | | long m_id; |
116 | | }; |
117 | | |
118 | | void SubDocument::parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType type) |
119 | 4.89k | { |
120 | 4.89k | if (!listener.get()) { |
121 | 0 | MWAW_DEBUG_MSG(("HanMacWrdKParserInternal::SubDocument::parse: no listener\n")); |
122 | 0 | return; |
123 | 0 | } |
124 | 4.89k | if (type != libmwaw::DOC_HEADER_FOOTER) { |
125 | 0 | MWAW_DEBUG_MSG(("HanMacWrdKParserInternal::SubDocument::parse: unexpected document type\n")); |
126 | 0 | return; |
127 | 0 | } |
128 | 4.89k | auto *parser=dynamic_cast<HanMacWrdKParser *>(m_parser); |
129 | 4.89k | if (!parser) { |
130 | 0 | MWAW_DEBUG_MSG(("HanMacWrdKParserInternal::SubDocument::parse: no listener\n")); |
131 | 0 | return; |
132 | 0 | } |
133 | 4.89k | long pos = m_input->tell(); |
134 | 4.89k | parser->sendText(m_id, 0); |
135 | 4.89k | m_input->seek(pos, librevenge::RVNG_SEEK_SET); |
136 | 4.89k | } |
137 | | } |
138 | | |
139 | | //////////////////////////////////////////////////////////// |
140 | | // constructor/destructor + basic interface ... |
141 | | //////////////////////////////////////////////////////////// |
142 | | HanMacWrdKParser::HanMacWrdKParser(MWAWInputStreamPtr const &input, MWAWRSRCParserPtr const &rsrcParser, MWAWHeader *header) |
143 | 9.16k | : MWAWTextParser(input, rsrcParser, header) |
144 | 9.16k | , m_state() |
145 | 9.16k | , m_graphParser() |
146 | 9.16k | , m_textParser() |
147 | 9.16k | { |
148 | 9.16k | init(); |
149 | 9.16k | } |
150 | | |
151 | | HanMacWrdKParser::~HanMacWrdKParser() |
152 | 9.16k | { |
153 | 9.16k | } |
154 | | |
155 | | void HanMacWrdKParser::init() |
156 | 9.16k | { |
157 | 9.16k | resetTextListener(); |
158 | 9.16k | setAsciiName("main-1"); |
159 | | |
160 | 9.16k | m_state.reset(new HanMacWrdKParserInternal::State); |
161 | | |
162 | | // reduce the margin (in case, the page is not defined) |
163 | 9.16k | getPageSpan().setMarginTop(0.1); |
164 | 9.16k | getPageSpan().setMarginBottom(0.1); |
165 | 9.16k | getPageSpan().setMarginLeft(0.1); |
166 | 9.16k | getPageSpan().setMarginRight(0.1); |
167 | | |
168 | 9.16k | m_graphParser.reset(new HanMacWrdKGraph(*this)); |
169 | 9.16k | m_textParser.reset(new HanMacWrdKText(*this)); |
170 | 9.16k | } |
171 | | |
172 | | bool HanMacWrdKParser::sendText(long id, long subId, MWAWListenerPtr listener) |
173 | 4.95k | { |
174 | 4.95k | return m_textParser->sendText(id, subId, listener); |
175 | 4.95k | } |
176 | | |
177 | | bool HanMacWrdKParser::canSendTextAsGraphic(long id, long subId) |
178 | 1 | { |
179 | 1 | return m_textParser->canSendTextAsGraphic(id, subId); |
180 | 1 | } |
181 | | |
182 | | bool HanMacWrdKParser::sendZone(long zId) |
183 | 61 | { |
184 | 61 | MWAWPosition pos(MWAWVec2f(0,0), MWAWVec2f(0,0), librevenge::RVNG_POINT); |
185 | 61 | pos.setRelativePosition(MWAWPosition::Char); |
186 | 61 | return m_graphParser->sendFrame(zId, pos); |
187 | 61 | } |
188 | | |
189 | | bool HanMacWrdKParser::getColor(int colId, int patternId, MWAWColor &color) const |
190 | 112k | { |
191 | 112k | return m_graphParser->getColor(colId, patternId, color); |
192 | 112k | } |
193 | | |
194 | | //////////////////////////////////////////////////////////// |
195 | | // position and height |
196 | | //////////////////////////////////////////////////////////// |
197 | | MWAWVec2f HanMacWrdKParser::getPageLeftTop() const |
198 | 0 | { |
199 | 0 | return MWAWVec2f(float(getPageSpan().getMarginLeft()), |
200 | 0 | float(getPageSpan().getMarginTop()+m_state->m_headerHeight/72.0)); |
201 | 0 | } |
202 | | |
203 | | //////////////////////////////////////////////////////////// |
204 | | // new page |
205 | | //////////////////////////////////////////////////////////// |
206 | | void HanMacWrdKParser::newPage(int number) |
207 | 4.05k | { |
208 | 4.05k | if (number <= m_state->m_actPage || number > m_state->m_numPages) |
209 | 145 | return; |
210 | | |
211 | 7.83k | while (m_state->m_actPage < number) { |
212 | 3.93k | m_state->m_actPage++; |
213 | 3.93k | if (!getTextListener() || m_state->m_actPage == 1) |
214 | 2.22k | continue; |
215 | 1.70k | getTextListener()->insertBreak(MWAWTextListener::PageBreak); |
216 | 1.70k | } |
217 | 3.90k | } |
218 | | |
219 | | //////////////////////////////////////////////////////////// |
220 | | // the parser |
221 | | //////////////////////////////////////////////////////////// |
222 | | void HanMacWrdKParser::parse(librevenge::RVNGTextInterface *docInterface) |
223 | 3.69k | { |
224 | 3.69k | if (!getInput().get() || !checkHeader(nullptr)) throw(libmwaw::ParseException()); |
225 | 3.69k | bool ok = true; |
226 | 3.69k | try { |
227 | | // create the asciiFile |
228 | 3.69k | ascii().setStream(getInput()); |
229 | 3.69k | ascii().open(asciiName()); |
230 | | |
231 | 3.69k | checkHeader(nullptr); |
232 | 3.69k | ok = createZones(); |
233 | 3.69k | if (ok) { |
234 | 3.43k | createDocument(docInterface); |
235 | 3.43k | auto const &tokenIds = m_textParser->getTokenIdList(); |
236 | 3.43k | m_graphParser->sendPageGraphics(tokenIds); |
237 | 3.43k | m_textParser->sendMainText(); |
238 | | |
239 | | #ifdef DEBUG |
240 | | m_textParser->flushExtra(); |
241 | | m_graphParser->flushExtra(); |
242 | | #endif |
243 | 3.43k | } |
244 | 3.69k | ascii().reset(); |
245 | 3.69k | } |
246 | 3.69k | catch (...) { |
247 | 0 | MWAW_DEBUG_MSG(("HanMacWrdKParser::parse: exception catched when parsing\n")); |
248 | 0 | ok = false; |
249 | 0 | } |
250 | | |
251 | 3.69k | resetTextListener(); |
252 | 3.69k | if (!ok) throw(libmwaw::ParseException()); |
253 | 3.69k | } |
254 | | |
255 | | //////////////////////////////////////////////////////////// |
256 | | // create the document |
257 | | //////////////////////////////////////////////////////////// |
258 | | void HanMacWrdKParser::createDocument(librevenge::RVNGTextInterface *documentInterface) |
259 | 3.43k | { |
260 | 3.43k | if (!documentInterface) return; |
261 | 3.43k | if (getTextListener()) { |
262 | 0 | MWAW_DEBUG_MSG(("HanMacWrdKParser::createDocument: listener already exist\n")); |
263 | 0 | return; |
264 | 0 | } |
265 | | |
266 | | // update the page |
267 | 3.43k | m_state->m_actPage = 0; |
268 | | |
269 | 3.43k | int numPage = m_textParser->numPages(); |
270 | 3.43k | if (m_graphParser->numPages() > numPage) |
271 | 1 | numPage = m_graphParser->numPages(); |
272 | 3.43k | m_state->m_numPages = numPage; |
273 | | |
274 | | // create the page list |
275 | 3.43k | MWAWPageSpan ps(getPageSpan()); |
276 | 3.43k | long headerId, footerId; |
277 | 3.43k | m_textParser->getHeaderFooterId(headerId, footerId); |
278 | 3.43k | if (headerId) { |
279 | 2.44k | MWAWHeaderFooter header(MWAWHeaderFooter::HEADER, MWAWHeaderFooter::ALL); |
280 | 2.44k | header.m_subDocument.reset(new HanMacWrdKParserInternal::SubDocument |
281 | 2.44k | (*this, getInput(), headerId)); |
282 | 2.44k | ps.setHeaderFooter(header); |
283 | 2.44k | } |
284 | 3.43k | if (footerId) { |
285 | 2.44k | MWAWHeaderFooter footer(MWAWHeaderFooter::FOOTER, MWAWHeaderFooter::ALL); |
286 | 2.44k | footer.m_subDocument.reset(new HanMacWrdKParserInternal::SubDocument |
287 | 2.44k | (*this, getInput(), footerId)); |
288 | 2.44k | ps.setHeaderFooter(footer); |
289 | 2.44k | } |
290 | | |
291 | 3.43k | ps.setPageSpan(m_state->m_numPages+1); |
292 | 3.43k | std::vector<MWAWPageSpan> pageList(1,ps); |
293 | | // |
294 | 3.43k | MWAWTextListenerPtr listen(new MWAWTextListener(*getParserState(), pageList, documentInterface)); |
295 | 3.43k | setTextListener(listen); |
296 | 3.43k | listen->startDocument(); |
297 | 3.43k | } |
298 | | |
299 | | |
300 | | //////////////////////////////////////////////////////////// |
301 | | // |
302 | | // Intermediate level |
303 | | // |
304 | | //////////////////////////////////////////////////////////// |
305 | | bool HanMacWrdKParser::createZones() |
306 | 3.69k | { |
307 | 3.69k | if (!HanMacWrdKParser::readZonesList()) |
308 | 259 | return false; |
309 | | |
310 | 3.43k | libmwaw::DebugStream f; |
311 | 3.43k | for (auto const &it : m_state->m_zonesMap) |
312 | 124k | readZone(it.second); |
313 | 124k | for (auto const &it : m_state->m_zonesMap) { |
314 | 124k | std::shared_ptr<HanMacWrdKZone> const &zone = it.second; |
315 | 124k | if (!zone || !zone->valid() || zone->m_parsed) |
316 | 116k | continue; |
317 | 8.51k | f.str(""); |
318 | 8.51k | f << "Entries(" << std::hex << zone->name() << std::dec << "):"; |
319 | 8.51k | zone->ascii().addPos(0); |
320 | 8.51k | zone->ascii().addNote(f.str().c_str()); |
321 | 8.51k | } |
322 | | |
323 | | // retrieve the text type and pass information to text parser |
324 | 3.43k | m_graphParser->prepareStructures(); |
325 | 3.43k | auto idTypeMap = m_graphParser->getTextFrameInformations(); |
326 | 3.43k | m_textParser->updateTextZoneTypes(idTypeMap); |
327 | | |
328 | 3.43k | return true; |
329 | 3.69k | } |
330 | | |
331 | | //////////////////////////////////////////////////////////// |
332 | | // |
333 | | // Low level |
334 | | // |
335 | | //////////////////////////////////////////////////////////// |
336 | | bool HanMacWrdKParser::readZonesList() |
337 | 3.69k | { |
338 | 3.69k | MWAWInputStreamPtr input = getInput(); |
339 | 3.69k | if (m_state->m_zonesListBegin <= 0 || !input->checkPosition(m_state->m_zonesListBegin)) { |
340 | 0 | MWAW_DEBUG_MSG(("HanMacWrdKParser::readZonesList: the list entry is not set \n")); |
341 | 0 | return false; |
342 | 0 | } |
343 | 3.69k | libmwaw::DebugStream f; |
344 | | |
345 | 3.69k | long debZone = m_state->m_zonesListBegin; |
346 | 3.69k | std::set<long> seeDebZone; |
347 | 3.70k | while (debZone) { |
348 | 3.70k | if (seeDebZone.find(debZone) != seeDebZone.end()) { |
349 | 0 | MWAW_DEBUG_MSG(("HanMacWrdKParser::readZonesList: oops, we have already see this zone\n")); |
350 | 0 | break; |
351 | 0 | } |
352 | 3.70k | seeDebZone.insert(debZone); |
353 | 3.70k | long pos = debZone; |
354 | 3.70k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
355 | 3.70k | auto numZones = int(input->readULong(1)); |
356 | 3.70k | f.str(""); |
357 | 3.70k | f << "Entries(Zones):"; |
358 | 3.70k | f << "N=" << numZones << ","; |
359 | 3.70k | if (!numZones || !input->checkPosition(pos+16*(numZones+1))) { |
360 | 149 | MWAW_DEBUG_MSG(("HanMacWrdKParser::readZonesList: can not read the number of zones\n")); |
361 | 149 | ascii().addPos(pos); |
362 | 149 | ascii().addNote(f.str().c_str()); |
363 | 149 | break; |
364 | 149 | } |
365 | 3.55k | int val; |
366 | 14.2k | for (int i = 0; i < 3; i++) { |
367 | 10.6k | val = int(input->readLong(1)); |
368 | 10.6k | if (val) f << "f" << i << "=" << val << ","; |
369 | 10.6k | } |
370 | 3.55k | auto ptr = long(input->readULong(4)); |
371 | 3.55k | if (ptr != debZone) { |
372 | 115 | MWAW_DEBUG_MSG(("HanMacWrdKParser::readZonesList: can not read the zone begin ptr\n")); |
373 | 115 | f << "#ptr=" << std::hex << ptr << std::dec << ","; |
374 | 115 | ascii().addPos(pos); |
375 | 115 | ascii().addNote(f.str().c_str()); |
376 | 115 | break; |
377 | 115 | } |
378 | 3.43k | auto nextPtr = long(input->readULong(4)); |
379 | 3.43k | if (nextPtr) { |
380 | 31 | f << "nextPtr=" << std::hex << nextPtr << std::dec; |
381 | 31 | if (!input->checkPosition(nextPtr)) { |
382 | 26 | MWAW_DEBUG_MSG(("HanMacWrdKParser::readZonesList: can not read the next zone begin ptr\n")); |
383 | 26 | nextPtr = 0; |
384 | 26 | f << "###"; |
385 | 26 | } |
386 | 31 | f << ","; |
387 | 31 | } |
388 | 10.3k | for (int i = 0; i < 2; i++) { // always 0,0? |
389 | 6.87k | val = int(input->readLong(2)); |
390 | 6.87k | if (val) f << "f" << i+3 << "=" << val << ","; |
391 | 6.87k | } |
392 | 3.43k | ascii().addPos(pos); |
393 | 3.43k | ascii().addNote(f.str().c_str()); |
394 | 3.43k | input->seek(pos+16, librevenge::RVNG_SEEK_SET); |
395 | | |
396 | 128k | for (int i = 0; i < numZones; i++) { |
397 | 124k | pos = input->tell(); |
398 | 124k | f.str(""); |
399 | 124k | std::shared_ptr<HanMacWrdKZone> zone(new HanMacWrdKZone(std::shared_ptr<libmwaw::DebugFile>(new libmwaw::DebugFile(MWAWInputStreamPtr())))); |
400 | 124k | zone->m_type = int(input->readLong(2)); |
401 | 124k | val = int(input->readLong(2)); |
402 | 124k | if (val) f << "f0=" << val << ","; |
403 | 124k | zone->setFileBeginPos(long(input->readULong(4))); |
404 | 124k | zone->m_id = long(input->readULong(4)); |
405 | 124k | zone->m_subId = long(input->readULong(4)); |
406 | 124k | zone->m_extra = f.str(); |
407 | 124k | f.str(""); |
408 | 124k | f << "Zones-" << i << ":" << *zone; |
409 | 124k | if (!input->checkPosition(ptr)) { |
410 | 0 | MWAW_DEBUG_MSG(("HanMacWrdKParser::readZonesList: can not read the %d zone address\n", i)); |
411 | 0 | f << ",#Ptr"; |
412 | 0 | } |
413 | 124k | else |
414 | 124k | m_state->m_zonesMap.insert |
415 | 124k | (std::multimap<long,std::shared_ptr<HanMacWrdKZone> >::value_type(zone->m_id,zone)); |
416 | 124k | ascii().addDelimiter(input->tell(), '|'); |
417 | 124k | ascii().addPos(pos); |
418 | 124k | ascii().addNote(f.str().c_str()); |
419 | 124k | input->seek(pos+16, librevenge::RVNG_SEEK_SET); |
420 | 124k | } |
421 | | |
422 | 3.43k | ascii().addPos(input->tell()); |
423 | 3.43k | ascii().addNote("_"); |
424 | 3.43k | if (!nextPtr) break; |
425 | 5 | debZone = nextPtr; |
426 | 5 | } |
427 | 3.69k | return m_state->m_zonesMap.size(); |
428 | 3.69k | } |
429 | | |
430 | | bool HanMacWrdKParser::readZone(std::shared_ptr<HanMacWrdKZone> zone) |
431 | 124k | { |
432 | 124k | if (!zone) { |
433 | 0 | MWAW_DEBUG_MSG(("HanMacWrdKParser::readZone: can not find the zone\n")); |
434 | 0 | return false; |
435 | 0 | } |
436 | | |
437 | 124k | MWAWInputStreamPtr input = getInput(); |
438 | 124k | libmwaw::DebugStream f; |
439 | 124k | long pos = zone->fileBeginPos(); |
440 | 124k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
441 | 124k | f << "Entries(" << zone->name() << "):"; |
442 | 124k | auto n = int(input->readLong(2)); |
443 | 124k | f << "n?=" << n << ","; |
444 | 124k | auto val = long(input->readLong(2)); |
445 | 124k | if (val) f << "unkn=" << val << ","; |
446 | | |
447 | 124k | auto totalSz = long(input->readULong(4)); |
448 | 124k | auto dataSz = long(input->readULong(4)); |
449 | 124k | if (totalSz != dataSz+12 || !input->checkPosition(pos+totalSz)) { |
450 | 96.1k | MWAW_DEBUG_MSG(("HanMacWrdKParser::readZone: can not read the zone size\n")); |
451 | 96.1k | f << "###"; |
452 | 96.1k | ascii().addPos(pos); |
453 | 96.1k | ascii().addNote(f.str().c_str()); |
454 | 96.1k | return false; |
455 | 96.1k | } |
456 | 28.6k | zone->setFileLength(totalSz); |
457 | 28.6k | ascii().addPos(pos); |
458 | 28.6k | ascii().addNote(f.str().c_str()); |
459 | | |
460 | 28.6k | decodeZone(zone); |
461 | 28.6k | if (!zone->valid()) |
462 | 3 | return false; |
463 | | |
464 | 28.6k | switch (zone->m_type) { |
465 | 6.34k | case 1: |
466 | 6.34k | if (m_textParser->readTextZone(zone)) |
467 | 6.34k | return true; |
468 | 0 | break; |
469 | 344 | case 2: |
470 | 344 | if (m_graphParser->readFrames(zone)) |
471 | 342 | return true; |
472 | 2 | break; |
473 | 3.16k | case 3: |
474 | 3.16k | if (m_textParser->readStyles(zone)) |
475 | 729 | return true; |
476 | 2.43k | break; |
477 | 2.88k | case 4: |
478 | 2.88k | if (m_textParser->readSections(zone)) |
479 | 2.71k | return true; |
480 | 176 | break; |
481 | 2.48k | case 5: |
482 | 2.48k | if (m_textParser->readFontNames(zone)) |
483 | 1.74k | return true; |
484 | 741 | break; |
485 | 1.77k | case 6: |
486 | 1.77k | if (readZone6(zone)) |
487 | 1.32k | return true; |
488 | 443 | break; |
489 | 1.70k | case 7: |
490 | 1.70k | if (readPrintInfo(*zone)) |
491 | 1.31k | return true; |
492 | 390 | break; |
493 | 1.93k | case 8: |
494 | 1.93k | if (readZone8(zone)) |
495 | 1.76k | return true; |
496 | 163 | break; |
497 | 163 | case 9: |
498 | 79 | if (readFramesUnkn(zone)) |
499 | 66 | return true; |
500 | 13 | break; |
501 | 1.79k | case 0xa: |
502 | 1.79k | if (readZonea(zone)) |
503 | 1.51k | return true; |
504 | 285 | break; |
505 | 1.83k | case 0xb: |
506 | 1.83k | if (readZoneb(*zone)) |
507 | 1.65k | return true; |
508 | 181 | break; |
509 | 3.31k | case 0xc: |
510 | 3.31k | if (readZonec(zone)) |
511 | 2.94k | return true; |
512 | 374 | MWAW_FALLTHROUGH; |
513 | 467 | case 0xd: |
514 | 467 | if (m_graphParser->readPicture(zone)) |
515 | 44 | return true; |
516 | 423 | break; |
517 | 937 | default: |
518 | 937 | break; |
519 | 28.6k | } |
520 | | /** type1: text, type7: printInfo: typed: graphic */ |
521 | 6.19k | f.str(""); |
522 | 6.19k | f << zone->name() << "[data]:PTR=" << std::hex << zone->fileBeginPos() << std::dec << ","; |
523 | 6.19k | zone->ascii().addPos(0); |
524 | 6.19k | zone->ascii().addNote(f.str().c_str()); |
525 | | |
526 | 6.19k | return true; |
527 | 28.6k | } |
528 | | |
529 | | // read the print info data |
530 | | bool HanMacWrdKParser::readPrintInfo(HanMacWrdKZone &zone) |
531 | 1.70k | { |
532 | 1.70k | long dataSz = zone.length(); |
533 | 1.70k | MWAWInputStreamPtr input = zone.m_input; |
534 | 1.70k | libmwaw::DebugFile &asciiFile = zone.ascii(); |
535 | 1.70k | long pos = zone.begin(); |
536 | | |
537 | 1.70k | if (dataSz < 192 || !input->checkPosition(zone.end())) { |
538 | 35 | MWAW_DEBUG_MSG(("HanMacWrdKParser::readPrintInfo: the zone seems too short\n")); |
539 | 35 | return false; |
540 | 35 | } |
541 | | |
542 | 1.66k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
543 | 1.66k | libmwaw::DebugStream f; |
544 | 1.66k | zone.m_parsed = true; |
545 | | |
546 | 1.66k | f << zone.name() << "(A):PTR=" << std::hex << zone.fileBeginPos() << std::dec << ","; |
547 | 1.66k | long val; |
548 | 1.66k | f << "margins?=["; |
549 | 1.66k | float margins[4]; // L, T, R, B |
550 | 6.67k | for (auto &margin : margins) { |
551 | 6.67k | margin = float(input->readLong(4))/65536.f; |
552 | 6.67k | f << margin << ","; |
553 | 6.67k | } |
554 | 1.66k | f << "],"; |
555 | 1.66k | int dim[4]; |
556 | 6.67k | for (auto &d : dim) d=int(input->readLong(2)); |
557 | 1.66k | f << "paper=[" << dim[1] << "x" << dim[0] << " " << dim[3] << "x" << dim[2] << "],"; |
558 | 1.66k | val = long(input->readULong(2)); |
559 | 1.66k | if (val != 1) f << "firstSectNumber=" << val << ","; |
560 | 1.66k | val = long(input->readULong(2)); |
561 | 1.66k | if (val) f << "f0=" << val << ","; |
562 | | |
563 | | // after unknown |
564 | 1.66k | asciiFile.addDelimiter(input->tell(),'|'); |
565 | 1.66k | asciiFile.addPos(pos); |
566 | 1.66k | asciiFile.addNote(f.str().c_str()); |
567 | 1.66k | pos += 68; |
568 | 1.66k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
569 | 1.66k | f.str(""); |
570 | 1.66k | f << zone.name() << "(B):"; |
571 | 1.66k | auto sz = long(input->readULong(4)); |
572 | 1.66k | if (sz < 0x78) { |
573 | 52 | MWAW_DEBUG_MSG(("HanMacWrdKParser::readPrintInfo: the print info data zone seems too short\n")); |
574 | 52 | f << "###"; |
575 | 52 | asciiFile.addPos(pos); |
576 | 52 | asciiFile.addNote(f.str().c_str()); |
577 | 52 | return false; |
578 | 52 | } |
579 | | |
580 | | // print info |
581 | 1.61k | libmwaw::PrinterInfo info; |
582 | 1.61k | if (!info.read(input)) { |
583 | 303 | f << "###"; |
584 | 303 | asciiFile.addPos(pos); |
585 | 303 | asciiFile.addNote(f.str().c_str()); |
586 | 303 | return false; |
587 | 303 | } |
588 | | |
589 | 1.31k | MWAWVec2i paperSize = info.paper().size(); |
590 | 1.31k | MWAWVec2i pageSize = info.page().size(); |
591 | | |
592 | 1.31k | bool useDocInfo = (float(dim[3]-dim[1])>margins[2]+margins[0]) && |
593 | 1.25k | (float(dim[2]-dim[0])>margins[3]+margins[1]); |
594 | 1.31k | bool usePrintInfo = pageSize.x() > 0 && pageSize.y() > 0 && |
595 | 1.22k | paperSize.x() > 0 && paperSize.y() > 0; |
596 | | |
597 | 1.31k | MWAWVec2f lTopMargin(margins[0],margins[1]), rBotMargin(margins[2],margins[3]); |
598 | | // define margin from print info |
599 | 1.31k | if (useDocInfo) |
600 | 1.23k | paperSize = MWAWVec2i(dim[3]-dim[1],dim[2]-dim[0]); |
601 | 77 | else if (usePrintInfo) { |
602 | 24 | lTopMargin= MWAWVec2f(-float(info.paper().pos(0)[0]), -float(info.paper().pos(0)[1])); |
603 | 24 | rBotMargin= MWAWVec2f(info.paper().pos(1) - info.page().pos(1)); |
604 | | |
605 | | // move margin left | top |
606 | 24 | float decalX = lTopMargin.x() > 14 ? 14 : 0; |
607 | 24 | float decalY = lTopMargin.y() > 14 ? 14 : 0; |
608 | 24 | lTopMargin -= MWAWVec2f(decalX, decalY); |
609 | 24 | rBotMargin += MWAWVec2f(decalX, decalY); |
610 | 24 | } |
611 | | |
612 | | // decrease right | bottom |
613 | 1.31k | float rightMarg = rBotMargin.x() -10; |
614 | 1.31k | if (rightMarg < 0) rightMarg=0; |
615 | 1.31k | float botMarg = rBotMargin.y() -50; |
616 | 1.31k | if (botMarg < 0) botMarg=0; |
617 | | |
618 | 1.31k | if (useDocInfo || usePrintInfo) { |
619 | 1.26k | getPageSpan().setMarginTop(double(lTopMargin.y())/72.0); |
620 | 1.26k | getPageSpan().setMarginBottom(double(botMarg)/72.0); |
621 | 1.26k | getPageSpan().setMarginLeft(double(lTopMargin.x())/72.0); |
622 | 1.26k | getPageSpan().setMarginRight(double(rightMarg)/72.0); |
623 | 1.26k | getPageSpan().setFormLength(paperSize.y()/72.); |
624 | 1.26k | getPageSpan().setFormWidth(paperSize.x()/72.); |
625 | | |
626 | 1.26k | f << info; |
627 | 1.26k | } |
628 | 53 | else |
629 | 53 | f << "###"; |
630 | | |
631 | 1.31k | asciiFile.addPos(pos); |
632 | 1.31k | asciiFile.addNote(f.str().c_str()); |
633 | 1.31k | if (input->tell()!=zone.end()) { |
634 | 1.28k | asciiFile.addDelimiter(input->tell(),'|'); |
635 | 1.28k | input->seek(zone.end(), librevenge::RVNG_SEEK_SET); |
636 | 1.28k | } |
637 | 1.31k | return true; |
638 | 1.61k | } |
639 | | |
640 | | // a small unknown zone: link to table, frame? |
641 | | bool HanMacWrdKParser::readFramesUnkn(std::shared_ptr<HanMacWrdKZone> zone) |
642 | 79 | { |
643 | 79 | if (!zone) { |
644 | 0 | MWAW_DEBUG_MSG(("HanMacWrdKParser::readFramesUnkn: called without any zone\n")); |
645 | 0 | return false; |
646 | 0 | } |
647 | 79 | long dataSz = zone->length(); |
648 | 79 | if (dataSz < 2) { |
649 | 0 | MWAW_DEBUG_MSG(("HanMacWrdKParser::readFramesUnkn: the zone seems too short\n")); |
650 | 0 | return false; |
651 | 0 | } |
652 | | |
653 | 79 | MWAWInputStreamPtr input = zone->m_input; |
654 | 79 | libmwaw::DebugFile &asciiFile = zone->ascii(); |
655 | 79 | libmwaw::DebugStream f; |
656 | 79 | zone->m_parsed = true; |
657 | | |
658 | 79 | f << zone->name() << ":PTR=" << std::hex << zone->fileBeginPos() << std::dec << ","; |
659 | 79 | input->seek(0, librevenge::RVNG_SEEK_SET); |
660 | 79 | auto N= static_cast<int>(input->readLong(2)); // always find val=0, so :-~ |
661 | 79 | f << "N?=" << N << ","; |
662 | 79 | long expectedSz = N*6+2; |
663 | 79 | if (expectedSz != dataSz && expectedSz+1 != dataSz) { |
664 | 13 | MWAW_DEBUG_MSG(("HanMacWrdKParser::readFramesUnkn: the zone size seems odd\n")); |
665 | 13 | return false; |
666 | 13 | } |
667 | 66 | asciiFile.addPos(0); |
668 | 66 | asciiFile.addNote(f.str().c_str()); |
669 | | |
670 | 66 | for (int i = 0; i < N; i++) { |
671 | 0 | long pos = input->tell(); |
672 | 0 | f.str(""); |
673 | 0 | f << zone->name() << "-" << i << ":"; |
674 | 0 | long id = input->readLong(4); |
675 | 0 | f << "id=" << std::hex << id << std::dec << ","; |
676 | 0 | auto type = static_cast<int>(input->readLong(2)); |
677 | 0 | switch (type) { |
678 | 0 | case 4: |
679 | 0 | f << "textbox,"; |
680 | 0 | break; |
681 | 0 | case 6: |
682 | 0 | f << "picture,"; |
683 | 0 | break; |
684 | 0 | case 8: |
685 | 0 | f << "basicGraphic,"; |
686 | 0 | break; |
687 | 0 | case 9: |
688 | 0 | f << "table,"; |
689 | 0 | break; |
690 | 0 | case 10: |
691 | 0 | f << "textbox[withHeader],"; |
692 | 0 | break; |
693 | 0 | case 11: |
694 | 0 | f << "group"; |
695 | 0 | break; |
696 | 0 | default: |
697 | 0 | f << "#type=" << type << ","; |
698 | 0 | break; |
699 | 0 | } |
700 | 0 | asciiFile.addPos(pos); |
701 | 0 | asciiFile.addNote(f.str().c_str()); |
702 | 0 | input->seek(pos+6, librevenge::RVNG_SEEK_SET); |
703 | 0 | } |
704 | 66 | if (!input->isEnd()) |
705 | 66 | asciiFile.addDelimiter(input->tell(),'|'); |
706 | 66 | return true; |
707 | 66 | } |
708 | | |
709 | | // a unknown zone |
710 | | bool HanMacWrdKParser::readZone6(std::shared_ptr<HanMacWrdKZone> zone) |
711 | 1.77k | { |
712 | 1.77k | if (!zone) { |
713 | 0 | MWAW_DEBUG_MSG(("HanMacWrdKParser::readZone6: called without any zone\n")); |
714 | 0 | return false; |
715 | 0 | } |
716 | | |
717 | 1.77k | long dataSz = zone->length(); |
718 | 1.77k | if (dataSz < 8) { |
719 | 0 | MWAW_DEBUG_MSG(("HanMacWrdKParser::readZone6: the zone seems too short\n")); |
720 | 0 | return false; |
721 | 0 | } |
722 | | |
723 | 1.77k | MWAWInputStreamPtr input = zone->m_input; |
724 | 1.77k | libmwaw::DebugFile &asciiFile = zone->ascii(); |
725 | 1.77k | libmwaw::DebugStream f; |
726 | 1.77k | zone->m_parsed = true; |
727 | 1.77k | long pos=0; |
728 | 1.77k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
729 | | |
730 | | // no sure, checkme |
731 | 4.81k | for (int st = 0; st < 2; st++) { |
732 | 3.49k | pos = input->tell(); |
733 | 3.49k | auto sz = long(input->readULong(4)); |
734 | 3.49k | if (sz<0 || pos+sz+4 > dataSz) { |
735 | 443 | MWAW_DEBUG_MSG(("HanMacWrdKParser::readZone6: zone%d ptr seems bad\n", st)); |
736 | 443 | return false; |
737 | 443 | } |
738 | | |
739 | 3.04k | f.str(""); |
740 | 3.04k | if (st==0) |
741 | 1.72k | f << zone->name() << "(A):PTR=" << std::hex << zone->fileBeginPos() << std::dec << ","; |
742 | 1.32k | else |
743 | 1.32k | f << zone->name() << "(B):"; |
744 | | |
745 | 3.04k | asciiFile.addDelimiter(input->tell(),'|'); |
746 | 3.04k | asciiFile.addPos(pos); |
747 | 3.04k | asciiFile.addNote(f.str().c_str()); |
748 | 3.04k | input->seek(pos+4+sz, librevenge::RVNG_SEEK_SET); |
749 | 3.04k | } |
750 | 1.32k | return true; |
751 | 1.77k | } |
752 | | |
753 | | // a small unknown zone |
754 | | bool HanMacWrdKParser::readZone8(std::shared_ptr<HanMacWrdKZone> zone) |
755 | 1.93k | { |
756 | 1.93k | if (!zone) { |
757 | 0 | MWAW_DEBUG_MSG(("HanMacWrdKParser::readZone8: called without any zone\n")); |
758 | 0 | return false; |
759 | 0 | } |
760 | 1.93k | long dataSz = zone->length(); |
761 | 1.93k | if (dataSz < 78) { |
762 | 163 | MWAW_DEBUG_MSG(("HanMacWrdKParser::readZone8: the zone seems too short\n")); |
763 | 163 | return false; |
764 | 163 | } |
765 | | |
766 | 1.76k | MWAWInputStreamPtr input = zone->m_input; |
767 | 1.76k | libmwaw::DebugFile &asciiFile = zone->ascii(); |
768 | 1.76k | libmwaw::DebugStream f; |
769 | 1.76k | zone->m_parsed = true; |
770 | | |
771 | 1.76k | f << zone->name() << ":PTR=" << std::hex << zone->fileBeginPos() << std::dec << ","; |
772 | 1.76k | input->seek(0, librevenge::RVNG_SEEK_SET); |
773 | | // find f0=1 (N?), f3=1, f20=8, f22=6, f24=2, f26=144, f28=1, f30=1 |
774 | 70.7k | for (int i = 0; i < 39; i++) { |
775 | 68.9k | long val = input->readLong(2); |
776 | 68.9k | if (val) f << "f" << i << "=" << val << ","; |
777 | 68.9k | } |
778 | | |
779 | 1.76k | asciiFile.addPos(0); |
780 | 1.76k | asciiFile.addNote(f.str().c_str()); |
781 | 1.76k | if (!input->isEnd()) |
782 | 1.63k | asciiFile.addDelimiter(input->tell(),'|'); |
783 | 1.76k | return true; |
784 | 1.93k | } |
785 | | |
786 | | // a small unknown zone |
787 | | bool HanMacWrdKParser::readZonea(std::shared_ptr<HanMacWrdKZone> zone) |
788 | 1.79k | { |
789 | 1.79k | if (!zone) { |
790 | 0 | MWAW_DEBUG_MSG(("HanMacWrdKParser::readZonea: called without any zone\n")); |
791 | 0 | return false; |
792 | 0 | } |
793 | 1.79k | long dataSz = zone->length(); |
794 | 1.79k | if (dataSz < 114) { |
795 | 285 | MWAW_DEBUG_MSG(("HanMacWrdKParser::readZonea: the zone seems too short\n")); |
796 | 285 | return false; |
797 | 285 | } |
798 | | |
799 | 1.51k | MWAWInputStreamPtr input = zone->m_input; |
800 | 1.51k | libmwaw::DebugFile &asciiFile = zone->ascii(); |
801 | 1.51k | libmwaw::DebugStream f; |
802 | 1.51k | zone->m_parsed = true; |
803 | | |
804 | 1.51k | f << zone->name() << ":PTR=" << std::hex << zone->fileBeginPos() << std::dec << ","; |
805 | 1.51k | input->seek(0, librevenge::RVNG_SEEK_SET); |
806 | 1.51k | long val; |
807 | 62.0k | for (int i = 0; i < 40; i++) { // always 0 ? |
808 | 60.5k | val = input->readLong(2); |
809 | 60.5k | if (!val) continue; |
810 | 300 | f << "f" << i << "=" << val << ","; |
811 | 300 | } |
812 | 6.05k | for (int i = 0; i < 3; i++) { // g0=g1=g2=a665 |
813 | 4.53k | val = long(input->readULong(2)); |
814 | 4.53k | if (!val) continue; |
815 | 4.47k | f << "g" << i << "=" << std::hex << val << std::dec << ","; |
816 | 4.47k | } |
817 | 22.6k | for (int i = 0; i < 14; i++) { // h5=h6=h8=h9=-1 |
818 | 21.1k | val = input->readLong(2); |
819 | 21.1k | if (!val) continue; |
820 | 10.7k | f << "h" << i << "=" << val << ","; |
821 | 10.7k | } |
822 | | |
823 | 1.51k | asciiFile.addPos(0); |
824 | 1.51k | asciiFile.addNote(f.str().c_str()); |
825 | 1.51k | if (!input->isEnd()) |
826 | 1.04k | asciiFile.addDelimiter(input->tell(),'|'); |
827 | 1.51k | return true; |
828 | 1.79k | } |
829 | | |
830 | | // a small unknown zone |
831 | | bool HanMacWrdKParser::readZoneb(HanMacWrdKZone &zone) |
832 | 1.83k | { |
833 | 1.83k | long dataSz = zone.length(); |
834 | 1.83k | MWAWInputStreamPtr input = zone.m_input; |
835 | 1.83k | libmwaw::DebugFile &asciiFile = zone.ascii(); |
836 | 1.83k | long pos=zone.begin(); |
837 | | |
838 | 1.83k | if (dataSz < 34 || !input->checkPosition(zone.end())) { |
839 | 181 | MWAW_DEBUG_MSG(("HanMacWrdKParser::readZoneb: the zone seems too short\n")); |
840 | 181 | return false; |
841 | 181 | } |
842 | | |
843 | 1.65k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
844 | 1.65k | libmwaw::DebugStream f; |
845 | 1.65k | zone.m_parsed = true; |
846 | | |
847 | 1.65k | f << zone.name() << ":PTR=" << std::hex << zone.fileBeginPos() << std::dec << ","; |
848 | | |
849 | 1.65k | long val = input->readLong(4); // 1c58b4 |
850 | 1.65k | f << "dim?=" << float(val)/65536.f << ","; |
851 | | |
852 | 8.27k | for (int i = 0; i < 4; i++) { // always 7,7,0,0 |
853 | 6.61k | val = input->readLong(2); |
854 | 6.61k | if (!val) continue; |
855 | 3.49k | f << "f" << i << "=" << val << ","; |
856 | 3.49k | } |
857 | 1.65k | val = input->readLong(4); // 2d5ab ~dim/10. |
858 | 1.65k | f << "dim2?=" << float(val)/65536.f << ","; |
859 | 8.27k | for (int i = 0; i < 4; i++) { // 0,4,0, 0 |
860 | 6.61k | val = long(input->readULong(2)); |
861 | 6.61k | if (!val) continue; |
862 | 2.07k | f << "g" << i << "=" << val << ","; |
863 | 2.07k | } |
864 | 8.27k | for (int i = 0; i < 4; i++) { // 1,1,1,0 |
865 | 6.61k | val = input->readLong(1); |
866 | 6.61k | if (!val) continue; |
867 | 4.94k | f << "h" << i << "=" << val << ","; |
868 | 4.94k | } |
869 | 6.61k | for (int i = 0; i < 3; i++) { // always 6,0,0 |
870 | 4.96k | val = input->readLong(2); |
871 | 4.96k | if (!val) continue; |
872 | 2.24k | f << "j" << i << "=" << val << ","; |
873 | 2.24k | } |
874 | 1.65k | if (dataSz >= 36) { |
875 | 1.53k | val = input->readLong(2); |
876 | 1.53k | if (val) f << "j3=" << val << ","; |
877 | 1.53k | } |
878 | | |
879 | 1.65k | asciiFile.addPos(pos); |
880 | 1.65k | asciiFile.addNote(f.str().c_str()); |
881 | 1.65k | if (input->tell()!=zone.end()) { |
882 | 1.44k | asciiFile.addDelimiter(input->tell(),'|'); |
883 | 1.44k | input->seek(zone.end(), librevenge::RVNG_SEEK_SET); |
884 | 1.44k | } |
885 | 1.65k | return true; |
886 | 1.83k | } |
887 | | |
888 | | // a small unknown zone |
889 | | bool HanMacWrdKParser::readZonec(std::shared_ptr<HanMacWrdKZone> zone) |
890 | 3.31k | { |
891 | 3.31k | if (!zone) { |
892 | 0 | MWAW_DEBUG_MSG(("HanMacWrdKParser::readZonec: called without any zone\n")); |
893 | 0 | return false; |
894 | 0 | } |
895 | 3.31k | long dataSz = zone->length(); |
896 | 3.31k | if (dataSz < 52) { |
897 | 374 | MWAW_DEBUG_MSG(("HanMacWrdKParser::readZonec: the zone seems too short\n")); |
898 | 374 | return false; |
899 | 374 | } |
900 | | |
901 | 2.94k | MWAWInputStreamPtr input = zone->m_input; |
902 | 2.94k | libmwaw::DebugFile &asciiFile = zone->ascii(); |
903 | 2.94k | libmwaw::DebugStream f; |
904 | 2.94k | zone->m_parsed = true; |
905 | | |
906 | 2.94k | f << zone->name() << ":PTR=" << std::hex << zone->fileBeginPos() << std::dec << ","; |
907 | 2.94k | input->seek(0, librevenge::RVNG_SEEK_SET); |
908 | 2.94k | long val = input->readLong(2); // 1|4 |
909 | 2.94k | if (val != 1) f << "f0=" << val << ","; |
910 | 17.6k | for (int j = 0; j < 5; j++) { // always 0 expect f2=0|800 |
911 | 14.7k | val = input->readLong(2); |
912 | 14.7k | if (val) f << "f" << j+1 << "=" << val << ","; |
913 | 14.7k | } |
914 | 2.94k | f << "id=" << std::hex << input->readULong(4) << std::dec << ","; |
915 | 20.6k | for (int j = 0; j < 6; j++) { // always 0 |
916 | 17.6k | val = input->readLong(2); |
917 | 17.6k | if (val) f << "g" << j << "=" << val << ","; |
918 | 17.6k | } |
919 | | // two similar number: selection? |
920 | 2.94k | long sel[2]; |
921 | 5.88k | for (auto &s : sel) s = input->readLong(4); |
922 | 2.94k | if (sel[0] || sel[1]) { |
923 | 2.82k | f << "sel?=" << sel[0]; |
924 | 2.82k | if (sel[1] != sel[0]) f << "<->" << sel[1] << ","; |
925 | 2.82k | f << ","; |
926 | 2.82k | } |
927 | 26.4k | for (int j = 0; j < 8; j++) { // always 0 |
928 | 23.5k | val = input->readLong(2); |
929 | 23.5k | if (val) f << "h" << j << "=" << val << ","; |
930 | 23.5k | } |
931 | 2.94k | asciiFile.addDelimiter(input->tell(),'|'); |
932 | 2.94k | asciiFile.addPos(0); |
933 | 2.94k | asciiFile.addNote(f.str().c_str()); |
934 | | |
935 | 2.94k | input->seek(52, librevenge::RVNG_SEEK_SET); |
936 | 2.94k | return true; |
937 | 3.31k | } |
938 | | //////////////////////////////////////////////////////////// |
939 | | // code to uncompress a zone |
940 | | //////////////////////////////////////////////////////////// |
941 | | /* implementation of a basic splay tree to decode a block |
942 | | freely inspired from: ftp://ftp.cs.uiowa.edu/pub/jones/compress/minunsplay.c : |
943 | | |
944 | | Author: Douglas Jones, Dept. of Comp. Sci., U. of Iowa, Iowa City, IA 52242. |
945 | | Date: Nov. 5, 1990. |
946 | | (derived from the Feb. 14 1990 version by stripping out irrelevancies) |
947 | | (minor revision of Feb. 20, 1989 to add exit(0) at end of program). |
948 | | (minor revision of Nov. 14, 1988 to detect corrupt input better). |
949 | | (minor revision of Aug. 8, 1988 to eliminate unused vars, fix -c). |
950 | | Copyright: This material is derived from code Copyrighted 1988 by |
951 | | Jeffrey Chilton and Douglas Jones. That code contained a copyright |
952 | | notice allowing copying for personal or research purposes, so long |
953 | | as copies of the code were not sold for direct commercial advantage. |
954 | | This version of the code has been stripped of most of the material |
955 | | added by Jeff Chilton, and this release of the code may be used or |
956 | | copied for any purpose, public or private. |
957 | | Patents: The algorithm central to this code is entirely the invention of |
958 | | Douglas Jones, and it has not been patented. Any patents claiming |
959 | | to cover this material are invalid. |
960 | | Exportability: Splay-tree based compression algorithms may be used for |
961 | | cryptography, and when used as such, they may not be exported from |
962 | | the United States without appropriate approval. All cryptographic |
963 | | features of the original version of this code have been removed. |
964 | | Language: C |
965 | | Purpose: Data uncompression program, a companion to minsplay.c |
966 | | Algorithm: Uses a splay-tree based prefix code. For a full understanding |
967 | | of the operation of this data compression scheme, refer to the paper |
968 | | "Applications of Splay Trees to Data Compression" by Douglas W. Jones |
969 | | in Communications of the ACM, Aug. 1988, pages 996-1007. |
970 | | */ |
971 | | std::shared_ptr<HanMacWrdKZone> HanMacWrdKParser::decodeZone(std::shared_ptr<HanMacWrdKZone> zone) |
972 | 28.6k | { |
973 | 28.6k | if (!zone || zone->fileBeginPos()+12 >= zone->fileEndPos()) { |
974 | 3 | MWAW_DEBUG_MSG(("HanMacWrdKParser::decodeZone: called with an invalid zone\n")); |
975 | 3 | return zone; |
976 | 3 | } |
977 | 28.6k | short const maxChar=256; |
978 | 28.6k | short const maxSucc=maxChar+1; |
979 | 28.6k | short const twoMaxChar=2*maxChar+1; |
980 | 28.6k | short const twoMaxSucc=2*maxSucc; |
981 | | |
982 | | // first build the tree data |
983 | 28.6k | short left[maxSucc]; |
984 | 28.6k | short right[maxSucc]; |
985 | 28.6k | short up[twoMaxSucc]; |
986 | 14.7M | for (short i = 0; i <= twoMaxChar; ++i) |
987 | 14.7M | up[i] = i/2; |
988 | 7.40M | for (short j = 0; j <= maxChar; ++j) { |
989 | 7.37M | left[j] = short(2 * j); |
990 | 7.37M | right[j] = short(2 * j + 1); |
991 | 7.37M | } |
992 | | |
993 | 28.6k | short const root = 0; |
994 | 28.6k | short const sizeBit = 8; |
995 | 28.6k | short const highBit=128; /* mask for the most sig bit of 8 bit byte */ |
996 | | |
997 | 28.6k | short bitbuffer = 0; /* buffer to hold a byte for unpacking bits */ |
998 | 28.6k | short bitcounter = 0; /* count of remaining bits in buffer */ |
999 | | |
1000 | 28.6k | MWAWInputStreamPtr input = getInput(); |
1001 | 28.6k | input->seek(zone->fileBeginPos()+12, librevenge::RVNG_SEEK_SET); |
1002 | 28.6k | librevenge::RVNGBinaryData &dt = zone->getBinaryData(); |
1003 | 44.8M | while (!input->isEnd() && input->tell() < zone->fileEndPos()) { |
1004 | 44.7M | short a = root; |
1005 | 44.7M | bool ok = true; |
1006 | 86.2M | do { /* once for each bit on path */ |
1007 | 86.2M | if (bitcounter == 0) { |
1008 | 10.8M | if (input->isEnd() || input->tell() >= zone->fileEndPos()) { |
1009 | 1.09k | MWAW_DEBUG_MSG(("HanMacWrdKParser::decodeZone: find some uncomplete data for zone%lx\n", static_cast<long unsigned int>(zone->fileBeginPos()))); |
1010 | 1.09k | dt.append(static_cast<unsigned char>(a)); |
1011 | 1.09k | ok = false; |
1012 | 1.09k | break; |
1013 | 1.09k | } |
1014 | | |
1015 | 10.8M | bitbuffer = short(input->readULong(1)); |
1016 | 10.8M | bitcounter = sizeBit; |
1017 | 10.8M | } |
1018 | 86.2M | --bitcounter; |
1019 | 86.2M | if ((bitbuffer & highBit) != 0) |
1020 | 39.1M | a = right[a]; |
1021 | 47.1M | else |
1022 | 47.1M | a = left[a]; |
1023 | 86.2M | bitbuffer = short(bitbuffer << 1); |
1024 | 86.2M | } |
1025 | 86.2M | while (a <= maxChar); |
1026 | 44.7M | if (!ok) |
1027 | 1.09k | break; |
1028 | 44.7M | dt.append(static_cast<unsigned char>(a - maxSucc)); |
1029 | | |
1030 | | /* now splay tree about leaf a */ |
1031 | 61.0M | do { /* walk up the tree semi-rotating pairs of nodes */ |
1032 | 61.0M | short c; |
1033 | 61.0M | if ((c = up[a]) != root) { /* a pair remains */ |
1034 | 24.3M | short d = up[c]; |
1035 | 24.3M | short b = left[d]; |
1036 | 24.3M | if (c == b) { |
1037 | 13.5M | b = right[d]; |
1038 | 13.5M | right[d] = a; |
1039 | 13.5M | } |
1040 | 10.7M | else |
1041 | 10.7M | left[d] = a; |
1042 | 24.3M | if (left[c] == a) |
1043 | 13.2M | left[c] = b; |
1044 | 11.0M | else |
1045 | 11.0M | right[c] = b; |
1046 | 24.3M | up[a] = d; |
1047 | 24.3M | up[b] = c; |
1048 | 24.3M | a = d; |
1049 | 24.3M | } |
1050 | 36.7M | else |
1051 | 36.7M | a = c; |
1052 | 61.0M | } |
1053 | 61.0M | while (a != root); |
1054 | 44.7M | } |
1055 | 28.6k | if (dt.size()==0) { |
1056 | 0 | MWAW_DEBUG_MSG(("HanMacWrdKParser::decodeZone: oops an empty zone\n")); |
1057 | 0 | zone.reset(); |
1058 | 0 | return zone; |
1059 | 0 | } |
1060 | | |
1061 | 28.6k | zone->m_input=MWAWInputStream::get(zone->getBinaryData(), false); |
1062 | 28.6k | if (!zone->m_input) { |
1063 | 0 | MWAW_DEBUG_MSG(("HanMacWrdKParser::decodeZone: can not find my input\n")); |
1064 | 0 | zone.reset(); |
1065 | 0 | return zone; |
1066 | 0 | } |
1067 | | |
1068 | 28.6k | zone->m_input->seek(0,librevenge::RVNG_SEEK_SET); |
1069 | 28.6k | zone->ascii().setStream(zone->m_input); |
1070 | 28.6k | static int fId = 0; |
1071 | 28.6k | std::stringstream s; |
1072 | 28.6k | s << zone->name() << "-" << fId++; |
1073 | 28.6k | zone->ascii().open(s.str()); |
1074 | | |
1075 | 28.6k | ascii().skipZone(zone->fileBeginPos()+12, zone->fileEndPos()-1); |
1076 | 28.6k | return zone; |
1077 | 28.6k | } |
1078 | | |
1079 | | //////////////////////////////////////////////////////////// |
1080 | | // read the header |
1081 | | //////////////////////////////////////////////////////////// |
1082 | | bool HanMacWrdKParser::checkHeader(MWAWHeader *header, bool strict) |
1083 | 12.8k | { |
1084 | 12.8k | *m_state = HanMacWrdKParserInternal::State(); |
1085 | | |
1086 | 12.8k | MWAWInputStreamPtr input = getInput(); |
1087 | 12.8k | if (!input || !input->hasDataFork()) |
1088 | 2 | return false; |
1089 | 12.8k | libmwaw::DebugStream f; |
1090 | 12.8k | f << "FileHeader:"; |
1091 | 12.8k | long const headerSize=0x33c; |
1092 | 12.8k | if (!input->checkPosition(headerSize)) { |
1093 | 60 | MWAW_DEBUG_MSG(("HanMacWrdKParser::checkHeader: file is too short\n")); |
1094 | 60 | return false; |
1095 | 60 | } |
1096 | 12.8k | input->seek(0,librevenge::RVNG_SEEK_SET); |
1097 | 12.8k | int head[3]; |
1098 | 12.8k | for (int &i : head) |
1099 | 38.4k | i = static_cast<int>(input->readULong(2)); |
1100 | 12.8k | if (head[0] != 0x4859 || head[1] != 0x4c53 || head[2] != 0x0210) |
1101 | 160 | return false; |
1102 | 12.6k | auto val = static_cast<int>(input->readLong(1)); |
1103 | 12.6k | if (val==1) f << "hasPassword,"; |
1104 | 12.6k | else if (val) { |
1105 | 107 | if (strict) return false; |
1106 | 52 | f << "#hasPassword=" << val << ","; |
1107 | 52 | } |
1108 | 12.5k | val = static_cast<int>(input->readLong(1)); |
1109 | 12.5k | if (val) { |
1110 | 208 | if (strict && (val<0||val>2)) return false; |
1111 | 141 | f << "f0=" << val << ","; |
1112 | 141 | } |
1113 | | |
1114 | 12.5k | m_state->m_zonesListBegin = static_cast<int>(input->readULong(4)); // always 0x042c ? |
1115 | 12.5k | if (m_state->m_zonesListBegin<0x14 || !input->checkPosition(m_state->m_zonesListBegin)) |
1116 | 169 | return false; |
1117 | 12.3k | if (m_state->m_zonesListBegin < 0x33c) { |
1118 | 2 | MWAW_DEBUG_MSG(("HanMacWrdKParser::checkHeader: the header size seems short\n")); |
1119 | 2 | } |
1120 | 12.3k | f << "zonesBeg=" << std::hex << m_state->m_zonesListBegin << std::dec << ","; |
1121 | 12.3k | auto fLength = long(input->readULong(4)); |
1122 | 12.3k | if (fLength < m_state->m_zonesListBegin) |
1123 | 78 | return false; |
1124 | 12.2k | if (!input->checkPosition(fLength)) { |
1125 | 4.28k | if (!input->checkPosition(fLength/2)) return false; |
1126 | 4.07k | MWAW_DEBUG_MSG(("HanMacWrdKParser::checkHeader: file seems incomplete, try to continue\n")); |
1127 | 4.07k | f << "#len=" << std::hex << fLength << std::dec << ","; |
1128 | 4.07k | } |
1129 | 12.0k | auto tLength = long(input->readULong(4)); |
1130 | 12.0k | f << "textLength=" << tLength << ","; |
1131 | 12.0k | ascii().addPos(0); |
1132 | 12.0k | ascii().addNote(f.str().c_str()); |
1133 | | |
1134 | 12.0k | long pos; |
1135 | | // title, subject, author, revision, remark, [2 documents tags], mail: |
1136 | 12.0k | int const fieldSizes[] = { 128, 128, 32, 32, 256, 40, 64, 64, 64 }; |
1137 | 118k | for (int i = 0; i < 9; i++) { |
1138 | 106k | pos=input->tell(); |
1139 | 106k | if (i == 5) { |
1140 | 11.7k | ascii().addPos(pos); |
1141 | 11.7k | ascii().addNote("FileHeader[DocTags]:"); |
1142 | 11.7k | input->seek(pos+fieldSizes[i], librevenge::RVNG_SEEK_SET); |
1143 | 11.7k | continue; |
1144 | 11.7k | } |
1145 | 94.7k | auto fSz = static_cast<int>(input->readULong(1)); |
1146 | 94.7k | if (fSz >= fieldSizes[i]) { |
1147 | 2.85k | if (strict) |
1148 | 458 | return false; |
1149 | 2.39k | MWAW_DEBUG_MSG(("HanMacWrdKParser::checkHeader: can not read field size %i\n", i)); |
1150 | 2.39k | ascii().addPos(pos); |
1151 | 2.39k | ascii().addNote("FileHeader#"); |
1152 | 2.39k | input->seek(pos+fieldSizes[i], librevenge::RVNG_SEEK_SET); |
1153 | 2.39k | continue; |
1154 | 2.85k | } |
1155 | 91.8k | f.str(""); |
1156 | 91.8k | if (fSz == 0) |
1157 | 45.9k | f << "_"; |
1158 | 45.9k | else { |
1159 | 45.9k | std::string name(""); |
1160 | 639k | for (int c = 0; c < fSz; c++) |
1161 | 593k | name+=char(input->readULong(1)); |
1162 | 45.9k | f.str(""); |
1163 | 45.9k | f << "FileHeader[field"<<i<< "]:" << name; |
1164 | 45.9k | } |
1165 | 91.8k | ascii().addPos(pos); |
1166 | 91.8k | ascii().addNote(f.str().c_str()); |
1167 | 91.8k | input->seek(pos+fieldSizes[i], librevenge::RVNG_SEEK_SET); |
1168 | 91.8k | } |
1169 | 11.6k | pos=input->tell(); |
1170 | 11.6k | f.str(""); |
1171 | 11.6k | f << "FileHeader(B):"; // 240(K) bytes |
1172 | 11.6k | ascii().addPos(pos); |
1173 | 11.6k | ascii().addNote(f.str().c_str()); |
1174 | | |
1175 | 11.6k | input->seek(m_state->m_zonesListBegin, librevenge::RVNG_SEEK_SET); |
1176 | 11.6k | if (header) |
1177 | 4.21k | header->reset(MWAWDocument::MWAW_T_HANMACWORDK, 1); |
1178 | | |
1179 | 11.6k | return true; |
1180 | 12.0k | } |
1181 | | |
1182 | | //////////////////////////////////////////////////////////// |
1183 | | // HanMacWrdKZone |
1184 | | //////////////////////////////////////////////////////////// |
1185 | | HanMacWrdKZone::HanMacWrdKZone(MWAWInputStreamPtr const &input, libmwaw::DebugFile &asciiFile) |
1186 | 0 | : m_type(-1) |
1187 | 0 | , m_id(-1) |
1188 | 0 | , m_subId(-1) |
1189 | 0 | , m_input(input) |
1190 | 0 | , m_extra("") |
1191 | 0 | , m_parsed(false) |
1192 | 0 | , m_filePos(-1) |
1193 | 0 | , m_endFilePos(-1) |
1194 | 0 | , m_data() |
1195 | 0 | , m_asciiFile(&asciiFile) |
1196 | 0 | , m_asciiFilePtr() |
1197 | 0 | { |
1198 | 0 | } |
1199 | | |
1200 | | HanMacWrdKZone::HanMacWrdKZone(std::shared_ptr<libmwaw::DebugFile> const &asciiFile) |
1201 | 124k | : m_type(-1) |
1202 | 124k | , m_id(-1) |
1203 | 124k | , m_subId(-1) |
1204 | 124k | , m_input() |
1205 | 124k | , m_extra("") |
1206 | 124k | , m_parsed(false) |
1207 | 124k | , m_filePos(-1) |
1208 | 124k | , m_endFilePos(-1) |
1209 | 124k | , m_data() |
1210 | 124k | , m_asciiFile(asciiFile.get()) |
1211 | 124k | , m_asciiFilePtr(asciiFile) |
1212 | 124k | { |
1213 | 124k | } |
1214 | | |
1215 | | HanMacWrdKZone::~HanMacWrdKZone() |
1216 | 124k | { |
1217 | 124k | if (m_asciiFilePtr) |
1218 | 124k | ascii().reset(); |
1219 | 124k | } |
1220 | | |
1221 | | std::ostream &operator<<(std::ostream &o, HanMacWrdKZone const &zone) |
1222 | 0 | { |
1223 | 0 | o << zone.name(); |
1224 | 0 | if (zone.m_id > 0) o << "[" << std::hex << zone.m_id << std::dec << "]"; |
1225 | 0 | if (zone.m_subId > 0) o << "[subId=" << std::hex << zone.m_subId << std::dec << "]"; |
1226 | 0 | if (zone.m_extra.length()) o << "," << zone.m_extra; |
1227 | 0 | return o; |
1228 | 0 | } |
1229 | | |
1230 | | std::string HanMacWrdKZone::name(int type) |
1231 | 279k | { |
1232 | 279k | switch (type) { |
1233 | 87.2k | case 1: |
1234 | 87.2k | return "TextZone"; |
1235 | 1.13k | case 2: |
1236 | 1.13k | return "FrameDef"; |
1237 | 25.8k | case 3: |
1238 | 25.8k | return "Style"; |
1239 | 12.5k | case 4: |
1240 | 12.5k | return "Section"; |
1241 | 15.7k | case 5: |
1242 | 15.7k | return "FontsName"; |
1243 | 8.62k | case 7: |
1244 | 8.62k | return "PrintInfo"; |
1245 | 3.01k | case 9: |
1246 | 3.01k | return "FrameExt"; |
1247 | 401 | case 0xd: |
1248 | 401 | return "Picture"; |
1249 | 124k | default: |
1250 | 124k | break; |
1251 | 279k | } |
1252 | 124k | std::stringstream s; |
1253 | 124k | s << "Zone" << std::hex << type << std::dec; |
1254 | 124k | return s.str(); |
1255 | 279k | } |
1256 | | |
1257 | | // vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: |