/src/libmwaw/src/lib/DocMkrParser.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 "MWAWPictData.hxx" |
46 | | #include "MWAWPosition.hxx" |
47 | | #include "MWAWPrinter.hxx" |
48 | | #include "MWAWRSRCParser.hxx" |
49 | | #include "MWAWSubDocument.hxx" |
50 | | |
51 | | #include "DocMkrText.hxx" |
52 | | |
53 | | #include "DocMkrParser.hxx" |
54 | | |
55 | | /** Internal: the structures of a DocMkrParser */ |
56 | | namespace DocMkrParserInternal |
57 | | { |
58 | | //////////////////////////////////////// |
59 | | //! Internal: store a picture information in DocMkrParser |
60 | | struct PictInfo { |
61 | | //! constructor |
62 | | PictInfo() |
63 | 0 | : m_id(-1) |
64 | 0 | , m_sndId(-1) |
65 | 0 | , m_align(1) |
66 | 0 | , m_print(false) |
67 | 0 | , m_invert(false) |
68 | 0 | , m_action(0) |
69 | 0 | , m_actionString("") |
70 | 0 | , m_extra("") |
71 | 0 | { |
72 | 0 | for (auto &next : m_next) next=0; |
73 | 0 | } |
74 | | //! operator<< |
75 | | friend std::ostream &operator<<(std::ostream &o, PictInfo const &info); |
76 | | //! the picture id |
77 | | int m_id; |
78 | | //! the sound id |
79 | | int m_sndId; |
80 | | //! the alignment ( 1:center, ... ) |
81 | | int m_align; |
82 | | //! true if the picture is printed |
83 | | bool m_print; |
84 | | //! true if we must invert the picture |
85 | | bool m_invert; |
86 | | //! the action |
87 | | int m_action; |
88 | | //! the action string |
89 | | std::string m_actionString; |
90 | | //! the next chapter/paragraph position for goChapter |
91 | | int m_next[2]; |
92 | | //! the applescript type |
93 | | std::string m_appleScript[3]; |
94 | | //! extra data |
95 | | std::string m_extra; |
96 | | }; |
97 | | |
98 | | std::ostream &operator<<(std::ostream &o, PictInfo const &info) |
99 | 0 | { |
100 | 0 | if (info.m_id >= 0) o << "pictId=" << info.m_id << ","; |
101 | 0 | switch (info.m_align) { |
102 | 0 | case 1: |
103 | 0 | o << "center,"; |
104 | 0 | break; |
105 | 0 | case 2: |
106 | 0 | o << "left,"; |
107 | 0 | break; |
108 | 0 | case 3: |
109 | 0 | o << "right,"; |
110 | 0 | break; |
111 | 0 | default: |
112 | 0 | o << "#align=" << info.m_align << ","; |
113 | 0 | break; |
114 | 0 | } |
115 | 0 | if (info.m_action >= 0 && info.m_action <= 16) { |
116 | 0 | static char const* const wh[]= { |
117 | 0 | "", "goTo", "aboutDialog", "print", "quit", "launch", "sound", "QMOV", |
118 | 0 | "note", "export[asText]", "last[chapter]", "TOC[show]", "find", "appleEvent", |
119 | 0 | "next[chapter]", "prev[chapter]", "script" |
120 | 0 | }; |
121 | 0 | o << wh[info.m_action]; |
122 | 0 | } |
123 | 0 | else |
124 | 0 | o << "#action=" << info.m_action << ","; |
125 | 0 | switch (info.m_action) { |
126 | 0 | case 1: |
127 | 0 | o << "[chapter=" << info.m_next[0]; |
128 | 0 | if (info.m_next[1]) o << ",para=" << info.m_next[1] << "]"; |
129 | 0 | else o << "]"; |
130 | 0 | break; |
131 | 0 | case 5: |
132 | 0 | case 7: |
133 | 0 | case 8: |
134 | 0 | case 0x10: |
135 | 0 | o << "[" << info.m_actionString << "]"; |
136 | 0 | break; |
137 | 0 | case 6: |
138 | 0 | o << "[id=" << info.m_sndId << "]"; |
139 | 0 | break; |
140 | 0 | case 0xd: |
141 | 0 | o << "[appli=" << info.m_appleScript[0] << ",class=" << info.m_appleScript[1] |
142 | 0 | << ",eventid=" << info.m_appleScript[2]; |
143 | 0 | if (info.m_actionString.size()) |
144 | 0 | o << ",data=" <<info.m_actionString; |
145 | 0 | o << "]"; |
146 | 0 | break; |
147 | 0 | default: |
148 | 0 | break; |
149 | 0 | } |
150 | 0 | o << "],"; |
151 | 0 | if (!info.m_print) o << "noPrint,"; |
152 | 0 | if (info.m_invert) o << "invert,"; |
153 | 0 | o << info.m_extra; |
154 | 0 | return o; |
155 | 0 | } |
156 | | //////////////////////////////////////// |
157 | | //! Internal: the state of a DocMkrParser |
158 | | struct State { |
159 | | //! constructor |
160 | | State() |
161 | 2.64k | : m_idPictEntryMap() |
162 | 2.64k | , m_idPictInfoMap() |
163 | 2.64k | , m_zonePictInfoUnit(100) |
164 | 2.64k | , m_actPage(0) |
165 | 2.64k | , m_numPages(0) |
166 | 2.64k | , m_headerHeight(0) |
167 | 2.64k | , m_footerHeight(0) |
168 | 2.64k | { |
169 | 2.64k | } |
170 | | //! return a pictinfo id corresponding to a zone and a local if |
171 | | int pictInfoId(int zId, int lId) const |
172 | 11 | { |
173 | 11 | return (zId+2)*m_zonePictInfoUnit+lId; |
174 | 11 | } |
175 | | //! try to find the picture info unit (fixme: a hack) |
176 | | void findPictInfoUnit(int nZones); |
177 | | //! a map id->pictEntry |
178 | | std::map<int,MWAWEntry> m_idPictEntryMap; |
179 | | //! a map id->pictInfo |
180 | | std::map<int,PictInfo> m_idPictInfoMap; |
181 | | //! the zone unit to retrieve pictInfo |
182 | | int m_zonePictInfoUnit; |
183 | | int m_actPage /** the actual page */, m_numPages /** the number of page of the final document */; |
184 | | |
185 | | int m_headerHeight /** the header height if known */, |
186 | | m_footerHeight /** the footer height if known */; |
187 | | }; |
188 | | |
189 | | void State::findPictInfoUnit(int nZones) |
190 | 314 | { |
191 | 314 | if (m_idPictInfoMap.empty()) |
192 | 314 | return; |
193 | 0 | bool is100=true, is1000=true; |
194 | 0 | for (auto const &it : m_idPictInfoMap) { |
195 | 0 | int id=it.first; |
196 | 0 | if (id > (nZones+3)*100 || id < 200) |
197 | 0 | is100=false; |
198 | 0 | if (id > (nZones+3)*1000 || id < 2000) |
199 | 0 | is1000=false; |
200 | 0 | } |
201 | 0 | if (is100 && !is1000) |
202 | 0 | m_zonePictInfoUnit=100; |
203 | 0 | else if (is1000 && !is100) |
204 | 0 | m_zonePictInfoUnit=1000; |
205 | 0 | else { |
206 | 0 | MWAW_DEBUG_MSG(("DocMkrParserInternal::State::findPictInfoUnit can not find unit\n")); |
207 | 0 | } |
208 | 0 | } |
209 | | } |
210 | | |
211 | | //////////////////////////////////////////////////////////// |
212 | | // constructor/destructor, ... |
213 | | //////////////////////////////////////////////////////////// |
214 | | DocMkrParser::DocMkrParser(MWAWInputStreamPtr const &input, MWAWRSRCParserPtr const &rsrcParser, MWAWHeader *header) |
215 | 1.10k | : MWAWTextParser(input, rsrcParser, header) |
216 | 1.10k | , m_state() |
217 | 1.10k | , m_textParser() |
218 | 1.10k | { |
219 | 1.10k | init(); |
220 | 1.10k | } |
221 | | |
222 | | DocMkrParser::~DocMkrParser() |
223 | 1.10k | { |
224 | 1.10k | } |
225 | | |
226 | | void DocMkrParser::init() |
227 | 1.10k | { |
228 | 1.10k | resetTextListener(); |
229 | | |
230 | 1.10k | m_state.reset(new DocMkrParserInternal::State); |
231 | | |
232 | 1.10k | m_textParser.reset(new DocMkrText(*this)); |
233 | 1.10k | } |
234 | | |
235 | | MWAWInputStreamPtr DocMkrParser::rsrcInput() |
236 | 2.39k | { |
237 | 2.39k | return getRSRCParser()->getInput(); |
238 | 2.39k | } |
239 | | |
240 | | libmwaw::DebugFile &DocMkrParser::rsrcAscii() |
241 | 1.81k | { |
242 | 1.81k | return getRSRCParser()->ascii(); |
243 | 1.81k | } |
244 | | |
245 | | //////////////////////////////////////////////////////////// |
246 | | // new page |
247 | | //////////////////////////////////////////////////////////// |
248 | | void DocMkrParser::newPage(int number) |
249 | 215k | { |
250 | 215k | if (number <= m_state->m_actPage || number > m_state->m_numPages) |
251 | 214 | return; |
252 | | |
253 | 431k | while (m_state->m_actPage < number) { |
254 | 215k | m_state->m_actPage++; |
255 | 215k | if (!getTextListener() || m_state->m_actPage == 1) |
256 | 214 | continue; |
257 | 215k | getTextListener()->insertBreak(MWAWTextListener::PageBreak); |
258 | 215k | } |
259 | 215k | } |
260 | | |
261 | | //////////////////////////////////////////////////////////// |
262 | | // the parser |
263 | | //////////////////////////////////////////////////////////// |
264 | | void DocMkrParser::parse(librevenge::RVNGTextInterface *docInterface) |
265 | 434 | { |
266 | 434 | if (!getInput().get() || !getRSRCParser() || !checkHeader(nullptr)) throw(libmwaw::ParseException()); |
267 | 434 | bool ok = false; |
268 | 434 | try { |
269 | 434 | checkHeader(nullptr); |
270 | 434 | ok = createZones(); |
271 | 434 | if (ok) { |
272 | 314 | createDocument(docInterface); |
273 | 314 | m_textParser->sendMainText(); |
274 | 314 | m_textParser->sendTOC(); |
275 | | #ifdef DEBUG |
276 | | m_textParser->flushExtra(); |
277 | | flushExtra(); |
278 | | #endif |
279 | 314 | } |
280 | 434 | ascii().reset(); |
281 | 434 | } |
282 | 434 | catch (...) { |
283 | 0 | MWAW_DEBUG_MSG(("DocMkrParser::parse: exception catched when parsing\n")); |
284 | 0 | ok = false; |
285 | 0 | } |
286 | | |
287 | 434 | resetTextListener(); |
288 | 434 | if (!ok) throw(libmwaw::ParseException()); |
289 | 434 | } |
290 | | |
291 | | //////////////////////////////////////////////////////////// |
292 | | // create the document |
293 | | //////////////////////////////////////////////////////////// |
294 | | void DocMkrParser::createDocument(librevenge::RVNGTextInterface *documentInterface) |
295 | 314 | { |
296 | 314 | if (!documentInterface) return; |
297 | 314 | if (getTextListener()) { |
298 | 0 | MWAW_DEBUG_MSG(("DocMkrParser::createDocument: listener already exist\n")); |
299 | 0 | return; |
300 | 0 | } |
301 | | |
302 | | // update the page |
303 | 314 | m_state->m_actPage = 0; |
304 | | |
305 | | // create the page list |
306 | 314 | std::vector<MWAWPageSpan> pageList; |
307 | 314 | m_textParser->updatePageSpanList(pageList); |
308 | 314 | m_state->m_numPages = int(pageList.size()); |
309 | | |
310 | | // |
311 | 314 | MWAWTextListenerPtr listen(new MWAWTextListener(*getParserState(), pageList, documentInterface)); |
312 | 314 | setTextListener(listen); |
313 | 314 | listen->startDocument(); |
314 | 314 | } |
315 | | |
316 | | |
317 | | //////////////////////////////////////////////////////////// |
318 | | // |
319 | | // Intermediate level |
320 | | // |
321 | | //////////////////////////////////////////////////////////// |
322 | | bool DocMkrParser::createZones() |
323 | 434 | { |
324 | 434 | MWAWRSRCParserPtr rsrcParser = getRSRCParser(); |
325 | 434 | auto const &entryMap = rsrcParser->getEntriesMap(); |
326 | | |
327 | 434 | if (!m_textParser->createZones()) |
328 | 120 | return false; |
329 | | // the different pict zones |
330 | 314 | auto it = entryMap.lower_bound("PICT"); |
331 | 628 | while (it != entryMap.end()) { |
332 | 628 | if (it->first != "PICT") |
333 | 314 | break; |
334 | 314 | MWAWEntry const &entry = it++->second; |
335 | 314 | m_state->m_idPictEntryMap[entry.id()]=entry; |
336 | 314 | } |
337 | 314 | it = entryMap.lower_bound("conp"); // local picture 5000-...? |
338 | 5.94k | while (it != entryMap.end()) { |
339 | 5.94k | if (it->first != "conp") |
340 | 314 | break; |
341 | 5.63k | MWAWEntry const &entry = it++->second; |
342 | 5.63k | librevenge::RVNGBinaryData data; |
343 | 5.63k | rsrcParser->parsePICT(entry, data); |
344 | 5.63k | } |
345 | 314 | it = entryMap.lower_bound("pInf"); // 201|202,301..309,401..410,501.. |
346 | 314 | while (it != entryMap.end()) { |
347 | 314 | if (it->first != "pInf") |
348 | 314 | break; |
349 | 0 | MWAWEntry const &entry = it++->second; |
350 | 0 | readPictInfo(entry); |
351 | 0 | } |
352 | | |
353 | | // chapiter name STR 2000.. |
354 | | // entry 0: copyright |
355 | 314 | it = entryMap.lower_bound("Dk@P"); |
356 | 627 | while (it != entryMap.end()) { |
357 | 627 | if (it->first != "Dk@P") |
358 | 314 | break; |
359 | 313 | MWAWEntry const &entry = it++->second; |
360 | 313 | std::string str; |
361 | 313 | rsrcParser->parseSTR(entry, str); |
362 | 313 | } |
363 | 314 | it = entryMap.lower_bound("sTwD"); |
364 | 623 | while (it != entryMap.end()) { |
365 | 623 | if (it->first != "sTwD") |
366 | 314 | break; |
367 | 309 | MWAWEntry const &entry = it++->second; |
368 | 309 | readSTwD(entry); |
369 | 309 | } |
370 | 314 | it = entryMap.lower_bound("xtr2"); |
371 | 628 | while (it != entryMap.end()) { |
372 | 390 | if (it->first != "xtr2") |
373 | 76 | break; |
374 | 314 | MWAWEntry const &entry = it++->second; |
375 | 314 | readXtr2(entry); |
376 | 314 | } |
377 | | // 1000:docname, 1001:footer name, 2001-... chapter name, others ... |
378 | 314 | it = entryMap.lower_bound("STR "); |
379 | 1.25k | while (it != entryMap.end()) { |
380 | 1.25k | if (it->first != "STR ") |
381 | 314 | break; |
382 | 942 | MWAWEntry const &entry = it++->second; |
383 | 942 | std::string str; |
384 | 942 | rsrcParser->parseSTR(entry, str); |
385 | 942 | } |
386 | | |
387 | 314 | m_state->findPictInfoUnit(m_textParser->numChapters()); |
388 | | |
389 | | #ifdef DEBUG_WITH_FILES |
390 | | // get rid of the default application resource |
391 | | libmwaw::DebugFile &ascFile = rsrcAscii(); |
392 | | static char const* const appliRsrc[]= { |
393 | | // default, Dialog (3000: DLOG,DITL,DLGX,dctb","ictb","STR ") |
394 | | "ALRT","BNDL","CNTL","CURS","CDEF", "DLOG","DLGX","DITL","FREF","ICON", "ICN#","MENU","SIZE", |
395 | | "crsr","dctb","icl4","icl8","ics4", "ics8","ics#","ictb","snd ", |
396 | | // local |
397 | | "mstr" /* menu string */, "aete" /* some function name?*/ |
398 | | }; |
399 | | for (int r=0; r < 13+9+2; r++) { |
400 | | it = entryMap.lower_bound(appliRsrc[r]); |
401 | | while (it != entryMap.end()) { |
402 | | if (it->first != appliRsrc[r]) |
403 | | break; |
404 | | MWAWEntry const &entry = it++->second; |
405 | | if (entry.isParsed()) continue; |
406 | | entry.setParsed(true); |
407 | | ascFile.skipZone(entry.begin()-4,entry.end()-1); |
408 | | } |
409 | | } |
410 | | #endif |
411 | 314 | return true; |
412 | 434 | } |
413 | | |
414 | | void DocMkrParser::flushExtra() |
415 | 0 | { |
416 | 0 | MWAWRSRCParserPtr rsrcParser = getRSRCParser(); |
417 | 0 | for (auto const &it : m_state->m_idPictEntryMap) { |
418 | 0 | MWAWEntry const &entry=it.second; |
419 | 0 | if (entry.isParsed()) continue; |
420 | 0 | librevenge::RVNGBinaryData data; |
421 | 0 | rsrcParser->parsePICT(entry,data); |
422 | 0 | } |
423 | 0 | } |
424 | | |
425 | | //////////////////////////////////////////////////////////// |
426 | | // |
427 | | // Low level |
428 | | // |
429 | | //////////////////////////////////////////////////////////// |
430 | | bool DocMkrParser::sendPicture(int zId, int lId, double /*lineW*/) |
431 | 11 | { |
432 | 11 | int pictId=m_state->pictInfoId(zId,lId); |
433 | 11 | auto it=m_state->m_idPictInfoMap.find(pictId); |
434 | 11 | if (it==m_state->m_idPictInfoMap.end()) { |
435 | 11 | MWAW_DEBUG_MSG(("DocMkrText::sendPicture: can not find picture for zone=%d, id=%d\n",zId,lId)); |
436 | 11 | return false; |
437 | 11 | } |
438 | 0 | DocMkrParserInternal::PictInfo const &info=it->second; |
439 | 0 | if (m_state->m_idPictEntryMap.find(info.m_id)==m_state->m_idPictEntryMap.end()) { |
440 | 0 | MWAW_DEBUG_MSG(("DocMkrText::sendPicture: can not find picture for id=%d\n",info.m_id)); |
441 | 0 | return false; |
442 | 0 | } |
443 | 0 | if (!getTextListener()) { |
444 | 0 | MWAW_DEBUG_MSG(("DocMkrText::sendPicture: can not find the listener\n")); |
445 | 0 | return false; |
446 | 0 | } |
447 | | |
448 | 0 | if (info.m_action==8 && info.m_actionString.size()) |
449 | 0 | m_textParser->sendComment(info.m_actionString); |
450 | 0 | MWAWInputStreamPtr input = rsrcInput(); |
451 | 0 | MWAWRSRCParserPtr rsrcParser = getRSRCParser(); |
452 | 0 | MWAWEntry const &entry=m_state->m_idPictEntryMap.find(info.m_id)->second; |
453 | |
|
454 | 0 | librevenge::RVNGBinaryData data; |
455 | 0 | long pos = input->tell(); |
456 | 0 | rsrcParser->parsePICT(entry,data); |
457 | 0 | input->seek(pos,librevenge::RVNG_SEEK_SET); |
458 | |
|
459 | 0 | auto dataSz=int(data.size()); |
460 | 0 | if (!dataSz) { |
461 | 0 | return false; |
462 | 0 | } |
463 | 0 | MWAWInputStreamPtr pictInput=MWAWInputStream::get(data, false); |
464 | 0 | if (!pictInput) { |
465 | 0 | MWAW_DEBUG_MSG(("DocMkrText::sendPicture: oops can not find an input\n")); |
466 | 0 | return false; |
467 | 0 | } |
468 | 0 | MWAWBox2f box; |
469 | 0 | auto res = MWAWPictData::check(pictInput, dataSz,box); |
470 | 0 | if (res == MWAWPict::MWAW_R_BAD) { |
471 | 0 | MWAW_DEBUG_MSG(("DocMkrText::sendPicture: can not find the picture\n")); |
472 | 0 | return false; |
473 | 0 | } |
474 | 0 | pictInput->seek(0,librevenge::RVNG_SEEK_SET); |
475 | 0 | std::shared_ptr<MWAWPict> thePict(MWAWPictData::get(pictInput, dataSz)); |
476 | 0 | MWAWPosition pictPos=MWAWPosition(MWAWVec2f(0,0),box.size(), librevenge::RVNG_POINT); |
477 | 0 | auto xpos= (info.m_align==1) ? MWAWPosition::XCenter : |
478 | 0 | (info.m_align==3) ? MWAWPosition::XRight : MWAWPosition::XLeft; |
479 | 0 | pictPos.setRelativePosition(MWAWPosition::Paragraph, xpos); |
480 | 0 | pictPos.m_wrapping = MWAWPosition::WRunThrough; |
481 | 0 | if (thePict) { |
482 | 0 | MWAWEmbeddedObject picture; |
483 | 0 | if (thePict->getBinary(picture)) |
484 | 0 | getTextListener()->insertPicture(pictPos, picture); |
485 | 0 | } |
486 | 0 | return true; |
487 | 0 | } |
488 | | |
489 | | bool DocMkrParser::readPictInfo(MWAWEntry const &entry) |
490 | 0 | { |
491 | 0 | long length = entry.length(); |
492 | 0 | if (!entry.valid() || length<8) { |
493 | 0 | MWAW_DEBUG_MSG(("DocMkrText::readPictInfo: the entry seems very short\n")); |
494 | 0 | return false; |
495 | 0 | } |
496 | | |
497 | 0 | entry.setParsed(true); |
498 | 0 | long pos = entry.begin(); |
499 | 0 | long endPos = entry.end(); |
500 | 0 | MWAWInputStreamPtr input = rsrcInput(); |
501 | 0 | libmwaw::DebugFile &ascFile = rsrcAscii(); |
502 | 0 | input->seek(pos, librevenge::RVNG_SEEK_SET); |
503 | |
|
504 | 0 | libmwaw::DebugStream f; |
505 | 0 | DocMkrParserInternal::PictInfo info; |
506 | 0 | info.m_id = static_cast<int>(input->readULong(2)); |
507 | 0 | info.m_align = static_cast<int>(input->readLong(2)); |
508 | 0 | auto val =static_cast<int>(input->readLong(2)); // 0|1 |
509 | 0 | if (val) f << "unkn=" << val << ","; |
510 | |
|
511 | 0 | auto action =static_cast<int>(input->readLong(2)); // 0..b |
512 | 0 | auto extraN = int(endPos-input->tell()); |
513 | 0 | if (action < 0) { |
514 | 0 | info.m_invert=true; |
515 | 0 | action = -action; |
516 | 0 | } |
517 | 0 | info.m_action=action; |
518 | 0 | switch (action) { |
519 | 0 | case 1: |
520 | 0 | if (extraN < 2) { |
521 | 0 | f << "actionArg##,"; |
522 | 0 | break; |
523 | 0 | } |
524 | 0 | info.m_next[0]=static_cast<int>(input->readLong(2)); |
525 | 0 | if (extraN < 4) |
526 | 0 | break; |
527 | 0 | info.m_next[1]=static_cast<int>(input->readLong(2)); |
528 | 0 | break; |
529 | 0 | case 5: |
530 | 0 | case 7: |
531 | 0 | case 8: |
532 | 0 | case 0x10: { |
533 | 0 | if (extraN < 1) { |
534 | 0 | f << "actionArg##,"; |
535 | 0 | } |
536 | 0 | auto fSz=static_cast<int>(input->readULong(1)); |
537 | 0 | if (extraN < fSz+1) { |
538 | 0 | f << "##[N=" << fSz << "],"; |
539 | 0 | break; |
540 | 0 | } |
541 | 0 | std::string name(""); |
542 | 0 | for (int i = 0; i < fSz; i++) |
543 | 0 | name += char(input->readULong(1)); |
544 | 0 | info.m_actionString=name; |
545 | 0 | break; |
546 | 0 | } |
547 | 0 | case 6: { |
548 | 0 | if (extraN < 4) { |
549 | 0 | f << "actionArg##,"; |
550 | 0 | break; |
551 | 0 | } |
552 | 0 | info.m_sndId=static_cast<int>(input->readULong(2)); |
553 | 0 | val = static_cast<int>(input->readULong(2)); // loop? |
554 | 0 | if (val) |
555 | 0 | f << "sndFlag=" << val << ","; |
556 | 0 | break; |
557 | 0 | } |
558 | 0 | case 0xd: { |
559 | 0 | if (extraN < 13) { |
560 | 0 | f << "actionArg##,"; |
561 | 0 | break; |
562 | 0 | } |
563 | 0 | for (auto &w : info.m_appleScript) { |
564 | 0 | std::string name(""); |
565 | 0 | for (int i = 0; i < 4; i++) |
566 | 0 | name += char(input->readULong(1)); |
567 | 0 | w=name; |
568 | 0 | } |
569 | 0 | auto fSz=static_cast<int>(input->readULong(1)); |
570 | 0 | if (extraN < fSz+13) { |
571 | 0 | f << "##[N=" << fSz << "],"; |
572 | 0 | break; |
573 | 0 | } |
574 | 0 | std::string name(""); |
575 | 0 | for (int i = 0; i < fSz; i++) |
576 | 0 | name += char(input->readULong(1)); |
577 | 0 | info.m_actionString=name; |
578 | 0 | break; |
579 | 0 | } |
580 | 0 | default: |
581 | 0 | break; |
582 | 0 | } |
583 | 0 | extraN = int(endPos-input->tell())/2; |
584 | 0 | if (extraN==1) { |
585 | 0 | val =static_cast<int>(input->readLong(2)); |
586 | 0 | if (val==0) |
587 | 0 | info.m_print = false; |
588 | 0 | else if (val==1) |
589 | 0 | info.m_print = true; |
590 | 0 | else if (val) { |
591 | 0 | f << "#print=" << val << ","; |
592 | 0 | } |
593 | 0 | } |
594 | 0 | else { |
595 | 0 | for (int i = 0; i < extraN; i++) { // g0=0|1 |
596 | 0 | val =static_cast<int>(input->readLong(2)); |
597 | 0 | if (val) |
598 | 0 | f << "#g" << i << "=" << val << ","; |
599 | 0 | } |
600 | 0 | } |
601 | 0 | info.m_extra=f.str(); |
602 | 0 | m_state->m_idPictInfoMap[entry.id()]=info; |
603 | 0 | f.str(""); |
604 | 0 | f << "Entries(PctInfo)[" << entry.type() << "-" << entry.id() << "]:" << info; |
605 | |
|
606 | 0 | if (input->tell()!=entry.end()) |
607 | 0 | ascFile.addDelimiter(input->tell(),'|'); |
608 | 0 | ascFile.addPos(pos-4); |
609 | 0 | ascFile.addNote(f.str().c_str()); |
610 | 0 | return true; |
611 | 0 | } |
612 | | |
613 | | //////////////////////////////////////////////////////////// |
614 | | // read some unknown zone |
615 | | //////////////////////////////////////////////////////////// |
616 | | bool DocMkrParser::readSTwD(MWAWEntry const &entry) |
617 | 309 | { |
618 | 309 | if (!entry.valid() || entry.length()<10) { |
619 | 138 | MWAW_DEBUG_MSG(("DocMkrText::readSTwD: the entry seems very short\n")); |
620 | 138 | return false; |
621 | 138 | } |
622 | | |
623 | 171 | entry.setParsed(true); |
624 | 171 | long pos = entry.begin(); |
625 | 171 | MWAWInputStreamPtr input = rsrcInput(); |
626 | 171 | libmwaw::DebugFile &ascFile = rsrcAscii(); |
627 | 171 | input->seek(pos, librevenge::RVNG_SEEK_SET); |
628 | | |
629 | 171 | libmwaw::DebugStream f; |
630 | 171 | f << "Entries(STwD)[" << entry.type() << "-" << entry.id() << "]:"; |
631 | 171 | int val; |
632 | 513 | for (int i=0; i < 2; i++) { // f0=2, f1=1|2 |
633 | 342 | val =static_cast<int>(input->readLong(2)); |
634 | 342 | if (val) |
635 | 188 | f << "f" << i << "=" << val << ","; |
636 | 342 | } |
637 | 171 | auto flag =static_cast<int>(input->readLong(2)); // 320|7d0|1388 ? |
638 | 171 | f << "fl=" << std::hex << flag << std::dec << ","; |
639 | 171 | f << "dim=" << static_cast<int>(input->readLong(2)) << ","; // 0x1Fa|0x200 |
640 | 513 | for (int i=0; i < 2; i++) { // f0=1, f1=0|1 |
641 | 342 | val =static_cast<int>(input->readLong(1)); |
642 | 342 | if (val) |
643 | 172 | f << "f" << i+2 << "=" << val << ","; |
644 | 342 | } |
645 | 171 | f << "],"; |
646 | 171 | if (input->tell()!=entry.end()) |
647 | 162 | ascFile.addDelimiter(input->tell(),'|'); |
648 | 171 | ascFile.addPos(pos-4); |
649 | 171 | ascFile.addNote(f.str().c_str()); |
650 | 171 | return true; |
651 | 309 | } |
652 | | |
653 | | bool DocMkrParser::readXtr2(MWAWEntry const &entry) |
654 | 314 | { |
655 | 314 | if (!entry.valid() || entry.length()<1) { |
656 | 134 | MWAW_DEBUG_MSG(("DocMkrText::readXtr2: the entry seems very short\n")); |
657 | 134 | return false; |
658 | 134 | } |
659 | | |
660 | 180 | entry.setParsed(true); |
661 | 180 | long pos = entry.begin(); |
662 | 180 | MWAWInputStreamPtr input = rsrcInput(); |
663 | 180 | libmwaw::DebugFile &ascFile = rsrcAscii(); |
664 | 180 | input->seek(pos, librevenge::RVNG_SEEK_SET); |
665 | | |
666 | 180 | libmwaw::DebugStream f; |
667 | 180 | f << "Entries(Xtr2)[" << entry.type() << "-" << entry.id() << "]:"; |
668 | 180 | int N=1; |
669 | 180 | if (entry.length() != 1) { |
670 | 171 | MWAW_DEBUG_MSG(("DocMkrText::readXtr2: find more than one flag\n")); |
671 | 171 | N = entry.length()>20 ? 20 : int(entry.length()); |
672 | 171 | } |
673 | | // f0=79|a8|b9|99 |
674 | 3.59k | for (int i=0; i < N; i++) { |
675 | 3.41k | auto val =static_cast<int>(input->readULong(1)); |
676 | 3.41k | if (val) |
677 | 2.40k | f << "f" << i << "=" << std::hex << val << std::dec << ","; |
678 | 3.41k | } |
679 | 180 | if (input->tell()!=entry.end()) |
680 | 170 | ascFile.addDelimiter(input->tell(),'|'); |
681 | 180 | ascFile.addPos(pos-4); |
682 | 180 | ascFile.addNote(f.str().c_str()); |
683 | 180 | return true; |
684 | 314 | } |
685 | | |
686 | | //////////////////////////////////////////////////////////// |
687 | | // read the header |
688 | | //////////////////////////////////////////////////////////// |
689 | | bool DocMkrParser::checkHeader(MWAWHeader *header, bool /*strict*/) |
690 | 1.53k | { |
691 | 1.53k | *m_state = DocMkrParserInternal::State(); |
692 | | /** no data fork, may be ok, but this means |
693 | | that the file contains no text, so... */ |
694 | 1.53k | MWAWInputStreamPtr input = getInput(); |
695 | 1.53k | if (!input || !getRSRCParser()) |
696 | 96 | return false; |
697 | 1.44k | if (input->hasDataFork()) { |
698 | 0 | MWAW_DEBUG_MSG(("DocMkrParser::checkHeader: find a datafork, odd!!!\n")); |
699 | 0 | } |
700 | 1.44k | MWAWRSRCParser::Version vers; |
701 | | // read the Docmaker version |
702 | 1.44k | int docmakerVersion = 1; |
703 | 1.44k | MWAWEntry entry = getRSRCParser()->getEntry("vers", 2); |
704 | 1.44k | if (entry.valid() && getRSRCParser()->parseVers(entry, vers)) |
705 | 238 | docmakerVersion = vers.m_majorVersion; |
706 | 1.20k | else { |
707 | 1.20k | MWAW_DEBUG_MSG(("DocMkrParser::checkHeader: can not find the DocMaker version\n")); |
708 | 1.20k | } |
709 | 1.44k | setVersion(docmakerVersion); |
710 | 1.44k | if (header) |
711 | 573 | header->reset(MWAWDocument::MWAW_T_DOCMAKER, version()); |
712 | | |
713 | 1.44k | return true; |
714 | 1.53k | } |
715 | | |
716 | | // vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: |