/src/libmwaw/src/lib/MsWksSSParser.cxx
Line | Count | Source |
1 | | /* -*- Mode: C++; c-default-style: "k&r"; indent-tabs-mode: nil; tab-width: 2; c-basic-offset: 2 -*- */ |
2 | | |
3 | | /* libmwaw |
4 | | * Version: MPL 2.0 / LGPLv2+ |
5 | | * |
6 | | * The contents of this file are subject to the Mozilla Public License Version |
7 | | * 2.0 (the "License"); you may not use this file except in compliance with |
8 | | * the License or as specified alternatively below. You may obtain a copy of |
9 | | * the License at http://www.mozilla.org/MPL/ |
10 | | * |
11 | | * Software distributed under the License is distributed on an "AS IS" basis, |
12 | | * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License |
13 | | * for the specific language governing rights and limitations under the |
14 | | * License. |
15 | | * |
16 | | * Major Contributor(s): |
17 | | * Copyright (C) 2002 William Lachance (wrlach@gmail.com) |
18 | | * Copyright (C) 2002,2004 Marc Maurer (uwog@uwog.net) |
19 | | * Copyright (C) 2004-2006 Fridrich Strba (fridrich.strba@bluewin.ch) |
20 | | * Copyright (C) 2006, 2007 Andrew Ziem |
21 | | * Copyright (C) 2011, 2012 Alonso Laurent (alonso@loria.fr) |
22 | | * |
23 | | * |
24 | | * All Rights Reserved. |
25 | | * |
26 | | * For minor contributions see the git repository. |
27 | | * |
28 | | * Alternatively, the contents of this file may be used under the terms of |
29 | | * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"), |
30 | | * in which case the provisions of the LGPLv2+ are applicable |
31 | | * instead of those above. |
32 | | */ |
33 | | |
34 | | #include <iomanip> |
35 | | #include <iostream> |
36 | | #include <limits> |
37 | | #include <sstream> |
38 | | |
39 | | #include <librevenge/librevenge.h> |
40 | | |
41 | | |
42 | | #include "MWAWCell.hxx" |
43 | | #include "MWAWFont.hxx" |
44 | | #include "MWAWFontConverter.hxx" |
45 | | #include "MWAWHeader.hxx" |
46 | | #include "MWAWOLEParser.hxx" |
47 | | #include "MWAWPrinter.hxx" |
48 | | #include "MWAWSpreadsheetListener.hxx" |
49 | | #include "MWAWSubDocument.hxx" |
50 | | |
51 | | #include "MsWksGraph.hxx" |
52 | | #include "MsWks3Text.hxx" |
53 | | #include "MsWksDocument.hxx" |
54 | | |
55 | | #include "MsWksSSParser.hxx" |
56 | | |
57 | | /** Internal: the structures of a MsWksSSParser */ |
58 | | namespace MsWksSSParserInternal |
59 | | { |
60 | | /** a cell of a MsWksSSParser */ |
61 | | class Cell final : public MWAWCell |
62 | | { |
63 | | public: |
64 | | /// constructor |
65 | | Cell() |
66 | 8.62k | : m_content() |
67 | 8.62k | , m_noteId(0) |
68 | 8.62k | { |
69 | 8.62k | } |
70 | 9.49k | Cell(Cell const &)=default; |
71 | | Cell &operator=(Cell const &)=default; |
72 | 4.31k | Cell &operator=(Cell &&)=default; |
73 | | //! destructor |
74 | | ~Cell() final; |
75 | | //! returns true if the cell do contain any content |
76 | | bool isEmpty() const |
77 | 4.27k | { |
78 | 4.27k | return m_content.empty() && !hasBorders() && !m_noteId; |
79 | 4.27k | } |
80 | | |
81 | | //! operator<< |
82 | | friend std::ostream &operator<<(std::ostream &o, Cell const &cell); |
83 | | |
84 | | //! the cell content |
85 | | MWAWCellContent m_content; |
86 | | |
87 | | /** the note id */ |
88 | | int m_noteId; |
89 | | }; |
90 | | |
91 | | //! operator<< |
92 | | std::ostream &operator<<(std::ostream &o, Cell const &cell) |
93 | 0 | { |
94 | 0 | o << static_cast<MWAWCell const &>(cell); |
95 | |
|
96 | 0 | if (cell.m_noteId) o << ", noteId=" << cell.m_noteId; |
97 | 0 | return o; |
98 | 0 | } |
99 | | |
100 | | /** the spreadsheet of a of a MsWksSSParser */ |
101 | | class Spreadsheet |
102 | | { |
103 | | public: |
104 | | //! constructor |
105 | | Spreadsheet() |
106 | 34.5k | : m_font(3,12) |
107 | 34.5k | , m_widthCols() |
108 | 34.5k | , m_cells() |
109 | 34.5k | , m_listPageBreaks() |
110 | 34.5k | , m_idNoteMap() |
111 | 34.5k | , m_name("Sheet0") |
112 | 34.5k | { |
113 | 34.5k | } |
114 | | //! convert the m_widthCols in a vector of of point size |
115 | | std::vector<float> convertInPoint(std::vector<int> const &list, float defSize) const |
116 | 265 | { |
117 | 265 | auto numCols=size_t(getRightBottomPosition()[0]+1); |
118 | 265 | std::vector<float> res; |
119 | 265 | res.resize(numCols); |
120 | 13.2k | for (size_t i = 0; i < numCols; i++) { |
121 | 12.9k | if (i>=list.size() || list[i] < 0) res[i] = defSize; |
122 | 8.03k | else res[i] = float(list[i]); |
123 | 12.9k | } |
124 | 265 | return res; |
125 | 265 | } |
126 | | |
127 | | /** the default font */ |
128 | | MWAWFont m_font; |
129 | | /** the column size in pixels(?) */ |
130 | | std::vector<int> m_widthCols; |
131 | | /** the list of not empty cells */ |
132 | | std::vector<Cell> m_cells; |
133 | | /** the list of page break */ |
134 | | std::vector<int> m_listPageBreaks; |
135 | | /** a map id->note content */ |
136 | | std::map<int, MWAWEntry> m_idNoteMap; |
137 | | /** the spreadsheet name */ |
138 | | std::string m_name; |
139 | | protected: |
140 | | /** returns the last Right Bottom cell position */ |
141 | | MWAWVec2i getRightBottomPosition() const |
142 | 265 | { |
143 | 265 | int maxX = 0, maxY = 0; |
144 | 4.23k | for (auto const &cell : m_cells) { |
145 | 4.23k | MWAWVec2i const &p = cell.position(); |
146 | 4.23k | if (p[0] > maxX) maxX = p[0]; |
147 | 4.23k | if (p[1] > maxY) maxY = p[1]; |
148 | 4.23k | } |
149 | 265 | return MWAWVec2i(maxX, maxY); |
150 | 265 | } |
151 | | }; |
152 | | |
153 | | Cell::~Cell() |
154 | 18.1k | { |
155 | 18.1k | } |
156 | | |
157 | | //////////////////////////////////////// |
158 | | //! Internal: the state of a MsWksSSParser |
159 | | struct State { |
160 | | //! constructor |
161 | | State() |
162 | 30.8k | : m_spreadsheet() |
163 | 30.8k | , m_actPage(0) |
164 | 30.8k | , m_numPages(0) |
165 | 30.8k | , m_pageLength(-1) |
166 | 30.8k | { |
167 | 30.8k | } |
168 | | |
169 | | /** the spreadsheet */ |
170 | | Spreadsheet m_spreadsheet; |
171 | | int m_actPage /** the actual page */, m_numPages /** the number of page of the final document */; |
172 | | |
173 | | //! the page length in point (if known) |
174 | | int m_pageLength; |
175 | | }; |
176 | | |
177 | | //////////////////////////////////////// |
178 | | //! Internal: the subdocument of a MsWksSSParser |
179 | | class SubDocument final : public MWAWSubDocument |
180 | | { |
181 | | public: |
182 | | SubDocument(MsWksSSParser &pars, MWAWInputStreamPtr const &input, int zoneId) |
183 | 1.37k | : MWAWSubDocument(&pars, input, MWAWEntry()) |
184 | 1.37k | ,m_id(zoneId) |
185 | 1.37k | { |
186 | 1.37k | } |
187 | | |
188 | | //! destructor |
189 | 0 | ~SubDocument() final {} |
190 | | |
191 | | //! operator!= |
192 | | bool operator!=(MWAWSubDocument const &doc) const final; |
193 | | |
194 | | //! the parser function |
195 | | void parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType type) final; |
196 | | |
197 | | protected: |
198 | | /** the subdocument id*/ |
199 | | int m_id; |
200 | | }; |
201 | | |
202 | | void SubDocument::parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType /*type*/) |
203 | 1.37k | { |
204 | 1.37k | if (!listener.get()) { |
205 | 0 | MWAW_DEBUG_MSG(("MsWksSSParserInternal::SubDocument::parse: no listener\n")); |
206 | 0 | return; |
207 | 0 | } |
208 | 1.37k | auto *parser = dynamic_cast<MsWksSSParser *>(m_parser); |
209 | 1.37k | if (!parser) { |
210 | 0 | MWAW_DEBUG_MSG(("MsWksSSParserInternal::SubDocument::parse: no parser\n")); |
211 | 0 | return; |
212 | 0 | } |
213 | 1.37k | long pos = m_input->tell(); |
214 | 1.37k | parser->sendNote(m_id); |
215 | 1.37k | m_input->seek(pos, librevenge::RVNG_SEEK_SET); |
216 | 1.37k | } |
217 | | |
218 | | bool SubDocument::operator!=(MWAWSubDocument const &doc) const |
219 | 0 | { |
220 | 0 | if (MWAWSubDocument::operator!=(doc)) return true; |
221 | 0 | auto const *sDoc = dynamic_cast<SubDocument const *>(&doc); |
222 | 0 | if (!sDoc) return true; |
223 | 0 | if (m_id != sDoc->m_id) return true; |
224 | 0 | return false; |
225 | 0 | } |
226 | | } |
227 | | |
228 | | |
229 | | //////////////////////////////////////////////////////////// |
230 | | // constructor/destructor, ... |
231 | | //////////////////////////////////////////////////////////// |
232 | | MsWksSSParser::MsWksSSParser(MWAWInputStreamPtr const &input, MWAWRSRCParserPtr const &rsrcParser, MWAWHeader *header) |
233 | 13.5k | : MWAWSpreadsheetParser(input, rsrcParser, header) |
234 | 13.5k | , m_state() |
235 | 13.5k | , m_listZones() |
236 | 13.5k | , m_document() |
237 | 13.5k | { |
238 | 13.5k | MWAWInputStreamPtr mainInput=input; |
239 | 13.5k | if (!input) return; |
240 | 13.5k | if (input->isStructured()) { |
241 | 664 | MWAWInputStreamPtr mainOle = input->getSubStreamByName("MN0"); |
242 | 664 | if (mainOle) |
243 | 664 | mainInput=mainOle; |
244 | 664 | } |
245 | 13.5k | m_document.reset(new MsWksDocument(mainInput, *this)); |
246 | 13.5k | init(); |
247 | 13.5k | } |
248 | | |
249 | | MsWksSSParser::~MsWksSSParser() |
250 | 13.5k | { |
251 | 13.5k | } |
252 | | |
253 | | void MsWksSSParser::init() |
254 | 13.5k | { |
255 | 13.5k | resetSpreadsheetListener(); |
256 | 13.5k | setAsciiName("main-1"); |
257 | | |
258 | 13.5k | m_state.reset(new MsWksSSParserInternal::State); |
259 | | |
260 | | // reduce the margin (in case, the page is not defined) |
261 | 13.5k | getPageSpan().setMargins(0.1); |
262 | 13.5k | } |
263 | | |
264 | | //////////////////////////////////////////////////////////// |
265 | | // the parser |
266 | | //////////////////////////////////////////////////////////// |
267 | | void MsWksSSParser::parse(librevenge::RVNGSpreadsheetInterface *docInterface) |
268 | 3.74k | { |
269 | 3.74k | if (!m_document || !m_document->getInput() || !checkHeader(nullptr)) throw(libmwaw::ParseException()); |
270 | 3.74k | bool ok = true; |
271 | 3.74k | try { |
272 | | #ifdef DEBUG |
273 | | MWAWInputStreamPtr &input= getInput(); |
274 | | if (input->isStructured()) { |
275 | | std::shared_ptr<MWAWOLEParser> oleParser(new MWAWOLEParser("MN0", getParserState()->m_fontConverter, 3)); |
276 | | oleParser->parse(input); |
277 | | } |
278 | | #endif |
279 | | // create the asciiFile |
280 | 3.74k | m_document->initAsciiFile(asciiName()); |
281 | | |
282 | 3.74k | checkHeader(nullptr); |
283 | 3.74k | createZones(); |
284 | 3.74k | ok=!m_state->m_spreadsheet.m_cells.empty(); |
285 | 3.74k | if (ok) { |
286 | 265 | createDocument(docInterface); |
287 | 265 | sendSpreadsheet(); |
288 | 265 | } |
289 | 3.74k | } |
290 | 3.74k | catch (...) { |
291 | 0 | MWAW_DEBUG_MSG(("MsWksSSParser::parse: exception catched when parsing\n")); |
292 | 0 | ok = false; |
293 | 0 | } |
294 | 3.74k | m_document->ascii().reset(); |
295 | | |
296 | 3.74k | resetSpreadsheetListener(); |
297 | 3.74k | if (!ok) throw(libmwaw::ParseException()); |
298 | 3.74k | } |
299 | | |
300 | | void MsWksSSParser::sendNote(int noteId) |
301 | 1.37k | { |
302 | 1.37k | MWAWListenerPtr listener=getSpreadsheetListener(); |
303 | 1.37k | if (!listener|| |
304 | 1.37k | m_state->m_spreadsheet.m_idNoteMap.find(noteId)==m_state->m_spreadsheet.m_idNoteMap.end()) { |
305 | 1.34k | MWAW_DEBUG_MSG(("MsWksSSParser::sendNote: can not send note %d\n", noteId)); |
306 | 1.34k | return; |
307 | 1.34k | } |
308 | 25 | MWAWEntry const &entry=m_state->m_spreadsheet.m_idNoteMap.find(noteId)->second; |
309 | 25 | int const vers=version(); |
310 | 25 | if (!entry.valid()) return; |
311 | 25 | MWAWInputStreamPtr input = m_document->getInput(); |
312 | 25 | input->seek(entry.begin(), librevenge::RVNG_SEEK_SET); |
313 | 1.30k | while (1) { |
314 | 1.30k | long pos=input->tell(); |
315 | 1.30k | if (input->isEnd() || pos>=entry.end()) return; |
316 | 1.27k | auto c = static_cast<int>(input->readULong(1)); |
317 | 1.27k | switch (c) { |
318 | 0 | case 0x9: |
319 | 0 | listener->insertTab(); |
320 | 0 | break; |
321 | 1 | case 0x10: // cursor pos |
322 | 1 | case 0x11: |
323 | 1 | break; |
324 | 1.27k | default: |
325 | 1.27k | if (c >= 0x15 && c <= 0x19 && vers >= 3) { |
326 | 10 | int sz = (c==0x19) ? 0 : (c == 0x18) ? 1 : 2; |
327 | 10 | if (sz && pos+1+sz <= entry.end()) |
328 | 10 | input->seek(sz, librevenge::RVNG_SEEK_CUR); |
329 | 10 | switch (c) { |
330 | 0 | case 0x19: |
331 | 0 | listener->insertField(MWAWField(MWAWField::Title)); |
332 | 0 | break; |
333 | 4 | case 0x18: |
334 | 4 | listener->insertField(MWAWField(MWAWField::PageNumber)); |
335 | 4 | break; |
336 | 3 | case 0x16: |
337 | 3 | listener->insertField(MWAWField(MWAWField::Time)); |
338 | 3 | break; |
339 | 0 | case 0x17: // id = 0 : short date ; id=9 : long date |
340 | 0 | listener->insertField(MWAWField(MWAWField::Date)); |
341 | 0 | break; |
342 | 3 | case 0x15: |
343 | 3 | MWAW_DEBUG_MSG(("MsWksSSParser::sendNote: find unknown field type 0x15\n")); |
344 | 3 | break; |
345 | 0 | default: |
346 | 0 | break; |
347 | 10 | } |
348 | 10 | } |
349 | 1.26k | else if (c <= 0x1f) { |
350 | 840 | MWAW_DEBUG_MSG(("MsWksSSParser::sendNote: find char=%x\n", static_cast<unsigned int>(c))); |
351 | 840 | } |
352 | 425 | else |
353 | 425 | listener->insertCharacter(static_cast<unsigned char>(c), input, entry.end()); |
354 | 1.27k | break; |
355 | 1.27k | } |
356 | | |
357 | 1.27k | } |
358 | 25 | } |
359 | | |
360 | | //////////////////////////////////////////////////////////// |
361 | | // create the document |
362 | | //////////////////////////////////////////////////////////// |
363 | | void MsWksSSParser::createDocument(librevenge::RVNGSpreadsheetInterface *documentInterface) |
364 | 265 | { |
365 | 265 | if (!documentInterface) return; |
366 | 265 | if (getSpreadsheetListener()) { |
367 | 0 | MWAW_DEBUG_MSG(("MsWksSSParser::createDocument: listener already exist\n")); |
368 | 0 | return; |
369 | 0 | } |
370 | | |
371 | 265 | std::vector<MWAWPageSpan> pageList; |
372 | 265 | m_state->m_actPage = 0; |
373 | 265 | m_document->getPageSpanList(pageList, m_state->m_numPages); |
374 | 265 | MWAWSpreadsheetListenerPtr listen(new MWAWSpreadsheetListener(*getParserState(), pageList, documentInterface)); |
375 | 265 | setSpreadsheetListener(listen); |
376 | 265 | listen->startDocument(); |
377 | | // time to send page information the graph parser and the text parser |
378 | 265 | m_document->getGraphParser()->setPageLeftTop |
379 | 265 | (MWAWVec2f(72.f *float(getPageSpan().getMarginLeft()), |
380 | 265 | 72.f *float(getPageSpan().getMarginTop())+m_document->getHeaderFooterHeight(true))); |
381 | 265 | } |
382 | | |
383 | | |
384 | | //////////////////////////////////////////////////////////// |
385 | | // |
386 | | // Intermediate level |
387 | | // |
388 | | //////////////////////////////////////////////////////////// |
389 | | bool MsWksSSParser::createZones() |
390 | 3.74k | { |
391 | 3.74k | if (getInput()->isStructured()) |
392 | 141 | m_document->createOLEZones(getInput()); |
393 | 3.74k | MWAWInputStreamPtr input = m_document->getInput(); |
394 | 3.74k | const int vers=version(); |
395 | 3.74k | long pos; |
396 | 3.74k | if (vers>2) { |
397 | 2.91k | pos = input->tell(); |
398 | 2.91k | if (!m_document->readDocumentInfo(0x9a)) |
399 | 1.11k | m_document->getInput()->seek(pos, librevenge::RVNG_SEEK_SET); |
400 | 2.91k | pos = input->tell(); |
401 | 2.91k | if (m_document->hasHeader() && !m_document->readGroupHeaderFooter(true,99)) |
402 | 637 | input->seek(pos, librevenge::RVNG_SEEK_SET); |
403 | 2.91k | pos = input->tell(); |
404 | 2.91k | if (m_document->hasFooter() && !m_document->readGroupHeaderFooter(false,99)) |
405 | 1.87k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
406 | 2.91k | } |
407 | 3.74k | readSSheetZone(); |
408 | | |
409 | 3.74k | auto &typeZoneMap=m_document->getTypeZoneMap(); |
410 | | // fixme: getNewZoneId here |
411 | 3.74k | int mainId=MsWksDocument::Z_MAIN; |
412 | 3.74k | typeZoneMap.insert(std::multimap<int, MsWksDocument::Zone>::value_type |
413 | 3.74k | (MsWksDocument::Z_MAIN,MsWksDocument::Zone(MsWksDocument::Z_MAIN, mainId))); |
414 | 3.74k | pos = input->tell(); |
415 | 3.74k | libmwaw::DebugFile &ascFile = m_document->ascii(); |
416 | 3.74k | if (input->isEnd() || input->readLong(2)!=0) |
417 | 2.26k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
418 | 1.48k | else { |
419 | 1.48k | MWAWEntry group; |
420 | 1.48k | group.setId(mainId); |
421 | 1.48k | group.setName("RBDR"); |
422 | 1.48k | if (!m_document->m_graphParser->readRB(input,group,1)) { |
423 | 1.30k | MWAW_DEBUG_MSG(("MsWksSSParser::createZones: can not read RBDR group\n")); |
424 | 1.30k | ascFile.addPos(pos+2); |
425 | 1.30k | ascFile.addNote("Entries(RBDR):###"); |
426 | 1.30k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
427 | 1.30k | } |
428 | 1.48k | } |
429 | | |
430 | | // normally, the file is now parsed, let check for potential remaining zones |
431 | 35.4k | while (!input->isEnd()) { |
432 | 35.2k | MWAW_DEBUG_MSG(("MsWksSSParser::createZones: find some unexpected data\n")); |
433 | 35.2k | pos = input->tell(); |
434 | 35.2k | MsWksDocument::Zone unknown; |
435 | 35.2k | if (!m_document->readZone(unknown) || input->tell() <= pos) { |
436 | 3.53k | ascFile.addPos(pos); |
437 | 3.53k | ascFile.addNote("Entries(End)"); |
438 | 3.53k | ascFile.addPos(pos+100); |
439 | 3.53k | ascFile.addNote("_"); |
440 | 3.53k | break; |
441 | 3.53k | } |
442 | 35.2k | } |
443 | | |
444 | | // ok, prepare the data |
445 | 3.74k | m_state->m_numPages = 1; |
446 | 3.74k | std::vector<int> linesH, pagesH; |
447 | 3.74k | m_document->getGraphParser()->computePositions(mainId, linesH, pagesH); |
448 | 3.74k | return true; |
449 | 3.74k | } |
450 | | |
451 | | //////////////////////////////////////////////////////////// |
452 | | // read a spreadsheet zone |
453 | | //////////////////////////////////////////////////////////// |
454 | | bool MsWksSSParser::readSSheetZone() |
455 | 3.74k | { |
456 | 3.74k | auto &sheet=m_state->m_spreadsheet; |
457 | 3.74k | sheet=MsWksSSParserInternal::Spreadsheet(); |
458 | 3.74k | int const vers=version(); |
459 | | |
460 | 3.74k | MWAWInputStreamPtr input=m_document->getInput(); |
461 | 3.74k | libmwaw::DebugFile &ascFile=m_document->ascii(); |
462 | 3.74k | long pos = input->tell(), sheetDebPos=pos; |
463 | 3.74k | if (!input->checkPosition(pos+0x30+0x30+0x408)) { |
464 | 2.85k | MWAW_DEBUG_MSG(("MsWksSSParser::readSSheetZone:Can not read part A/B\n")); |
465 | 2.85k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
466 | 2.85k | return false; |
467 | 2.85k | } |
468 | | |
469 | 883 | ascFile.addPos(pos); |
470 | 883 | libmwaw::DebugStream f, f2; |
471 | 883 | f << "Entries(SSheet): v0=["; // always 8, -1 ? |
472 | 2.64k | for (int i = 0; i < 2; i++) |
473 | 1.76k | f << input->readLong(1) << ","; |
474 | 883 | f << "],"; |
475 | | |
476 | 883 | int N[2]; // max col, max row |
477 | 1.76k | for (auto &n : N) n = static_cast<int>(input->readLong(2)); |
478 | 883 | f << "maxCol=" << N[0] << "," << "maxRow=" << N[1] << ","; |
479 | | |
480 | 883 | f << "unk0=" << std::hex << input->readULong(4) << std::dec << ","; // big number |
481 | | |
482 | 883 | int zoneSize[3]; |
483 | 883 | zoneSize[0] = static_cast<int>(input->readLong(2)); |
484 | 883 | if (zoneSize[0]) f << "zone[SheetF]=" << std::hex << zoneSize[0] << std::dec << ","; |
485 | 883 | auto numPageBreak = static_cast<int>(input->readLong(2)); |
486 | 883 | if (numPageBreak) f << "nPgBreak=" << numPageBreak << ","; |
487 | 883 | auto numColBreak = static_cast<int>(input->readLong(2)); |
488 | 883 | if (numColBreak) f << "nColBreak=" << numColBreak << ","; |
489 | 883 | zoneSize[1]= static_cast<int>(input->readLong(2)); |
490 | 883 | if (zoneSize[1]) f << "zone[DocInfo]=" << zoneSize[1] << ","; |
491 | 883 | f << "unk1=" << std::hex << input->readULong(4) << std::dec << ","; // big number |
492 | 883 | f << std::dec; |
493 | | |
494 | 883 | int val; |
495 | 2.64k | for (int i = 0; i < 2; i++) { |
496 | 1.76k | val = static_cast<int>(input->readLong(2)); |
497 | 1.76k | if (val) |
498 | 579 | f << "w" << i << "=" << val << ","; |
499 | 1.76k | } |
500 | 883 | f << "v2=["; // [_,_,_,_,_,_,] or [_,1,3,_,1,3,] or [_,5,5,_,4,2,] |
501 | 6.18k | for (int i = 0; i < 6; i++) { |
502 | 5.29k | val = static_cast<int>(input->readLong(1)); |
503 | 5.29k | if (val) |
504 | 2.10k | f << val << ","; |
505 | 3.19k | else |
506 | 3.19k | f << "_,"; |
507 | 5.29k | } |
508 | 883 | f << "]"; |
509 | 883 | f << ", v3=["; // [_,_,_,_,] or [_,_,_,1,] or [_,_,_,11,] |
510 | 4.41k | for (int i = 0; i < 4; i++) { |
511 | 3.53k | val = static_cast<int>(input->readLong(2)); |
512 | 3.53k | if (val) |
513 | 1.57k | f << val << ","; |
514 | 1.95k | else |
515 | 1.95k | f << "_,"; |
516 | 3.53k | } |
517 | 883 | f << "]"; |
518 | | |
519 | 883 | f << ", v4=[" << std::hex; |
520 | 4.41k | for (int i = 0; i < 4; i++) { |
521 | 3.53k | val = static_cast<int>(input->readLong(2)); |
522 | 3.53k | if (val) |
523 | 1.35k | f << val << ","; |
524 | 2.17k | else |
525 | 2.17k | f << "_,"; |
526 | 3.53k | } |
527 | 883 | f << "]" << std::dec; |
528 | | |
529 | 883 | ascFile.addNote(f.str().c_str()); |
530 | | |
531 | 883 | pos = input->tell(); |
532 | 883 | f.str(""); |
533 | 883 | ascFile.addPos(pos); |
534 | 883 | f << "SSheetB: "; |
535 | | |
536 | 883 | std::vector<int> colPos; |
537 | | |
538 | 883 | int prevW = -1; |
539 | 883 | bool ok = true; |
540 | 80.2k | for (int i = 0; i < 257; i++) { |
541 | 79.9k | auto col = static_cast<int>(input->readULong(2)); |
542 | 79.9k | if ((col & 0xFFF) != i+1) { |
543 | 575 | ok = false; |
544 | 575 | break; |
545 | 575 | } |
546 | 79.4k | auto w = static_cast<int>(input->readLong(2)); |
547 | 79.4k | if (w > 0) { |
548 | 79.3k | if (prevW > w && i < 200) { |
549 | 7 | ok = false; |
550 | 7 | break; |
551 | 7 | } |
552 | 79.2k | if (prevW > w) w = prevW; |
553 | 78.6k | else prevW = w; |
554 | 79.2k | } |
555 | 79.3k | colPos.push_back(w); |
556 | 79.3k | } |
557 | | |
558 | 883 | if (!ok) { |
559 | 582 | MWAW_DEBUG_MSG(("MsWksSSParser::readSSheetZone:Can not read part B\n")); |
560 | 582 | input->seek(pos, librevenge::RVNG_SEEK_SET); |
561 | 582 | return false; |
562 | 582 | } |
563 | | |
564 | 301 | f << "lastN=" << input->readULong(2); |
565 | 301 | f << ", lastV=" << input->readULong(2); |
566 | 301 | f << ", width=["; |
567 | 301 | std::vector<int> &colSize = sheet.m_widthCols; |
568 | 301 | colSize.resize(256); |
569 | 77.6k | for (size_t i = 0; i < 257; i++) { |
570 | 77.3k | int cPos = colPos[i]; |
571 | 77.3k | int lastPos = (i == 0) ? 0 : colPos[i-1]; |
572 | 77.3k | if (cPos == 0) f << "_"; |
573 | 77.3k | else if (cPos == -1) { |
574 | 1 | f << "Inf"; |
575 | 1 | cPos = 0; |
576 | 1 | } |
577 | 77.3k | else f << cPos-lastPos; |
578 | | |
579 | 77.3k | if (i< 256) { |
580 | 77.0k | if (cPos) colSize[i]=cPos-lastPos; |
581 | 7 | else colSize[i]=0; |
582 | 77.0k | } |
583 | | |
584 | 77.3k | f << ","; |
585 | 77.3k | } |
586 | 301 | f << "]" << std::dec; |
587 | 301 | ascFile.addNote(f.str().c_str()); |
588 | | |
589 | 301 | pos = input->tell(); |
590 | 301 | f.str(""); |
591 | 301 | ascFile.addPos(pos); |
592 | 301 | long endPos=pos+256; |
593 | 301 | f << "SSheetC:"; |
594 | 301 | int numCharts=0; |
595 | 435 | for (int i=0; i < 8; ++i) { |
596 | | // the chart names in v2, can we have more than 8 charts ? |
597 | 424 | long cPos=input->tell(); |
598 | 424 | val = static_cast<int>(input->readLong(2)); |
599 | 424 | auto sSz=static_cast<int>(input->readULong(1)); |
600 | 424 | if (!sSz || sSz>32-7) { |
601 | 290 | input->seek(cPos, librevenge::RVNG_SEEK_SET); |
602 | 290 | break; |
603 | 290 | } |
604 | 134 | ++numCharts; |
605 | 134 | f << "Chart" << i << "=["; |
606 | 134 | if (val) f << "unkn=" << val << ","; |
607 | 134 | std::string name(""); |
608 | 1.45k | for (int c=0; c<sSz; ++c) |
609 | 1.32k | name += char(input->readULong(1)); |
610 | 134 | f << name << ","; |
611 | 134 | if ((sSz%2)==0) input->seek(1, librevenge::RVNG_SEEK_CUR); |
612 | 134 | f << "id=" << std::hex << input->readULong(4) << std::dec << "],"; |
613 | 134 | input->seek(cPos+32, librevenge::RVNG_SEEK_SET); |
614 | 134 | } |
615 | 301 | int numRemains=int(endPos-input->tell())/2; |
616 | 36.6k | for (int i = 0; i < numRemains; i++) { |
617 | 36.3k | val = static_cast<int>(input->readLong(2)); |
618 | 36.3k | if (val) f << "f" << i << "=" << val << ","; |
619 | 36.3k | } |
620 | 301 | ascFile.addNote(f.str().c_str()); |
621 | 301 | input->seek(endPos, librevenge::RVNG_SEEK_SET); |
622 | | |
623 | 301 | pos = input->tell(); |
624 | 301 | f.str(""); |
625 | 301 | ascFile.addPos(pos); |
626 | | |
627 | 301 | if (!input->checkPosition(pos+52)) { |
628 | 1 | MWAW_DEBUG_MSG(("MsWksSSParser::readSSheetZone:Can not read part D\n")); |
629 | 1 | input->seek(pos, librevenge::RVNG_SEEK_SET); |
630 | 1 | return false; |
631 | 1 | } |
632 | | |
633 | 300 | f << "SSheetD:"; |
634 | 1.80k | for (int i = 0; i < 5; i++) { |
635 | 1.50k | val = static_cast<int>(input->readLong(2)); |
636 | 1.50k | if (i==3) { |
637 | 300 | if (val==44) continue; |
638 | 27 | f << "unkn=" << val << ","; |
639 | 27 | } |
640 | 1.20k | else if (val) |
641 | 290 | f << "f" << i << "=" << val << ","; |
642 | 1.50k | } |
643 | 300 | f << "dim?=["; // in general 1,1,1,1 but can be X,X,1,1 |
644 | 1.50k | for (int i = 0; i < 4; i++) |
645 | 1.20k | f << input->readLong(2) << ","; |
646 | 300 | f << "]"; |
647 | | |
648 | | // always g0=3ffe, g1=100 ? |
649 | 900 | for (int i = 0; i < 2; i++) { |
650 | 600 | f << ", g" << i << "=" << std::hex << input->readLong(2) << std::dec; |
651 | 600 | } |
652 | 300 | auto fId = static_cast<int>(input->readLong(2)); |
653 | 300 | auto fSize = static_cast<int>(input->readLong(2)); |
654 | 300 | sheet.m_font = MWAWFont(fId, float(fSize)); |
655 | 300 | f << ", [" << sheet.m_font.getDebugString(getParserState()->m_fontConverter) << "]"; |
656 | | // , [0,{33|255},] ? |
657 | 300 | f << ", unk=[" << std::dec; |
658 | 900 | for (int i = 0; i < 2; i++) |
659 | 600 | f << input->readLong(2) << ","; |
660 | 300 | f << "]"; |
661 | 300 | int numRemain=int(sheetDebPos+m_document->getLengthOfFileHeader3()-input->tell())/2; |
662 | 5.53k | for (int i = 0; i < numRemain; i++) { |
663 | 5.23k | val = static_cast<int>(input->readLong(2)); |
664 | 5.23k | if (val) f << "f" << i << "=" << val << ","; |
665 | 5.23k | } |
666 | 300 | ascFile.addNote(f.str().c_str()); |
667 | 300 | input->seek(sheetDebPos+m_document->getLengthOfFileHeader3(), librevenge::RVNG_SEEK_SET); |
668 | | |
669 | | // part E |
670 | 300 | MWAWVec2i cellPos(0,0); |
671 | 1.49k | while (1) { |
672 | 1.49k | if (cellPos[1] == N[1]) break; |
673 | | |
674 | 1.44k | long posRow = input->tell(); |
675 | 1.44k | unsigned long length = input->readULong(4); |
676 | 1.44k | if (length & 0xF0000000L) { |
677 | 371 | int nRow = length & 0x0FFFFFFFL; |
678 | 371 | if ((length >> 28) != 8 || std::numeric_limits<int>::max() - cellPos[1] < nRow) { |
679 | 27 | input->seek(posRow, librevenge::RVNG_SEEK_SET); |
680 | 27 | break; |
681 | 27 | } |
682 | 344 | f.str(""); |
683 | 344 | f << "SSheetE:skipRow=" << std::hex << nRow; |
684 | 344 | cellPos[1]+=nRow; |
685 | 344 | ascFile.addPos(posRow); |
686 | 344 | ascFile.addNote(f.str().c_str()); |
687 | 344 | continue; |
688 | 371 | } |
689 | 1.07k | long endRow = posRow+long(length)+4; |
690 | | |
691 | 1.07k | if (!input->checkPosition(endRow)) { |
692 | 30 | MWAW_DEBUG_MSG(("MsWksSSParser::readSSheetZone:Can not read part E(row)\n")); |
693 | 30 | input->seek(posRow, librevenge::RVNG_SEEK_SET); |
694 | 30 | return false; |
695 | 30 | } |
696 | | |
697 | 1.04k | f.str(""); |
698 | 1.04k | cellPos[0]=0; |
699 | 1.04k | f << "SSheetE(Row" << std::dec << cellPos[1]+1 << "): "; |
700 | 12.6k | while (input->tell() < endRow-1) { |
701 | 11.6k | pos = input->tell(); |
702 | 11.6k | auto sz = static_cast<int>(input->readULong(1)); |
703 | | |
704 | 11.6k | if (sz == 0xFE) { // skip next cell |
705 | 228 | auto numC = static_cast<int>(input->readULong(1)); |
706 | 228 | f2.str(""); |
707 | 228 | f2 << "SSheetE:skipC=" << numC; |
708 | 228 | cellPos[0]+=numC; |
709 | 228 | ascFile.addPos(pos); |
710 | 228 | ascFile.addNote(f2.str().c_str()); |
711 | 228 | continue; |
712 | 228 | } |
713 | | |
714 | 11.4k | if (sz == 0) { |
715 | 7.13k | ascFile.addPos(pos); |
716 | 7.13k | ascFile.addNote("SSheetE:empty"); |
717 | 7.13k | ++cellPos[0]; |
718 | 7.13k | continue; |
719 | 7.13k | } |
720 | 4.31k | MsWksSSParserInternal::Cell cell; |
721 | 4.31k | if (!readCell(sz, cellPos, cell)) { |
722 | 35 | input->seek(pos, librevenge::RVNG_SEEK_SET); |
723 | 35 | break; |
724 | 35 | } |
725 | 4.27k | if (!cell.isEmpty()) |
726 | 4.23k | sheet.m_cells.push_back(cell); |
727 | 4.27k | ++cellPos[0]; |
728 | 4.27k | } |
729 | | |
730 | 1.04k | ++cellPos[1]; |
731 | 1.04k | if (input->tell() != endRow-1) { |
732 | 173 | MWAW_DEBUG_MSG(("MsWksSSParser::readSSheetZone:Can not read part E(cells)\n")); |
733 | 173 | input->seek(posRow, librevenge::RVNG_SEEK_SET); |
734 | 173 | return false; |
735 | 173 | } |
736 | 872 | ascFile.addDelimiter(endRow-1,'|'); |
737 | 872 | val = static_cast<int>(input->readULong(1)); |
738 | 872 | if (val == 0) f << "*"; |
739 | 850 | else if (val != 0xFF) |
740 | 19 | f << "##end=" << std::hex << val << std::dec; |
741 | | |
742 | 872 | ascFile.addPos(posRow); |
743 | 872 | ascFile.addNote(f.str().c_str()); |
744 | 872 | if (val == 0) |
745 | 22 | break; |
746 | 872 | } |
747 | | |
748 | 97 | pos = input->tell(); |
749 | 97 | if (!input->checkPosition(pos+zoneSize[0])) { |
750 | 3 | input->seek(pos, librevenge::RVNG_SEEK_SET); |
751 | 3 | MWAW_DEBUG_MSG(("MsWksSSParser::readSSheetZone:Can not read part F\n")); |
752 | 3 | return false; |
753 | 3 | } |
754 | | |
755 | 94 | f.str(""); |
756 | 94 | f << "SSheetF[A]:"; |
757 | 94 | ascFile.addPos(pos); |
758 | 94 | ascFile.addNote(f.str().c_str()); |
759 | 94 | input->seek(pos+zoneSize[0]-10, librevenge::RVNG_SEEK_SET); |
760 | | |
761 | 94 | pos = input->tell(); |
762 | 94 | f.str(""); |
763 | 94 | f << "SSheetF[B]:" << std::dec; |
764 | 470 | for (int i = 0; i < 4; i++) { |
765 | 376 | val = static_cast<int>(input->readLong(2)); |
766 | 376 | if (val) f << "f" << i << "=" << val << ","; |
767 | 376 | } |
768 | 94 | val = static_cast<int>(input->readULong(2)); |
769 | 94 | if (val) f << std::hex << "fl=" << val << "," << std::dec; |
770 | 94 | ascFile.addPos(pos); |
771 | 94 | ascFile.addNote(f.str().c_str()); |
772 | | |
773 | 94 | if (numPageBreak || numColBreak) { |
774 | 16 | pos=input->tell(); |
775 | 16 | f.str(""); |
776 | 16 | f << "SSheetG:"; |
777 | 16 | if (numPageBreak > 0) { |
778 | 11 | sheet.m_listPageBreaks.resize(size_t(numPageBreak)); |
779 | 11 | f << "pgBreak=["; |
780 | 88.4k | for (auto &pgBreak : sheet.m_listPageBreaks) { |
781 | 88.4k | pgBreak = static_cast<int>(input->readULong(2)); |
782 | 88.4k | f << pgBreak << ","; |
783 | 88.4k | } |
784 | 11 | f << "],"; |
785 | 11 | } |
786 | | // columns/notes break? |
787 | 16 | if (numColBreak) { |
788 | 14 | f << "colBreak=["; |
789 | 97.9k | for (int i = 0; i < numColBreak; i++) |
790 | 97.9k | f << input->readULong(2) << ","; |
791 | 14 | f << "],"; |
792 | 14 | } |
793 | 16 | ascFile.addPos(pos); |
794 | 16 | ascFile.addNote(f.str().c_str()); |
795 | 16 | } |
796 | | |
797 | 94 | if (zoneSize[1]>0) { |
798 | | // only version<=2 seems to contains the print data with size 0x15e |
799 | 9 | pos = input->tell(); |
800 | 9 | MWAWEntry zone; |
801 | 9 | if (!m_document->readDocumentInfo(zoneSize[1])) { |
802 | 9 | input->seek(pos+zoneSize[1], librevenge::RVNG_SEEK_SET); |
803 | 9 | MWAW_DEBUG_MSG(("MsWksSSParser::readSSheetZone:can not read print info\n")); |
804 | 9 | ascii().addPos(pos); |
805 | 9 | ascii().addNote("SSheet[printInfo]:###"); |
806 | 9 | } |
807 | 9 | } |
808 | | |
809 | 94 | if (vers==2) { |
810 | 31 | for (int i=0; i < numCharts; ++i) { |
811 | 4 | pos=input->tell(); |
812 | 4 | if (!input->checkPosition(pos+256)) { |
813 | 1 | MWAW_DEBUG_MSG(("MsWksSSParser::readSSheetZone:can not find chart %d data\n", i)); |
814 | 1 | input->seek(pos, librevenge::RVNG_SEEK_SET); |
815 | 1 | return false; |
816 | 1 | } |
817 | 3 | f.str(""); |
818 | 3 | f << "Entries(Chart)[" << i << "]:"; |
819 | 3 | ascFile.addPos(pos); |
820 | 3 | ascFile.addNote(f.str().c_str()); |
821 | 3 | input->seek(pos+256, librevenge::RVNG_SEEK_SET); |
822 | 3 | } |
823 | 28 | } |
824 | | |
825 | 93 | long HDebPos = input->tell(); |
826 | 93 | f.str(""); |
827 | 93 | f << "SSheetH:" << std::dec; |
828 | 93 | int numNote = 0; |
829 | 119 | while (1) { |
830 | 119 | pos = input->tell(); |
831 | 119 | auto idNote = static_cast<int>(input->readLong(2)); |
832 | 119 | if (idNote == 0) break; |
833 | 65 | if (idNote != ++numNote) { |
834 | 35 | input->seek(pos, librevenge::RVNG_SEEK_CUR); |
835 | 35 | MWAW_DEBUG_MSG(("MsWksSSParser::readSSheetZone:Pb when reading a note\n")); |
836 | 35 | return false; |
837 | 35 | } |
838 | | // a pascal string |
839 | 30 | auto pSz = static_cast<int>(input->readLong(2)); |
840 | 30 | MWAWEntry note; |
841 | 30 | note.setBegin(input->tell()); |
842 | 30 | note.setLength(pSz); |
843 | 30 | std::string str=""; |
844 | 15.3k | for (int s = 0; s < pSz; s++) |
845 | 15.3k | str += char(input->readLong(1)); |
846 | 30 | if (input->tell() != pos+4+pSz) { |
847 | 4 | input->seek(pos, librevenge::RVNG_SEEK_CUR); |
848 | 4 | MWAW_DEBUG_MSG(("MsWksSSParser::readSSheetZone:Pb when reading a note\n")); |
849 | 4 | return false; |
850 | 4 | } |
851 | 26 | if (pSz) { |
852 | 25 | sheet.m_idNoteMap[idNote] = note; |
853 | 25 | f << "Note" << idNote << "=\"" << str << "\","; |
854 | 25 | } |
855 | 26 | } |
856 | | |
857 | 54 | ascFile.addPos(HDebPos); |
858 | 54 | ascFile.addNote(f.str().c_str()); |
859 | 54 | return true; |
860 | 93 | } |
861 | | |
862 | | bool MsWksSSParser::readCell(int sz, MWAWVec2i const &cellPos, MsWksSSParserInternal::Cell &cell) |
863 | 4.31k | { |
864 | 4.31k | int const vers=version(); |
865 | 4.31k | cell = MsWksSSParserInternal::Cell(); |
866 | 4.31k | cell.setPosition(cellPos); |
867 | 4.31k | if (sz == 0xFF || sz < 5) return false; |
868 | | |
869 | 4.28k | MWAWInputStreamPtr input=m_document->getInput(); |
870 | 4.28k | long debPos = input->tell(); |
871 | | |
872 | 4.28k | libmwaw::DebugFile &ascFile=m_document->ascii(); |
873 | 4.28k | libmwaw::DebugStream f; |
874 | 4.28k | long endPos = debPos+sz-5; |
875 | 4.28k | input->seek(endPos+5, librevenge::RVNG_SEEK_SET); |
876 | 4.28k | if (input->tell() !=endPos+5) return false; |
877 | | |
878 | | // read the flag |
879 | 4.27k | input->seek(endPos, librevenge::RVNG_SEEK_SET); |
880 | 4.27k | int fl[5]; |
881 | 21.3k | for (auto &flag : fl) flag = static_cast<int>(input->readULong(1)); |
882 | 4.27k | MWAWCell::Format format; |
883 | 4.27k | MWAWCellContent &content=cell.m_content; |
884 | 4.27k | int style = 0, align = 0, subformat = 0; |
885 | 4.27k | if (vers >= 3) { |
886 | 3.20k | style = (fl[4]>>1) & 0x1f; |
887 | 3.20k | align = (fl[4]>>6); |
888 | 3.20k | fl[4] &= 1; |
889 | 3.20k | subformat = fl[2] >> 4; |
890 | 3.20k | cell.setBorders(fl[2] & 0xF, MWAWBorder()); // checkme |
891 | 3.20k | fl[2] = 0; |
892 | 3.20k | } |
893 | 1.07k | else { |
894 | 1.07k | style = fl[4] & 0x18; |
895 | 1.07k | align = (fl[4]>>5)&3; |
896 | 1.07k | subformat= (fl[4]&7); |
897 | 1.07k | fl[4] &= 0x80; |
898 | 1.07k | } |
899 | 4.27k | switch (align) { |
900 | 1.22k | case 0: |
901 | 1.22k | cell.setHAlignment(MWAWCell::HALIGN_LEFT); |
902 | 1.22k | break; |
903 | 340 | case 1: |
904 | 340 | cell.setHAlignment(MWAWCell::HALIGN_CENTER); |
905 | 340 | break; |
906 | 287 | case 2: |
907 | 287 | cell.setHAlignment(MWAWCell::HALIGN_RIGHT); |
908 | 287 | break; |
909 | 0 | default: |
910 | 2.42k | case 3: |
911 | 2.42k | break; // default |
912 | 4.27k | } |
913 | 4.27k | cell.m_noteId = fl[1] & 0xf; |
914 | 4.27k | fl[1] >>= 4; |
915 | 4.27k | int type = fl[3] >> 4; |
916 | 4.27k | format.m_digits=(fl[3] & 0xf); |
917 | 4.27k | fl[3] &= 1; |
918 | | |
919 | 4.27k | MWAWFont font=m_state->m_spreadsheet.m_font; |
920 | 4.27k | MWAWColor col; |
921 | 4.27k | if (vers>=3&&m_document->getColor(fl[0],col,3)) { |
922 | 3.20k | font.setColor(col); |
923 | 3.20k | fl[0]=0; |
924 | 3.20k | } |
925 | 4.27k | uint32_t fflags = 0; |
926 | 4.27k | if (style) { |
927 | 1.87k | if (style & 1) fflags |= MWAWFont::shadowBit; |
928 | 1.87k | if (style & 2) fflags |= MWAWFont::embossBit; |
929 | 1.87k | if (style & 4) fflags |= MWAWFont::italicBit; |
930 | 1.87k | if (style & 8) font.setUnderlineStyle(MWAWFont::Line::Simple); |
931 | 1.87k | if (style & 16) fflags |= MWAWFont::boldBit; |
932 | 1.87k | } |
933 | 4.27k | font.setFlags(fflags); |
934 | 4.27k | cell.setFont(font); |
935 | | |
936 | 4.27k | content.m_contentType=MWAWCellContent::C_NONE; |
937 | 4.27k | if (type & 2) { // checkme: is this also ok for v2? |
938 | 663 | cell.setProtected(true); |
939 | 663 | type &= 0xFD; |
940 | 663 | } |
941 | 4.27k | switch (type>>2) { |
942 | 2.38k | case 0: |
943 | 2.38k | content.m_contentType=MWAWCellContent::C_TEXT; |
944 | 2.38k | format.m_format=MWAWCell::F_TEXT; |
945 | 2.38k | break; |
946 | 1.35k | case 1: |
947 | 1.35k | format.m_format=MWAWCell::F_NUMBER; |
948 | 1.35k | content.m_contentType=MWAWCellContent::C_NUMBER; |
949 | 1.35k | break; |
950 | 211 | case 3: |
951 | 211 | f << "type" << type << ","; |
952 | 211 | MWAW_FALLTHROUGH; |
953 | 544 | case 2: //number general |
954 | 544 | format.m_format=MWAWCell::F_NUMBER; |
955 | 544 | content.m_contentType=MWAWCellContent::C_FORMULA; |
956 | 544 | break; |
957 | 0 | default: |
958 | 0 | break; |
959 | 4.27k | } |
960 | 4.27k | if (vers <= 2 && format.m_format==MWAWCell::F_NUMBER) { |
961 | 409 | switch (subformat) { |
962 | 146 | case 0: |
963 | 146 | format.m_numberFormat=MWAWCell::F_NUMBER_DECIMAL; |
964 | 146 | break; |
965 | 28 | case 1: |
966 | 28 | format.m_numberFormat=MWAWCell::F_NUMBER_CURRENCY; |
967 | 28 | break; |
968 | 19 | case 2: |
969 | 19 | format.m_numberFormat=MWAWCell::F_NUMBER_PERCENT; |
970 | 19 | break; |
971 | 77 | case 4: |
972 | 77 | format.m_numberFormat=MWAWCell::F_NUMBER_SCIENTIFIC; |
973 | 77 | break; |
974 | 15 | case 5: |
975 | 67 | case 6: |
976 | 67 | format.m_format=MWAWCell::F_DATE; |
977 | 67 | break; |
978 | 28 | case 7: |
979 | 28 | format.m_format=MWAWCell::F_TIME; |
980 | 28 | break; |
981 | 44 | case 3: // generic |
982 | 44 | default: |
983 | 44 | format.m_numberFormat=MWAWCell::F_NUMBER_GENERIC; |
984 | 44 | break; |
985 | 409 | } |
986 | 409 | } |
987 | 3.86k | else if (vers>2) { |
988 | 3.20k | if (type&1) { |
989 | 492 | format.m_format= (subformat < 4) ? MWAWCell::F_TIME : MWAWCell::F_DATE; |
990 | 492 | fl[3] = 0; |
991 | 492 | } |
992 | 3.20k | switch (format.m_format) { |
993 | 1.20k | case MWAWCell::F_NUMBER: |
994 | 1.20k | format.m_numberFormat=MWAWCell::F_NUMBER_GENERIC; |
995 | 1.20k | switch (subformat) { |
996 | 674 | case 0: |
997 | 674 | break; |
998 | 109 | case 1: |
999 | 109 | format.m_numberFormat=MWAWCell::F_NUMBER_DECIMAL; |
1000 | 109 | break; |
1001 | 78 | case 2: |
1002 | 78 | format.m_numberFormat=MWAWCell::F_NUMBER_CURRENCY; |
1003 | 78 | break; |
1004 | 57 | case 3: |
1005 | 57 | format.m_thousandHasSeparator=true; |
1006 | 57 | break; |
1007 | 22 | case 4: |
1008 | 22 | format.m_numberFormat=MWAWCell::F_NUMBER_CURRENCY; |
1009 | 22 | format.m_thousandHasSeparator=true; |
1010 | 22 | break; |
1011 | 70 | case 5: |
1012 | 70 | format.m_numberFormat=MWAWCell::F_NUMBER_SCIENTIFIC; |
1013 | 70 | break; |
1014 | 76 | case 6: |
1015 | 76 | format.m_numberFormat=MWAWCell::F_NUMBER_PERCENT; |
1016 | 76 | break; |
1017 | 5 | case 7: |
1018 | 5 | format.m_numberFormat=MWAWCell::F_NUMBER_PERCENT; |
1019 | 5 | format.m_thousandHasSeparator=true; |
1020 | 5 | break; |
1021 | 115 | default: |
1022 | 115 | f << ",subform==##unkn" << subformat; |
1023 | 115 | break; |
1024 | 1.20k | } |
1025 | 1.20k | break; |
1026 | 1.20k | case MWAWCell::F_TIME: |
1027 | 251 | if (subformat >= 0 && subformat < 4) { |
1028 | 251 | static char const* const wh[]= {"%I:%M:%S %p", "%I:%M %p", "%H:%M:%S", "%H:%M"}; |
1029 | 251 | format.m_DTFormat=wh[subformat]; |
1030 | 251 | } |
1031 | 0 | else |
1032 | 0 | f << ",subform==##unkn" << subformat; |
1033 | 251 | break; |
1034 | 241 | case MWAWCell::F_DATE: |
1035 | 241 | switch (subformat) { |
1036 | 49 | case 4: |
1037 | 58 | case 5: |
1038 | 78 | case 6: |
1039 | 111 | case 7: |
1040 | 116 | case 8: { |
1041 | 116 | static char const* const wh[]= {"%m/%d/%y", "%b %d, %Y", "%b, %d", "%b, %Y", "%a, %d %b, %Y" }; |
1042 | 116 | format.m_DTFormat=wh[subformat-4]; |
1043 | 116 | break; |
1044 | 111 | } |
1045 | 6 | case 10: |
1046 | 11 | case 11: |
1047 | 11 | format.m_DTFormat="%B %d %Y"; |
1048 | 11 | break; |
1049 | 22 | case 12: |
1050 | 54 | case 13: |
1051 | 54 | format.m_DTFormat="%A, %B %d, %Y"; |
1052 | 54 | break; |
1053 | 60 | default: |
1054 | 60 | f << ",subform==##unkn" << subformat; |
1055 | 60 | break; |
1056 | 241 | } |
1057 | 241 | break; |
1058 | 1.50k | case MWAWCell::F_TEXT: |
1059 | 1.50k | break; |
1060 | 0 | case MWAWCell::F_BOOLEAN: |
1061 | 0 | case MWAWCell::F_UNKNOWN: |
1062 | 0 | MWAW_DEBUG_MSG(("MsWksSSParser::readCell: unexpected format\n")); |
1063 | 0 | break; |
1064 | | #if !defined(__clang__) |
1065 | | default: |
1066 | | f << ",subform==##unkn" << subformat; |
1067 | | break; |
1068 | | #endif |
1069 | 3.20k | } |
1070 | 3.20k | } |
1071 | 4.27k | long pos = debPos; |
1072 | 4.27k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
1073 | | |
1074 | 4.27k | if (pos != endPos) { |
1075 | 4.13k | bool ok = true; |
1076 | 4.13k | switch (content.m_contentType) { |
1077 | 2.24k | case MWAWCellContent::C_TEXT: { |
1078 | 2.24k | content.m_textEntry.setBegin(pos); |
1079 | 2.24k | content.m_textEntry.setEnd(endPos); |
1080 | 2.24k | if (content.m_textEntry.length()>=0) { |
1081 | 2.24k | std::string text(""); |
1082 | 56.4k | for (long i=0; i <content.m_textEntry.length(); ++i) |
1083 | 54.2k | text += char(input->readULong(1)); |
1084 | 2.24k | f << text << ","; |
1085 | 2.24k | } |
1086 | 0 | else |
1087 | 0 | f << "###text,"; |
1088 | 2.24k | break; |
1089 | 0 | } |
1090 | 1.34k | case MWAWCellContent::C_NUMBER: { |
1091 | 1.34k | double val; |
1092 | 1.34k | bool isNan; |
1093 | 1.34k | std::string str; |
1094 | 1.34k | if (!m_document->readDBNumber(endPos, val, isNan, str)) { |
1095 | 230 | ok=false; |
1096 | 230 | f << "###number"; |
1097 | 230 | } |
1098 | 1.11k | else |
1099 | 1.11k | content.setValue(val); |
1100 | 1.34k | f << val; |
1101 | 1.34k | if (!str.empty()) f << "[" << str << "],"; |
1102 | 1.34k | break; |
1103 | 0 | } |
1104 | 544 | case MWAWCellContent::C_FORMULA: { |
1105 | 544 | std::string extra(""); |
1106 | 544 | if (!m_document->readFormula(endPos, content, extra)) { |
1107 | 278 | ok=false; |
1108 | 278 | f << "###"; |
1109 | 278 | } |
1110 | 544 | f << extra; |
1111 | 544 | break; |
1112 | 0 | } |
1113 | 0 | case MWAWCellContent::C_NONE: |
1114 | 0 | break; |
1115 | 0 | case MWAWCellContent::C_UNKNOWN: |
1116 | | #if !defined(__clang__) |
1117 | | default: |
1118 | | #endif |
1119 | 0 | ok = false; |
1120 | 4.13k | } |
1121 | 4.13k | if (!ok) |
1122 | 508 | f << ",###pb"; |
1123 | 4.13k | } |
1124 | 4.27k | cell.setFormat(format); |
1125 | | // change the reference date from 1/1/1904 to 1/1/1900 |
1126 | 4.27k | if (format.m_format==MWAWCell::F_DATE && content.isValueSet()) |
1127 | 116 | content.setValue(content.m_value+1460.); |
1128 | | |
1129 | 4.27k | std::string extra = f.str(); |
1130 | 4.27k | f.str(""); |
1131 | 4.27k | f << "SSheetE:" << cell << ",unk=[" << std::hex; |
1132 | 21.3k | for (auto flag : fl) { |
1133 | 21.3k | if (!flag) f << "_,"; |
1134 | 3.81k | else f << flag << ","; |
1135 | 21.3k | } |
1136 | 4.27k | f << "]" << std::dec; |
1137 | 4.27k | if (extra.size()) f << ", extra=" << extra; |
1138 | | |
1139 | | |
1140 | 4.27k | pos = input->tell(); |
1141 | 4.27k | if (pos != endPos) { |
1142 | 664 | ascFile.addDelimiter(pos,'['); |
1143 | 664 | ascFile.addDelimiter(endPos,']'); |
1144 | 664 | } |
1145 | | |
1146 | 4.27k | ascFile.addPos(debPos-1); |
1147 | 4.27k | ascFile.addNote(f.str().c_str()); |
1148 | 4.27k | input->seek(endPos+5, librevenge::RVNG_SEEK_SET); |
1149 | 4.27k | return true; |
1150 | 4.27k | } |
1151 | | |
1152 | | //////////////////////////////////////////////////////////// |
1153 | | //////////////////////////////////////////////////////////// |
1154 | | bool MsWksSSParser::sendSpreadsheet() |
1155 | 265 | { |
1156 | 265 | MWAWSpreadsheetListenerPtr listener=getSpreadsheetListener(); |
1157 | 265 | MWAWInputStreamPtr &input= m_document->getInput(); |
1158 | 265 | if (!listener) { |
1159 | 0 | MWAW_DEBUG_MSG(("MsWksSSParser::sendSpreadsheet: I can not find the listener\n")); |
1160 | 0 | return false; |
1161 | 0 | } |
1162 | 265 | auto &sheet = m_state->m_spreadsheet; |
1163 | | |
1164 | 265 | int prevRow = -1; |
1165 | 265 | listener->openSheet(sheet.convertInPoint(sheet.m_widthCols,76), librevenge::RVNG_POINT, std::vector<int>(), sheet.m_name); |
1166 | | // fixme: this sends the pictures present in the main page, but not the picture present in header/footer |
1167 | 265 | auto zone=m_document->getZone(MsWksDocument::Z_MAIN); |
1168 | 265 | m_document->getGraphParser()->sendAll(zone.m_zoneId, true); |
1169 | | |
1170 | 4.23k | for (auto const &cell : sheet.m_cells) { |
1171 | | // FIXME: find the row height... |
1172 | 4.23k | if (cell.position()[1]>prevRow+1) { |
1173 | 206 | if (prevRow != -1) listener->closeSheetRow(); |
1174 | 206 | int numRepeat=cell.position()[1]-1-prevRow; |
1175 | 206 | listener->openSheetRow(16, librevenge::RVNG_POINT, numRepeat); |
1176 | 206 | prevRow+=numRepeat; |
1177 | 206 | } |
1178 | 4.23k | if (cell.position()[1] > prevRow) { |
1179 | 1.03k | if (prevRow != -1) listener->closeSheetRow(); |
1180 | 1.03k | ++prevRow; |
1181 | 1.03k | listener->openSheetRow(16, librevenge::RVNG_POINT); |
1182 | 1.03k | } |
1183 | 4.23k | listener->openSheetCell(cell, cell.m_content); |
1184 | 4.23k | if (cell.m_content.m_textEntry.valid()) { |
1185 | 2.24k | listener->setFont(cell.isFontSet() ? cell.getFont() : sheet.m_font); |
1186 | 2.24k | input->seek(cell.m_content.m_textEntry.begin(), librevenge::RVNG_SEEK_SET); |
1187 | 56.4k | while (!input->isEnd() && input->tell()<cell.m_content.m_textEntry.end()) { |
1188 | 54.2k | auto c=static_cast<unsigned char>(input->readULong(1)); |
1189 | 54.2k | if (c==0xd) |
1190 | 1.68k | listener->insertEOL(); |
1191 | 52.5k | else |
1192 | 52.5k | listener->insertCharacter(c); |
1193 | 54.2k | } |
1194 | 2.24k | } |
1195 | 4.23k | if (cell.m_noteId>0) { |
1196 | 1.37k | MWAWSubDocumentPtr subDoc(new MsWksSSParserInternal::SubDocument(*this, input, cell.m_noteId)); |
1197 | 1.37k | listener->insertComment(subDoc); |
1198 | 1.37k | } |
1199 | 4.23k | listener->closeSheetCell(); |
1200 | 4.23k | } |
1201 | 265 | if (prevRow!=-1) listener->closeSheetRow(); |
1202 | 265 | listener->closeSheet(); |
1203 | 265 | return true; |
1204 | 265 | } |
1205 | | |
1206 | | //////////////////////////////////////////////////////////// |
1207 | | // |
1208 | | // Low level |
1209 | | // |
1210 | | //////////////////////////////////////////////////////////// |
1211 | | |
1212 | | //////////////////////////////////////////////////////////// |
1213 | | // read the header |
1214 | | //////////////////////////////////////////////////////////// |
1215 | | bool MsWksSSParser::checkHeader(MWAWHeader *header, bool strict) |
1216 | 17.2k | { |
1217 | 17.2k | *m_state = MsWksSSParserInternal::State(); |
1218 | 17.2k | if (!m_document || !m_document->checkHeader3(header, strict)) return false; |
1219 | 13.3k | if (m_document->getKind() != MWAWDocument::MWAW_K_SPREADSHEET) |
1220 | 12 | return false; |
1221 | 13.3k | #ifndef DEBUG |
1222 | 13.3k | if (version() == 1) |
1223 | 300 | return false; |
1224 | 13.0k | #endif |
1225 | 13.0k | return true; |
1226 | 13.3k | } |
1227 | | |
1228 | | // vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: |