/src/libmwaw/src/lib/MsWksDocument.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 <string.h> |
35 | | |
36 | | #include <iomanip> |
37 | | #include <iostream> |
38 | | #include <limits> |
39 | | #include <set> |
40 | | #include <sstream> |
41 | | |
42 | | #include <librevenge/librevenge.h> |
43 | | |
44 | | #include "MWAWTextListener.hxx" |
45 | | #include "MWAWHeader.hxx" |
46 | | #include "MWAWOLEParser.hxx" |
47 | | #include "MWAWParagraph.hxx" |
48 | | #include "MWAWParser.hxx" |
49 | | #include "MWAWPosition.hxx" |
50 | | #include "MWAWPrinter.hxx" |
51 | | #include "MWAWSection.hxx" |
52 | | #include "MWAWSubDocument.hxx" |
53 | | #include "MWAWRSRCParser.hxx" |
54 | | |
55 | | #include "MsWksGraph.hxx" |
56 | | #include "MsWks3Text.hxx" |
57 | | #include "MsWks4Text.hxx" |
58 | | #include "MsWks4Zone.hxx" |
59 | | |
60 | | #include "MsWksDocument.hxx" |
61 | | |
62 | | /** Internal: the structures of a MsWksDocument */ |
63 | | namespace MsWksDocumentInternal |
64 | | { |
65 | | |
66 | | //////////////////////////////////////// |
67 | | //! Internal: the state of a MsWksDocument |
68 | | struct State { |
69 | | //! constructor |
70 | | State() |
71 | 636k | : m_kind(MWAWDocument::MWAW_K_TEXT) |
72 | 636k | , m_fileHeaderSize(0) |
73 | 636k | , m_freeZoneId(0) |
74 | 636k | , m_typeZoneMap() |
75 | 636k | , m_entryMap() |
76 | 636k | , m_hasHeader(false) |
77 | 636k | , m_hasFooter(false) |
78 | 636k | , m_oleParser() |
79 | 636k | , m_headerParser() |
80 | 636k | , m_footerParser() |
81 | 636k | , m_footnoteParser() |
82 | 636k | , m_frameParserMap() |
83 | 636k | , m_unparsedOlesName() |
84 | 636k | , m_actPage(0) |
85 | 636k | , m_numPages(0) |
86 | 636k | , m_headerHeight(0) |
87 | 636k | , m_footerHeight(0) |
88 | 636k | { |
89 | 636k | } |
90 | | //! returns a color palette |
91 | | std::vector<MWAWColor> const &getPalette(int vers); |
92 | | //! the type of document |
93 | | MWAWDocument::Kind m_kind; |
94 | | //! the file header size |
95 | | long m_fileHeaderSize; |
96 | | //! an id to count the number of free map |
97 | | mutable int m_freeZoneId; |
98 | | //! the list of zone (for v1-v3) document |
99 | | std::multimap<int, MsWksDocument::Zone> m_typeZoneMap; |
100 | | //! the list of entries, name->entry ( for v4 document) |
101 | | std::multimap<std::string, MWAWEntry> m_entryMap; |
102 | | bool m_hasHeader /** true if there is a header v3*/, m_hasFooter /** true if there is a footer v3*/; |
103 | | |
104 | | // ole data |
105 | | /** the ole parser */ |
106 | | std::shared_ptr<MWAWOLEParser> m_oleParser; |
107 | | std::shared_ptr<MsWks4Zone> m_headerParser /**parser of the header ole*/, m_footerParser /**parser of the footer ole*/, |
108 | | m_footnoteParser /**parser of the footnote ole*/; |
109 | | /**the frame parsers: name-> parser*/ |
110 | | std::map<std::string, std::shared_ptr<MsWks4Zone> > m_frameParserMap; |
111 | | //! the list of unparsed OLEs |
112 | | std::vector<std::string> m_unparsedOlesName; |
113 | | //! the color palette |
114 | | std::vector<MWAWColor> m_colorPalette[4]; |
115 | | int m_actPage /** the actual page */, m_numPages /** the number of page of the final document */; |
116 | | |
117 | | int m_headerHeight /** the header height if known */, |
118 | | m_footerHeight /** the footer height if known */; |
119 | | }; |
120 | | |
121 | | std::vector<MWAWColor> const &State::getPalette(int vers) |
122 | 86.8M | { |
123 | 86.8M | switch (vers) { |
124 | 1.25M | case 2: { |
125 | 1.25M | if (!m_colorPalette[0].empty()) |
126 | 1.24M | return m_colorPalette[0]; |
127 | 14.3k | m_colorPalette[0].resize(9); |
128 | 14.3k | m_colorPalette[0][0]=MWAWColor(0,0,0); // undef |
129 | 14.3k | m_colorPalette[0][1]=MWAWColor(0,0,0); |
130 | 14.3k | m_colorPalette[0][2]=MWAWColor(255,255,255); |
131 | 14.3k | m_colorPalette[0][3]=MWAWColor(255,0,0); |
132 | 14.3k | m_colorPalette[0][4]=MWAWColor(0,255,0); |
133 | 14.3k | m_colorPalette[0][5]=MWAWColor(0,0,255); |
134 | 14.3k | m_colorPalette[0][6]=MWAWColor(0, 255,255); |
135 | 14.3k | m_colorPalette[0][7]=MWAWColor(255,0,255); |
136 | 14.3k | m_colorPalette[0][8]=MWAWColor(255,255,0); |
137 | 14.3k | return m_colorPalette[0]; |
138 | 1.25M | } |
139 | 84.8M | case 3: { |
140 | 84.8M | if (!m_colorPalette[1].empty()) |
141 | 84.7M | return m_colorPalette[1]; |
142 | 38.8k | m_colorPalette[1].resize(256); |
143 | 38.8k | size_t ind=0; |
144 | 271k | for (int k = 0; k < 6; k++) { |
145 | 1.63M | for (int j = 0; j < 6; j++) { |
146 | 8.84M | for (int i = 0; i < 6; i++, ind++) { |
147 | 7.68M | if (j==5 && i==2) break; |
148 | 7.45M | m_colorPalette[1][ind]=MWAWColor(static_cast<unsigned char>(255-51*i), static_cast<unsigned char>(255-51*k), static_cast<unsigned char>(255-51*j)); |
149 | 7.45M | } |
150 | 1.39M | } |
151 | 232k | } |
152 | | |
153 | | // the last 2 lines |
154 | 116k | for (int r = 0; r < 2; r++) { |
155 | | // the black, red, green, blue zone of 5*2 |
156 | 388k | for (int c = 0; c < 4; c++) { |
157 | 1.86M | for (int i = 0; i < 5; i++, ind++) { |
158 | 1.55M | int val = 17*r+51*i; |
159 | 1.55M | if (c == 0) { |
160 | 388k | m_colorPalette[1][ind]=MWAWColor(static_cast<unsigned char>(val), static_cast<unsigned char>(val), static_cast<unsigned char>(val)); |
161 | 388k | continue; |
162 | 388k | } |
163 | 1.16M | int color[3]= {0,0,0}; |
164 | 1.16M | color[c-1]=val; |
165 | 1.16M | m_colorPalette[1][ind]=MWAWColor(static_cast<unsigned char>(color[0]),static_cast<unsigned char>(color[1]),static_cast<unsigned char>(color[2])); |
166 | 1.16M | } |
167 | 310k | } |
168 | | // last part of j==5, i=2..5 |
169 | 310k | for (int k = r; k < 6; k+=2) { |
170 | 1.16M | for (int i = 2; i < 6; i++, ind++) |
171 | 931k | m_colorPalette[1][ind]=MWAWColor(static_cast<unsigned char>(255-51*i), static_cast<unsigned char>(255-51*k), static_cast<unsigned char>(255-51*5)); |
172 | 232k | } |
173 | 77.6k | } |
174 | 38.8k | return m_colorPalette[1]; |
175 | 84.8M | } |
176 | 61.3k | case 4: { |
177 | 61.3k | if (!m_colorPalette[2].empty()) |
178 | 61.2k | return m_colorPalette[2]; |
179 | 145 | m_colorPalette[2].resize(256); |
180 | 145 | size_t ind=0; |
181 | 1.01k | for (int k = 0; k < 6; k++) { |
182 | 6.09k | for (int j = 0; j < 6; j++) { |
183 | 36.5k | for (int i = 0; i < 6; i++, ind++) { |
184 | 31.3k | m_colorPalette[2][ind]= |
185 | 31.3k | MWAWColor(static_cast<unsigned char>(255-51*k), static_cast<unsigned char>(255-51*j), |
186 | 31.3k | static_cast<unsigned char>(255-51*i)); |
187 | 31.3k | } |
188 | 5.22k | } |
189 | 870 | } |
190 | 145 | ind--; // remove the black color |
191 | 725 | for (int c = 0; c < 4; c++) { |
192 | 580 | unsigned char color[3] = {0,0,0}; |
193 | 580 | auto val=static_cast<unsigned char>(251); |
194 | 6.38k | for (int i = 0; i < 10; i++) { |
195 | 5.80k | val = static_cast<unsigned char>(val-17); |
196 | 5.80k | if (c == 3) m_colorPalette[2][ind++]=MWAWColor(val, val, val); |
197 | 4.35k | else { |
198 | 4.35k | color[c] = val; |
199 | 4.35k | m_colorPalette[2][ind++]=MWAWColor(color[0],color[1],color[2]); |
200 | 4.35k | } |
201 | 5.80k | if ((i%2)==1) val = static_cast<unsigned char>(val-17); |
202 | 5.80k | } |
203 | 580 | } |
204 | | |
205 | | // last is black |
206 | 145 | m_colorPalette[2][ind++]=MWAWColor(0,0,0); |
207 | 145 | return m_colorPalette[2]; |
208 | 61.3k | } |
209 | 715k | default: |
210 | 715k | break; |
211 | 86.8M | } |
212 | 715k | MWAW_DEBUG_MSG(("MsWksDocumentInternal::State::getPalette: can not find palette for version %d\n", vers)); |
213 | 715k | return m_colorPalette[3]; |
214 | 86.8M | } |
215 | | |
216 | | //////////////////////////////////////// |
217 | | //! Internal: the subdocument of a MsWksDocument |
218 | | class SubDocument final : public MWAWSubDocument |
219 | | { |
220 | | public: |
221 | | enum Type { Note, OLE, Zone, Text }; |
222 | | SubDocument(MsWksDocument &document, MWAWInputStreamPtr const &input, Type type, int zoneId) |
223 | 31.2k | : MWAWSubDocument(document.m_parser, input, MWAWEntry()) |
224 | 31.2k | , m_document(document) |
225 | 31.2k | , m_type(type) |
226 | 31.2k | , m_id(zoneId) |
227 | 31.2k | { |
228 | 31.2k | } |
229 | | |
230 | | //! destructor |
231 | 0 | ~SubDocument() final {} |
232 | | |
233 | | //! operator!= |
234 | | bool operator!=(MWAWSubDocument const &doc) const final; |
235 | | |
236 | | //! the parser function |
237 | | void parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType type) final; |
238 | | |
239 | | protected: |
240 | | /** the main document */ |
241 | | MsWksDocument &m_document; |
242 | | /** the type */ |
243 | | Type m_type; |
244 | | /** the subdocument id*/ |
245 | | int m_id; |
246 | | }; |
247 | | |
248 | | void SubDocument::parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType /*type*/) |
249 | 1.49M | { |
250 | 1.49M | if (!listener.get()) { |
251 | 0 | MWAW_DEBUG_MSG(("MsWksDocument::SubDocument::parse: no listener\n")); |
252 | 0 | return; |
253 | 0 | } |
254 | | |
255 | 1.49M | long pos = m_input->tell(); |
256 | 1.49M | switch (m_type) { |
257 | 843 | case Note: |
258 | 843 | m_document.sendFootnoteContent(m_id); |
259 | 843 | break; |
260 | 4.51k | case OLE: |
261 | 4.51k | if (m_id==MsWksDocument::Z_HEADER) m_document.sendTextbox(MWAWEntry(),"QHdr"); |
262 | 1.91k | else if (m_id==MsWksDocument::Z_FOOTER) m_document.sendTextbox(MWAWEntry(),"QFtr"); |
263 | 0 | else { |
264 | 0 | MWAW_DEBUG_MSG(("MsWksDocument::SubDocument::parse: unexpected ole zone %d\n", m_id)); |
265 | 0 | } |
266 | 4.51k | break; |
267 | 4.30k | case Text: |
268 | 4.30k | m_document.sendText(m_id); |
269 | 4.30k | break; |
270 | 1.48M | case Zone: |
271 | 1.48M | m_document.sendZone(m_id); |
272 | 1.48M | break; |
273 | | #if !defined(__clang__) |
274 | | default: |
275 | | MWAW_DEBUG_MSG(("MsWksDocument::SubDocument::parse: unexpected zone type\n")); |
276 | | break; |
277 | | #endif |
278 | 1.49M | } |
279 | 1.49M | m_input->seek(pos, librevenge::RVNG_SEEK_SET); |
280 | 1.49M | } |
281 | | |
282 | | bool SubDocument::operator!=(MWAWSubDocument const &doc) const |
283 | 0 | { |
284 | 0 | if (MWAWSubDocument::operator!=(doc)) return true; |
285 | 0 | auto const *sDoc = dynamic_cast<SubDocument const *>(&doc); |
286 | 0 | if (!sDoc) return true; |
287 | 0 | if (&m_document != &sDoc->m_document) return true; |
288 | 0 | if (m_id != sDoc->m_id) return true; |
289 | 0 | if (m_type != sDoc->m_type) return true; |
290 | 0 | return false; |
291 | 0 | } |
292 | | } |
293 | | |
294 | | //////////////////////////////////////////////////////////// |
295 | | // constructor/destructor, accessor functions... |
296 | | //////////////////////////////////////////////////////////// |
297 | | MsWksDocument::MsWksDocument(MWAWInputStreamPtr const &input, MWAWParser &parser) |
298 | 284k | : m_state() |
299 | 284k | , m_parserState(parser.getParserState()) |
300 | 284k | , m_parser(&parser) |
301 | 284k | , m_parentDocument(nullptr) |
302 | 284k | , m_input(input) |
303 | 284k | , m_asciiFile(MWAWInputStreamPtr()) |
304 | 284k | , m_graphParser() |
305 | 284k | , m_textParser3() |
306 | 284k | , m_textParser4() |
307 | 284k | , m_newPage(nullptr) |
308 | 284k | { |
309 | 284k | m_state.reset(new MsWksDocumentInternal::State()); |
310 | 284k | m_graphParser.reset(new MsWksGraph(*this)); |
311 | 284k | } |
312 | | |
313 | | MsWksDocument::~MsWksDocument() |
314 | 284k | { |
315 | 284k | } |
316 | | |
317 | | void MsWksDocument::initAsciiFile(std::string const &name) |
318 | 116k | { |
319 | 116k | m_asciiFile.setStream(m_input); |
320 | 116k | m_asciiFile.open(name); |
321 | 116k | } |
322 | | |
323 | | std::shared_ptr<MsWks3Text> MsWksDocument::getTextParser3() |
324 | 65.3M | { |
325 | 65.3M | if (!m_textParser3) m_textParser3.reset(new MsWks3Text(*this)); |
326 | 65.3M | return m_textParser3; |
327 | 65.3M | } |
328 | | |
329 | | std::shared_ptr<MsWks4Text> MsWksDocument::getTextParser4() |
330 | 71.0k | { |
331 | 71.0k | if (!m_textParser4) m_textParser4.reset(new MsWks4Text(*this)); |
332 | 71.0k | return m_textParser4; |
333 | 71.0k | } |
334 | | |
335 | | void MsWksDocument::setVersion(int vers) |
336 | 351k | { |
337 | 351k | m_parserState->m_version=vers; |
338 | 351k | } |
339 | | |
340 | | int MsWksDocument::version() const |
341 | 23.3M | { |
342 | 23.3M | return m_parserState->m_version; |
343 | 23.3M | } |
344 | | |
345 | | MWAWDocument::Kind MsWksDocument::getKind() const |
346 | 290k | { |
347 | 290k | return m_state->m_kind; |
348 | 290k | } |
349 | | |
350 | | void MsWksDocument::setKind(MWAWDocument::Kind kind) |
351 | 0 | { |
352 | 0 | m_state->m_kind=kind; |
353 | 0 | } |
354 | | |
355 | | int MsWksDocument::getNewZoneId() const |
356 | 11.8k | { |
357 | 11.8k | return MsWksDocument::Z_NONE + ++m_state->m_freeZoneId; |
358 | 11.8k | } |
359 | | |
360 | | MsWksDocument::Zone MsWksDocument::getZone(MsWksDocument::ZoneType type) const |
361 | 1.75M | { |
362 | 1.75M | Zone res; |
363 | 1.75M | if (m_state->m_typeZoneMap.find(int(type)) != m_state->m_typeZoneMap.end()) |
364 | 1.62M | res = m_state->m_typeZoneMap.find(int(type))->second; |
365 | 1.75M | return res; |
366 | 1.75M | } |
367 | | |
368 | | std::multimap<int, MsWksDocument::Zone> &MsWksDocument::getTypeZoneMap() |
369 | 112k | { |
370 | 112k | return m_state->m_typeZoneMap; |
371 | 112k | } |
372 | | |
373 | | std::multimap<std::string, MWAWEntry> &MsWksDocument::getEntryMap() |
374 | 358k | { |
375 | 358k | return m_state->m_entryMap; |
376 | 358k | } |
377 | | |
378 | | long MsWksDocument::getLengthOfFileHeader3() const |
379 | 1.24k | { |
380 | 1.24k | return m_state->m_fileHeaderSize; |
381 | 1.24k | } |
382 | | |
383 | | void MsWksDocument::sendText(int id) |
384 | 1.30M | { |
385 | 1.30M | if (m_textParser3) m_textParser3->sendZone(id); |
386 | 1.30M | } |
387 | | |
388 | | void MsWksDocument::sendZone(int zoneType) |
389 | 1.54M | { |
390 | 1.54M | Zone zone=getZone(ZoneType(zoneType)); |
391 | 1.54M | if (zone.m_zoneId >= 0) |
392 | 1.54M | m_graphParser->sendAll(zone.m_zoneId, zoneType==MsWksDocument::Z_MAIN); |
393 | 1.54M | if (zone.m_textId >= 0) sendText(zone.m_textId); |
394 | 1.54M | } |
395 | | |
396 | | void MsWksDocument::sendFootnoteContent(int noteId) |
397 | 843 | { |
398 | 843 | if (!m_parserState->getMainListener()) return; |
399 | 843 | if (!m_state->m_footnoteParser) { |
400 | 536 | MWAW_DEBUG_MSG(("MsWksDocument::sendFootnoteContent: can not found the footnote parser\n")); |
401 | 536 | m_parserState->getMainListener()->insertChar(' '); |
402 | 536 | return; |
403 | 536 | } |
404 | 307 | m_state->m_footnoteParser->createZones(false); |
405 | 307 | m_state->m_footnoteParser->readFootNote(noteId); |
406 | 307 | } |
407 | | |
408 | | //////////////////////////////////////////////////////////// |
409 | | // page span function |
410 | | //////////////////////////////////////////////////////////// |
411 | | bool MsWksDocument::hasHeader() const |
412 | 58.5k | { |
413 | 58.5k | return m_state->m_hasHeader; |
414 | 58.5k | } |
415 | | |
416 | | bool MsWksDocument::hasFooter() const |
417 | 53.6k | { |
418 | 53.6k | return m_state->m_hasFooter; |
419 | 53.6k | } |
420 | | |
421 | | float MsWksDocument::getHeaderFooterHeight(bool header) const |
422 | 66.7k | { |
423 | 66.7k | return header ? float(m_state->m_headerHeight) : float(m_state->m_footerHeight); |
424 | 66.7k | } |
425 | | |
426 | | void MsWksDocument::getPageSpanList(std::vector<MWAWPageSpan> &pagesList, int &numPages) |
427 | 71.3k | { |
428 | 71.3k | Zone mainZone=getZone(Z_MAIN); |
429 | | // first count the page |
430 | 71.3k | numPages = 1; |
431 | 71.3k | if (m_textParser3 && mainZone.m_textId >= 0 && m_textParser3->numPages(mainZone.m_textId) > numPages) |
432 | 7.68k | numPages = m_textParser3->numPages(mainZone.m_textId); |
433 | 71.3k | if (m_textParser4 && m_textParser4->numPages() > numPages) |
434 | 1.17k | numPages = m_textParser4->numPages(); |
435 | 71.3k | if (m_graphParser->numPages(mainZone.m_zoneId) > numPages) |
436 | 3.41k | numPages = m_graphParser->numPages(mainZone.m_zoneId); |
437 | | // now update the page list |
438 | 71.3k | MWAWPageSpan ps(m_parserState->m_pageSpan); |
439 | 71.3k | int id = m_textParser3 ? m_textParser3->getHeader() : -1; |
440 | 71.3k | if (id >= 0) { |
441 | 2.45k | m_state->m_headerHeight=12; |
442 | 2.45k | MWAWHeaderFooter header(MWAWHeaderFooter::HEADER, MWAWHeaderFooter::ALL); |
443 | 2.45k | header.m_subDocument.reset |
444 | 2.45k | (new MsWksDocumentInternal::SubDocument |
445 | 2.45k | (*this, getInput(), MsWksDocumentInternal::SubDocument::Text, id)); |
446 | 2.45k | ps.setHeaderFooter(header); |
447 | 2.45k | } |
448 | 68.9k | else if (getZone(MsWksDocument::Z_HEADER).m_zoneId >= 0) { |
449 | 17.1k | MWAWHeaderFooter header(MWAWHeaderFooter::HEADER, MWAWHeaderFooter::ALL); |
450 | 17.1k | header.m_subDocument.reset |
451 | 17.1k | (new MsWksDocumentInternal::SubDocument |
452 | 17.1k | (*this, getInput(), MsWksDocumentInternal::SubDocument::Zone, int(MsWksDocument::Z_HEADER))); |
453 | 17.1k | ps.setHeaderFooter(header); |
454 | 17.1k | } |
455 | 51.7k | else if (m_state->m_headerParser) { |
456 | 2.59k | MWAWHeaderFooter header(MWAWHeaderFooter::HEADER, MWAWHeaderFooter::ALL); |
457 | 2.59k | header.m_subDocument.reset |
458 | 2.59k | (new MsWksDocumentInternal::SubDocument |
459 | 2.59k | (*this, getInput(), MsWksDocumentInternal::SubDocument::OLE, int(MsWksDocument::Z_HEADER))); |
460 | 2.59k | ps.setHeaderFooter(header); |
461 | 2.59k | } |
462 | 71.3k | id = m_textParser3 ? m_textParser3->getFooter() : -1; |
463 | 71.3k | if (id >= 0) { |
464 | 1.85k | m_state->m_footerHeight=12; |
465 | 1.85k | MWAWHeaderFooter footer(MWAWHeaderFooter::FOOTER, MWAWHeaderFooter::ALL); |
466 | 1.85k | footer.m_subDocument.reset |
467 | 1.85k | (new MsWksDocumentInternal::SubDocument |
468 | 1.85k | (*this, getInput(), MsWksDocumentInternal::SubDocument::Text, id)); |
469 | 1.85k | ps.setHeaderFooter(footer); |
470 | 1.85k | } |
471 | 69.5k | else if (getZone(MsWksDocument::Z_FOOTER).m_zoneId >= 0) { |
472 | 4.48k | MWAWHeaderFooter footer(MWAWHeaderFooter::FOOTER, MWAWHeaderFooter::ALL); |
473 | 4.48k | footer.m_subDocument.reset |
474 | 4.48k | (new MsWksDocumentInternal::SubDocument |
475 | 4.48k | (*this, getInput(), MsWksDocumentInternal::SubDocument::Zone, int(MsWksDocument::Z_FOOTER))); |
476 | 4.48k | ps.setHeaderFooter(footer); |
477 | 4.48k | } |
478 | 65.0k | else if (m_state->m_footerParser) { |
479 | 1.91k | MWAWHeaderFooter footer(MWAWHeaderFooter::FOOTER, MWAWHeaderFooter::ALL); |
480 | 1.91k | footer.m_subDocument.reset |
481 | 1.91k | (new MsWksDocumentInternal::SubDocument |
482 | 1.91k | (*this, getInput(), MsWksDocumentInternal::SubDocument::OLE, int(MsWksDocument::Z_FOOTER))); |
483 | 1.91k | ps.setHeaderFooter(footer); |
484 | 1.91k | } |
485 | 71.3k | ps.setPageSpan(numPages+1); |
486 | 71.3k | pagesList=std::vector<MWAWPageSpan>(1,ps); |
487 | 71.3k | } |
488 | | |
489 | | //////////////////////////////////////////////////////////// |
490 | | // interface via callback |
491 | | //////////////////////////////////////////////////////////// |
492 | | void MsWksDocument::newPage(int page, bool softBreak) |
493 | 30.4k | { |
494 | 30.4k | if (m_parentDocument) |
495 | 39 | return m_parentDocument->newPage(page, softBreak); |
496 | 30.4k | if (!m_newPage) { |
497 | 115 | MWAW_DEBUG_MSG(("MsWksDocument::newPage: can not find the newPage callback\n")); |
498 | 115 | return; |
499 | 115 | } |
500 | 30.3k | (m_parser->*m_newPage)(page, softBreak); |
501 | 30.3k | } |
502 | | |
503 | | void MsWksDocument::sendFootnote(int id) |
504 | 843 | { |
505 | 843 | if (m_parentDocument) |
506 | 0 | return m_parentDocument->sendFootnote(id); |
507 | 843 | if (!m_parserState->getMainListener()) return; |
508 | | |
509 | 843 | MWAWSubDocumentPtr subdoc(new MsWksDocumentInternal::SubDocument |
510 | 843 | (*this, getInput(), MsWksDocumentInternal::SubDocument::Note, id)); |
511 | 843 | m_parserState->getMainListener()->insertNote(MWAWNote(MWAWNote::FootNote), subdoc); |
512 | 843 | } |
513 | | |
514 | | void MsWksDocument::sendOLE(int id, MWAWPosition const &pictPos, MWAWGraphicStyle const &style) |
515 | 78.2k | { |
516 | 78.2k | if (m_parentDocument) |
517 | 0 | return m_parentDocument->sendOLE(id, pictPos, style); |
518 | | |
519 | 78.2k | if (!m_parserState->getMainListener()) return; |
520 | 78.2k | librevenge::RVNGBinaryData data; |
521 | 78.2k | MWAWPosition pos; |
522 | 78.2k | std::string type; |
523 | 78.2k | if (!m_state->m_oleParser || !m_state->m_oleParser->getObject(id, data, pos, type)) { |
524 | 78.2k | MWAW_DEBUG_MSG(("MsWksDocument::sendOLE: can not find OLE%d\n", id)); |
525 | 78.2k | return; |
526 | 78.2k | } |
527 | 0 | m_parserState->getMainListener()->insertPicture(pictPos, MWAWEmbeddedObject(data, type), style); |
528 | 0 | } |
529 | | |
530 | | void MsWksDocument::sendRBIL(int id, MWAWVec2i const &sz) |
531 | 0 | { |
532 | 0 | MsWksGraph::SendData sendData; |
533 | 0 | sendData.m_type = MsWksGraph::SendData::RBIL; |
534 | 0 | sendData.m_id = id; |
535 | 0 | sendData.m_anchor = MWAWPosition::Char; |
536 | 0 | sendData.m_size = sz; |
537 | 0 | m_graphParser->sendObjects(sendData); |
538 | 0 | } |
539 | | |
540 | | void MsWksDocument::sendTextbox(MWAWEntry const &entry, std::string const &frame) |
541 | 187k | { |
542 | 187k | if (m_parentDocument) |
543 | 0 | return m_parentDocument->sendTextbox(entry,frame); |
544 | 187k | MWAWListenerPtr listener=m_parserState->getMainListener(); |
545 | 187k | if (!listener) return; |
546 | | |
547 | 187k | if (entry.length()==0) { |
548 | 98.8k | listener->insertChar(' '); |
549 | 98.8k | return; |
550 | 98.8k | } |
551 | | |
552 | 88.3k | MsWks4Zone *parser = nullptr; |
553 | 88.3k | if (frame == "QHdr") parser=m_state->m_headerParser.get(); |
554 | 85.7k | else if (frame == "QFtr") parser=m_state->m_footerParser.get(); |
555 | 83.7k | else { |
556 | 83.7k | auto frameIt = m_state->m_frameParserMap.find(frame); |
557 | 83.7k | if (frameIt != m_state->m_frameParserMap.end()) |
558 | 773 | parser = frameIt->second.get(); |
559 | 83.7k | } |
560 | 88.3k | if (!parser || (entry.length() && parser->getTextPosition().length() < entry.end())) { |
561 | 83.0k | MWAW_DEBUG_MSG(("MsWksDocument::sendTextbox: can not find frame ole: %s\n", frame.c_str())); |
562 | 83.0k | listener->insertChar(' '); |
563 | 83.0k | return; |
564 | 83.0k | } |
565 | | |
566 | | // ok, create the entry |
567 | 5.25k | MWAWEntry ent(entry); |
568 | 5.25k | ent.setBegin(entry.begin()+parser->getTextPosition().begin()); |
569 | 5.25k | parser->createZones(false); |
570 | 5.25k | parser->readContentZones(ent, false); |
571 | 5.25k | } |
572 | | |
573 | | //////////////////////////////////////////////////////////// |
574 | | // |
575 | | // Intermediate level |
576 | | // |
577 | | //////////////////////////////////////////////////////////// |
578 | | std::vector<MWAWColor> const &MsWksDocument::getPalette(int vers) |
579 | 86.8M | { |
580 | 86.8M | return m_state->getPalette(vers); |
581 | 86.8M | } |
582 | | |
583 | | bool MsWksDocument::getColor(int id, MWAWColor &col, int vers) |
584 | 86.8M | { |
585 | 86.8M | std::vector<MWAWColor> const &palette = getPalette(vers); |
586 | 86.8M | if (palette.size()==0 || id < 0 || id >= int(palette.size()) || |
587 | 58.0M | (vers==2 && id==0)) { |
588 | 58.0M | static bool first = true; |
589 | 58.0M | if (first) { |
590 | 36 | MWAW_DEBUG_MSG(("MsWksDocument::getColor: unknown color=%d\n", id)); |
591 | 36 | first = false; |
592 | 36 | } |
593 | 58.0M | return false; |
594 | 58.0M | } |
595 | 28.7M | col = palette[size_t(id)]; |
596 | 28.7M | return true; |
597 | 86.8M | } |
598 | | |
599 | | //////////////////////////////////////////////////////////// |
600 | | // |
601 | | // Low level |
602 | | // |
603 | | //////////////////////////////////////////////////////////// |
604 | | |
605 | | //////////////////////////////////////////////////////////// |
606 | | // create the ole structures or get list of unparsed zones |
607 | | //////////////////////////////////////////////////////////// |
608 | | std::vector<std::string> const &MsWksDocument::getUnparsedOLEZones() const |
609 | 4.59k | { |
610 | 4.59k | return m_state->m_unparsedOlesName; |
611 | 4.59k | } |
612 | | |
613 | | bool MsWksDocument::createOLEZones(MWAWInputStreamPtr input) |
614 | 7.82k | { |
615 | 7.82k | if (!input || !input->isStructured()) return false; |
616 | 7.82k | m_state->m_oleParser.reset(new MWAWOLEParser("MN0", m_parserState->m_fontConverter, 3)); |
617 | | |
618 | 7.82k | if (!m_state->m_oleParser->parse(input)) return false; |
619 | | |
620 | | // normally, |
621 | | // MacWorks/QHdr, MacWorks/QFtr, MacWorks/QFootnotes, MacWorks/QFrm<number> |
622 | | // MN0 (the main header), MM (almost empty) |
623 | | // MatOST/MatadorObject?/*: the picture |
624 | | // but no metadata |
625 | 7.82k | auto unparsed = m_state->m_oleParser->getNotParse(); |
626 | | |
627 | 7.82k | unparsed.push_back("MN0"); |
628 | | |
629 | 22.9k | for (auto const &name : unparsed) { |
630 | | // separated the directory and the name |
631 | | // MatOST/MatadorObject1/Ole10Native |
632 | | // -> dir="MatOST/MatadorObject1", base="Ole10Native" |
633 | 22.9k | auto pos = name.find_last_of('/'); |
634 | 22.9k | std::string dir, base; |
635 | 22.9k | if (pos == std::string::npos) base = name; |
636 | 13.8k | else if (pos == 0) base = name.substr(1); |
637 | 13.8k | else { |
638 | 13.8k | dir = name.substr(0,pos); |
639 | 13.8k | base = name.substr(pos+1); |
640 | 13.8k | } |
641 | | |
642 | 22.9k | if (dir == "" && base == "MN0") continue; |
643 | 15.1k | bool ok = false; |
644 | 15.1k | bool isFrame = false; |
645 | 15.1k | if (dir == "MacWorks") { |
646 | 12.6k | ok = (base == "QHdr" || base == "QFtr" || base == "QFootnotes"); |
647 | 12.6k | if (!ok && strncmp(base.c_str(),"QFrm",4)==0) |
648 | 1.75k | ok = isFrame = true; |
649 | 12.6k | } |
650 | 15.1k | if (!ok) { |
651 | 3.45k | m_state->m_unparsedOlesName.push_back(name); |
652 | 3.45k | continue; |
653 | 3.45k | } |
654 | | |
655 | 11.7k | MWAWInputStreamPtr ole = input->getSubStreamByName(name.c_str()); |
656 | 11.7k | if (!ole.get()) { |
657 | 0 | MWAW_DEBUG_MSG(("MsWksDocument::createOLEZones: error: can not find OLE part: \"%s\"\n", name.c_str())); |
658 | 0 | continue; |
659 | 0 | } |
660 | | |
661 | 11.7k | std::shared_ptr<MsWks4Zone> newParser(new MsWks4Zone(ole, m_parserState, *m_parser, name)); |
662 | 11.7k | try { |
663 | 11.7k | ok = newParser->createZones(false); |
664 | 11.7k | } |
665 | 11.7k | catch (...) { |
666 | 1.21k | ok = false; |
667 | 1.21k | } |
668 | | |
669 | 11.7k | if (!ok) { |
670 | 4.05k | MWAW_DEBUG_MSG(("MsWksDocument::createOLEZones: error: can not parse OLE: \"%s\"\n", name.c_str())); |
671 | 4.05k | continue; |
672 | 4.05k | } |
673 | | |
674 | | // first update the parent document |
675 | 7.66k | newParser->m_document->m_parentDocument=this; |
676 | 7.66k | if (base == "QHdr") m_state->m_headerParser = newParser; |
677 | 5.06k | else if (base == "QFtr") m_state->m_footerParser = newParser; |
678 | 3.14k | else if (isFrame) { |
679 | 1.49k | auto frameIt = m_state->m_frameParserMap.find(base); |
680 | 1.49k | if (frameIt != m_state->m_frameParserMap.end()) { |
681 | 0 | MWAW_DEBUG_MSG(("MsWksDocument::createOLEZones: error: oops, I already find a frame zone %s\n", base.c_str())); |
682 | 0 | } |
683 | 1.49k | else |
684 | 1.49k | m_state->m_frameParserMap[base] = newParser; |
685 | 1.49k | } |
686 | 1.65k | else if (base == "QFootnotes") m_state->m_footnoteParser = newParser; |
687 | 7.66k | } |
688 | | |
689 | 7.82k | return true; |
690 | 7.82k | } |
691 | | |
692 | | //////////////////////////////////////////////////////////// |
693 | | // read the print info |
694 | | //////////////////////////////////////////////////////////// |
695 | | bool MsWksDocument::readPrintInfo() |
696 | 16.7M | { |
697 | 16.7M | MWAWInputStreamPtr input = getInput(); |
698 | 16.7M | long pos = input->tell(); |
699 | 16.7M | libmwaw::DebugStream f; |
700 | | // print info |
701 | 16.7M | libmwaw::PrinterInfo info; |
702 | 16.7M | if (!input->checkPosition(pos+0x78+8) || !info.read(input)) return false; |
703 | 9.43M | f << "Entries(PrintInfo):"<< info; |
704 | | |
705 | 9.43M | MWAWVec2i paperSize = info.paper().size(); |
706 | 9.43M | MWAWVec2i pageSize = info.page().size(); |
707 | 9.43M | if (pageSize.x() <= 0 || pageSize.y() <= 0 || |
708 | 7.27M | paperSize.x() <= 0 || paperSize.y() <= 0) return false; |
709 | | |
710 | | // now read the margin |
711 | 5.07M | int margin[4]; |
712 | 5.07M | int maxSize = paperSize.x() > paperSize.y() ? paperSize.x() : paperSize.y(); |
713 | 5.07M | f << ", margin=("; |
714 | 12.0M | for (int i = 0; i < 4; i++) { |
715 | 12.0M | margin[i] = int(72.f/120.f *float(input->readLong(2))); |
716 | 12.0M | if (margin[i] < -maxSize || margin[i] > maxSize) return false; |
717 | 6.94M | f << margin[i]; |
718 | 6.94M | if (i != 3) f << ", "; |
719 | 6.94M | } |
720 | 9.87k | f << ")"; |
721 | | |
722 | | // fixme: compute the real page length here... |
723 | | // define margin from print info |
724 | 9.87k | MWAWVec2i lTopMargin(margin[0],margin[1]), rBotMargin(margin[2],margin[3]); |
725 | 9.87k | lTopMargin += paperSize - pageSize; |
726 | | |
727 | 9.87k | int leftMargin = lTopMargin.x(); |
728 | 9.87k | int topMargin = lTopMargin.y(); |
729 | | |
730 | | // decrease a little right and bottom margins Margin |
731 | 9.87k | int rightMarg = rBotMargin.x()-50; |
732 | 9.87k | if (rightMarg < 0) { |
733 | 5.38k | leftMargin -= (-rightMarg); |
734 | 5.38k | if (leftMargin < 0) leftMargin=0; |
735 | 5.38k | rightMarg=0; |
736 | 5.38k | } |
737 | 9.87k | int botMarg = rBotMargin.y()-50; |
738 | 9.87k | if (botMarg < 0) { |
739 | 5.34k | topMargin -= (-botMarg); |
740 | 5.34k | if (topMargin < 0) topMargin=0; |
741 | 5.34k | botMarg=0; |
742 | 5.34k | } |
743 | | |
744 | 9.87k | m_parserState->m_pageSpan.setMarginTop(topMargin/72.0); |
745 | 9.87k | m_parserState->m_pageSpan.setMarginBottom(botMarg/72.0); |
746 | 9.87k | m_parserState->m_pageSpan.setMarginLeft(leftMargin/72.0); |
747 | 9.87k | m_parserState->m_pageSpan.setMarginRight(rightMarg/72.0); |
748 | 9.87k | m_parserState->m_pageSpan.setFormLength(paperSize.y()/72.); |
749 | 9.87k | m_parserState->m_pageSpan.setFormWidth(paperSize.x()/72.); |
750 | | |
751 | 9.87k | ascii().addPos(pos); |
752 | 9.87k | ascii().addNote(f.str().c_str()); |
753 | 9.87k | input->seek(pos+0x78+8, librevenge::RVNG_SEEK_SET); |
754 | | |
755 | 9.87k | return true; |
756 | 5.07M | } |
757 | | |
758 | | //////////////////////////////////////////////////////////// |
759 | | // read the document info |
760 | | //////////////////////////////////////////////////////////// |
761 | | bool MsWksDocument::readDocumentInfo(long sz) |
762 | 21.3M | { |
763 | 21.3M | MWAWInputStreamPtr input = getInput(); |
764 | 21.3M | long pos = input->tell(); |
765 | 21.3M | libmwaw::DebugStream f; |
766 | | |
767 | 21.3M | int vers = m_parserState->m_kind==MWAWDocument::MWAW_K_DATABASE ? 2 : version(); |
768 | 21.3M | int docId = 0; |
769 | 21.3M | int docExtra = 0; |
770 | 21.3M | int flag = 0; |
771 | 21.3M | int expectedSz = 0x80; |
772 | 21.3M | if (sz<=0) { |
773 | 21.2M | if (input->readLong(1) != 2) |
774 | 59.6k | return false; |
775 | 21.2M | docId = static_cast<int>(input->readULong(1)); |
776 | 21.2M | docExtra = static_cast<int>(input->readULong(1)); |
777 | 21.2M | flag = static_cast<int>(input->readULong(1)); |
778 | 21.2M | sz = long(input->readULong(2)); |
779 | 21.2M | expectedSz = vers<=2 ? 0x15e : 0x9a; |
780 | 21.2M | } |
781 | 21.2M | long endPos = input->tell()+sz; |
782 | 21.2M | if (!input->checkPosition(endPos)) |
783 | 2.76M | return false; |
784 | | |
785 | 18.4M | if (sz < expectedSz) { |
786 | 16.7M | if (sz < 0x78+8) { |
787 | 1.74M | MWAW_DEBUG_MSG(("MsWksDocument::readDocumentInfo: size is too short\n")); |
788 | 1.74M | return false; |
789 | 1.74M | } |
790 | 15.0M | MWAW_DEBUG_MSG(("MsWksDocument::readDocumentInfo: size is too short: try to continue\n")); |
791 | 15.0M | } |
792 | | |
793 | 16.7M | f << "Entries(DocInfo):"; |
794 | 16.7M | if (docId) f << "id=0x"<< std::hex << docId << ","; |
795 | 16.7M | if (docExtra) f << "unk=" << docExtra << ","; // in v3: find 3, 7, 1x |
796 | 16.7M | if (flag) f << "fl=" << flag << ","; // in v3: find 80, 84, e0 |
797 | 16.7M | ascii().addPos(pos); |
798 | 16.7M | ascii().addNote(f.str().c_str()); |
799 | | |
800 | 16.7M | if (!readPrintInfo()) { |
801 | 16.7M | input->seek(pos, librevenge::RVNG_SEEK_SET); |
802 | 16.7M | return true; |
803 | 16.7M | } |
804 | | |
805 | 9.87k | if (sz < 0x9a) { |
806 | 391 | input->seek(endPos, librevenge::RVNG_SEEK_SET); |
807 | 391 | return true; |
808 | 391 | } |
809 | 9.48k | pos = input->tell(); |
810 | 9.48k | f.str(""); |
811 | 9.48k | f << "DocInfo-1:"; |
812 | 9.48k | auto val = static_cast<int>(input->readLong(2)); |
813 | 9.48k | if ((val & 0x0400) && vers >= 3) { |
814 | 222 | f << "titlepage,"; |
815 | 222 | val &= 0xFBFF; |
816 | 222 | } |
817 | 9.48k | if (val) f << "unkn=" << val << ","; |
818 | 9.48k | if (vers <= 2) { |
819 | 20.7k | for (int wh = 0; wh < 2; wh++) { |
820 | 13.8k | long debPos = input->tell(); |
821 | 13.8k | std::string name(wh==0 ? "header" : "footer"); |
822 | 13.8k | std::string text = getTextParser3()->readHeaderFooterString(wh==0); |
823 | 13.8k | if (text.size()) f << name << "="<< text << ","; |
824 | | |
825 | 13.8k | long remain = debPos+100 - input->tell(); |
826 | 1.09M | for (long i = 0; i < remain; i++) { |
827 | 1.08M | auto c = static_cast<unsigned char>(input->readULong(1)); |
828 | 1.08M | if (c == 0) continue; |
829 | 486k | f << std::dec << "f"<< i << "=" << static_cast<int>(c) << ","; |
830 | 486k | } |
831 | 13.8k | } |
832 | 6.90k | f << "defFid=" << input->readULong(2) << ","; |
833 | 6.90k | f << "defFsz=" << input->readULong(2)/2 << ","; |
834 | 6.90k | val = static_cast<int>(input->readULong(2)); // 0 or 8 |
835 | 6.90k | if (val) f << "#unkn=" << val << ","; |
836 | 6.90k | int dim[2]; |
837 | 13.8k | for (auto &d : dim) d = static_cast<int>(input->readULong(2)); |
838 | 6.90k | f << "dim=" << dim[0] << "x" << dim[1] << ","; |
839 | | /* followed by 0 (v1) or 0|0x21|0* (v2)*/ |
840 | 6.90k | ascii().addPos(pos); |
841 | 6.90k | ascii().addNote(f.str().c_str()); |
842 | 6.90k | pos = input->tell(); |
843 | 6.90k | f.str(""); |
844 | 6.90k | f << "DocInfo-2:"; |
845 | 6.90k | } |
846 | | |
847 | | // last data ( normally 26) |
848 | 9.48k | auto numData = int((endPos - input->tell())/2); |
849 | 139k | for (int i = 0; i < numData; i++) { |
850 | 129k | val = static_cast<int>(input->readLong(2)); |
851 | 129k | switch (i) { |
852 | 3.04k | case 2: |
853 | 3.04k | if (val!=1) f << "firstPageNumber=" << val << ","; |
854 | 3.04k | break; |
855 | 3.02k | case 3: |
856 | 3.02k | if (val!=1) f << "firstNoteNumber=" << val << ","; |
857 | 3.02k | break; |
858 | 123k | default: |
859 | 123k | if (val) |
860 | 50.0k | f << "g" << i << "=" << val << ","; |
861 | 123k | break; |
862 | 129k | } |
863 | 129k | } |
864 | 9.48k | ascii().addPos(pos); |
865 | 9.48k | ascii().addNote(f.str().c_str()); |
866 | | |
867 | 9.48k | input->seek(endPos, librevenge::RVNG_SEEK_SET); |
868 | | |
869 | 9.48k | return true; |
870 | 9.48k | } |
871 | | |
872 | | //////////////////////////////////////////////////////////// |
873 | | // read a header/footer zone info |
874 | | //////////////////////////////////////////////////////////// |
875 | | bool MsWksDocument::readGroupHeaderFooter(bool header, int check) |
876 | 66.4k | { |
877 | 66.4k | if (version() < 3) return false; |
878 | | |
879 | 66.4k | MWAWInputStreamPtr input=getInput(); |
880 | 66.4k | long debPos = input->tell(); |
881 | | |
882 | 66.4k | auto ptr = long(input->readULong(2)); |
883 | 66.4k | if (input->isEnd()) return false; |
884 | 65.0k | if (ptr) { |
885 | 49.5k | if (check == 49) return false; |
886 | 49.5k | if (check == 99) { |
887 | 49.5k | MWAW_DEBUG_MSG(("MsWksDocument::readGroupHeaderFooter: find ptr=0x%lx\n", static_cast<long unsigned int>(ptr))); |
888 | 49.5k | } |
889 | 49.5k | } |
890 | | |
891 | 65.0k | libmwaw::DebugStream f; |
892 | | |
893 | 65.0k | int size = static_cast<int>(input->readLong(2))+4; |
894 | 65.0k | int realSize = 0x11; |
895 | 65.0k | if (size < realSize) return false; |
896 | 53.2k | if (input->readLong(2) != 0) return false; |
897 | 42.8k | f << "Entries(GroupHInfo)"; |
898 | 42.8k | if (header) |
899 | 34.0k | f << "[header]"; |
900 | 8.80k | else |
901 | 8.80k | f << "[footer]"; |
902 | 42.8k | f << ": size=" << std::hex << size << std::dec << " BTXT"; |
903 | | |
904 | 42.8k | if (!input->checkPosition(debPos+size)) return false; |
905 | | |
906 | 41.3k | input->seek(debPos+6, librevenge::RVNG_SEEK_SET); |
907 | 41.3k | auto N=static_cast<int>(input->readLong(2)); |
908 | 41.3k | f << ", N=" << N; |
909 | 41.3k | int dim[4]; |
910 | 165k | for (auto &d : dim) d = static_cast<int>(input->readLong(2)); |
911 | | |
912 | 41.3k | MWAWBox2i box(MWAWVec2i(dim[1], dim[0]), MWAWVec2i(dim[3], dim[2])); |
913 | 41.3k | if (box.size().x() < -2000 || box.size().y() < -2000 || |
914 | 40.4k | box.size().x() > 2000 || box.size().y() > 2000 || |
915 | 39.4k | box.min().x() < -200 || box.min().y() < -200) return false; |
916 | 39.0k | if (check == 49 && box.size().x() == 0 && box.size().y() == 0) return false; |
917 | 39.0k | f << ", BDBox =" << box; |
918 | 39.0k | auto val = static_cast<int>(input->readULong(1)); |
919 | 39.0k | if (val) f << ", flag=" << val; |
920 | | |
921 | 39.0k | input->seek(debPos+size, librevenge::RVNG_SEEK_SET); |
922 | 39.0k | if (check < 99) return true; |
923 | 39.0k | if (header) m_state->m_headerHeight = box.size().y(); |
924 | 6.80k | else m_state->m_footerHeight = box.size().y(); |
925 | 39.0k | std::multimap<int, MsWksDocument::Zone> &typeZoneMap=getTypeZoneMap(); |
926 | 39.0k | MsWksDocument::ZoneType type= |
927 | 39.0k | header ? MsWksDocument::Z_HEADER : MsWksDocument::Z_FOOTER; |
928 | 39.0k | MsWksDocument::Zone zone(type, int(typeZoneMap.size())); |
929 | | |
930 | 39.0k | ascii().addPos(debPos); |
931 | 39.0k | ascii().addNote(f.str().c_str()); |
932 | 39.0k | ascii().addPos(input->tell()); |
933 | | |
934 | 39.0k | input->seek(debPos+realSize, librevenge::RVNG_SEEK_SET); |
935 | 39.0k | input->pushLimit(debPos+size); |
936 | 39.0k | bool limitSet = true; |
937 | 82.0M | for (int i = 0; i < N; i++) { |
938 | 81.9M | long pos = input->tell(); |
939 | 81.9M | if (limitSet && pos==debPos+size) { |
940 | 28.3k | limitSet = false; |
941 | 28.3k | input->popLimit(); |
942 | 28.3k | } |
943 | 81.9M | if (readZone(zone)) continue; |
944 | 65.2M | input->seek(pos, librevenge::RVNG_SEEK_SET); |
945 | 65.2M | zone.m_textId = getTextParser3()->createZones(N-i, false); |
946 | 65.2M | if (zone.m_textId >= 0) |
947 | 12.4k | break; |
948 | 65.2M | MWAW_DEBUG_MSG(("MsWksDocument::readGroupHeaderFooter: can not find end of group\n")); |
949 | 65.2M | input->seek(pos, librevenge::RVNG_SEEK_SET); |
950 | 65.2M | } |
951 | 39.0k | if (limitSet) input->popLimit(); |
952 | 39.0k | if (long(input->tell()) < debPos+size) { |
953 | 10.1k | ascii().addPos(input->tell()); |
954 | 10.1k | ascii().addNote("GroupHInfo-II"); |
955 | | |
956 | 10.1k | input->seek(debPos+size, librevenge::RVNG_SEEK_SET); |
957 | | |
958 | 10.1k | ascii().addPos(debPos + size); |
959 | 10.1k | ascii().addNote("_"); |
960 | 10.1k | } |
961 | | // getGraphParser()->addDeltaToPositions(zone.m_zoneId, -1*box[0]); |
962 | 39.0k | if (typeZoneMap.find(int(type)) != typeZoneMap.end()) { |
963 | 0 | MWAW_DEBUG_MSG(("MsWksDocument::readGroupHeaderFooter: the zone already exists\n")); |
964 | 0 | } |
965 | 39.0k | else |
966 | 39.0k | typeZoneMap.insert(std::multimap<int, MsWksDocument::Zone>::value_type(int(type),zone)); |
967 | 39.0k | return true; |
968 | 39.0k | } |
969 | | |
970 | | //////////////////////////////////////////////////////////// |
971 | | // read a generic zone |
972 | | //////////////////////////////////////////////////////////// |
973 | | bool MsWksDocument::readZone(MsWksDocument::Zone &zone) |
974 | 82.8M | { |
975 | 82.8M | MWAWInputStreamPtr input = getInput(); |
976 | 82.8M | if (input->isEnd()) return false; |
977 | 80.8M | long pos = input->tell(); |
978 | 80.8M | MWAWEntry pict; |
979 | 80.8M | auto val = static_cast<int>(input->readLong(1)); |
980 | 80.8M | input->seek(-1, librevenge::RVNG_SEEK_CUR); |
981 | 80.8M | switch (val) { |
982 | 39.0M | case 0: { |
983 | 39.0M | if (m_graphParser->getEntryPicture(zone.m_zoneId, pict)>=0) { |
984 | 757k | input->seek(pict.end(), librevenge::RVNG_SEEK_SET); |
985 | 757k | return true; |
986 | 757k | } |
987 | 38.3M | break; |
988 | 39.0M | } |
989 | 38.3M | case 1: { |
990 | 9.00M | if (m_graphParser->getEntryPictureV1(zone.m_zoneId, pict)>=0) { |
991 | 31.5k | input->seek(pict.end(), librevenge::RVNG_SEEK_SET); |
992 | 31.5k | return true; |
993 | 31.5k | } |
994 | 8.97M | break; |
995 | 9.00M | } |
996 | 21.2M | case 2: |
997 | 21.2M | if (readDocumentInfo()) |
998 | 16.7M | return true; |
999 | 4.49M | break; |
1000 | 4.49M | case 3: { |
1001 | | // checkme, ok for text but is it also ok for other ? |
1002 | 2.35M | MWAWEntry group; |
1003 | 2.35M | group.setId(zone.m_zoneId); |
1004 | 2.35M | group.setName("RBDR"); |
1005 | 2.35M | if (m_graphParser->readRB(input, group, 2)) |
1006 | 22.2k | return true; |
1007 | 2.33M | break; |
1008 | 2.35M | } |
1009 | 9.20M | default: |
1010 | 9.20M | break; |
1011 | 80.8M | } |
1012 | | |
1013 | 63.3M | input->seek(pos, librevenge::RVNG_SEEK_SET); |
1014 | 63.3M | return false; |
1015 | 80.8M | } |
1016 | | |
1017 | | //////////////////////////////////////////////////////////// |
1018 | | // read the header |
1019 | | //////////////////////////////////////////////////////////// |
1020 | | bool MsWksDocument::checkHeader3(MWAWHeader *header, bool strict) |
1021 | 352k | { |
1022 | 352k | *m_state = MsWksDocumentInternal::State(); |
1023 | 352k | MWAWInputStreamPtr input = getInput(); |
1024 | 352k | if (!input || !input->hasDataFork()) |
1025 | 63 | return false; |
1026 | | |
1027 | 352k | int numError = 0, val; |
1028 | | |
1029 | 352k | const int headerSize = 0x20; |
1030 | | |
1031 | 352k | libmwaw::DebugStream f; |
1032 | | |
1033 | 352k | input->seek(0,librevenge::RVNG_SEEK_SET); |
1034 | | |
1035 | 352k | m_state->m_hasHeader = m_state->m_hasFooter = false; |
1036 | 352k | auto vers = static_cast<int>(input->readULong(4)); |
1037 | 352k | switch (vers) { |
1038 | 61.2k | case 11: |
1039 | 61.2k | setVersion(4); |
1040 | 61.2k | break; |
1041 | 155k | case 9: |
1042 | 155k | setVersion(3); |
1043 | 155k | break; |
1044 | 80.6k | case 8: |
1045 | 80.6k | setVersion(2); |
1046 | 80.6k | break; |
1047 | 53.5k | case 4: |
1048 | 53.5k | setVersion(1); |
1049 | 53.5k | break; |
1050 | 1.32k | default: |
1051 | 1.32k | if (strict) return false; |
1052 | | |
1053 | 793 | MWAW_DEBUG_MSG(("MsWksDocument::checkHeader3: find unknown version 0x%x\n", static_cast<unsigned int>(vers))); |
1054 | | // must we stop in this case, or can we continue ? |
1055 | 793 | if (vers < 0 || vers > 14) { |
1056 | 158 | MWAW_DEBUG_MSG(("MsWksDocument::checkHeader3: version too big, we stop\n")); |
1057 | 158 | return false; |
1058 | 158 | } |
1059 | 635 | setVersion((vers < 4) ? 1 : (vers < 8) ? 2 : (vers < 11) ? 3 : 4); |
1060 | 352k | } |
1061 | 351k | if (input->seek(headerSize,librevenge::RVNG_SEEK_SET) != 0 || input->isEnd()) |
1062 | 496 | return false; |
1063 | | |
1064 | 351k | if (input->seek(12,librevenge::RVNG_SEEK_SET) != 0) return false; |
1065 | | |
1066 | 1.40M | for (int i = 0; i < 3; i++) { |
1067 | 1.05M | val = static_cast<int>(input->readLong(1)); |
1068 | 1.05M | if (val < -10 || val > 10) { |
1069 | 111k | MWAW_DEBUG_MSG(("MsWksDocument::checkHeader3: find odd val%d=0x%x: not implemented\n", i, static_cast<unsigned int>(val))); |
1070 | 111k | numError++; |
1071 | 111k | } |
1072 | 1.05M | } |
1073 | 351k | input->seek(1,librevenge::RVNG_SEEK_CUR); |
1074 | 351k | auto type = static_cast<int>(input->readLong(2)); |
1075 | 351k | switch (type) { |
1076 | | // Text document |
1077 | 208k | case 1: |
1078 | 208k | break; |
1079 | 16.4k | case 2: |
1080 | 16.4k | m_state->m_kind = MWAWDocument::MWAW_K_DATABASE; |
1081 | 16.4k | break; |
1082 | 26.4k | case 3: |
1083 | 26.4k | m_state->m_kind = MWAWDocument::MWAW_K_SPREADSHEET; |
1084 | 26.4k | break; |
1085 | 100k | case 12: |
1086 | 100k | m_state->m_kind = MWAWDocument::MWAW_K_DRAW; |
1087 | 100k | break; |
1088 | 89 | default: |
1089 | 89 | MWAW_DEBUG_MSG(("MsWksDocument::checkHeader3: find odd type=%d: not implemented\n", type)); |
1090 | 89 | return false; |
1091 | 351k | } |
1092 | | |
1093 | 351k | if (version() < 1 || version() > 4) |
1094 | 0 | return false; |
1095 | | |
1096 | | // |
1097 | 351k | input->seek(0,librevenge::RVNG_SEEK_SET); |
1098 | 351k | f << "FileHeader: "; |
1099 | 351k | f << "version= " << input->readULong(4); |
1100 | 351k | long dim[4]; |
1101 | 1.40M | for (auto &d : dim) d = input->readLong(2); |
1102 | 351k | bool checkDatabaseFileHSize=false; |
1103 | 351k | if (dim[2] <= dim[0] || dim[3] <= dim[1]) { |
1104 | | // bdbox(0,0,0,0) can appear if there is no document info, so do not consider this an error for database file |
1105 | 200k | if (dim[0]==0 && dim[1]==0 && dim[2]==0 && dim[3]==0 && m_state->m_kind == MWAWDocument::MWAW_K_DATABASE) { |
1106 | 432 | checkDatabaseFileHSize=true; |
1107 | 432 | } |
1108 | 200k | else { |
1109 | 200k | MWAW_DEBUG_MSG(("MsWksDocument::checkHeader3: find odd bdbox\n")); |
1110 | 200k | numError++; |
1111 | 200k | } |
1112 | 200k | } |
1113 | 351k | f << ", windowdbdbox?=("; |
1114 | 1.40M | for (auto d : dim) f << d <<","; |
1115 | 351k | f << "),"; |
1116 | 351k | auto fileHeaderSize=long(input->readULong(4)); |
1117 | 351k | if (checkDatabaseFileHSize && strict) { |
1118 | 216 | if ((version()==2 && fileHeaderSize!=0x516) || (version()==3&&fileHeaderSize!=0x50)) |
1119 | 115 | return false; |
1120 | 216 | } |
1121 | 351k | if (fileHeaderSize) |
1122 | 259k | f << "headerSize=" << std::hex << fileHeaderSize << std::dec << ","; |
1123 | | |
1124 | 351k | if (m_state->m_kind==MWAWDocument::MWAW_K_SPREADSHEET) { |
1125 | | /* CHECKME: normally 0x56c, but find one time 0x56a in a v2 file |
1126 | | which seems to imply that the spreadsheet begins earlier */ |
1127 | 26.4k | if (fileHeaderSize!=0x56c && fileHeaderSize > long(0x550) && input->checkPosition(fileHeaderSize+0x20)) |
1128 | 999 | m_state->m_fileHeaderSize=fileHeaderSize; |
1129 | 25.4k | else |
1130 | 25.4k | m_state->m_fileHeaderSize=0x56c; |
1131 | 26.4k | } |
1132 | 351k | type = static_cast<int>(input->readULong(2)); |
1133 | 351k | f << std::dec; |
1134 | 351k | switch (type) { |
1135 | 208k | case 1: |
1136 | 208k | f << "doc,"; |
1137 | 208k | break; |
1138 | 16.2k | case 2: |
1139 | 16.2k | f << "database,"; |
1140 | 16.2k | break; // with ##v3=50 |
1141 | 26.4k | case 3: |
1142 | 26.4k | f << "spreadsheet,"; |
1143 | 26.4k | break; // with ##v2=5,##v3=6c |
1144 | 100k | case 12: |
1145 | 100k | f << "draw,"; |
1146 | 100k | break; |
1147 | 0 | default: |
1148 | 0 | f << "###type=" << type << ","; |
1149 | 0 | break; |
1150 | 351k | } |
1151 | 351k | f << "numlines?=" << input->readLong(2) << ","; |
1152 | 351k | val = static_cast<int>(input->readLong(1)); // 0, v2: 0, 4 or -4 |
1153 | 351k | if (val) f << "f0=" << val << ","; |
1154 | 351k | val = static_cast<int>(input->readLong(1)); // almost always 1 |
1155 | 351k | if (val != 1) f << "f1=" << val << ","; |
1156 | 2.10M | for (int i = 11; i < headerSize/2; i++) { // v1: 0, 0, v2: 0, 0|1 |
1157 | 1.75M | val = static_cast<int>(input->readULong(2)); |
1158 | 1.75M | if (!val) continue; |
1159 | 1.15M | f << "f" << i << "=" << std::hex << val << std::dec; |
1160 | 1.15M | if (version() >= 3 && i == 12) { |
1161 | 204k | if (val & 0x100) { |
1162 | 153k | m_state->m_hasHeader = true; |
1163 | 153k | f << "(Head)"; |
1164 | 153k | } |
1165 | 204k | if (val & 0x200) { |
1166 | 112k | m_state->m_hasFooter = true; |
1167 | 112k | f << "(Foot)"; |
1168 | 112k | } |
1169 | 204k | } |
1170 | 1.15M | f << ","; |
1171 | 1.15M | } |
1172 | | |
1173 | 351k | if (header) |
1174 | 166k | header->reset(MWAWDocument::MWAW_T_MICROSOFTWORKS, version(), m_state->m_kind); |
1175 | | |
1176 | 351k | ascii().addPos(0); |
1177 | 351k | ascii().addNote(f.str().c_str()); |
1178 | 351k | ascii().addPos(headerSize); |
1179 | | |
1180 | 351k | input->seek(headerSize,librevenge::RVNG_SEEK_SET); |
1181 | 351k | return strict ? (numError==0) : (numError < 3); |
1182 | 351k | } |
1183 | | |
1184 | | //////////////////////////////////////////////////////////// |
1185 | | // spreadsheet/database function |
1186 | | //////////////////////////////////////////////////////////// |
1187 | | bool MsWksDocument::readDBString(long endPos, std::string &res) |
1188 | 56.7k | { |
1189 | 56.7k | MWAWInputStreamPtr input=getInput(); |
1190 | 56.7k | res = ""; |
1191 | 56.7k | int error = 0; |
1192 | 56.7k | int ok = 0; |
1193 | 1.97M | while (!input->isEnd() && input->tell() < endPos) { |
1194 | 1.92M | auto c = char(input->readLong(1)); |
1195 | 1.92M | if (c < 27 && c != '\t' && c != '\n') error++; |
1196 | 1.18M | else ok++; |
1197 | 1.92M | res += c; |
1198 | 1.92M | } |
1199 | 56.7k | return ok >= error; |
1200 | 56.7k | } |
1201 | | |
1202 | | bool MsWksDocument::readDBNumber(long endPos, double &res, bool &isNan, std::string &str) |
1203 | 45.2k | { |
1204 | 45.2k | MWAWInputStreamPtr input=getInput(); |
1205 | 45.2k | res = 0; |
1206 | 45.2k | str=""; |
1207 | 45.2k | long pos = input->tell(); |
1208 | 45.2k | if (endPos > pos+10 && !readDBString(endPos-10,str)) return false; |
1209 | 38.6k | return input->tell() == endPos-10 && input->readDouble10(res,isNan); |
1210 | 45.2k | } |
1211 | | |
1212 | | bool MsWksDocument::readCellInFormula(MWAWCellContent::FormulaInstruction &instr, bool is2D) |
1213 | 6.60k | { |
1214 | 6.60k | MWAWInputStreamPtr input=getInput(); |
1215 | 6.60k | instr=MWAWCellContent::FormulaInstruction(); |
1216 | 6.60k | instr.m_type=MWAWCellContent::FormulaInstruction::F_Cell; |
1217 | 6.60k | bool ok = true; |
1218 | 6.60k | if (is2D) { |
1219 | 305 | bool absolute[2] = { false, false}; |
1220 | 305 | auto type = static_cast<int>(input->readULong(1)); |
1221 | 305 | if (type & 0x80) { |
1222 | 135 | absolute[0] = true; |
1223 | 135 | type &= 0x7F; |
1224 | 135 | } |
1225 | 305 | if (type & 0x40) { |
1226 | 121 | absolute[1] = true; |
1227 | 121 | type &= 0xBF; |
1228 | 121 | } |
1229 | 305 | if (type) { |
1230 | 203 | MWAW_DEBUG_MSG(("MSWksSSParser::readCellInFormula:Pb find fl=%d when reading a cell\n", type)); |
1231 | 203 | ok = false; |
1232 | 203 | } |
1233 | 305 | int pos[2]= {1,0}; |
1234 | 610 | for (auto &p : pos) p = static_cast<int>(input->readULong(1)); |
1235 | | |
1236 | 305 | if (pos[0] < 1 || pos[1] < 0) { |
1237 | 24 | if (ok) { |
1238 | 6 | MWAW_DEBUG_MSG(("MSWksSSParser::readCellInFormula: can not read cell position\n")); |
1239 | 6 | } |
1240 | 24 | return false; |
1241 | 24 | } |
1242 | 281 | instr.m_position[0]=MWAWVec2i(pos[1],pos[0]-1); |
1243 | 281 | instr.m_positionRelative[0]=MWAWVec2b(!absolute[1], !absolute[0]); |
1244 | 281 | } |
1245 | 6.30k | else |
1246 | 6.30k | instr.m_position[0]=MWAWVec2i(static_cast<int>(input->readULong(1)),0); |
1247 | 6.58k | return ok; |
1248 | 6.60k | } |
1249 | | |
1250 | | bool MsWksDocument::readFormula(long endPos, MWAWCellContent &content, std::string &extra) |
1251 | 8.72k | { |
1252 | 8.72k | MWAWInputStreamPtr input=getInput(); |
1253 | 8.72k | long pos = input->tell(); |
1254 | 8.72k | extra=""; |
1255 | 8.72k | if (pos == endPos) return false; |
1256 | 8.72k | if (!input->checkPosition(endPos)) { |
1257 | 0 | MWAW_DEBUG_MSG(("MsWksDocument::readFormula: bad endPos\n")); |
1258 | 0 | extra="###endPos"; |
1259 | 0 | return false; |
1260 | 0 | } |
1261 | | |
1262 | 8.72k | std::stringstream f; |
1263 | 8.72k | auto &formula=content.m_formula; |
1264 | 8.72k | bool is2D=m_parserState->m_kind!=MWAWDocument::MWAW_K_DATABASE; |
1265 | 8.72k | bool ok=true; |
1266 | 30.2k | while (input->tell() < endPos && !input->isEnd()) { |
1267 | 26.1k | pos = input->tell(); |
1268 | 26.1k | auto code = static_cast<int>(input->readLong(1)); |
1269 | 26.1k | MWAWCellContent::FormulaInstruction instr; |
1270 | 26.1k | bool findEnd=false; |
1271 | 26.1k | switch (code) { |
1272 | 2.52k | case 0x0: |
1273 | 8.57k | case 0x2: |
1274 | 9.79k | case 0x4: |
1275 | 11.9k | case 0x6: { |
1276 | 11.9k | static char const* const wh[]= {"+","-","*","/"}; |
1277 | 11.9k | instr.m_type=MWAWCellContent::FormulaInstruction::F_Operator; |
1278 | 11.9k | instr.m_content=wh[code/2]; |
1279 | 11.9k | break; |
1280 | 9.79k | } |
1281 | 494 | case 0x8: { // a number |
1282 | 494 | auto sz = static_cast<int>(input->readULong(1)); |
1283 | 494 | std::string s; |
1284 | 494 | double val; |
1285 | 494 | bool isNan; |
1286 | 494 | if (pos+sz+12 <= endPos && readDBNumber((pos+2)+sz+10, val, isNan, s)) { |
1287 | 144 | instr.m_type=MWAWCellContent::FormulaInstruction::F_Double; |
1288 | 144 | instr.m_doubleValue=val; |
1289 | 144 | break; |
1290 | 144 | } |
1291 | 350 | f << "###number" << s; |
1292 | 350 | ok=false; |
1293 | 350 | break; |
1294 | 494 | } |
1295 | 3.33k | case 0x0a: { // a cell |
1296 | 3.33k | if (!readCellInFormula(instr, is2D)) |
1297 | 125 | f << "#"; |
1298 | 3.33k | break; |
1299 | 494 | } |
1300 | 1.97k | case 0x0c: { // function |
1301 | 1.97k | auto v = static_cast<int>(input->readULong(1)); |
1302 | 1.97k | static char const* const listFunc [0x41] = { |
1303 | 1.97k | "Abs", "Sum", "Na", "Error", "ACos", "And", "ASin", "ATan", |
1304 | 1.97k | "ATan2", "Average", "Choose", "Cos", "Count", "Exp", "False", "FV", |
1305 | 1.97k | "HLookup", "If", "Index", "Int", "IRR", "IsBlank", "IsError", "IsNa", |
1306 | 1.97k | "##Funct[30]", "Ln", "Lookup", "Log10", "Max", "Min", "Mod", "Not", |
1307 | 1.97k | "NPer", "NPV", "Or", "Pi", "Pmt", "PV", "Rand", "Round", |
1308 | 1.97k | "Sign", "Sin", "Sqrt", "StDev", "Tan", "True", "Var", "VLookup", |
1309 | 1.97k | "Match", "MIRR", "Rate", "Type", "Radians", "Degrees", "Sum" /*"SSum: checkme"*/, "Date", |
1310 | 1.97k | "Day", "Hour", "Minute", "Month", "Now", "Second", "Time", "Weekday", |
1311 | 1.97k | "Year" |
1312 | 1.97k | }; |
1313 | 1.97k | instr.m_type=MWAWCellContent::FormulaInstruction::F_Function; |
1314 | 1.97k | if ((v%2) == 0 && v >= 0 && v/2 <= 0x40) |
1315 | 1.87k | instr.m_content=listFunc[v/2]; |
1316 | 100 | else { |
1317 | 100 | f << "###"; |
1318 | 100 | MWAW_DEBUG_MSG(("MSWksSSParser::readFormula: find unknown function %x\n", static_cast<unsigned int>(v))); |
1319 | 100 | std::stringstream s; |
1320 | 100 | s << "Funct" << std::hex << v << std::dec; |
1321 | 100 | instr.m_content=s.str(); |
1322 | 100 | } |
1323 | 1.97k | break; |
1324 | 494 | } |
1325 | 2.00k | case 0x0e: { // list of cell |
1326 | 2.00k | MWAWCellContent::FormulaInstruction instr2; |
1327 | 2.00k | if (endPos-pos< (is2D ? 9 : 5)) { |
1328 | 330 | f << "###list cell short"; |
1329 | 330 | ok = false; |
1330 | 330 | break; |
1331 | 330 | } |
1332 | 1.67k | if (!readCellInFormula(instr, is2D) || !readCellInFormula(instr2, is2D)) |
1333 | 84 | f << "#"; |
1334 | 1.67k | instr.m_type=MWAWCellContent::FormulaInstruction::F_CellList; |
1335 | 1.67k | instr.m_position[1]=instr2.m_position[0]; |
1336 | 1.67k | instr.m_positionRelative[1]=instr2.m_positionRelative[0]; |
1337 | 1.67k | break; |
1338 | 2.00k | } |
1339 | 405 | case 0x16: |
1340 | 405 | findEnd=true; |
1341 | 405 | input->seek(-1, librevenge::RVNG_SEEK_CUR); |
1342 | 405 | f << ","; |
1343 | 405 | break; |
1344 | 6.00k | default: |
1345 | 6.00k | if ((code%2)==0 && code>=0x10 && code<=0x22) { |
1346 | 2.47k | static char const* const wh[]= {"(", ")", ";", "end", "<", ">", "=", "<=", ">=", "<>" }; |
1347 | 2.47k | instr.m_type=MWAWCellContent::FormulaInstruction::F_Operator; |
1348 | 2.47k | instr.m_content=wh[(code-0x10)/2]; |
1349 | 2.47k | break; |
1350 | 2.47k | } |
1351 | 3.53k | f << "###" << std::hex << code << std::dec; |
1352 | 3.53k | ok = false; |
1353 | 3.53k | break; |
1354 | 26.1k | } |
1355 | 26.1k | if (!ok || findEnd) |
1356 | 4.62k | break; |
1357 | 21.5k | f << instr; |
1358 | 21.5k | formula.push_back(instr); |
1359 | 21.5k | } |
1360 | 8.72k | extra=f.str(); |
1361 | 8.72k | pos = input->tell(); |
1362 | 8.72k | if (endPos - pos < 21) |
1363 | 7.09k | return ok; |
1364 | | // test if we have the value |
1365 | 1.62k | if (input->readLong(1) != 0x16) { |
1366 | 1.23k | input->seek(-1, librevenge::RVNG_SEEK_CUR); |
1367 | 1.23k | return true; |
1368 | 1.23k | } |
1369 | | |
1370 | 394 | f.str(""); |
1371 | 394 | f << std::dec << "unk1=["; |
1372 | | // looks a little as a zone of cell ?? but this seems eroneous |
1373 | 1.18k | for (int i = 0; i < 2; i++) { |
1374 | 788 | auto v = static_cast<int>(input->readULong(1)); |
1375 | | |
1376 | 788 | auto n0 = static_cast<int>(input->readULong(1)); |
1377 | 788 | auto n1 = static_cast<int>(input->readULong(1)); |
1378 | 788 | if (i == 1) f << ":"; |
1379 | 788 | f << n0 << "x" << n1; |
1380 | 788 | if (v) f << "##v"; |
1381 | 788 | } |
1382 | 394 | f << std::hex << "],unk2=["; // 0, followed by a small number between 1 and 140 |
1383 | 1.18k | for (int i = 0; i < 2; i++) |
1384 | 788 | f << input->readULong(2) << ","; |
1385 | 394 | f << "]"; |
1386 | | |
1387 | | // the value |
1388 | 394 | double value; |
1389 | 394 | bool isNan; |
1390 | 394 | std::string res; |
1391 | 394 | if (!readDBNumber(endPos, value, isNan, res)) { |
1392 | 277 | MWAW_DEBUG_MSG(("MsWksDocument::readFormula: can not read val number\n")); |
1393 | 277 | input->seek(pos, librevenge::RVNG_SEEK_SET); |
1394 | 277 | f << ",###"; |
1395 | 277 | } |
1396 | 117 | else { |
1397 | 117 | content.setValue(value); |
1398 | 117 | f << ":" << value << ","; |
1399 | 117 | } |
1400 | 394 | extra += f.str(); |
1401 | 394 | return true; |
1402 | 1.62k | } |
1403 | | |
1404 | | // vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: |