/src/libmwaw/src/lib/ClarisWksSpreadsheet.cxx
Line | Count | Source |
1 | | /* -*- Mode: C++; c-default-style: "k&r"; indent-tabs-mode: nil; tab-width: 2; c-basic-offset: 2 -*- */ |
2 | | |
3 | | /* libmwaw |
4 | | * Version: MPL 2.0 / LGPLv2+ |
5 | | * |
6 | | * The contents of this file are subject to the Mozilla Public License Version |
7 | | * 2.0 (the "License"); you may not use this file except in compliance with |
8 | | * the License or as specified alternatively below. You may obtain a copy of |
9 | | * the License at http://www.mozilla.org/MPL/ |
10 | | * |
11 | | * Software distributed under the License is distributed on an "AS IS" basis, |
12 | | * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License |
13 | | * for the specific language governing rights and limitations under the |
14 | | * License. |
15 | | * |
16 | | * Major Contributor(s): |
17 | | * Copyright (C) 2002 William Lachance (wrlach@gmail.com) |
18 | | * Copyright (C) 2002,2004 Marc Maurer (uwog@uwog.net) |
19 | | * Copyright (C) 2004-2006 Fridrich Strba (fridrich.strba@bluewin.ch) |
20 | | * Copyright (C) 2006, 2007 Andrew Ziem |
21 | | * Copyright (C) 2011, 2012 Alonso Laurent (alonso@loria.fr) |
22 | | * |
23 | | * |
24 | | * All Rights Reserved. |
25 | | * |
26 | | * For minor contributions see the git repository. |
27 | | * |
28 | | * Alternatively, the contents of this file may be used under the terms of |
29 | | * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"), |
30 | | * in which case the provisions of the LGPLv2+ are applicable |
31 | | * instead of those above. |
32 | | */ |
33 | | |
34 | | #include <iomanip> |
35 | | #include <iostream> |
36 | | #include <limits> |
37 | | #include <map> |
38 | | #include <sstream> |
39 | | |
40 | | #include <librevenge/librevenge.h> |
41 | | |
42 | | #include "MWAWCell.hxx" |
43 | | #include "MWAWFont.hxx" |
44 | | #include "MWAWFontConverter.hxx" |
45 | | #include "MWAWListener.hxx" |
46 | | #include "MWAWParser.hxx" |
47 | | #include "MWAWSpreadsheetListener.hxx" |
48 | | #include "MWAWTable.hxx" |
49 | | |
50 | | #include "ClarisWksDbaseContent.hxx" |
51 | | #include "ClarisWksDocument.hxx" |
52 | | #include "ClarisWksStruct.hxx" |
53 | | #include "ClarisWksStyleManager.hxx" |
54 | | |
55 | | #include "ClarisWksSpreadsheet.hxx" |
56 | | |
57 | | /** Internal: the structures of a ClarisWksSpreadsheet */ |
58 | | namespace ClarisWksSpreadsheetInternal |
59 | | { |
60 | | //! Internal the spreadsheet |
61 | | struct Spreadsheet final : public ClarisWksStruct::DSET { |
62 | | // constructor |
63 | | explicit Spreadsheet(ClarisWksStruct::DSET const &dset = ClarisWksStruct::DSET()) : |
64 | 424k | ClarisWksStruct::DSET(dset), m_colWidths(), m_rowHeightMap(), m_content() |
65 | 424k | { |
66 | 424k | } |
67 | | //! destructor |
68 | | ~Spreadsheet() final; |
69 | | //! operator<< |
70 | | friend std::ostream &operator<<(std::ostream &o, Spreadsheet const &doc) |
71 | 0 | { |
72 | 0 | o << static_cast<ClarisWksStruct::DSET const &>(doc); |
73 | 0 | return o; |
74 | 0 | } |
75 | | //! returns the row size in point |
76 | | float getRowHeight(int row) const |
77 | 6.21M | { |
78 | 6.21M | if (m_rowHeightMap.find(row)!=m_rowHeightMap.end()) |
79 | 330k | return float(m_rowHeightMap.find(row)->second); |
80 | 5.88M | return 14; |
81 | 6.21M | } |
82 | | //! returns the height of a row in point and updated repeated row |
83 | | float getRowHeight(int row, int &numRepeated) const |
84 | 404k | { |
85 | 404k | int res=14; |
86 | 404k | if (m_rowHeightMap.empty()) { |
87 | 303k | numRepeated=1000; |
88 | 303k | return float(res); |
89 | 303k | } |
90 | 101k | auto it=m_rowHeightMap.lower_bound(row); |
91 | 101k | if (it==m_rowHeightMap.end()) { |
92 | 6.29k | numRepeated=1000; |
93 | 6.29k | return float(res); |
94 | 6.29k | } |
95 | 94.7k | numRepeated=1; |
96 | 94.7k | if (it->first==row) |
97 | 79.1k | res=it++->second; |
98 | 94.7k | int lastRow=row; |
99 | 126k | while (it!=m_rowHeightMap.end()) { |
100 | 126k | int nRow=it->first; |
101 | 126k | int nextH=it++->second; |
102 | | |
103 | 126k | if (nRow!=lastRow+1) { |
104 | 21.8k | if (res!=14) |
105 | 10.3k | break; |
106 | 11.4k | else |
107 | 11.4k | numRepeated+=(nRow-(lastRow+1)); |
108 | 21.8k | } |
109 | 116k | if (nRow==row) |
110 | 0 | continue; |
111 | 116k | numRepeated=(nRow-row); |
112 | 116k | if (nextH!=res) |
113 | 84.1k | break; |
114 | 31.9k | ++numRepeated; |
115 | 31.9k | lastRow=nRow; |
116 | 31.9k | } |
117 | 94.7k | return float(res); |
118 | 101k | } |
119 | | |
120 | | //! the columns width |
121 | | std::vector<int> m_colWidths; |
122 | | //! a map row to height |
123 | | std::map<int, int> m_rowHeightMap; |
124 | | //! the data |
125 | | std::shared_ptr<ClarisWksDbaseContent> m_content; |
126 | | }; |
127 | | |
128 | | Spreadsheet::~Spreadsheet() |
129 | 424k | { |
130 | 424k | } |
131 | | |
132 | | //! Internal: the state of a ClarisWksSpreadsheet |
133 | | struct State { |
134 | | //! constructor |
135 | | State() |
136 | 500k | : m_spreadsheetMap() |
137 | 500k | { |
138 | 500k | } |
139 | | //! a map zoneId to spreadsheet |
140 | | std::map<int, std::shared_ptr<Spreadsheet> > m_spreadsheetMap; |
141 | | }; |
142 | | |
143 | | } |
144 | | |
145 | | //////////////////////////////////////////////////////////// |
146 | | // constructor/destructor, ... |
147 | | //////////////////////////////////////////////////////////// |
148 | | ClarisWksSpreadsheet::ClarisWksSpreadsheet(ClarisWksDocument &document) |
149 | 500k | : m_document(document) |
150 | 500k | , m_parserState(document.m_parserState) |
151 | 500k | , m_state(new ClarisWksSpreadsheetInternal::State) |
152 | 500k | , m_mainParser(&document.getMainParser()) |
153 | 500k | { |
154 | 500k | } |
155 | | |
156 | | ClarisWksSpreadsheet::~ClarisWksSpreadsheet() |
157 | 500k | { } |
158 | | |
159 | | int ClarisWksSpreadsheet::version() const |
160 | 1.03M | { |
161 | 1.03M | return m_parserState->m_version; |
162 | 1.03M | } |
163 | | |
164 | | // fixme |
165 | | int ClarisWksSpreadsheet::numPages() const |
166 | 167k | { |
167 | 167k | return 1; |
168 | 167k | } |
169 | | //////////////////////////////////////////////////////////// |
170 | | // Intermediate level |
171 | | //////////////////////////////////////////////////////////// |
172 | | |
173 | | //////////////////////////////////////////////////////////// |
174 | | // a document part |
175 | | //////////////////////////////////////////////////////////// |
176 | | std::shared_ptr<ClarisWksStruct::DSET> ClarisWksSpreadsheet::readSpreadsheetZone |
177 | | (ClarisWksStruct::DSET const &zone, MWAWEntry const &entry, bool &complete) |
178 | 433k | { |
179 | 433k | complete = false; |
180 | 433k | if (!entry.valid() || zone.m_fileType != 2 || entry.length() < 256) |
181 | 8.81k | return std::shared_ptr<ClarisWksStruct::DSET>(); |
182 | 424k | long pos = entry.begin(); |
183 | 424k | MWAWInputStreamPtr &input= m_parserState->m_input; |
184 | 424k | input->seek(pos+8+16, librevenge::RVNG_SEEK_SET); // avoid header+8 generic number |
185 | 424k | libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile; |
186 | 424k | libmwaw::DebugStream f; |
187 | 424k | std::shared_ptr<ClarisWksSpreadsheetInternal::Spreadsheet> |
188 | 424k | sheet(new ClarisWksSpreadsheetInternal::Spreadsheet(zone)); |
189 | | |
190 | 424k | f << "Entries(SpreadsheetDef):" << *sheet << ","; |
191 | 424k | ascFile.addDelimiter(input->tell(), '|'); |
192 | 424k | ascFile.addPos(pos); |
193 | 424k | ascFile.addNote(f.str().c_str()); |
194 | | |
195 | | // read the last part |
196 | 424k | long data0Length = zone.m_dataSz; |
197 | 424k | long N = zone.m_numData; |
198 | 424k | if (entry.length() -8-12 != data0Length*N + zone.m_headerSz) { |
199 | 266k | if (data0Length == 0 && N) { |
200 | 5.47k | MWAW_DEBUG_MSG(("ClarisWksSpreadsheet::readSpreadsheetZone: can not find definition size\n")); |
201 | 5.47k | input->seek(entry.end(), librevenge::RVNG_SEEK_SET); |
202 | 5.47k | return std::shared_ptr<ClarisWksStruct::DSET>(); |
203 | 5.47k | } |
204 | | |
205 | 260k | MWAW_DEBUG_MSG(("ClarisWksSpreadsheet::readSpreadsheetZone: unexpected size for zone definition, try to continue\n")); |
206 | 260k | } |
207 | 418k | int debColSize = 0; |
208 | 418k | int vers = version(); |
209 | 418k | switch (vers) { |
210 | 111k | case 1: |
211 | 111k | debColSize = 72; |
212 | 111k | break; |
213 | 44.6k | case 2: |
214 | 96.1k | case 3: // checkme... |
215 | 141k | case 4: |
216 | 256k | case 5: |
217 | 256k | debColSize = 76; |
218 | 256k | break; |
219 | 50.6k | case 6: |
220 | 50.6k | debColSize = 72; |
221 | 50.6k | break; |
222 | 0 | default: |
223 | 0 | break; |
224 | 418k | } |
225 | | |
226 | 418k | sheet->m_colWidths.resize(0); |
227 | 418k | sheet->m_colWidths.resize(256,36); |
228 | 418k | if (debColSize) { |
229 | 418k | pos = entry.begin()+debColSize; |
230 | 418k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
231 | 418k | f.str(""); |
232 | 418k | f << "Entries(SpreadsheetCol):width,"; |
233 | 107M | for (size_t i = 0; i < 256; ++i) { |
234 | 107M | auto w=static_cast<int>(input->readULong(1)); |
235 | 107M | sheet->m_colWidths[i]=w; |
236 | 107M | if (w!=36) // default |
237 | 78.7M | f << "w" << i << "=" << w << ","; |
238 | 107M | } |
239 | 418k | ascFile.addPos(pos); |
240 | 418k | ascFile.addNote(f.str().c_str()); |
241 | | |
242 | 418k | ascFile.addPos(input->tell()); |
243 | 418k | ascFile.addNote("SpreadsheetDef-A"); |
244 | 418k | } |
245 | | |
246 | 418k | long dataEnd = entry.end()-N*data0Length; |
247 | 418k | int numLast = version()==6 ? 4 : 0; |
248 | 418k | if (long(input->tell()) + data0Length + numLast <= dataEnd) { |
249 | 188k | ascFile.addPos(dataEnd-data0Length-numLast); |
250 | 188k | ascFile.addNote("SpreadsheetDef-_"); |
251 | 188k | if (numLast) { |
252 | 31.1k | ascFile.addPos(dataEnd-numLast); |
253 | 31.1k | ascFile.addNote("SpreadsheetDef-extra"); |
254 | 31.1k | } |
255 | 188k | } |
256 | 418k | input->seek(dataEnd, librevenge::RVNG_SEEK_SET); |
257 | | |
258 | 1.38M | for (long i = 0; i < N; i++) { |
259 | 967k | pos = input->tell(); |
260 | | |
261 | 967k | f.str(""); |
262 | 967k | f << "SpreadsheetDef-" << i; |
263 | 967k | ascFile.addPos(pos); |
264 | 967k | ascFile.addNote(f.str().c_str()); |
265 | 967k | input->seek(pos+data0Length, librevenge::RVNG_SEEK_SET); |
266 | 967k | } |
267 | | |
268 | 418k | input->seek(entry.end(), librevenge::RVNG_SEEK_SET); |
269 | | |
270 | 418k | if (m_state->m_spreadsheetMap.find(sheet->m_id) != m_state->m_spreadsheetMap.end()) { |
271 | 352k | MWAW_DEBUG_MSG(("ClarisWksSpreadsheet::readSpreadsheetZone: zone %d already exists!!!\n", sheet->m_id)); |
272 | 352k | } |
273 | 66.6k | else |
274 | 66.6k | m_state->m_spreadsheetMap[sheet->m_id] = sheet; |
275 | | |
276 | 418k | sheet->m_otherChilds.push_back(sheet->m_id+1); |
277 | 418k | pos = input->tell(); |
278 | | |
279 | 418k | bool ok = readZone1(*sheet); |
280 | 418k | if (ok) { |
281 | 291k | pos = input->tell(); |
282 | 291k | ok = ClarisWksStruct::readStructZone(*m_parserState, "SpreadsheetZone2", false); |
283 | 291k | } |
284 | 418k | if (ok) { |
285 | 250k | pos = input->tell(); |
286 | 250k | std::shared_ptr<ClarisWksDbaseContent> content(new ClarisWksDbaseContent(m_document, true)); |
287 | 250k | ok = content->readContent(); |
288 | 250k | if (ok) sheet->m_content=content; |
289 | 250k | } |
290 | 418k | if (ok) { |
291 | 111k | pos = input->tell(); |
292 | 111k | if (!readRowHeightZone(*sheet)) { |
293 | 50.3k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
294 | 50.3k | ok = ClarisWksStruct::readStructZone(*m_parserState, "SpreadsheetRowHeight", false); |
295 | 50.3k | } |
296 | 111k | } |
297 | 418k | if (ok && vers <= 2) { // field with size 0xa in v2 |
298 | 22.6k | pos = input->tell(); |
299 | 22.6k | ok = ClarisWksStruct::readStructZone(*m_parserState, "SpreadsheetUnkn1", false); |
300 | 22.6k | } |
301 | | /* checkme: now a sequence of 5/6 lists: when filed the first two zones are a list of cell, |
302 | | while the last 2 lists contains only 4 numbers */ |
303 | 1.28M | while (ok) { |
304 | 909k | pos=input->tell(); |
305 | 909k | auto sz=long(input->readULong(4)); |
306 | 909k | if (!input->checkPosition(pos+4+sz)) { |
307 | 40.6k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
308 | 40.6k | break; |
309 | 40.6k | } |
310 | | // empty or list of 2*uint16_t ? |
311 | 869k | if (!sz) { |
312 | 848k | ascFile.addPos(pos); |
313 | 848k | ascFile.addNote("Entries(SpreadsheetListCell):_"); |
314 | 848k | continue; |
315 | 848k | } |
316 | 20.9k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
317 | 20.9k | std::vector<MWAWVec2i> res; |
318 | 20.9k | ok = m_document.readStructCellZone("SpreadsheetListCell", false, res); |
319 | 20.9k | if (ok) continue; |
320 | 17.5k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
321 | 17.5k | ok = ClarisWksStruct::readStructZone(*m_parserState, "SpreadsheetUnkn2", false); |
322 | 17.5k | if (ok) { |
323 | 4.26k | MWAW_DEBUG_MSG(("ClarisWksSpreadsheet::readSpreadsheetZone: find unexpected Unkn2 zone\n")); |
324 | 4.26k | } |
325 | 17.5k | } |
326 | 418k | if (ok) { |
327 | 40.6k | pos=input->tell(); |
328 | 40.6k | auto sz=long(input->readULong(4)); |
329 | 40.6k | if (input->checkPosition(pos+4+sz)) { |
330 | 0 | input->seek(pos+4+sz, librevenge::RVNG_SEEK_SET); |
331 | 0 | ascFile.addPos(pos); |
332 | 0 | MWAW_DEBUG_MSG(("ClarisWksSpreadsheet::readSpreadsheetZone: find some extra block\n")); |
333 | 0 | ascFile.addNote("Entries(SpreadsheetEnd):###"); |
334 | 0 | } |
335 | 40.6k | else |
336 | 40.6k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
337 | 40.6k | } |
338 | | |
339 | 418k | if (!ok) { |
340 | 378k | MWAW_DEBUG_MSG(("ClarisWksSpreadsheet::readSpreadsheetZone: find a bad block\n")); |
341 | 378k | ascFile.addPos(pos); |
342 | 378k | ascFile.addNote("Entries(SpreadsheetEnd):###"); |
343 | 378k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
344 | 378k | } |
345 | 418k | return sheet; |
346 | 418k | } |
347 | | |
348 | | //////////////////////////////////////////////////////////// |
349 | | // |
350 | | // Intermediate level |
351 | | // |
352 | | //////////////////////////////////////////////////////////// |
353 | | bool ClarisWksSpreadsheet::readZone1(ClarisWksSpreadsheetInternal::Spreadsheet &/*sheet*/) |
354 | 418k | { |
355 | 418k | MWAWInputStreamPtr &input= m_parserState->m_input; |
356 | 418k | long pos = input->tell(); |
357 | 418k | auto sz = long(input->readULong(4)); |
358 | 418k | long endPos = pos+4+sz; |
359 | 418k | input->seek(endPos, librevenge::RVNG_SEEK_SET); |
360 | 418k | if (long(input->tell()) != endPos) { |
361 | 107k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
362 | 107k | MWAW_DEBUG_MSG(("ClarisWksSpreadsheet::readZone1: spreadsheet\n")); |
363 | 107k | return false; |
364 | 107k | } |
365 | 311k | libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile; |
366 | 311k | if (sz == 0) { |
367 | 113k | ascFile.addPos(pos); |
368 | 113k | ascFile.addNote("Nop"); |
369 | 113k | return true; |
370 | 113k | } |
371 | 197k | int fSize = 0; |
372 | 197k | switch (version()) { |
373 | 18.0k | case 4: |
374 | 71.0k | case 5: |
375 | 71.0k | fSize = 4; |
376 | 71.0k | break; |
377 | 26.0k | case 6: |
378 | 26.0k | fSize = 6; |
379 | 26.0k | break; |
380 | 100k | default: |
381 | 100k | break; |
382 | 197k | } |
383 | 197k | if (!fSize) { |
384 | 100k | ascFile.addPos(pos); |
385 | 100k | ascFile.addNote("Entries(SpreadsheetZone1)"); |
386 | 100k | input->seek(endPos, librevenge::RVNG_SEEK_SET); |
387 | 100k | return true; |
388 | 100k | } |
389 | 97.1k | long numElts = sz/fSize; |
390 | 97.1k | if (numElts *fSize != sz) { |
391 | 19.8k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
392 | 19.8k | MWAW_DEBUG_MSG(("ClarisWksSpreadsheet::readZone1: unexpected size\n")); |
393 | 19.8k | return false; |
394 | 19.8k | } |
395 | | |
396 | 77.2k | ascFile.addPos(pos); |
397 | 77.2k | ascFile.addNote("Entries(SpreadsheetZone1)"); |
398 | | |
399 | 77.2k | libmwaw::DebugStream f; |
400 | 77.2k | input->seek(pos+4, librevenge::RVNG_SEEK_SET); |
401 | 1.49M | for (long i = 0; i < numElts; i++) { |
402 | 1.41M | pos = input->tell(); |
403 | | |
404 | 1.41M | f.str(""); |
405 | 1.41M | f << "SpreadsheetZone1-" << i << ":"; |
406 | 1.41M | f << "row?=" << input->readLong(2) << ","; |
407 | 1.41M | f << "col?=" << input->readLong(2) << ","; |
408 | 1.41M | if (fSize == 6) { |
409 | 266k | auto val = static_cast<int>(input->readLong(2)); |
410 | 266k | if (val != -1) |
411 | 229k | f << "#unkn=" << val << ","; |
412 | 266k | } |
413 | 1.41M | ascFile.addPos(pos); |
414 | 1.41M | ascFile.addNote(f.str().c_str()); |
415 | 1.41M | input->seek(pos+fSize, librevenge::RVNG_SEEK_SET); |
416 | 1.41M | } |
417 | 77.2k | return true; |
418 | 97.1k | } |
419 | | |
420 | | bool ClarisWksSpreadsheet::readRowHeightZone(ClarisWksSpreadsheetInternal::Spreadsheet &sheet) |
421 | 111k | { |
422 | 111k | MWAWInputStreamPtr &input= m_parserState->m_input; |
423 | 111k | long pos = input->tell(); |
424 | 111k | ClarisWksStruct::Struct header; |
425 | 111k | if (!header.readHeader(input,false)) { |
426 | 50.3k | MWAW_DEBUG_MSG(("ClarisWksSpreadsheet::readRowHeightZone: can not read the header\n")); |
427 | 50.3k | return false; |
428 | 50.3k | } |
429 | 61.0k | libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile; |
430 | 61.0k | libmwaw::DebugStream f; |
431 | 61.0k | if (header.m_size==0) { |
432 | 25.8k | ascFile.addPos(pos); |
433 | 25.8k | ascFile.addNote("Nop"); |
434 | 25.8k | return true; |
435 | 25.8k | } |
436 | 35.2k | long endPos=pos+4+header.m_size; |
437 | 35.2k | f << "Entries(SpreadsheetRowHeight):" << header; |
438 | 35.2k | if (header.m_dataSize!=4) { |
439 | 7.79k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
440 | 7.79k | MWAW_DEBUG_MSG(("ClarisWksSpreadsheet::readRowHeightZone: unexpected size for fieldSize\n")); |
441 | 7.79k | f << "###"; |
442 | 7.79k | ascFile.addPos(pos); |
443 | 7.79k | ascFile.addNote(f.str().c_str()); |
444 | 7.79k | input->seek(endPos, librevenge::RVNG_SEEK_SET); |
445 | 7.79k | return true; |
446 | 7.79k | } |
447 | 27.4k | if (header.m_headerSize) { |
448 | 15.1k | ascFile.addDelimiter(input->tell(),'|'); |
449 | 15.1k | input->seek(header.m_headerSize, librevenge::RVNG_SEEK_CUR); |
450 | 15.1k | } |
451 | 27.4k | ascFile.addPos(pos); |
452 | 27.4k | ascFile.addNote(f.str().c_str()); |
453 | | |
454 | 50.6M | for (long i = 0; i < header.m_numData; i++) { |
455 | 50.5M | pos = input->tell(); |
456 | | |
457 | 50.5M | f.str(""); |
458 | 50.5M | f << "SpreadsheetRowHeightZone-" << i << ":"; |
459 | 50.5M | auto row=static_cast<int>(input->readLong(2)); |
460 | 50.5M | auto h=static_cast<int>(input->readLong(2)); |
461 | 50.5M | sheet.m_rowHeightMap[row]=h; |
462 | 50.5M | f << "row=" << row << ", height=" << h << ","; |
463 | 50.5M | ascFile.addPos(pos); |
464 | 50.5M | ascFile.addNote(f.str().c_str()); |
465 | 50.5M | } |
466 | 27.4k | return true; |
467 | 35.2k | } |
468 | | |
469 | | //////////////////////////////////////////////////////////// |
470 | | // |
471 | | // send data |
472 | | // |
473 | | //////////////////////////////////////////////////////////// |
474 | | bool ClarisWksSpreadsheet::sendSpreadsheet(int zId, MWAWListenerPtr listener) |
475 | 281k | { |
476 | 281k | if (!listener) |
477 | 33.0k | listener=m_parserState->getMainListener(); |
478 | 281k | if (!listener) { |
479 | 0 | MWAW_DEBUG_MSG(("ClarisWksSpreadsheet::sendSpreadsheet: called without any listener\n")); |
480 | 0 | return false; |
481 | 0 | } |
482 | 281k | if (listener->getType()!=MWAWListener::Spreadsheet || |
483 | 219k | (m_parserState->m_kind==MWAWDocument::MWAW_K_SPREADSHEET && zId!=1)) |
484 | 61.9k | return sendSpreadsheetAsTable(zId, listener); |
485 | | |
486 | 219k | auto *sheetListener=static_cast<MWAWSpreadsheetListener *>(listener.get()); |
487 | 219k | auto it=m_state->m_spreadsheetMap.find(zId); |
488 | 219k | if (it == m_state->m_spreadsheetMap.end() || !it->second) { |
489 | 0 | MWAW_DEBUG_MSG(("ClarisWksSpreadsheet::sendSpreadsheet: can not find zone %d!!!\n", zId)); |
490 | 0 | return false; |
491 | 0 | } |
492 | 219k | auto &sheet=*it->second; |
493 | 219k | MWAWVec2i minData, maxData; |
494 | 219k | if (!sheet.m_content || !sheet.m_content->getExtrema(minData,maxData)) { |
495 | 97.7k | MWAW_DEBUG_MSG(("ClarisWksSpreadsheet::sendSpreadsheet: can not find content\n")); |
496 | 97.7k | return false; |
497 | 97.7k | } |
498 | 121k | if (m_parserState->m_kind==MWAWDocument::MWAW_K_SPREADSHEET && zId==1) |
499 | 477 | minData=MWAWVec2i(0,0); |
500 | 121k | std::vector<float> colSize(size_t(maxData[0]-minData[0]+1),72); |
501 | 560k | for (int c=minData[0], fC=0; c <= maxData[0]; ++c, ++fC) { |
502 | 439k | if (c>=0 && c < int(sheet.m_colWidths.size())) |
503 | 439k | colSize[size_t(fC)]=2.0f*float(sheet.m_colWidths[size_t(c)]); |
504 | 439k | } |
505 | 121k | sheetListener->openSheet(colSize, librevenge::RVNG_POINT); |
506 | 121k | MWAWInputStreamPtr &input= m_parserState->m_input; |
507 | 121k | std::vector<int> rowsPos, colsPos; |
508 | 121k | if (!sheet.m_content->getRecordList(rowsPos)) { |
509 | 0 | MWAW_DEBUG_MSG(("ClarisWksSpreadsheet::sendSpreadsheet: can not find the record position\n")); |
510 | 0 | sheetListener->closeSheet(); |
511 | 0 | return true; |
512 | 0 | } |
513 | 121k | bool recomputeCellPosition=(minData!=MWAWVec2i(0,0)); |
514 | 121k | int prevRow = minData[1]-1; |
515 | 6.21M | for (int r : rowsPos) { |
516 | 6.21M | int fR=r-minData[1]; |
517 | 6.21M | if (r>prevRow+1) { |
518 | 738k | while (r > prevRow+1) { |
519 | 404k | int numRepeat; |
520 | 404k | auto h=float(sheet.getRowHeight(prevRow+1, numRepeat)); |
521 | 404k | if (r<prevRow+1+numRepeat) |
522 | 317k | numRepeat=r-1-prevRow; |
523 | 404k | sheetListener->openSheetRow(h, librevenge::RVNG_POINT, numRepeat); |
524 | 404k | sheetListener->closeSheetRow(); |
525 | 404k | prevRow+=numRepeat; |
526 | 404k | } |
527 | 334k | } |
528 | 6.21M | sheetListener->openSheetRow(float(sheet.getRowHeight(r)), librevenge::RVNG_POINT); |
529 | 6.21M | prevRow=r; |
530 | 6.21M | colsPos.clear(); |
531 | 6.21M | if (!sheet.m_content->getColumnList(r, colsPos)) { |
532 | 0 | MWAW_DEBUG_MSG(("ClarisWksSpreadsheet::sendSpreadsheet: can not find the columns for row=%d\n", r)); |
533 | 0 | sheetListener->closeSheetRow(); |
534 | 0 | continue; |
535 | 0 | } |
536 | 9.36M | for (auto c : colsPos) { |
537 | 9.36M | ClarisWksDbaseContent::Record rec; |
538 | 9.36M | if (!sheet.m_content->get(MWAWVec2i(c,r),rec)) continue; |
539 | 9.36M | MWAWCell cell; |
540 | 9.36M | cell.setPosition(MWAWVec2i(c-minData[0],fR)); |
541 | 9.36M | cell.setFormat(rec.m_format); |
542 | 9.36M | cell.setHAlignment(rec.m_hAlign); |
543 | 9.36M | cell.setFont(rec.m_font); |
544 | 9.36M | if (recomputeCellPosition) |
545 | 312k | rec.updateFormulaCells(minData); |
546 | | // change the reference date from 1/1/1904 to 1/1/1900 |
547 | 9.36M | if (rec.m_format.m_format==MWAWCell::F_DATE && rec.m_content.isValueSet()) |
548 | 672k | rec.m_content.setValue(rec.m_content.m_value+1460); |
549 | 9.36M | if (rec.m_borders) { |
550 | 1.31M | int wh=0; |
551 | 6.58M | for (int b=0, bit=1; b < 4; ++b, bit*=2) { |
552 | 5.26M | if ((rec.m_borders&bit)==0) continue; |
553 | 2.92M | static int const what[] = {libmwaw::LeftBit, libmwaw::TopBit, libmwaw::RightBit, libmwaw::BottomBit}; |
554 | 2.92M | wh |= what[b]; |
555 | 2.92M | } |
556 | 1.31M | cell.setBorders(wh, MWAWBorder()); |
557 | 1.31M | } |
558 | 9.36M | if (!rec.m_backgroundColor.isWhite()) |
559 | 1.72k | cell.setBackgroundColor(rec.m_backgroundColor); |
560 | 9.36M | sheetListener->openSheetCell(cell, rec.m_content); |
561 | 9.36M | if (rec.m_content.m_textEntry.valid()) { |
562 | 283k | long fPos = input->tell(); |
563 | 283k | input->seek(rec.m_content.m_textEntry.begin(), librevenge::RVNG_SEEK_SET); |
564 | 283k | long endPos = rec.m_content.m_textEntry.end(); |
565 | 283k | sheetListener->setFont(rec.m_font); |
566 | 25.8M | while (!input->isEnd() && input->tell() < endPos) { |
567 | 25.5M | auto ch=static_cast<unsigned char>(input->readULong(1)); |
568 | 25.5M | if (ch==0xd || ch==0xa) |
569 | 371k | sheetListener->insertEOL(); |
570 | 25.1M | else |
571 | 25.1M | sheetListener->insertCharacter(ch, input, endPos); |
572 | 25.5M | } |
573 | 283k | input->seek(fPos,librevenge::RVNG_SEEK_SET); |
574 | 283k | } |
575 | 9.36M | sheetListener->closeSheetCell(); |
576 | 9.36M | } |
577 | 6.21M | sheetListener->closeSheetRow(); |
578 | 6.21M | } |
579 | 121k | sheetListener->closeSheet(); |
580 | 121k | return true; |
581 | 121k | } |
582 | | |
583 | | bool ClarisWksSpreadsheet::sendSpreadsheetAsTable(int zId, MWAWListenerPtr listener) |
584 | 61.9k | { |
585 | 61.9k | if (!listener) |
586 | 0 | listener=m_parserState->getMainListener(); |
587 | 61.9k | if (!listener) { |
588 | 0 | MWAW_DEBUG_MSG(("ClarisWksSpreadsheet::sendSpreadsheetAsTable: called without any listener\n")); |
589 | 0 | return false; |
590 | 0 | } |
591 | 61.9k | auto it=m_state->m_spreadsheetMap.find(zId); |
592 | 61.9k | if (it == m_state->m_spreadsheetMap.end() || !it->second) { |
593 | 0 | MWAW_DEBUG_MSG(("ClarisWksSpreadsheet::sendSpreadsheetAsTable: can not find zone %d!!!\n", zId)); |
594 | 0 | return false; |
595 | 0 | } |
596 | 61.9k | auto &sheet=*it->second; |
597 | 61.9k | MWAWVec2i minData, maxData; |
598 | 61.9k | if (!sheet.m_content || !sheet.m_content->getExtrema(minData,maxData)) { |
599 | 32.4k | MWAW_DEBUG_MSG(("ClarisWksSpreadsheet::sendSpreadsheetAsTable: can not find content\n")); |
600 | 32.4k | return false; |
601 | 32.4k | } |
602 | 29.5k | std::vector<float> colSize(size_t(maxData[0]-minData[0]+1),72); |
603 | 131k | for (int c=minData[0], fC=0; c <= maxData[0]; ++c, ++fC) { |
604 | 102k | if (c>=0 && c < int(sheet.m_colWidths.size())) |
605 | 102k | colSize[size_t(fC)]=2.0f*float(sheet.m_colWidths[size_t(c)]); |
606 | 102k | } |
607 | 29.5k | MWAWTable table(MWAWTable::TableDimBit); |
608 | 29.5k | table.setColsSize(colSize); |
609 | 29.5k | listener->openTable(table); |
610 | 1.69M | for (int r=minData[1], fR=0; r <= maxData[1]; ++r, ++fR) { |
611 | 1.66M | if (sheet.m_rowHeightMap.find(r)!=sheet.m_rowHeightMap.end()) |
612 | 99.5k | listener->openTableRow(float(sheet.m_rowHeightMap.find(r)->second), librevenge::RVNG_POINT); |
613 | 1.56M | else |
614 | 1.56M | listener->openTableRow(14.f, librevenge::RVNG_POINT); |
615 | 7.28M | for (int c=minData[0], fC=0; c <= maxData[0]; ++c, ++fC) { |
616 | 5.61M | MWAWCell cell; |
617 | 5.61M | cell.setPosition(MWAWVec2i(fC,fR)); |
618 | 5.61M | cell.setVAlignment(MWAWCell::VALIGN_BOTTOM); // always ? |
619 | 5.61M | listener->openTableCell(cell); |
620 | 5.61M | sheet.m_content->send(MWAWVec2i(c, r)); |
621 | 5.61M | listener->closeTableCell(); |
622 | 5.61M | } |
623 | 1.66M | listener->closeTableRow(); |
624 | 1.66M | } |
625 | 29.5k | listener->closeTable(); |
626 | 29.5k | return true; |
627 | 61.9k | } |
628 | | |
629 | | // vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: |