/src/libwps/src/lib/QuattroDosSpreadsheet.cpp
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ |
2 | | /* libwps |
3 | | * Version: MPL 2.0 / LGPLv2.1+ |
4 | | * |
5 | | * This Source Code Form is subject to the terms of the Mozilla Public |
6 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
7 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
8 | | * |
9 | | * Major Contributor(s): |
10 | | * Copyright (C) 2006, 2007 Andrew Ziem |
11 | | * Copyright (C) 2004 Marc Maurer (uwog@uwog.net) |
12 | | * Copyright (C) 2004-2006 Fridrich Strba (fridrich.strba@bluewin.ch) |
13 | | * |
14 | | * For minor contributions see the git repository. |
15 | | * |
16 | | * Alternatively, the contents of this file may be used under the terms |
17 | | * of the GNU Lesser General Public License Version 2.1 or later |
18 | | * (LGPLv2.1+), in which case the provisions of the LGPLv2.1+ are |
19 | | * applicable instead of those above. |
20 | | */ |
21 | | |
22 | | #include <stdlib.h> |
23 | | #include <string.h> |
24 | | |
25 | | #include <cmath> |
26 | | #include <limits> |
27 | | #include <set> |
28 | | #include <sstream> |
29 | | #include <stack> |
30 | | #include <string> |
31 | | |
32 | | #include <librevenge-stream/librevenge-stream.h> |
33 | | |
34 | | #include "libwps_internal.h" |
35 | | #include "libwps_tools_win.h" |
36 | | |
37 | | #include "WPSCell.h" |
38 | | #include "WKSContentListener.h" |
39 | | #include "WPSEntry.h" |
40 | | #include "WPSFont.h" |
41 | | #include "WPSTable.h" |
42 | | |
43 | | #include "QuattroDos.h" |
44 | | |
45 | | #include "QuattroDosSpreadsheet.h" |
46 | | |
47 | | namespace QuattroDosSpreadsheetInternal |
48 | | { |
49 | | |
50 | | /////////////////////////////////////////////////////////////////// |
51 | | //! a class used to store a style of a cell in QuattroDosSpreadsheet |
52 | | struct Style final : public WPSCellFormat |
53 | | { |
54 | | //! construtor |
55 | | explicit Style(libwps_tools_win::Font::Type type) |
56 | 85.1k | : WPSCellFormat() |
57 | 85.1k | , m_fontType(type) |
58 | 85.1k | , m_fileFormat(0xFF) |
59 | 85.1k | , m_extra("") |
60 | 85.1k | { |
61 | 85.1k | } |
62 | 18.8k | Style(Style const &)=default; |
63 | 15.6k | Style &operator=(Style const &)=default; |
64 | | //! destructor |
65 | | ~Style() final; |
66 | | //! operator<< |
67 | | friend std::ostream &operator<<(std::ostream &o, Style const &style); |
68 | | //! operator== |
69 | | bool operator==(Style const &st) const; |
70 | | //! operator!= |
71 | | bool operator!=(Style const &st) const |
72 | 0 | { |
73 | 0 | return !(*this==st); |
74 | 0 | } |
75 | | //! font encoding type |
76 | | libwps_tools_win::Font::Type m_fontType; |
77 | | //! the file format |
78 | | int m_fileFormat; |
79 | | /** extra data */ |
80 | | std::string m_extra; |
81 | | }; |
82 | | |
83 | | Style::~Style() |
84 | 104k | { |
85 | 104k | } |
86 | | |
87 | | //! operator<< |
88 | | std::ostream &operator<<(std::ostream &o, Style const &style) |
89 | 0 | { |
90 | 0 | o << static_cast<WPSCellFormat const &>(style) << ","; |
91 | 0 | if (style.m_fileFormat!=0xFF) |
92 | 0 | o << "format=" << std::hex << style.m_fileFormat << std::dec << ","; |
93 | 0 | if (style.m_extra.length()) |
94 | 0 | o << "extra=[" << style.m_extra << "],"; |
95 | |
|
96 | 0 | return o; |
97 | 0 | } |
98 | | |
99 | | bool Style::operator==(Style const &st) const |
100 | 0 | { |
101 | 0 | if (m_fontType!=st.m_fontType || m_fileFormat!=st.m_fileFormat) return false; |
102 | 0 | int diff = WPSCellFormat::compare(st); |
103 | 0 | if (diff) return false; |
104 | 0 | return m_extra==st.m_extra; |
105 | 0 | } |
106 | | |
107 | | /////////////////////////////////////////////////////////////////// |
108 | | //! the style manager |
109 | | class StyleManager |
110 | | { |
111 | | public: |
112 | | StyleManager() |
113 | 11.4k | : m_idStyleMap() {} |
114 | | //! add a new style and returns its id |
115 | | void add(int id, Style const &st) |
116 | 47.2k | { |
117 | 47.2k | if (m_idStyleMap.find(id)!=m_idStyleMap.end()) |
118 | 37.7k | { |
119 | 37.7k | WPS_DEBUG_MSG(("QuattroDosParserInternal::StyleManager::add style %d already exists\n", id)); |
120 | 37.7k | return; |
121 | 37.7k | } |
122 | 9.44k | m_idStyleMap.insert(std::map<int, Style>::value_type(id,st)); |
123 | 9.44k | } |
124 | | //! returns the style with id |
125 | | bool get(int id, Style &style) const |
126 | 54.4k | { |
127 | 54.4k | if (m_idStyleMap.find(id)==m_idStyleMap.end()) |
128 | 38.7k | { |
129 | 38.7k | WPS_DEBUG_MSG(("QuattroDosParserInternal::StyleManager::get can not find style %d\n", id)); |
130 | 38.7k | return false; |
131 | 38.7k | } |
132 | 15.6k | style=m_idStyleMap.find(id)->second; |
133 | 15.6k | return true; |
134 | 54.4k | } |
135 | | //! print a style |
136 | | void print(int id, std::ostream &o) const |
137 | 0 | { |
138 | 0 | if (m_idStyleMap.find(id)!=m_idStyleMap.end()) |
139 | 0 | o << ", style=" << m_idStyleMap.find(id)->second; |
140 | 0 | else |
141 | 0 | { |
142 | 0 | WPS_DEBUG_MSG(("QuattroDosParserInternal::StyleManager::print: can not find a style\n")); |
143 | 0 | o << ", ###style=" << id; |
144 | 0 | } |
145 | 0 | } |
146 | | |
147 | | protected: |
148 | | //! the styles |
149 | | std::map<int, Style> m_idStyleMap; |
150 | | }; |
151 | | |
152 | | //! a cellule of a Quattro spreadsheet |
153 | | class Cell final : public WPSCell |
154 | | { |
155 | | public: |
156 | | /// constructor |
157 | | explicit Cell(libwps_tools_win::Font::Type type) |
158 | 57.8k | : m_fontType(type) |
159 | 57.8k | , m_fileFormat(0xFF) |
160 | 57.8k | , m_content() { } |
161 | | |
162 | | //! operator<< |
163 | | friend std::ostream &operator<<(std::ostream &o, Cell const &cell); |
164 | | |
165 | | //! call when a cell must be send |
166 | | bool send(WPSListenerPtr &/*listener*/) final; |
167 | | |
168 | | //! call when the content of a cell must be send |
169 | | bool sendContent(WPSListenerPtr &/*listener*/) final |
170 | 0 | { |
171 | 0 | WPS_DEBUG_MSG(("QuattroDosSpreadsheetInternal::Cell::sendContent: must not be called\n")); |
172 | 0 | return false; |
173 | 0 | } |
174 | | |
175 | | //! update the cell format using file format |
176 | | void updateFormat() |
177 | 41.9k | { |
178 | 41.9k | switch ((m_fileFormat>>4)&7) |
179 | 41.9k | { |
180 | 15.5k | case 0: // fixed |
181 | 15.5k | setFormat(F_NUMBER, 1); |
182 | 15.5k | setDigits(m_fileFormat&0xF); |
183 | 15.5k | break; |
184 | 302 | case 1: // scientific |
185 | 302 | setFormat(F_NUMBER, 2); |
186 | 302 | setDigits(m_fileFormat&0xF); |
187 | 302 | break; |
188 | 510 | case 2: // currency |
189 | 510 | setFormat(F_NUMBER, 4); |
190 | 510 | setDigits(m_fileFormat&0xF); |
191 | 510 | break; |
192 | 279 | case 3: // percent |
193 | 279 | setFormat(F_NUMBER, 3); |
194 | 279 | setDigits(m_fileFormat&0xF); |
195 | 279 | break; |
196 | 3.34k | case 4: // decimal |
197 | 3.34k | setFormat(F_NUMBER, 1); |
198 | 3.34k | setDigits(m_fileFormat&0xF); |
199 | 3.34k | break; |
200 | 606 | case 5: |
201 | 606 | switch (m_fileFormat&0xF) |
202 | 606 | { |
203 | 60 | case 4: // a date but no sure which format is good |
204 | 60 | setDTFormat(F_DATE, "%m/%d/%y"); |
205 | 60 | break; |
206 | 249 | case 5: |
207 | 249 | setDTFormat(F_DATE, "%m/%d"); |
208 | 249 | break; |
209 | 297 | default: |
210 | 297 | WPS_DEBUG_MSG(("QuattroDosSpreadsheetInternal::Cell::updateFormat: unknown format %x\n", unsigned(m_fileFormat))); |
211 | 297 | break; |
212 | 606 | } |
213 | 606 | break; |
214 | 606 | case 6: |
215 | 327 | WPS_DEBUG_MSG(("QuattroDosSpreadsheetInternal::Cell::updateFormat: unknown format %x\n", unsigned(m_fileFormat))); |
216 | 327 | break; |
217 | 21.0k | case 7: |
218 | 21.0k | switch (m_fileFormat&0xF) |
219 | 21.0k | { |
220 | 206 | case 0: // +/- : kind of bool |
221 | 206 | setFormat(F_BOOLEAN); |
222 | 206 | break; |
223 | 8.55k | case 1: |
224 | 8.55k | setFormat(F_NUMBER, 0); |
225 | 8.55k | break; |
226 | 399 | case 2: |
227 | 399 | setDTFormat(F_DATE, "%d %B %y"); |
228 | 399 | break; |
229 | 143 | case 3: |
230 | 143 | setDTFormat(F_DATE, "%d %B"); |
231 | 143 | break; |
232 | 98 | case 4: |
233 | 98 | setDTFormat(F_DATE, "%B %y"); |
234 | 98 | break; |
235 | 177 | case 5: |
236 | 177 | setFormat(F_TEXT); |
237 | 177 | break; |
238 | 144 | case 6: |
239 | 144 | setFormat(F_TEXT); |
240 | 144 | m_font.m_attributes |= WPS_HIDDEN_BIT; |
241 | 144 | break; |
242 | 181 | case 7: |
243 | 181 | setDTFormat(F_TIME, "%I:%M:%S%p"); |
244 | 181 | break; |
245 | 279 | case 8: |
246 | 279 | setDTFormat(F_TIME, "%I:%M%p"); |
247 | 279 | break; |
248 | 123 | case 9: |
249 | 123 | setDTFormat(F_DATE, "%m/%d/%y"); |
250 | 123 | break; |
251 | 1.76k | case 0xa: |
252 | 1.76k | setDTFormat(F_DATE, "%m/%d"); |
253 | 1.76k | break; |
254 | 348 | case 0xb: |
255 | 348 | setDTFormat(F_TIME, "%H:%M:%S"); |
256 | 348 | break; |
257 | 118 | case 0xc: |
258 | 118 | setDTFormat(F_TIME, "%H:%M"); |
259 | 118 | break; |
260 | 161 | case 0xd: |
261 | 161 | setFormat(F_TEXT); |
262 | 161 | break; |
263 | 8.16k | case 0xf: // automatic |
264 | 8.16k | break; |
265 | 159 | default: |
266 | 159 | break; |
267 | 21.0k | } |
268 | 21.0k | break; |
269 | 21.0k | default: |
270 | 0 | break; |
271 | 41.9k | } |
272 | 41.9k | } |
273 | | //! font encoding type |
274 | | libwps_tools_win::Font::Type m_fontType; |
275 | | //! the file format |
276 | | int m_fileFormat; |
277 | | //! the content |
278 | | WKSContentListener::CellContent m_content; |
279 | | }; |
280 | | |
281 | | bool Cell::send(WPSListenerPtr &/*listener*/) |
282 | 0 | { |
283 | 0 | WPS_DEBUG_MSG(("QuattroDosSpreadsheetInternal::Cell::send: must not be called\n")); |
284 | 0 | return false; |
285 | 0 | } |
286 | | //! operator<< |
287 | | std::ostream &operator<<(std::ostream &o, Cell const &cell) |
288 | 0 | { |
289 | 0 | o << reinterpret_cast<WPSCell const &>(cell) << cell.m_content << ","; |
290 | 0 | if (cell.m_fileFormat!=0xFF) |
291 | 0 | o << "format=" << std::hex << cell.m_fileFormat << std::dec << ","; |
292 | 0 | return o; |
293 | 0 | } |
294 | | |
295 | | /////////////////////////////////////////////////////////////////// |
296 | | //! the spreadsheet of a QuattroDos Spreadsheet |
297 | | class Spreadsheet |
298 | | { |
299 | | public: |
300 | | //! the spreadsheet type |
301 | | enum Type { T_Spreadsheet, T_Filter, T_Report }; |
302 | | |
303 | | //! a constructor |
304 | | explicit Spreadsheet(Type type=T_Spreadsheet, int id=0) |
305 | 700k | : m_type(type) |
306 | 700k | , m_id(id) |
307 | 700k | , m_numCols(0) |
308 | 700k | , m_widthCols() |
309 | 700k | , m_rowHeightMap() |
310 | 700k | , m_heightDefault(16) |
311 | 700k | , m_widthDefault(76) |
312 | 700k | , m_positionToCellMap() |
313 | 700k | , m_lastCellPos() |
314 | 700k | , m_rowPageBreaksList() {} |
315 | | //! return a cell corresponding to a spreadsheet, create one if needed |
316 | | Cell &getCell(Vec2i const &pos, libwps_tools_win::Font::Type type) |
317 | 103k | { |
318 | 103k | if (m_positionToCellMap.find(pos)==m_positionToCellMap.end()) |
319 | 41.1k | { |
320 | 41.1k | Cell cell(type); |
321 | 41.1k | cell.setPosition(pos); |
322 | 41.1k | m_positionToCellMap.insert(std::map<Vec2i, Cell>::value_type(pos,cell)); |
323 | 41.1k | } |
324 | 103k | m_lastCellPos=pos; |
325 | 103k | return m_positionToCellMap.find(pos)->second; |
326 | 103k | } |
327 | | //! returns the last cell |
328 | | Cell *getLastCell() |
329 | 0 | { |
330 | 0 | if (m_positionToCellMap.find(m_lastCellPos)==m_positionToCellMap.end()) |
331 | 0 | return nullptr; |
332 | 0 | return &m_positionToCellMap.find(m_lastCellPos)->second; |
333 | 0 | } |
334 | | void insertChartPositions(std::map<Vec2i, Vec2i> const &chartPosMap, libwps_tools_win::Font::Type type) |
335 | 66.1k | { |
336 | 66.1k | int maxCol=-1; |
337 | 66.1k | for (auto const &it : chartPosMap) |
338 | 3.07k | { |
339 | 3.07k | if (it.second[0]>maxCol) maxCol=it.second[0]; |
340 | 3.07k | if (m_positionToCellMap.find(it.first)!=m_positionToCellMap.end()) |
341 | 146 | continue; |
342 | 2.93k | Cell cell(type); |
343 | 2.93k | cell.setPosition(it.first); |
344 | 2.93k | m_positionToCellMap.insert(std::map<Vec2i, Cell>::value_type(it.first,cell)); |
345 | 2.93k | } |
346 | 66.1k | if (maxCol>=int(m_widthCols.size())) |
347 | 1.48k | m_widthCols.resize(size_t(maxCol+1), -1); |
348 | 66.1k | } |
349 | | //! set the columns size |
350 | | void setColumnWidth(int col, int w=-1) |
351 | 6.11k | { |
352 | 6.11k | if (col < 0) return; |
353 | 6.11k | if (col >= int(m_widthCols.size())) m_widthCols.resize(size_t(col)+1, -1); |
354 | 6.11k | m_widthCols[size_t(col)] = w; |
355 | 6.11k | if (col >= m_numCols) m_numCols=col+1; |
356 | 6.11k | } |
357 | | |
358 | | //! return the columns format |
359 | | std::vector<WPSColumnFormat> getWidths() const |
360 | 66.1k | { |
361 | 66.1k | std::vector<WPSColumnFormat> widths; |
362 | 66.1k | WPSColumnFormat defWidth(static_cast<float>(m_widthDefault)), actWidth; |
363 | 66.1k | defWidth.m_useOptimalWidth=true; |
364 | 66.1k | int repeat=0; |
365 | 66.1k | for (auto const &w : m_widthCols) |
366 | 1.59M | { |
367 | 1.59M | WPSColumnFormat newWidth; |
368 | 1.59M | if (w < 0) |
369 | 1.59M | newWidth=defWidth; |
370 | 792 | else |
371 | 792 | newWidth=WPSColumnFormat(float(w)/20.f); |
372 | 1.59M | if (repeat && newWidth!=actWidth) |
373 | 632 | { |
374 | 632 | actWidth.m_numRepeat=repeat; |
375 | 632 | widths.push_back(actWidth); |
376 | 632 | repeat=0; |
377 | 632 | } |
378 | 1.59M | if (repeat==0) |
379 | 2.65k | actWidth=newWidth; |
380 | 1.59M | ++repeat; |
381 | 1.59M | } |
382 | 66.1k | if (repeat) |
383 | 2.02k | { |
384 | 2.02k | actWidth.m_numRepeat=repeat; |
385 | 2.02k | widths.push_back(actWidth); |
386 | 2.02k | } |
387 | 66.1k | return widths; |
388 | 66.1k | } |
389 | | //! returns the row size in point |
390 | | float getRowHeight(int row) const |
391 | 17.3k | { |
392 | 17.3k | auto rIt=m_rowHeightMap.lower_bound(Vec2i(-1,row)); |
393 | 17.3k | if (rIt!=m_rowHeightMap.end() && rIt->first[0]<=row && rIt->first[1]>=row) |
394 | 1.06k | return float(rIt->second); |
395 | 16.3k | return float(m_heightDefault); |
396 | 17.3k | } |
397 | | //! returns the height of a row in point and updated repeated row |
398 | | float getRowHeight(int row, int &numRepeated) const |
399 | 14.9k | { |
400 | 14.9k | auto rIt=m_rowHeightMap.lower_bound(Vec2i(-1,row)); |
401 | 14.9k | if (rIt!=m_rowHeightMap.end() && rIt->first[0]<=row && rIt->first[1]>=row) |
402 | 3.17k | { |
403 | 3.17k | numRepeated=rIt->first[1]-row+1; |
404 | 3.17k | return float(rIt->second); |
405 | 3.17k | } |
406 | 11.7k | numRepeated=10000; |
407 | 11.7k | return float(m_heightDefault); |
408 | 14.9k | } |
409 | | //! set the rows size |
410 | | void setRowHeight(int row, int h) |
411 | 5.12k | { |
412 | 5.12k | if (h>=0) |
413 | 5.12k | m_rowHeightMap[Vec2i(row,row)]=h; |
414 | 5.12k | } |
415 | | //! return the size of the zone containning two cells |
416 | | Vec2f getZoneSize(Vec2i const &cell0, Vec2i const &cell1) const |
417 | 3.07k | { |
418 | 3.07k | int w=0; |
419 | 3.07k | auto numCol=int(m_widthCols.size()); |
420 | 50.8k | for (int i=cell0[0]; i<=cell1[0]; ++i) |
421 | 47.8k | { |
422 | 47.8k | if (i<0 || i>=numCol) |
423 | 0 | w+=m_widthDefault; |
424 | 47.8k | else |
425 | 47.8k | w+=m_widthCols[size_t(i)]; |
426 | 47.8k | } |
427 | 3.07k | int h=0; |
428 | 3.07k | auto rIt=m_rowHeightMap.lower_bound(Vec2i(-1,cell0[1])); |
429 | 3.25M | for (int i=cell0[1]; i<=cell1[1]; ++i) |
430 | 3.24M | { |
431 | 3.24M | if (rIt==m_rowHeightMap.end()) |
432 | 3.04M | h+=m_heightDefault; |
433 | 205k | else if (rIt->first[0]<=i && rIt->first[1]>=i) |
434 | 205k | h+=rIt->second; |
435 | 253 | else |
436 | 253 | { |
437 | 253 | if (rIt->first[1]<i) ++rIt; |
438 | 253 | if (rIt==m_rowHeightMap.end() || rIt->first[0]>i) |
439 | 45 | h+=m_heightDefault; |
440 | 208 | else |
441 | 208 | h+=rIt->second; |
442 | 253 | } |
443 | 3.24M | } |
444 | 3.07k | return Vec2f(float(w),float(h)); |
445 | 3.07k | } |
446 | | //! try to compress the list of row height |
447 | | void compressRowHeights() |
448 | 66.1k | { |
449 | 66.1k | auto oldMap=m_rowHeightMap; |
450 | 66.1k | m_rowHeightMap.clear(); |
451 | 66.1k | int actHeight=-1; |
452 | 66.1k | Vec2i actPos(0, -1); |
453 | 66.1k | for (auto const &rIt : oldMap) |
454 | 2.16k | { |
455 | | // first check for not filled row |
456 | 2.16k | if (rIt.first[0]!=actPos[1]+1) |
457 | 1.92k | { |
458 | 1.92k | if (actHeight==m_heightDefault) |
459 | 40 | actPos[1]=rIt.first[0]-1; |
460 | 1.88k | else |
461 | 1.88k | { |
462 | 1.88k | if (actPos[1]>=actPos[0]) |
463 | 1.30k | m_rowHeightMap[actPos]=actHeight; |
464 | 1.88k | actHeight=m_heightDefault; |
465 | 1.88k | actPos=Vec2i(actPos[1]+1, rIt.first[0]-1); |
466 | 1.88k | } |
467 | 1.92k | } |
468 | 2.16k | if (rIt.second!=actHeight) |
469 | 2.09k | { |
470 | 2.09k | if (actPos[1]>=actPos[0]) |
471 | 1.86k | m_rowHeightMap[actPos]=actHeight; |
472 | 2.09k | actPos[0]=rIt.first[0]; |
473 | 2.09k | actHeight=rIt.second; |
474 | 2.09k | } |
475 | 2.16k | actPos[1]=rIt.first[1]; |
476 | 2.16k | } |
477 | 66.1k | if (actPos[1]>=actPos[0]) |
478 | 803 | m_rowHeightMap[actPos]=actHeight; |
479 | 66.1k | } |
480 | | //! returns true if the spreedsheet is empty |
481 | | bool empty() const |
482 | 442k | { |
483 | 442k | return m_positionToCellMap.empty(); |
484 | 442k | } |
485 | | //! the spreadsheet type |
486 | | Type m_type; |
487 | | //! the spreadsheet id |
488 | | int m_id; |
489 | | /** the number of columns */ |
490 | | int m_numCols; |
491 | | |
492 | | /** the column size in TWIP (?) */ |
493 | | std::vector<int> m_widthCols; |
494 | | /** the map Vec2i(min row, max row) to size in points */ |
495 | | std::map<Vec2i, int> m_rowHeightMap; |
496 | | /** the default row size in point */ |
497 | | int m_heightDefault; |
498 | | /** the default width size in point */ |
499 | | int m_widthDefault; |
500 | | /** a map cell to not empty cells */ |
501 | | std::map<Vec2i, Cell> m_positionToCellMap; |
502 | | /** the last cell position */ |
503 | | Vec2i m_lastCellPos; |
504 | | /** the list of row page break */ |
505 | | std::vector<int> m_rowPageBreaksList; |
506 | | |
507 | | }; |
508 | | |
509 | | //! the state of QuattroDosSpreadsheet |
510 | | struct State |
511 | | { |
512 | | //! constructor |
513 | | State() |
514 | 11.4k | : m_eof(-1) |
515 | 11.4k | , m_version(-1) |
516 | 11.4k | , m_styleManager() |
517 | 11.4k | , m_spreadsheetList() |
518 | 11.4k | , m_spreadsheetStack() |
519 | 11.4k | , m_idToSheetNameMap() |
520 | 11.4k | , m_sheetNameSet() |
521 | 11.4k | { |
522 | 11.4k | pushNewSheet(std::shared_ptr<Spreadsheet>(new Spreadsheet(Spreadsheet::T_Spreadsheet, 0))); |
523 | 11.4k | } |
524 | | //! returns the maximal spreadsheet |
525 | | int getMaximalSheet(Spreadsheet::Type type=Spreadsheet::T_Spreadsheet) const |
526 | 13.1k | { |
527 | 13.1k | int max=-1; |
528 | 13.1k | for (auto const &sheet : m_spreadsheetList) |
529 | 925k | { |
530 | 925k | if (!sheet || sheet->m_type != type || sheet->m_id<=max || sheet->empty()) continue; |
531 | 9.57k | max=sheet->m_id; |
532 | 9.57k | } |
533 | 13.1k | return max; |
534 | 13.1k | } |
535 | | //! returns the ith real spreadsheet |
536 | | std::shared_ptr<Spreadsheet> getSheet(Spreadsheet::Type type, int id) |
537 | 66.1k | { |
538 | 66.1k | for (auto const &sheet : m_spreadsheetList) |
539 | 52.6M | { |
540 | 52.6M | if (!sheet || sheet->m_type!=type || sheet->m_id!=id) |
541 | 52.6M | continue; |
542 | 6.27k | return sheet; |
543 | 52.6M | } |
544 | 59.9k | return std::shared_ptr<Spreadsheet>(); |
545 | 66.1k | } |
546 | | //! returns the ith spreadsheet |
547 | | librevenge::RVNGString getSheetName(int id) |
548 | 112k | { |
549 | 112k | auto it = m_idToSheetNameMap.find(id); |
550 | 112k | if (it!=m_idToSheetNameMap.end() && !it->second.empty()) |
551 | 45.6k | return it->second; |
552 | 66.7k | librevenge::RVNGString name; |
553 | 66.7k | name.sprintf("Sheet%d", id+1); |
554 | 66.7k | name=getUniqueSheetName(name); |
555 | 66.7k | m_idToSheetNameMap[id]=name; |
556 | 66.7k | return name; |
557 | 112k | } |
558 | | //! returns a unique sheet name build using the current name |
559 | | librevenge::RVNGString getUniqueSheetName(librevenge::RVNGString const &name) |
560 | 67.2k | { |
561 | 67.2k | if (m_sheetNameSet.find(name)==m_sheetNameSet.end()) |
562 | 66.9k | { |
563 | 66.9k | m_sheetNameSet.insert(name); |
564 | 66.9k | return name; |
565 | 66.9k | } |
566 | 267 | int i=0; |
567 | 716 | while (i<1000) |
568 | 716 | { |
569 | 716 | librevenge::RVNGString uniqueName(name); |
570 | 716 | uniqueName.append((std::string("_")+std::to_string(i++)).c_str()); |
571 | 716 | if (m_sheetNameSet.find(uniqueName)==m_sheetNameSet.end()) |
572 | 267 | { |
573 | 267 | m_sheetNameSet.insert(uniqueName); |
574 | 267 | return uniqueName; |
575 | 267 | } |
576 | 716 | } |
577 | 0 | return name; |
578 | 267 | } |
579 | | //! returns the actual sheet |
580 | | Spreadsheet &getActualSheet() |
581 | 124k | { |
582 | 124k | return *m_spreadsheetStack.top(); |
583 | 124k | } |
584 | | //! create a new sheet and stack id |
585 | | void pushNewSheet(std::shared_ptr<Spreadsheet> sheet) |
586 | 640k | { |
587 | 640k | if (!sheet) |
588 | 0 | { |
589 | 0 | WPS_DEBUG_MSG(("QuattroDosSpreadsheetInternal::State::pushSheet: can not find the sheet\n")); |
590 | 0 | return; |
591 | 0 | } |
592 | 640k | m_spreadsheetStack.push(sheet); |
593 | 640k | m_spreadsheetList.push_back(sheet); |
594 | 640k | } |
595 | | //! try to pop the actual sheet |
596 | | bool popSheet() |
597 | 1.08k | { |
598 | 1.08k | if (m_spreadsheetStack.size()<=1) |
599 | 0 | { |
600 | 0 | WPS_DEBUG_MSG(("QuattroDosSpreadsheetInternal::State::popSheet: can pop the main sheet\n")); |
601 | 0 | return false; |
602 | 0 | } |
603 | 1.08k | m_spreadsheetStack.pop(); |
604 | 1.08k | return true; |
605 | 1.08k | } |
606 | | |
607 | | //! the last file position |
608 | | long m_eof; |
609 | | //! the file version |
610 | | int m_version; |
611 | | //! the style manager |
612 | | StyleManager m_styleManager; |
613 | | |
614 | | //! the list of spreadsheet ( first: main spreadsheet, other report spreadsheet ) |
615 | | std::vector<std::shared_ptr<Spreadsheet> > m_spreadsheetList; |
616 | | //! the stack of spreadsheet id |
617 | | std::stack<std::shared_ptr<Spreadsheet> > m_spreadsheetStack; |
618 | | //! the map id to sheet's name |
619 | | std::map<int, librevenge::RVNGString> m_idToSheetNameMap; |
620 | | //! the set of used sheet name |
621 | | std::set<librevenge::RVNGString> m_sheetNameSet; |
622 | | |
623 | | }; |
624 | | |
625 | | } |
626 | | |
627 | | // constructor, destructor |
628 | | QuattroDosSpreadsheet::QuattroDosSpreadsheet(QuattroDosParser &parser) |
629 | 11.4k | : m_input(parser.getInput()) |
630 | 11.4k | , m_listener() |
631 | 11.4k | , m_mainParser(parser) |
632 | 11.4k | , m_state(new QuattroDosSpreadsheetInternal::State) |
633 | 11.4k | , m_asciiFile(parser.ascii()) |
634 | 11.4k | { |
635 | 11.4k | } |
636 | | |
637 | | QuattroDosSpreadsheet::~QuattroDosSpreadsheet() |
638 | 11.4k | { |
639 | 11.4k | } |
640 | | |
641 | | int QuattroDosSpreadsheet::version() const |
642 | 180k | { |
643 | 180k | if (m_state->m_version<0) |
644 | 7.03k | m_state->m_version=m_mainParser.version(); |
645 | 180k | return m_state->m_version; |
646 | 180k | } |
647 | | |
648 | | bool QuattroDosSpreadsheet::checkFilePosition(long pos) |
649 | 0 | { |
650 | 0 | if (m_state->m_eof < 0) |
651 | 0 | { |
652 | 0 | long actPos = m_input->tell(); |
653 | 0 | m_input->seek(0, librevenge::RVNG_SEEK_END); |
654 | 0 | m_state->m_eof=m_input->tell(); |
655 | 0 | m_input->seek(actPos, librevenge::RVNG_SEEK_SET); |
656 | 0 | } |
657 | 0 | return pos <= m_state->m_eof; |
658 | 0 | } |
659 | | |
660 | | int QuattroDosSpreadsheet::getNumSpreadsheets() const |
661 | 13.1k | { |
662 | 13.1k | return m_state->getMaximalSheet(QuattroDosSpreadsheetInternal::Spreadsheet::T_Spreadsheet)+1; |
663 | 13.1k | } |
664 | | |
665 | | librevenge::RVNGString QuattroDosSpreadsheet::getSheetName(int id) const |
666 | 46.1k | { |
667 | 46.1k | return m_state->getSheetName(id); |
668 | 46.1k | } |
669 | | |
670 | | //////////////////////////////////////////////////////////// |
671 | | // low level |
672 | | |
673 | | //////////////////////////////////////////////////////////// |
674 | | // parse sheet data |
675 | | //////////////////////////////////////////////////////////// |
676 | | bool QuattroDosSpreadsheet::readSheetSize() |
677 | 2.69k | { |
678 | 2.69k | libwps::DebugStream f; |
679 | 2.69k | long pos = m_input->tell(); |
680 | 2.69k | long type = libwps::read16(m_input); |
681 | 2.69k | if (type != 0x6) |
682 | 0 | { |
683 | 0 | WPS_DEBUG_MSG(("QuattroDosSpreadsheet::readSheetSize: not a sheet zone\n")); |
684 | 0 | return false; |
685 | 0 | } |
686 | 2.69k | long sz = libwps::readU16(m_input); |
687 | 2.69k | int const vers=version(); |
688 | 2.69k | if (sz < (vers>=2 ? 12 : 8)) |
689 | 16 | { |
690 | 16 | WPS_DEBUG_MSG(("QuattroDosSpreadsheet::readSheetSize: block is too short\n")); |
691 | 16 | return false; |
692 | 16 | } |
693 | 2.67k | f << "Entries(SheetSize):"; |
694 | 8.59k | for (int i = 0; i < (vers>=2 ? 3 : 2); i++) // always 2 zero ? |
695 | 5.91k | { |
696 | 5.91k | int val = libwps::read16(m_input); |
697 | 5.91k | if (!val) continue; |
698 | 2.14k | f << "f" << i << "=" << std::hex << val << std::dec << ","; |
699 | 2.14k | } |
700 | 2.67k | int nCol = libwps::read16(m_input)+1; |
701 | 2.67k | f << "nCols=" << nCol << ","; |
702 | 2.67k | int nRow = libwps::read16(m_input); |
703 | 2.67k | f << "nRow=" << nRow << ","; |
704 | 2.67k | int nSheet = vers<=1 ? 0 : libwps::read16(m_input); |
705 | 2.67k | if (nSheet>0) |
706 | 214 | f << "nSheet=" << nSheet << ","; |
707 | 2.67k | ascii().addPos(pos); |
708 | 2.67k | ascii().addNote(f.str().c_str()); |
709 | | // empty spreadsheet |
710 | 2.67k | if (nRow==-1 && nCol==0) return true; |
711 | 2.64k | if (nRow < 0 || nCol <= 0) return false; |
712 | 2.57k | m_state->getActualSheet().setColumnWidth(nCol-1); |
713 | 2.57k | return true; |
714 | | |
715 | 2.64k | } |
716 | | |
717 | | bool QuattroDosSpreadsheet::readRowSize() |
718 | 6.22k | { |
719 | 6.22k | libwps::DebugStream f; |
720 | 6.22k | long pos = m_input->tell(); |
721 | 6.22k | long type = libwps::read16(m_input); |
722 | 6.22k | if (type != 0xe0) |
723 | 0 | { |
724 | 0 | WPS_DEBUG_MSG(("QuattroDosSpreadsheet::readRowSize: not a row size zone\n")); |
725 | 0 | return false; |
726 | 0 | } |
727 | 6.22k | long sz = libwps::readU16(m_input); |
728 | 6.22k | if (sz < 3) |
729 | 990 | { |
730 | 990 | WPS_DEBUG_MSG(("QuattroDosSpreadsheet::readRowSize: block is too short\n")); |
731 | 990 | return false; |
732 | 990 | } |
733 | | |
734 | 5.23k | int row = libwps::read16(m_input); |
735 | 5.23k | int height = libwps::readU8(m_input); |
736 | | |
737 | 5.23k | bool ok = row >= 0; |
738 | 5.23k | f << "Entries(Row):Row" << row << ""; |
739 | 5.23k | if (!ok) f << "###"; |
740 | 5.23k | f << ":height=" << height << ","; |
741 | | |
742 | 5.23k | if (ok) |
743 | 5.12k | m_state->getActualSheet().setRowHeight(row, height); // point to TWIP |
744 | 5.23k | ascii().addPos(pos); |
745 | 5.23k | ascii().addNote(f.str().c_str()); |
746 | | |
747 | 5.23k | return ok; |
748 | 6.22k | } |
749 | | |
750 | | bool QuattroDosSpreadsheet::readColumnSize() |
751 | 3.88k | { |
752 | 3.88k | libwps::DebugStream f; |
753 | 3.88k | long pos = m_input->tell(); |
754 | 3.88k | long type = libwps::read16(m_input); |
755 | 3.88k | if (type != 0x8 && type != 0xe2) |
756 | 0 | { |
757 | 0 | WPS_DEBUG_MSG(("QuattroDosSpreadsheet::readColumnSize: not a column size zone\n")); |
758 | 0 | return false; |
759 | 0 | } |
760 | 3.88k | long sz = libwps::readU16(m_input); |
761 | 3.88k | if (sz < 3) |
762 | 215 | { |
763 | 215 | WPS_DEBUG_MSG(("QuattroDosSpreadsheet::readColumnSize: block is too short\n")); |
764 | 215 | return false; |
765 | 215 | } |
766 | | |
767 | 3.67k | int col = libwps::read16(m_input); |
768 | 3.67k | int width = libwps::readU8(m_input); |
769 | | |
770 | 3.67k | bool ok = col >= 0 && col < m_state->getActualSheet().m_numCols+10; |
771 | 3.67k | f << "Entries(Column):Col" << col << ""; |
772 | 3.67k | if (!ok) f << "###"; |
773 | 3.67k | f << ":width=" << width << ","; |
774 | | |
775 | 3.67k | if (ok) |
776 | 3.54k | { |
777 | 3.54k | if (col >= m_state->getActualSheet().m_numCols) |
778 | 849 | { |
779 | 849 | static bool first = true; |
780 | 849 | if (first) |
781 | 4 | { |
782 | 4 | first = false; |
783 | 4 | WPS_DEBUG_MSG(("QuattroDosSpreadsheet::readColumnSize: I must increase the number of columns\n")); |
784 | 4 | } |
785 | 849 | f << "#col[inc],"; |
786 | 849 | } |
787 | | // checkme: unit in character(?) -> TWIP |
788 | 3.54k | m_state->getActualSheet().setColumnWidth(col, width*105); |
789 | 3.54k | } |
790 | 3.67k | ascii().addPos(pos); |
791 | 3.67k | ascii().addNote(f.str().c_str()); |
792 | | |
793 | 3.67k | return ok; |
794 | 3.88k | } |
795 | | |
796 | | bool QuattroDosSpreadsheet::readHiddenColumns() |
797 | 1.21k | { |
798 | 1.21k | libwps::DebugStream f; |
799 | 1.21k | long pos = m_input->tell(); |
800 | 1.21k | long type = libwps::read16(m_input); |
801 | 1.21k | if (type != 0x64) |
802 | 0 | { |
803 | 0 | WPS_DEBUG_MSG(("QuattroDosSpreadsheet::readHiddenColumns: not a column hidden zone\n")); |
804 | 0 | return false; |
805 | 0 | } |
806 | 1.21k | long sz = libwps::readU16(m_input); |
807 | 1.21k | if (sz != 32) |
808 | 523 | { |
809 | 523 | WPS_DEBUG_MSG(("QuattroDosSpreadsheet::readHiddenColumns: block size seems bad\n")); |
810 | 523 | return false; |
811 | 523 | } |
812 | | |
813 | 687 | f << "Entries(HiddenCol):"; |
814 | 22.6k | for (int i=0; i<32; ++i) |
815 | 21.9k | { |
816 | 21.9k | auto val=int(libwps::readU8(m_input)); |
817 | 21.9k | if (!val) continue; |
818 | 7.12k | static bool first=true; |
819 | 7.12k | if (first) |
820 | 3 | { |
821 | 3 | WPS_DEBUG_MSG(("QuattroDosSpreadsheet::readHiddenColumns: find some hidden col, ignored\n")); |
822 | 3 | first=false; |
823 | 3 | } |
824 | | // checkme |
825 | 64.0k | for (int j=0, depl=1; j<8; ++j, depl<<=1) |
826 | 56.9k | { |
827 | 56.9k | if (val&depl) |
828 | 15.6k | f << "col" << j+8*i << "[hidden],"; |
829 | 56.9k | } |
830 | 7.12k | } |
831 | 687 | ascii().addPos(pos); |
832 | 687 | ascii().addNote(f.str().c_str()); |
833 | | |
834 | 687 | return true; |
835 | 1.21k | } |
836 | | |
837 | | bool QuattroDosSpreadsheet::readCellStyle() |
838 | 29.0k | { |
839 | 29.0k | libwps::DebugStream f; |
840 | 29.0k | long pos = m_input->tell(); |
841 | 29.0k | long type = libwps::read16(m_input); |
842 | 29.0k | int const vers=version(); |
843 | 29.0k | if (type != 0xd8) |
844 | 0 | { |
845 | 0 | WPS_DEBUG_MSG(("QuattroDosSpreadsheet::readCellStyle: not a style zone\n")); |
846 | 0 | return false; |
847 | 0 | } |
848 | 29.0k | long sz = libwps::readU16(m_input); |
849 | 29.0k | f << "Entries(CellStyle):"; |
850 | 29.0k | if ((vers==1&&(sz%12)!=0) || (vers>1 && sz!=0x16)) |
851 | 4.03k | { |
852 | 4.03k | WPS_DEBUG_MSG(("QuattroDosSpreadsheet::readCellStyle: size seems bad\n")); |
853 | 4.03k | f << "###"; |
854 | 4.03k | ascii().addPos(pos); |
855 | 4.03k | ascii().addNote(f.str().c_str()); |
856 | 4.03k | return true; |
857 | 4.03k | } |
858 | 25.0k | if (vers>1) |
859 | 16.5k | { |
860 | 16.5k | auto pId=int(libwps::readU16(m_input)); |
861 | 16.5k | QuattroDosSpreadsheetInternal::Style style(m_mainParser.getDefaultFontType()); |
862 | 16.5k | auto id=int(libwps::readU16(m_input)); |
863 | 16.5k | f.str(""); |
864 | 16.5k | if (!m_state->m_styleManager.get(pId, style)) |
865 | 7.78k | f << "###"; |
866 | 16.5k | if (pId!=0xFF0F) |
867 | 15.6k | { |
868 | 15.6k | f << "Ce" << (pId>>8); |
869 | 15.6k | if (pId&0xFF) f << "-" << (pId&0xFF); |
870 | 15.6k | f << "[parent],"; |
871 | 15.6k | } |
872 | 16.5k | int val; |
873 | 82.6k | for (int i=0; i<4; ++i) // small int, unknown |
874 | 66.1k | { |
875 | 66.1k | val=int(libwps::readU8(m_input)); |
876 | 66.1k | if (val) f << "f" << i << "=" << val << ","; |
877 | 66.1k | } |
878 | 16.5k | WPSFont font; |
879 | 16.5k | auto flags = int(libwps::readU16(m_input)); |
880 | 16.5k | uint32_t attributes = 0; |
881 | 16.5k | if (flags & 1) attributes |= WPS_BOLD_BIT; |
882 | 16.5k | if (flags & 2) attributes |= WPS_ITALICS_BIT; |
883 | 16.5k | if (flags & 8) attributes |= WPS_UNDERLINE_BIT; |
884 | | |
885 | 16.5k | font.m_attributes=attributes; |
886 | 16.5k | if (flags & 0xFFF4) |
887 | 11.4k | f << "fl=" << std::hex << (flags & 0xFFF4) << std::dec << ","; |
888 | 16.5k | auto fId=int(libwps::readU16(m_input)); |
889 | 16.5k | f << "fId=" << fId << ","; |
890 | 16.5k | auto fSize = int(libwps::readU16(m_input)); |
891 | 16.5k | if (fSize >= 1 && fSize <= 50) |
892 | 6.78k | font.m_size=double(fSize); |
893 | 9.75k | else |
894 | 9.75k | f << "###fSize=" << fSize << ","; |
895 | 16.5k | auto color = int(libwps::readU16(m_input)); |
896 | 16.5k | if (color && !m_mainParser.getColor(color, font.m_color)) |
897 | 11.7k | { |
898 | 11.7k | WPS_DEBUG_MSG(("QuattroDosParser::readCellStyle: unknown color\n")); |
899 | 11.7k | f << "##color=" << color << ","; |
900 | 11.7k | } |
901 | 16.5k | style.setFont(font); |
902 | | |
903 | 16.5k | val=int(libwps::readU8(m_input)); |
904 | 16.5k | if (val) |
905 | 14.9k | { |
906 | 74.9k | for (int i=0, depl=0; i<4; ++i, depl+=2) |
907 | 59.9k | { |
908 | 59.9k | int bd=(val>>depl)&3; |
909 | 59.9k | if (!bd) continue; |
910 | 43.8k | WPSBorder border; |
911 | 43.8k | switch (bd) |
912 | 43.8k | { |
913 | 16.0k | case 1: // normal |
914 | 16.0k | break; |
915 | 11.4k | case 2: |
916 | 11.4k | border.m_type = WPSBorder::Double; |
917 | 11.4k | break; |
918 | 16.4k | case 3: |
919 | 16.4k | border.m_width=2; |
920 | 16.4k | break; |
921 | 0 | default: |
922 | 0 | break; |
923 | 43.8k | } |
924 | 43.8k | int const wh[]= {WPSBorder::TopBit, WPSBorder::LeftBit, WPSBorder::BottomBit, WPSBorder::RightBit}; |
925 | 43.8k | style.setBorders(wh[i], border); |
926 | 43.8k | } |
927 | 14.9k | } |
928 | 16.5k | val=int(libwps::readU8(m_input)); // 8|10|18 |
929 | 16.5k | if (val) f << "g0=" << val << ","; |
930 | 16.5k | val=int(libwps::readU8(m_input)); |
931 | 16.5k | switch (val) |
932 | 16.5k | { |
933 | 3.84k | case 0: |
934 | 3.84k | break; |
935 | 1.76k | case 1: |
936 | 1.76k | style.setBackgroundColor(WPSColor(0x80,0x80,0x80)); |
937 | 1.76k | break; |
938 | 1.69k | case 2: |
939 | 1.69k | style.setBackgroundColor(WPSColor::black()); |
940 | 1.69k | break; |
941 | 9.23k | default: |
942 | 9.23k | if ((val&3)==3) |
943 | 882 | { |
944 | 882 | WPSColor col; |
945 | 882 | if (!m_mainParser.getColor(val>>2, col)) |
946 | 417 | { |
947 | 417 | WPS_DEBUG_MSG(("QuattroDosParser::readCellStyle: unknown background color\n")); |
948 | 417 | f << "##color=" << val << ","; |
949 | 417 | } |
950 | 465 | else |
951 | 465 | style.setBackgroundColor(col); |
952 | 882 | } |
953 | 8.34k | else |
954 | 8.34k | f << "##background=" << val << ","; |
955 | 9.23k | break; |
956 | 16.5k | } |
957 | 16.5k | style.m_fileFormat=int(libwps::readU8(m_input)); |
958 | 49.5k | for (int i=0; i<2; ++i) // g1=0|f8 |
959 | 33.0k | { |
960 | 33.0k | val=int(libwps::readU8(m_input)); |
961 | 33.0k | if (val) f << "g" << i+1 << "=" << val << ","; |
962 | 33.0k | } |
963 | | |
964 | 16.5k | style.m_extra=f.str(); |
965 | 16.5k | m_state->m_styleManager.add(id, style); |
966 | 16.5k | f.str(""); |
967 | 16.5k | f << "Entries(CellStyle):Ce" << (id>>8); |
968 | 16.5k | if (id&0xFF) |
969 | 12.8k | f << "-" << (id&0xFF) << "#"; |
970 | 16.5k | f << "," << style << ","; |
971 | | |
972 | 16.5k | ascii().addPos(pos); |
973 | 16.5k | ascii().addNote(f.str().c_str()); |
974 | 16.5k | return true; |
975 | 16.5k | } |
976 | 8.50k | ascii().addPos(pos); |
977 | 8.50k | ascii().addNote(f.str().c_str()); |
978 | 8.50k | auto N=int(sz/12); |
979 | 26.6k | for (int i=0; i<N; ++i) |
980 | 18.1k | { |
981 | 18.1k | pos=m_input->tell(); |
982 | 18.1k | QuattroDosSpreadsheetInternal::Style style(m_mainParser.getDefaultFontType()); |
983 | 18.1k | f.str(""); |
984 | 18.1k | auto id=int(libwps::readU16(m_input)); |
985 | | |
986 | 18.1k | WPSFont font; |
987 | 18.1k | auto flags = int(libwps::readU16(m_input)); |
988 | 18.1k | uint32_t attributes = 0; |
989 | 18.1k | if (flags & 1) attributes |= WPS_BOLD_BIT; |
990 | 18.1k | if (flags & 2) attributes |= WPS_ITALICS_BIT; |
991 | 18.1k | if (flags & 8) attributes |= WPS_UNDERLINE_BIT; |
992 | | |
993 | 18.1k | font.m_attributes=attributes; |
994 | 18.1k | if (flags & 0xFFF4) |
995 | 12.5k | f << "fl=" << std::hex << (flags & 0xFFF4) << std::dec << ","; |
996 | 18.1k | auto fId=int(libwps::readU16(m_input)); |
997 | 18.1k | f << "fId=" << fId << ","; |
998 | 18.1k | auto fSize = int(libwps::readU16(m_input)); |
999 | 18.1k | if (fSize >= 1 && fSize <= 50) |
1000 | 2.44k | font.m_size=double(fSize); |
1001 | 15.6k | else |
1002 | 15.6k | f << "###fSize=" << fSize << ","; |
1003 | 18.1k | auto color = int(libwps::readU16(m_input)); |
1004 | 18.1k | if (color && !m_mainParser.getColor(color, font.m_color)) |
1005 | 11.2k | { |
1006 | 11.2k | WPS_DEBUG_MSG(("QuattroDosParser::readCellStyle: unknown color\n")); |
1007 | 11.2k | f << "##color=" << color << ","; |
1008 | 11.2k | } |
1009 | 18.1k | style.setFont(font); |
1010 | 18.1k | auto val=int(libwps::readU16(m_input)); |
1011 | 18.1k | f << "f0=" << std::hex << val << std::dec << ","; |
1012 | | |
1013 | 18.1k | style.m_extra=f.str(); |
1014 | 18.1k | m_state->m_styleManager.add(id, style); |
1015 | 18.1k | f.str(""); |
1016 | 18.1k | f << "CellStyle-" << i << ":Ce" << id << "," << style << ","; |
1017 | | |
1018 | 18.1k | ascii().addPos(pos); |
1019 | 18.1k | ascii().addNote(f.str().c_str()); |
1020 | 18.1k | m_input->seek(pos+12, librevenge::RVNG_SEEK_SET); |
1021 | 18.1k | } |
1022 | 8.50k | return true; |
1023 | 25.0k | } |
1024 | | |
1025 | | bool QuattroDosSpreadsheet::readCellProperty() |
1026 | 14.5k | { |
1027 | 14.5k | libwps::DebugStream f; |
1028 | 14.5k | long pos = m_input->tell(); |
1029 | 14.5k | long type = libwps::read16(m_input); |
1030 | 14.5k | auto defFontType=m_mainParser.getDefaultFontType(); |
1031 | | |
1032 | 14.5k | if (type != 0x9d) |
1033 | 0 | { |
1034 | 0 | WPS_DEBUG_MSG(("QuattroDosSpreadsheet::readCellProperty: not a cell property zone zone\n")); |
1035 | 0 | return false; |
1036 | 0 | } |
1037 | 14.5k | f << "Entries(CellProperty):"; |
1038 | 14.5k | long sz = libwps::readU16(m_input); |
1039 | 14.5k | if (sz!=7) |
1040 | 762 | { |
1041 | 762 | WPS_DEBUG_MSG(("QuattroDosSpreadsheet::readCellProperty: the size seems bad\n")); |
1042 | 762 | f << "###sz"; |
1043 | 762 | ascii().addPos(pos); |
1044 | 762 | ascii().addNote(f.str().c_str()); |
1045 | 762 | return true; |
1046 | 762 | } |
1047 | 13.7k | auto format=int(libwps::readU8(m_input)); |
1048 | 13.7k | auto col=int(libwps::read16(m_input)); |
1049 | 13.7k | auto row=int(libwps::read16(m_input)); |
1050 | 13.7k | QuattroDosSpreadsheetInternal::Cell emptyCell(defFontType); |
1051 | 13.7k | auto *cell=&emptyCell; |
1052 | 13.7k | if (col<0 || row<0) |
1053 | 1.42k | { |
1054 | 1.42k | WPS_DEBUG_MSG(("QuattroDosSpreadsheet::readCellProperty: the position seems bad\n")); |
1055 | 1.42k | f << "###"; |
1056 | 1.42k | } |
1057 | 12.3k | else |
1058 | 12.3k | cell = &m_state->getActualSheet().getCell(Vec2i(col,row),defFontType); |
1059 | 13.7k | f << "C" << Vec2i(col,row) << ","; |
1060 | 13.7k | auto flag=int(libwps::readU8(m_input)); |
1061 | 13.7k | auto id=int(libwps::readU8(m_input)); |
1062 | 13.7k | if (id&0x80) |
1063 | 7.11k | { |
1064 | 7.11k | f << "Ce" << (id&0x7f) << ","; |
1065 | 7.11k | QuattroDosSpreadsheetInternal::Style style(cell->m_fontType); |
1066 | 7.11k | if (!m_state->m_styleManager.get((id&0x7f), style)) |
1067 | 6.53k | { |
1068 | 6.53k | WPS_DEBUG_MSG(("QuattroDosSpreadsheet::readCellProperty: can not find a style\n")); |
1069 | 6.53k | f << "###"; |
1070 | 6.53k | } |
1071 | 579 | else |
1072 | 579 | { |
1073 | 579 | if (style.m_fileFormat==0xFF) |
1074 | 385 | cell->m_fileFormat=style.m_fileFormat; |
1075 | 579 | cell->m_fontType=style.m_fontType; |
1076 | 579 | cell->setFont(style.getFont()); |
1077 | 579 | cell->setBackgroundColor(style.backgroundColor()); |
1078 | 579 | if (style.hasBorders()) |
1079 | 135 | cell->setBorders(style.borders()); |
1080 | 579 | } |
1081 | 7.11k | } |
1082 | 6.67k | else if (id) |
1083 | 3.99k | { |
1084 | 3.99k | if (id&0x7c) |
1085 | 3.91k | f << "Fo" << (id>>2) << ","; |
1086 | 3.99k | WPSFont font; |
1087 | 3.99k | if (!m_mainParser.getFont(id>>2, font, cell->m_fontType)) |
1088 | 3.92k | { |
1089 | 3.92k | WPS_DEBUG_MSG(("QuattroDosSpreadsheet::readCellProperty: can not find a font\n")); |
1090 | 3.92k | f << "###"; |
1091 | 3.92k | } |
1092 | 75 | else |
1093 | 75 | cell->setFont(font); |
1094 | 3.99k | if (id&0x3) |
1095 | 3.51k | f << "f0=" << (id&3) << ","; |
1096 | 3.99k | } |
1097 | 13.7k | if (format!=0xFF) |
1098 | 12.1k | { |
1099 | 12.1k | cell->m_fileFormat=format; |
1100 | 12.1k | f << "form=" << std::hex << format << std::dec << ","; |
1101 | 12.1k | } |
1102 | 13.7k | switch (flag>>6) |
1103 | 13.7k | { |
1104 | 737 | case 1: |
1105 | 737 | cell->setHAlignment(WPSCellFormat::HALIGN_LEFT); |
1106 | 737 | f << "left,"; |
1107 | 737 | break; |
1108 | 685 | case 2: |
1109 | 685 | cell->setHAlignment(WPSCellFormat::HALIGN_RIGHT); |
1110 | 685 | f << "right,"; |
1111 | 685 | break; |
1112 | 1.23k | case 3: |
1113 | 1.23k | cell->setHAlignment(WPSCellFormat::HALIGN_CENTER); |
1114 | 1.23k | f << "center,"; |
1115 | 1.23k | break; |
1116 | 0 | default: |
1117 | 11.1k | case 0: |
1118 | 11.1k | break; |
1119 | 13.7k | } |
1120 | 41.3k | for (int i=0; i<2; ++i) |
1121 | 27.5k | { |
1122 | 27.5k | int bd=(flag>>(2*i))&0x3; |
1123 | 27.5k | if (!bd) continue; |
1124 | 14.3k | f << "bord" << (i==0 ? "T" : "L"); |
1125 | 14.3k | WPSBorder border; |
1126 | 14.3k | switch (bd) |
1127 | 14.3k | { |
1128 | 6.94k | case 2: |
1129 | 6.94k | border.m_type = WPSBorder::Double; |
1130 | 6.94k | f << "[double]"; |
1131 | 6.94k | break; |
1132 | 4.67k | case 3: |
1133 | 4.67k | border.m_width=2; |
1134 | 4.67k | f << "[w=2]"; |
1135 | 4.67k | break; |
1136 | 0 | default: |
1137 | 2.75k | case 1: // normal |
1138 | 2.75k | break; |
1139 | 14.3k | } |
1140 | 14.3k | f << ","; |
1141 | 14.3k | cell->setBorders(i==0 ? WPSBorder::TopBit : WPSBorder::LeftBit, border); |
1142 | 14.3k | } |
1143 | 13.7k | switch ((flag>>4)&3) |
1144 | 13.7k | { |
1145 | 4.13k | case 1: |
1146 | 4.13k | cell->setBackgroundColor(WPSColor(0x80,0x80,0x80)); |
1147 | 4.13k | f << "back[grey],"; |
1148 | 4.13k | break; |
1149 | 1.82k | case 2: |
1150 | 1.82k | cell->setBackgroundColor(WPSColor::black()); |
1151 | 1.82k | f << "back[black],"; |
1152 | 1.82k | break; |
1153 | 1.19k | case 3: |
1154 | 1.19k | f << "#back[color]=3"; |
1155 | 1.19k | break; |
1156 | 6.63k | case 0: |
1157 | 6.63k | default: |
1158 | 6.63k | break; |
1159 | 13.7k | } |
1160 | 13.7k | ascii().addPos(pos); |
1161 | 13.7k | ascii().addNote(f.str().c_str()); |
1162 | 13.7k | return true; |
1163 | 13.7k | } |
1164 | | |
1165 | | bool QuattroDosSpreadsheet::readUserStyle() |
1166 | 13.8k | { |
1167 | 13.8k | libwps::DebugStream f; |
1168 | 13.8k | long pos = m_input->tell(); |
1169 | 13.8k | long type = libwps::read16(m_input); |
1170 | 13.8k | int const vers=version(); |
1171 | 13.8k | if (type != 0xc9) |
1172 | 0 | { |
1173 | 0 | WPS_DEBUG_MSG(("QuattroDosSpreadsheet::readUserStyle: not a style zone\n")); |
1174 | 0 | return false; |
1175 | 0 | } |
1176 | 13.8k | long sz = libwps::readU16(m_input); |
1177 | 13.8k | f << "Entries(UserStyle):"; |
1178 | 13.8k | if ((vers==1&&sz!=0x2a) || (vers>1 && sz!=0x24)) |
1179 | 1.31k | { |
1180 | 1.31k | WPS_DEBUG_MSG(("QuattroDosSpreadsheet::readUserStyle: size seems bad\n")); |
1181 | 1.31k | f << "###"; |
1182 | 1.31k | ascii().addPos(pos); |
1183 | 1.31k | ascii().addNote(f.str().c_str()); |
1184 | 1.31k | return true; |
1185 | 1.31k | } |
1186 | 12.5k | if (vers>1) |
1187 | 3.09k | { |
1188 | 3.09k | f.str(""); |
1189 | 3.09k | librevenge::RVNGString name(""); |
1190 | 3.09k | if (!m_mainParser.readPString(name,15)) |
1191 | 213 | f << "##sSz,"; |
1192 | 2.87k | else if (!name.empty()) |
1193 | 1.00k | f << name.cstr() << ","; |
1194 | 3.09k | m_input->seek(pos+20, librevenge::RVNG_SEEK_SET); |
1195 | | |
1196 | 3.09k | QuattroDosSpreadsheetInternal::Style style(m_mainParser.getDefaultFontType()); |
1197 | 3.09k | auto id=int(libwps::readU16(m_input)); |
1198 | 3.09k | int val; |
1199 | 15.4k | for (int i=0; i<4; ++i) // small int, unknown |
1200 | 12.3k | { |
1201 | 12.3k | val=int(libwps::readU8(m_input)); |
1202 | 12.3k | if (val) f << "f" << i << "=" << val << ","; |
1203 | 12.3k | } |
1204 | | |
1205 | 3.09k | WPSFont font; |
1206 | 3.09k | auto flags = int(libwps::readU16(m_input)); |
1207 | 3.09k | uint32_t attributes = 0; |
1208 | 3.09k | if (flags & 1) attributes |= WPS_BOLD_BIT; |
1209 | 3.09k | if (flags & 2) attributes |= WPS_ITALICS_BIT; |
1210 | 3.09k | if (flags & 8) attributes |= WPS_UNDERLINE_BIT; |
1211 | | |
1212 | 3.09k | font.m_attributes=attributes; |
1213 | 3.09k | if (flags & 0xFFF4) |
1214 | 2.57k | f << "fl=" << std::hex << (flags & 0xFFF4) << std::dec << ","; |
1215 | 3.09k | auto fId=int(libwps::readU16(m_input)); |
1216 | 3.09k | f << "fId=" << fId << ","; |
1217 | 3.09k | auto fSize = int(libwps::readU16(m_input)); |
1218 | 3.09k | if (fSize >= 1 && fSize <= 50) |
1219 | 377 | font.m_size=double(fSize); |
1220 | 2.71k | else |
1221 | 2.71k | f << "###fSize=" << fSize << ","; |
1222 | 3.09k | auto color = int(libwps::readU16(m_input)); |
1223 | 3.09k | if (color && !m_mainParser.getColor(color, font.m_color)) |
1224 | 2.31k | { |
1225 | 2.31k | WPS_DEBUG_MSG(("QuattroDosParser::readCellStyle: unknown color\n")); |
1226 | 2.31k | f << "##color=" << color << ","; |
1227 | 2.31k | } |
1228 | 3.09k | style.setFont(font); |
1229 | 3.09k | val=int(libwps::readU8(m_input)); |
1230 | 3.09k | if (val) |
1231 | 2.09k | { |
1232 | 10.4k | for (int i=0, depl=0; i<4; ++i, depl+=2) |
1233 | 8.36k | { |
1234 | 8.36k | int bd=(val>>depl)&3; |
1235 | 8.36k | if (!bd) continue; |
1236 | 6.44k | WPSBorder border; |
1237 | 6.44k | switch (bd) |
1238 | 6.44k | { |
1239 | 2.82k | case 1: // normal |
1240 | 2.82k | break; |
1241 | 1.63k | case 2: |
1242 | 1.63k | border.m_type = WPSBorder::Double; |
1243 | 1.63k | break; |
1244 | 1.97k | case 3: |
1245 | 1.97k | border.m_width=2; |
1246 | 1.97k | break; |
1247 | 0 | default: |
1248 | 0 | break; |
1249 | 6.44k | } |
1250 | 6.44k | int const wh[]= {WPSBorder::TopBit, WPSBorder::LeftBit, WPSBorder::BottomBit, WPSBorder::RightBit}; |
1251 | 6.44k | style.setBorders(wh[i], border); |
1252 | 6.44k | } |
1253 | 2.09k | } |
1254 | 3.09k | val=int(libwps::readU8(m_input)); // 8|10|18 |
1255 | 3.09k | if (val) f << "g0=" << val << ","; |
1256 | 3.09k | val=int(libwps::readU8(m_input)); |
1257 | 3.09k | switch (val) |
1258 | 3.09k | { |
1259 | 1.13k | case 0: |
1260 | 1.13k | break; |
1261 | 140 | case 1: |
1262 | 140 | style.setBackgroundColor(WPSColor(0x80,0x80,0x80)); |
1263 | 140 | break; |
1264 | 1.11k | case 2: |
1265 | 1.11k | style.setBackgroundColor(WPSColor::black()); |
1266 | 1.11k | break; |
1267 | 709 | default: |
1268 | 709 | f << "##background=" << val << ","; |
1269 | 709 | break; |
1270 | 3.09k | } |
1271 | 3.09k | style.m_fileFormat=int(libwps::readU8(m_input)); |
1272 | 9.27k | for (int i=0; i<2; ++i) // g1=0|f8 |
1273 | 6.18k | { |
1274 | 6.18k | val=int(libwps::readU8(m_input)); |
1275 | 6.18k | if (val) f << "g" << i+1 << "=" << val << ","; |
1276 | 6.18k | } |
1277 | | |
1278 | 3.09k | style.m_extra=f.str(); |
1279 | 3.09k | m_state->m_styleManager.add(id, style); |
1280 | 3.09k | f.str(""); |
1281 | 3.09k | f << "Entries(UserStyle):"; |
1282 | 3.09k | if (id!=0xFF0F) |
1283 | 3.07k | { |
1284 | 3.07k | f << "Ce" << (id>>8) << "-" << (id&0xFF); |
1285 | 3.07k | if ((id&0xFF)!=8) |
1286 | 2.95k | f << "#"; |
1287 | 3.07k | } |
1288 | 3.09k | f << "," << style << ","; |
1289 | | |
1290 | 3.09k | ascii().addPos(pos); |
1291 | 3.09k | ascii().addNote(f.str().c_str()); |
1292 | 3.09k | return true; |
1293 | 3.09k | } |
1294 | | |
1295 | 9.45k | QuattroDosSpreadsheetInternal::Style style(m_mainParser.getDefaultFontType()); |
1296 | 9.45k | auto id=int(libwps::readU16(m_input)); |
1297 | 9.45k | f.str(""); |
1298 | 9.45k | auto flags = int(libwps::readU16(m_input)); |
1299 | | |
1300 | 9.45k | WPSFont font; |
1301 | 9.45k | uint32_t attributes = 0; |
1302 | 9.45k | if (flags & 1) attributes |= WPS_BOLD_BIT; |
1303 | 9.45k | if (flags & 2) attributes |= WPS_ITALICS_BIT; |
1304 | 9.45k | if (flags & 8) attributes |= WPS_UNDERLINE_BIT; |
1305 | | |
1306 | 9.45k | font.m_attributes=attributes; |
1307 | 9.45k | if (flags & 0xFFF4) |
1308 | 6.81k | f << "font[fl]=" << std::hex << (flags & 0xFFF4) << std::dec << ","; |
1309 | 9.45k | auto fId=int(libwps::readU16(m_input)); |
1310 | 9.45k | f << "fId=" << fId << ","; |
1311 | 9.45k | auto fSize = int(libwps::readU16(m_input)); |
1312 | 9.45k | if (fSize >= 1 && fSize <= 50) |
1313 | 3.51k | font.m_size=double(fSize); |
1314 | 5.93k | else |
1315 | 5.93k | f << "###fSize=" << fSize << ","; |
1316 | 9.45k | auto color = int(libwps::readU16(m_input)); |
1317 | 9.45k | if (color && !m_mainParser.getColor(color, font.m_color)) |
1318 | 4.80k | { |
1319 | 4.80k | WPS_DEBUG_MSG(("QuattroDosSpreadsheet::readUserStyle: unknown color\n")); |
1320 | 4.80k | f << "##font[color]=" << color << ","; |
1321 | 4.80k | } |
1322 | 9.45k | style.setFont(font); |
1323 | 9.45k | auto val=int(libwps::read16(m_input)); |
1324 | 9.45k | if (val!=-1) f << "f1=" << val << ","; |
1325 | 9.45k | librevenge::RVNGString name(""); |
1326 | 9.45k | if (!m_mainParser.readPString(name,15)) |
1327 | 2.33k | f << "##sSz,"; |
1328 | 7.11k | else if (!name.empty()) |
1329 | 2.60k | f << name.cstr() << ","; |
1330 | 9.45k | m_input->seek(pos+32, librevenge::RVNG_SEEK_SET); |
1331 | 9.45k | val=int(libwps::readU16(m_input)); // probably list of modified flags |
1332 | 9.45k | if (val) |
1333 | 5.83k | f << "wh=" << std::hex << val << std::dec << ","; |
1334 | 47.2k | for (int i=0; i<4; ++i) |
1335 | 37.8k | { |
1336 | 37.8k | val=int(libwps::readU8(m_input)); |
1337 | 37.8k | if (!val) continue; |
1338 | 15.8k | WPSBorder border; |
1339 | 15.8k | switch (val) |
1340 | 15.8k | { |
1341 | 1.08k | case 1: // normal |
1342 | 1.08k | break; |
1343 | 1.46k | case 2: |
1344 | 1.46k | border.m_type = WPSBorder::Double; |
1345 | 1.46k | break; |
1346 | 1.96k | case 3: |
1347 | 1.96k | border.m_width=2; |
1348 | 1.96k | break; |
1349 | 11.3k | default: |
1350 | 11.3k | f << "#border" << i << "=" << val << ","; |
1351 | 11.3k | break; |
1352 | 15.8k | } |
1353 | 15.8k | int const wh[]= {WPSBorder::TopBit, WPSBorder::LeftBit, WPSBorder::BottomBit, WPSBorder::RightBit}; |
1354 | 15.8k | style.setBorders(wh[i], border); |
1355 | 15.8k | } |
1356 | 9.45k | val=int(libwps::readU8(m_input)); |
1357 | 9.45k | switch (val) |
1358 | 9.45k | { |
1359 | 4.56k | case 0: |
1360 | 4.56k | break; |
1361 | 94 | case 1: |
1362 | 94 | style.setBackgroundColor(WPSColor(0x80,0x80,0x80)); |
1363 | 94 | break; |
1364 | 440 | case 2: |
1365 | 440 | style.setBackgroundColor(WPSColor::black()); |
1366 | 440 | break; |
1367 | 4.35k | default: |
1368 | 4.35k | f << "#back[color]=" << val << ","; |
1369 | 4.35k | break; |
1370 | 9.45k | } |
1371 | 9.45k | val=int(libwps::readU8(m_input)); |
1372 | 9.45k | switch (val) |
1373 | 9.45k | { |
1374 | 6.48k | case 0: |
1375 | 6.48k | break; |
1376 | 65 | case 1: |
1377 | 65 | style.setHAlignment(WPSCellFormat::HALIGN_LEFT); |
1378 | 65 | break; |
1379 | 76 | case 2: |
1380 | 76 | style.setHAlignment(WPSCellFormat::HALIGN_RIGHT); |
1381 | 76 | break; |
1382 | 912 | case 3: |
1383 | 912 | style.setHAlignment(WPSCellFormat::HALIGN_CENTER); |
1384 | 912 | break; |
1385 | 1.91k | default: |
1386 | 1.91k | f << "#align=" << val << ","; |
1387 | 1.91k | break; |
1388 | 9.45k | } |
1389 | 9.45k | val=int(libwps::readU8(m_input)); |
1390 | 9.45k | switch (val) |
1391 | 9.45k | { |
1392 | 6.49k | case 0: |
1393 | 6.49k | break; |
1394 | 447 | case 1: |
1395 | 447 | f << "input=labels[only],"; |
1396 | 447 | break; |
1397 | 29 | case 2: |
1398 | 29 | f << "input=dates[only],"; |
1399 | 29 | break; |
1400 | 2.48k | default: |
1401 | 2.48k | f << "#input=" << val << ","; |
1402 | 2.48k | break; |
1403 | 9.45k | } |
1404 | 9.45k | style.m_fileFormat=int(libwps::readU8(m_input)); |
1405 | 37.8k | for (int i=0; i<3; ++i) |
1406 | 28.3k | { |
1407 | 28.3k | val=int(libwps::read8(m_input)); |
1408 | 28.3k | if (val) f << "f" << i+2 << "=" << val << ","; |
1409 | 28.3k | } |
1410 | | |
1411 | 9.45k | style.m_extra=f.str(); |
1412 | 9.45k | m_state->m_styleManager.add(id, style); |
1413 | 9.45k | f.str(""); |
1414 | 9.45k | f << "Entries(UserStyle):Ce" << id << "," << style << ","; |
1415 | 9.45k | ascii().addPos(pos); |
1416 | 9.45k | ascii().addNote(f.str().c_str()); |
1417 | 9.45k | return true; |
1418 | 9.45k | } |
1419 | | |
1420 | | //////////////////////////////////////////////////////////// |
1421 | | // general |
1422 | | //////////////////////////////////////////////////////////// |
1423 | | |
1424 | | bool QuattroDosSpreadsheet::readCell() |
1425 | 90.9k | { |
1426 | 90.9k | libwps::DebugStream f; |
1427 | | |
1428 | 90.9k | long pos = m_input->tell(); |
1429 | 90.9k | long type = libwps::read16(m_input); |
1430 | 90.9k | if (type < 0xc || type > 0x10) |
1431 | 0 | { |
1432 | 0 | WPS_DEBUG_MSG(("QuattroDosSpreadsheet::readCell: not a cell property\n")); |
1433 | 0 | return false; |
1434 | 0 | } |
1435 | 90.9k | long sz = libwps::readU16(m_input); |
1436 | 90.9k | long endPos = pos+4+sz; |
1437 | | |
1438 | 90.9k | if (sz < 5) |
1439 | 85 | { |
1440 | 85 | WPS_DEBUG_MSG(("QuattroDosSpreadsheet::readCell: cell def is too short\n")); |
1441 | 85 | return false; |
1442 | 85 | } |
1443 | 90.9k | int const vers=version(); |
1444 | 90.9k | auto defFontType=m_mainParser.getDefaultFontType(); |
1445 | 90.9k | bool dosFile = vers<=1; |
1446 | 90.9k | int format=0xFF; |
1447 | 90.9k | if (dosFile) |
1448 | 60.0k | format = int(libwps::readU8(m_input)); |
1449 | 90.9k | int cellPos[2]; |
1450 | 90.9k | cellPos[0]=int(libwps::readU8(m_input)); |
1451 | 90.9k | auto sheetId=int(libwps::readU8(m_input)); |
1452 | 90.9k | cellPos[1]=int(libwps::read16(m_input)); |
1453 | 90.9k | if (cellPos[1] < 0) |
1454 | 69 | { |
1455 | 69 | WPS_DEBUG_MSG(("QuattroDosSpreadsheet::readCell: cell pos is bad\n")); |
1456 | 69 | return false; |
1457 | 69 | } |
1458 | 90.8k | if (sheetId) |
1459 | 25.3k | { |
1460 | 25.3k | if (vers==1) |
1461 | 15.0k | { |
1462 | 15.0k | WPS_DEBUG_MSG(("QuattroDosSpreadsheet::readCell: find unexpected sheet id\n")); |
1463 | 15.0k | f << "###"; |
1464 | 15.0k | } |
1465 | 25.3k | f << "sheet[id]=" << sheetId << ","; |
1466 | 25.3k | } |
1467 | | |
1468 | 90.8k | auto &cell=m_state->getActualSheet().getCell(Vec2i(cellPos[0],cellPos[1]), defFontType); |
1469 | 90.8k | cell.m_fileFormat=format; |
1470 | 90.8k | if (!dosFile) |
1471 | 30.8k | { |
1472 | 30.8k | auto id=int(libwps::readU16(m_input)); |
1473 | 30.8k | if (id!=0xFF0F) |
1474 | 29.5k | { |
1475 | 29.5k | f << "Ce" << (id>>8); |
1476 | 29.5k | if (id&0xFF) f << "-" << (id&0xFF); |
1477 | 29.5k | f << ","; |
1478 | 29.5k | } |
1479 | 30.8k | QuattroDosSpreadsheetInternal::Style style(defFontType); |
1480 | 30.8k | if (!m_state->m_styleManager.get(id, style)) |
1481 | 24.4k | f << "###"; |
1482 | 6.35k | else |
1483 | 6.35k | { |
1484 | 6.35k | cell.m_fileFormat=style.m_fileFormat; |
1485 | 6.35k | cell.m_fontType=style.m_fontType; |
1486 | 6.35k | cell.setFont(style.getFont()); |
1487 | 6.35k | cell.setBackgroundColor(style.backgroundColor()); |
1488 | 6.35k | if (style.hasBorders()) |
1489 | 2.19k | cell.setBorders(style.borders()); |
1490 | 6.35k | } |
1491 | 30.8k | } |
1492 | | |
1493 | 90.8k | long dataPos = m_input->tell(); |
1494 | 90.8k | auto dataSz = int(endPos-dataPos); |
1495 | | |
1496 | 90.8k | bool ok = true; |
1497 | 90.8k | switch (type) |
1498 | 90.8k | { |
1499 | 10.8k | case 12: |
1500 | 10.8k | { |
1501 | 10.8k | if (dataSz == 0) |
1502 | 7.84k | { |
1503 | 7.84k | cell.m_content.m_contentType=WKSContentListener::CellContent::C_NONE; |
1504 | 7.84k | break; |
1505 | 7.84k | } |
1506 | 2.97k | ok = false; |
1507 | 2.97k | break; |
1508 | 10.8k | } |
1509 | 14.7k | case 13: |
1510 | 14.7k | { |
1511 | 14.7k | if (dataSz == 2) |
1512 | 9.13k | { |
1513 | 9.13k | cell.m_content.m_contentType=WKSContentListener::CellContent::C_NUMBER; |
1514 | 9.13k | cell.m_content.setValue(libwps::read16(m_input)); |
1515 | 9.13k | break; |
1516 | 9.13k | } |
1517 | 5.63k | ok = false; |
1518 | 5.63k | break; |
1519 | 14.7k | } |
1520 | 14.0k | case 14: |
1521 | 14.0k | { |
1522 | 14.0k | long double val; |
1523 | 14.0k | bool isNaN; |
1524 | 14.0k | if (dataSz == 8 && libwps::readDouble8(m_input, val, isNaN)) |
1525 | 5.14k | { |
1526 | 5.14k | cell.m_content.m_contentType=WKSContentListener::CellContent::C_NUMBER; |
1527 | 5.14k | cell.m_content.setValue(val); |
1528 | 5.14k | break; |
1529 | 5.14k | } |
1530 | 8.86k | ok = false; |
1531 | 8.86k | break; |
1532 | 14.0k | } |
1533 | 15.0k | case 15: |
1534 | 15.0k | { |
1535 | 15.0k | cell.m_content.m_contentType=WKSContentListener::CellContent::C_TEXT; |
1536 | 15.0k | long begText=m_input->tell()+2, endText=begText+dataSz-2; |
1537 | | // pascal string |
1538 | 15.0k | auto align=char(libwps::readU8(m_input)); |
1539 | 15.0k | if (align=='\'') cell.setHAlignment(WPSCellFormat::HALIGN_DEFAULT); |
1540 | 5.70k | else if (align=='\\') cell.setHAlignment(WPSCellFormat::HALIGN_LEFT); |
1541 | 5.45k | else if (align=='^') cell.setHAlignment(WPSCellFormat::HALIGN_CENTER); |
1542 | 5.07k | else if (align=='\"') cell.setHAlignment(WPSCellFormat::HALIGN_RIGHT); |
1543 | 4.19k | else f << "#align=" << int(align) << ","; |
1544 | | |
1545 | 15.0k | librevenge::RVNGString text(""); |
1546 | 15.0k | if (!m_mainParser.readPString(text,dataSz-2)) |
1547 | 12.9k | f << "##sSz,"; |
1548 | 2.06k | else |
1549 | 2.06k | { |
1550 | 2.06k | if (endText!=m_input->tell()) |
1551 | 1.28k | { |
1552 | 1.28k | endText=m_input->tell(); |
1553 | 1.28k | f << "#extra,"; |
1554 | 1.28k | ascii().addDelimiter(m_input->tell(), '|'); |
1555 | 1.28k | } |
1556 | 2.06k | if (!text.empty()) |
1557 | 1.08k | f << text.cstr() << ","; |
1558 | 2.06k | } |
1559 | 15.0k | cell.m_content.m_textEntry.setBegin(begText); |
1560 | 15.0k | cell.m_content.m_textEntry.setEnd(endText); |
1561 | 15.0k | break; |
1562 | 14.0k | } |
1563 | 36.2k | case 16: |
1564 | 36.2k | { |
1565 | 36.2k | long double val; |
1566 | 36.2k | bool isNaN; |
1567 | 36.2k | if (dataSz >= 8 && libwps::readDouble8(m_input, val, isNaN)) |
1568 | 33.4k | { |
1569 | 33.4k | cell.m_content.m_contentType=WKSContentListener::CellContent::C_FORMULA; |
1570 | 33.4k | cell.m_content.setValue(val); |
1571 | 33.4k | std::string error; |
1572 | 33.4k | if (!readFormula(endPos, cell.position(), sheetId, cell.m_content.m_formula, error)) |
1573 | 32.9k | { |
1574 | 32.9k | cell.m_content.m_contentType=WKSContentListener::CellContent::C_NUMBER; |
1575 | 32.9k | ascii().addDelimiter(m_input->tell()-1, '#'); |
1576 | 32.9k | } |
1577 | 33.4k | if (error.length()) f << error; |
1578 | 33.4k | break; |
1579 | 33.4k | } |
1580 | 2.74k | ok = false; |
1581 | 2.74k | break; |
1582 | 36.2k | } |
1583 | 0 | default: |
1584 | 0 | WPS_DEBUG_MSG(("QuattroDosSpreadsheet::readCell: unknown type=%ld\n", type)); |
1585 | 0 | ok = false; |
1586 | 0 | break; |
1587 | 90.8k | } |
1588 | 90.8k | if (!ok) ascii().addDelimiter(dataPos, '#'); |
1589 | | |
1590 | 90.8k | if (dosFile) |
1591 | 60.0k | { |
1592 | 60.0k | switch (cell.m_content.m_contentType) |
1593 | 60.0k | { |
1594 | 7.94k | case WKSContentListener::CellContent::C_NONE: |
1595 | 7.94k | break; |
1596 | 13.7k | case WKSContentListener::CellContent::C_TEXT: |
1597 | 13.7k | cell.setFormat(WPSCell::F_TEXT); |
1598 | 13.7k | break; |
1599 | 29.9k | case WKSContentListener::CellContent::C_NUMBER: |
1600 | 29.9k | case WKSContentListener::CellContent::C_FORMULA: |
1601 | 38.3k | case WKSContentListener::CellContent::C_UNKNOWN: |
1602 | 38.3k | default: |
1603 | 38.3k | cell.setFormat(WPSCell::F_NUMBER); |
1604 | 38.3k | break; |
1605 | 60.0k | } |
1606 | | |
1607 | 60.0k | } |
1608 | 90.8k | m_input->seek(pos+sz, librevenge::RVNG_SEEK_SET); |
1609 | | |
1610 | 90.8k | std::string extra=f.str(); |
1611 | 90.8k | f.str(""); |
1612 | 90.8k | f << "Entries(CellContent):" << cell << "," << extra; |
1613 | | |
1614 | 90.8k | ascii().addPos(pos); |
1615 | 90.8k | ascii().addNote(f.str().c_str()); |
1616 | | |
1617 | 90.8k | return true; |
1618 | 90.8k | } |
1619 | | |
1620 | | bool QuattroDosSpreadsheet::readCellFormulaResult() |
1621 | 1.12k | { |
1622 | 1.12k | libwps::DebugStream f; |
1623 | | |
1624 | 1.12k | long pos = m_input->tell(); |
1625 | 1.12k | long type = libwps::read16(m_input); |
1626 | 1.12k | if (type != 0x33) |
1627 | 0 | { |
1628 | 0 | WPS_DEBUG_MSG(("QuattroDosSpreadsheet::readCellFormulaResult: not a cell property\n")); |
1629 | 0 | return false; |
1630 | 0 | } |
1631 | 1.12k | long sz = libwps::readU16(m_input); |
1632 | 1.12k | if (sz<6) |
1633 | 10 | { |
1634 | 10 | WPS_DEBUG_MSG(("QuattroDosSpreadsheet::readCellFormulaResult: the zone seems to short\n")); |
1635 | 10 | return false; |
1636 | 10 | } |
1637 | 1.11k | long endPos = pos+4+sz; |
1638 | | |
1639 | 1.11k | bool dosFile = version() <= 1; |
1640 | | // skip format for dosFile |
1641 | 1.11k | m_input->seek(dosFile ? pos+5 : pos+4, librevenge::RVNG_SEEK_SET); |
1642 | 1.11k | f << "CellContent[res]:"; |
1643 | 1.11k | int dim[2]; |
1644 | 2.23k | for (int &i : dim) i=int(libwps::readU16(m_input)); |
1645 | 1.11k | f << "C" << dim[0] << "x" << dim[1] << ","; |
1646 | | // skip format for windows file |
1647 | 1.11k | if (!dosFile) m_input->seek(2, librevenge::RVNG_SEEK_CUR); |
1648 | 1.11k | librevenge::RVNGString text(""); |
1649 | 1.11k | if (!m_mainParser.readPString(text,endPos-m_input->tell()-1)) |
1650 | 545 | f << "##sSz,"; |
1651 | 570 | else if (!text.empty()) |
1652 | 328 | f << text.cstr() << ","; |
1653 | 1.11k | ascii().addPos(pos); |
1654 | 1.11k | ascii().addNote(f.str().c_str()); |
1655 | 1.11k | return true; |
1656 | 1.12k | } |
1657 | | |
1658 | | //////////////////////////////////////////////////////////// |
1659 | | // Data |
1660 | | //////////////////////////////////////////////////////////// |
1661 | | bool QuattroDosSpreadsheet::readSpreadsheetName() |
1662 | 3.62k | { |
1663 | 3.62k | libwps::DebugStream f; |
1664 | | |
1665 | 3.62k | long pos = m_input->tell(); |
1666 | 3.62k | auto type = long(libwps::readU16(m_input)); |
1667 | 3.62k | if (type != 0xde) |
1668 | 0 | { |
1669 | 0 | WPS_DEBUG_MSG(("QuattroDosSpreadsheet::readSpreadsheetName: not a spreadsheet header\n")); |
1670 | 0 | return false; |
1671 | 0 | } |
1672 | 3.62k | auto sz = int(libwps::readU16(m_input)); |
1673 | 3.62k | f << "Entries(SheetName):"; |
1674 | 3.62k | librevenge::RVNGString name(""); |
1675 | 3.62k | if (!m_mainParser.readPString(name,sz-1)) |
1676 | 1.60k | f << "##sSz,"; |
1677 | 2.02k | else if (!name.empty()) |
1678 | 1.44k | { |
1679 | 1.44k | f << name.cstr() << ","; |
1680 | 1.44k | if (m_state->m_spreadsheetStack.empty() || !m_state->m_spreadsheetStack.top()) |
1681 | 0 | { |
1682 | 0 | WPS_DEBUG_MSG(("QuattroDosSpreadsheet::readSpreadsheetName: can not find the current sheet\n")); |
1683 | 0 | f << "###current"; |
1684 | 0 | } |
1685 | 1.44k | else if (m_state->m_idToSheetNameMap.find(m_state->getActualSheet().m_id)!=m_state->m_idToSheetNameMap.end()) |
1686 | 933 | { |
1687 | 933 | WPS_DEBUG_MSG(("QuattroDosSpreadsheet::readSpreadsheetName: id=%d dupplicated\n", m_state->getActualSheet().m_id)); |
1688 | 933 | f << "###id"; |
1689 | 933 | } |
1690 | 507 | else |
1691 | 507 | m_state->m_idToSheetNameMap[m_state->getActualSheet().m_id]=m_state->getUniqueSheetName(name); |
1692 | 1.44k | } |
1693 | 3.62k | ascii().addPos(pos); |
1694 | 3.62k | ascii().addNote(f.str().c_str()); |
1695 | 3.62k | return true; |
1696 | 3.62k | } |
1697 | | |
1698 | | bool QuattroDosSpreadsheet::readSpreadsheetOpen() |
1699 | 674k | { |
1700 | 674k | libwps::DebugStream f; |
1701 | | |
1702 | 674k | long pos = m_input->tell(); |
1703 | 674k | auto type = long(libwps::readU16(m_input)); |
1704 | 674k | if (type != 0xdc) |
1705 | 0 | { |
1706 | 0 | WPS_DEBUG_MSG(("QuattroDosSpreadsheet::readSpreadsheetOpen: not a spreadsheet header\n")); |
1707 | 0 | return false; |
1708 | 0 | } |
1709 | 674k | auto sz = long(libwps::readU16(m_input)); |
1710 | 674k | f << "Entries(Spreadsheet)[beg]:"; |
1711 | 674k | if (sz!=2) |
1712 | 673k | { |
1713 | 673k | WPS_DEBUG_MSG(("QuattroDosSpreadsheet::readSpreadsheetOpen: the field size seems odd\n")); |
1714 | 673k | f << "###"; |
1715 | 673k | } |
1716 | 674k | auto id=int(libwps::readU16(m_input)); |
1717 | 674k | if (id<0||id>255) |
1718 | 2.46k | { |
1719 | 2.46k | f << "###"; |
1720 | 2.46k | WPS_DEBUG_MSG(("QuattroDosSpreadsheet::readSpreadsheetOpen: the id seems odd\n")); |
1721 | 2.46k | } |
1722 | 672k | else if (id==0 && m_state->m_spreadsheetStack.size()!=1) |
1723 | 39.0k | { |
1724 | 39.0k | WPS_DEBUG_MSG(("QuattroDosSpreadsheet::readSpreadsheetOpen: find 0 but the stack is not empty\n")); |
1725 | 39.0k | f << "###stack"; |
1726 | 39.0k | m_state->m_spreadsheetStack.push(m_state->m_spreadsheetList[0]); |
1727 | 39.0k | } |
1728 | 633k | else if (id) |
1729 | 629k | m_state->pushNewSheet(std::shared_ptr<QuattroDosSpreadsheetInternal::Spreadsheet> |
1730 | 629k | (new QuattroDosSpreadsheetInternal::Spreadsheet |
1731 | 629k | (QuattroDosSpreadsheetInternal::Spreadsheet::T_Spreadsheet, id))); |
1732 | 674k | f << id << ","; |
1733 | 674k | ascii().addPos(pos); |
1734 | 674k | ascii().addNote(f.str().c_str()); |
1735 | 674k | return true; |
1736 | 674k | } |
1737 | | |
1738 | | bool QuattroDosSpreadsheet::readSpreadsheetClose() |
1739 | 1.25k | { |
1740 | 1.25k | libwps::DebugStream f; |
1741 | | |
1742 | 1.25k | long pos = m_input->tell(); |
1743 | 1.25k | auto type = long(libwps::readU16(m_input)); |
1744 | 1.25k | if (type != 0xdd) |
1745 | 0 | { |
1746 | 0 | WPS_DEBUG_MSG(("QuattroDosSpreadsheet::readSpreadsheetClose: not a spreadsheet header\n")); |
1747 | 0 | return false; |
1748 | 0 | } |
1749 | 1.25k | auto sz = long(libwps::readU16(m_input)); |
1750 | 1.25k | f << "Entries(Spreadsheet)[end]:"; |
1751 | 1.25k | auto const &sheet=m_state->getActualSheet(); |
1752 | 1.25k | if (sheet.m_type!=QuattroDosSpreadsheetInternal::Spreadsheet::T_Spreadsheet) |
1753 | 0 | { |
1754 | 0 | WPS_DEBUG_MSG(("QuattroDosSpreadsheet::readSpreadsheetClose: can not find spreadsheet spreadsheet\n")); |
1755 | 0 | f << "###[noOpen],"; |
1756 | 0 | } |
1757 | 1.25k | else if (m_state->m_spreadsheetStack.size() > 1) |
1758 | 1.08k | m_state->popSheet(); |
1759 | 1.25k | if (sz!=0) |
1760 | 69 | { |
1761 | 69 | WPS_DEBUG_MSG(("QuattroDosSpreadsheet::readSpreadsheetClose: the field size seems odd\n")); |
1762 | 69 | f << "###"; |
1763 | 69 | } |
1764 | 1.25k | ascii().addPos(pos); |
1765 | 1.25k | ascii().addNote(f.str().c_str()); |
1766 | 1.25k | return true; |
1767 | 1.25k | } |
1768 | | |
1769 | | bool QuattroDosSpreadsheet::readCell |
1770 | | (Vec2i actPos, WKSContentListener::FormulaInstruction &instr, bool hasSheetId, int sheetId) |
1771 | 35.6k | { |
1772 | 35.6k | instr=WKSContentListener::FormulaInstruction(); |
1773 | 35.6k | instr.m_type=WKSContentListener::FormulaInstruction::F_Cell; |
1774 | 35.6k | bool ok = true; |
1775 | 35.6k | int pos[3]= {0,0,0}; |
1776 | 35.6k | bool absolute[3] = { true, true, true}; |
1777 | 113k | for (int dim = 0; dim < (hasSheetId ? 3 : 2); dim++) |
1778 | 77.7k | { |
1779 | 77.7k | auto val = int(libwps::readU16(m_input)); |
1780 | 77.7k | if (dim==0 && (val&0xF00) && (val&0xF000)!=0xF000) |
1781 | 11.5k | { |
1782 | | // checkme: probably (val>>8)&0x1f |
1783 | 11.5k | instr.m_fileName=m_mainParser.getFileName(int((val>>8)&0xF)); |
1784 | 11.5k | val &= 0xF0FF; |
1785 | 11.5k | } |
1786 | 77.7k | if ((val & 0xF000) == 0); // absolute value ? |
1787 | 13.8k | else if ((val & 0xc000) == 0x8000) // relative ? |
1788 | 9.54k | { |
1789 | 9.54k | if (version()==1 || dim==0) |
1790 | 7.28k | { |
1791 | 7.28k | val &= 0xFF; |
1792 | 7.28k | if ((val & 0x80) && val+actPos[dim] >= 0x100) |
1793 | | // sometimes this value is odd, so do not generate errors here |
1794 | 1.55k | val = val - 0x100; |
1795 | 7.28k | } |
1796 | 2.26k | else |
1797 | 2.26k | { |
1798 | 2.26k | val &= 0x3FFF; |
1799 | 2.26k | if (val>0x1000) val = val - 0x2000; |
1800 | 2.26k | } |
1801 | 9.54k | if (dim==2) |
1802 | 1.15k | val += sheetId; |
1803 | 8.39k | else |
1804 | 8.39k | val += actPos[dim]; |
1805 | 9.54k | absolute[dim] = false; |
1806 | 9.54k | } |
1807 | 4.27k | else if (val==0xFFFF) |
1808 | 1.05k | { |
1809 | 1.05k | static bool first=true; |
1810 | 1.05k | if (first) // in general associated with a nan value, so maybe be normal |
1811 | 4 | { |
1812 | 4 | WPS_DEBUG_MSG(("QuattroDosSpreadsheet::readCell: find some ffff cell\n")); |
1813 | 4 | first=false; |
1814 | 4 | } |
1815 | 1.05k | ok = false; |
1816 | 1.05k | } |
1817 | 3.22k | else |
1818 | 3.22k | { |
1819 | 3.22k | WPS_DEBUG_MSG(("QuattroDosSpreadsheet::readCell: can not read cell %x\n", unsigned(val))); |
1820 | 3.22k | ok = false; |
1821 | 3.22k | } |
1822 | 77.7k | pos[dim] = val; |
1823 | 77.7k | } |
1824 | | |
1825 | 35.6k | if (pos[0] < 0 || pos[1] < 0) |
1826 | 367 | { |
1827 | 367 | if (ok) |
1828 | 336 | { |
1829 | 336 | WPS_DEBUG_MSG(("QuattroDosSpreadsheet::readCell: can not read cell position\n")); |
1830 | 336 | } |
1831 | 367 | return false; |
1832 | 367 | } |
1833 | 35.2k | if (pos[0]>255) // FIXME: can happens in some list cell, so... |
1834 | 1.55k | pos[0]&=0xFF; |
1835 | 35.2k | if (hasSheetId && pos[2]>255) // CHECKME: this can also happen, unsure why |
1836 | 833 | pos[2]%=256; |
1837 | | |
1838 | 35.2k | instr.m_position[0]=Vec2i(pos[0],pos[1]); |
1839 | 35.2k | if (hasSheetId && sheetId!=pos[2]) instr.m_sheetId[0]=pos[2]; |
1840 | 30.5k | else if (!instr.m_fileName.empty()) instr.m_sheetId[0]=sheetId; |
1841 | 35.2k | instr.m_positionRelative[0]=Vec2b(!absolute[0], !absolute[1]); |
1842 | 35.2k | return ok; |
1843 | 35.6k | } |
1844 | | |
1845 | | namespace QuattroDosSpreadsheetInternal |
1846 | | { |
1847 | | struct Functions |
1848 | | { |
1849 | | char const *m_name; |
1850 | | int m_arity; |
1851 | | }; |
1852 | | |
1853 | | static Functions const s_listFunctions[] = |
1854 | | { |
1855 | | { "", 0} /*SPEC: number*/, {"", 0}/*SPEC: cell*/, {"", 0}/*SPEC: cells*/, {"=", 1} /*SPEC: end of formula*/, |
1856 | | { "(", 1} /* SPEC: () */, {"", 0}/*SPEC: number*/, { "", -2} /*SPEC: text*/, {"", -2}/*unused*/, |
1857 | | { "-", 1}, {"+", 2}, {"-", 2}, {"*", 2}, |
1858 | | { "/", 2}, { "^", 2}, {"=", 2}, {"<>", 2}, |
1859 | | |
1860 | | { "<=", 2},{ ">=", 2},{ "<", 2},{ ">", 2}, |
1861 | | { "And", 2},{ "Or", 2}, { "Not", 1}, { "+", 1}, |
1862 | | { "&", 2}, { "", -2} /*unused*/,{ "", -2} /*unused*/,{ "", -2} /*unused*/, |
1863 | | { "", -2} /*unused*/,{ "", -2} /*unused*/,{ "", -2} /*unused*/,{ "NA", 0} /*checkme*/, |
1864 | | |
1865 | | { "NA", 0} /* Error*/,{ "Abs", 1},{ "Int", 1},{ "Sqrt", 1}, |
1866 | | { "Log10", 1},{ "Ln", 1},{ "Pi", 0},{ "Sin", 1}, |
1867 | | { "Cos", 1},{ "Tan", 1},{ "Atan2", 2},{ "Atan", 1}, |
1868 | | { "Asin", 1},{ "Acos", 1},{ "Exp", 1},{ "Mod", 2}, |
1869 | | |
1870 | | { "Choose", -1},{ "IsNa", 1},{ "IsError", 1},{ "False", 0}, |
1871 | | { "True", 0},{ "Rand", 0},{ "Date", 3},{ "Now", 0}, |
1872 | | { "PMT", 3} /*BAD*/,{ "PV", 3} /*BAD*/,{ "FV", 3} /*BAD*/,{ "IF", 3}, |
1873 | | { "Day", 1},{ "Month", 1},{ "Year", 1},{ "Round", 2}, |
1874 | | |
1875 | | { "Time", 3},{ "Hour", 1},{ "Minute", 1},{ "Second", 1}, |
1876 | | { "IsNumber", 1},{ "IsText", 1},{ "Len", 1},{ "Value", 1}, |
1877 | | { "Fixed", 2}, { "Mid", 3}, { "Char", 1},{ "Ascii", 1}, |
1878 | | { "Find", 3},{ "DateValue", 1} /*checkme*/,{ "TimeValue", 1} /*checkme*/,{ "CellPointer", 1} /*checkme*/, |
1879 | | |
1880 | | { "Sum", -1},{ "Average", -1},{ "COUNT", -1},{ "Min", -1}, |
1881 | | { "Max", -1},{ "VLookUp", 3},{ "NPV", 2}, { "Var", -1}, |
1882 | | { "StDev", -1},{ "IRR", 2} /*BAD*/, { "HLookUp", 3},{ "DSum", 3}, |
1883 | | { "DAvg", 3},{ "DCount", 3},{ "DMin", 3},{ "DMax", 3}, |
1884 | | |
1885 | | { "DVar", 3},{ "DStd", 3},{ "Index", 3}, { "Columns", 1}, |
1886 | | { "Rows", 1},{ "Rept", 2},{ "Upper", 1},{ "Lower", 1}, |
1887 | | { "Left", 2},{ "Right", 2},{ "Replace", 4}, { "Proper", 1}, |
1888 | | { "Cell", 1} /*checkme*/,{ "Trim", 1},{ "Clean", 1} /*UNKN*/,{ "T", 1}, |
1889 | | |
1890 | | { "IsNonText", 1},{ "Exact", 2},{ "", -2} /*UNKN*/,{ "Indirect", 1}, |
1891 | | { "RRI", 3}, { "TERM", 3}, { "CTERM", 3}, { "SLN", 3}, |
1892 | | { "SYD", 4},{ "DDB", 4}, { "StDevP", -1}, { "VarP", -1}, |
1893 | | { "DBStdDevP", -1}, { "DBVarP", -1}, { "PV", 3}, { "PMT", 5}, |
1894 | | |
1895 | | { "FV", 3}, { "Nper", 5}, { "Rate", 5}, { "Ipmt", 4}, |
1896 | | { "Ppmt", 6}, { "SumProduct", 2}, { "", -2} /*UNKN*/,{ "", -2} /*UNKN*/, |
1897 | | { "", -2} /*UNKN*/,{ "", -2} /*UNKN*/,{ "", -2} /*UNKN*/,{ "", -2} /*UNKN*/, |
1898 | | { "", -2} /*UNKN*/,{ "And", -1},{ "Or", -1},{ "Not", 1}, |
1899 | | |
1900 | | }; |
1901 | | } |
1902 | | |
1903 | | bool QuattroDosSpreadsheet::readFormula(long endPos, Vec2i const &position, int sheetId, |
1904 | | std::vector<WKSContentListener::FormulaInstruction> &formula, std::string &error) |
1905 | 33.4k | { |
1906 | 33.4k | int const vers=version(); |
1907 | 33.4k | formula.resize(0); |
1908 | 33.4k | error = ""; |
1909 | 33.4k | long pos = m_input->tell(); |
1910 | 33.4k | if (endPos - pos < (vers==1 ? 6 : 4)) return false; |
1911 | 32.6k | auto sz = int(libwps::readU16(m_input)); |
1912 | 32.6k | if (endPos-pos-2 != sz) return false; |
1913 | | |
1914 | 23.3k | std::vector<WKSContentListener::FormulaInstruction> listCellsPos; |
1915 | 23.3k | int fieldPos[2]= {0,sz}; |
1916 | 23.3k | for (int &i : fieldPos) |
1917 | 34.0k | { |
1918 | 34.0k | i= int(libwps::readU16(m_input)); |
1919 | 34.0k | if (vers>1) break; |
1920 | 34.0k | } |
1921 | 23.3k | if (fieldPos[0]<0||fieldPos[0]>fieldPos[1]||fieldPos[1]>sz) |
1922 | 2.48k | { |
1923 | 2.48k | WPS_DEBUG_MSG(("QuattroDosSpreadsheet::readFormula: can not find the field header\n")); |
1924 | 2.48k | error="###fieldPos"; |
1925 | 2.48k | return false; |
1926 | 2.48k | } |
1927 | 20.8k | int NSingle=0; |
1928 | 20.8k | if (fieldPos[0]!=sz) |
1929 | 11.9k | { |
1930 | 11.9k | m_input->seek(pos+2+fieldPos[0], librevenge::RVNG_SEEK_SET); |
1931 | 11.9k | ascii().addDelimiter(pos+2+fieldPos[0],'|'); |
1932 | 11.9k | if (vers==1) |
1933 | 8.44k | { |
1934 | 8.44k | int N=int(sz-fieldPos[0])/4; |
1935 | 8.44k | NSingle=int(fieldPos[1]-fieldPos[0])/4; |
1936 | 35.1k | for (int i=0; i<N; ++i) |
1937 | 29.2k | { |
1938 | 29.2k | WKSContentListener::FormulaInstruction cell; |
1939 | 29.2k | if (!readCell(position, cell)) |
1940 | 2.52k | { |
1941 | 2.52k | ascii().addDelimiter(pos+2+fieldPos[0]+i*4,'@'); |
1942 | 2.52k | WPS_DEBUG_MSG(("QuattroDosSpreadsheet::readFormula: can not read some cell\n")); |
1943 | 2.52k | error="###cell,"; |
1944 | 2.52k | break; |
1945 | 2.52k | } |
1946 | 26.6k | listCellsPos.push_back(cell); |
1947 | 26.6k | } |
1948 | 8.44k | } |
1949 | 3.50k | else |
1950 | 3.50k | { |
1951 | 7.95k | while (!m_input->isEnd()) |
1952 | 7.93k | { |
1953 | 7.93k | long actPos=m_input->tell(); |
1954 | 7.93k | if (actPos+8>endPos) break; |
1955 | 6.73k | auto type=int(libwps::readU16(m_input)); |
1956 | 6.73k | WKSContentListener::FormulaInstruction cell, cell2; |
1957 | 6.73k | if (type==0) |
1958 | 5.23k | { |
1959 | 5.23k | if (!readCell(position, cell, true, sheetId)) |
1960 | 931 | { |
1961 | 931 | m_input->seek(actPos, librevenge::RVNG_SEEK_SET); |
1962 | 931 | break; |
1963 | 931 | } |
1964 | 4.30k | listCellsPos.push_back(cell); |
1965 | 4.30k | continue; |
1966 | 5.23k | } |
1967 | 1.49k | if (type!=0x1000 || actPos+14>endPos || !readCell(position, cell, true, sheetId) || |
1968 | 515 | !readCell(position, cell2, true, sheetId)) |
1969 | 1.35k | { |
1970 | 1.35k | m_input->seek(actPos, librevenge::RVNG_SEEK_SET); |
1971 | 1.35k | break; |
1972 | 1.35k | } |
1973 | 140 | cell.m_type=WKSContentListener::FormulaInstruction::F_CellList; |
1974 | 140 | cell.m_position[1]=cell2.m_position[0]; |
1975 | 140 | cell.m_positionRelative[1]=cell2.m_positionRelative[0]; |
1976 | 140 | cell.m_sheetId[1]=cell2.m_sheetId[0]; |
1977 | 140 | listCellsPos.push_back(cell); |
1978 | 140 | } |
1979 | 3.50k | if (m_input->tell() !=endPos) |
1980 | 3.21k | { |
1981 | 3.21k | ascii().addDelimiter(m_input->tell(),'@'); |
1982 | 3.21k | WPS_DEBUG_MSG(("QuattroDosSpreadsheet::readFormula: can not read some cell\n")); |
1983 | 3.21k | error="###cell,"; |
1984 | 3.21k | } |
1985 | 3.50k | } |
1986 | 11.9k | m_input->seek(pos+4+(vers==1 ? 2 : 0), librevenge::RVNG_SEEK_SET); |
1987 | 11.9k | endPos=pos+2+fieldPos[0]; |
1988 | 11.9k | } |
1989 | 20.8k | std::stringstream f; |
1990 | 20.8k | std::vector<std::vector<WKSContentListener::FormulaInstruction> > stack; |
1991 | 20.8k | bool ok = true; |
1992 | 20.8k | size_t actCellId=0, actDualCellId=size_t(NSingle); |
1993 | 53.3k | while (long(m_input->tell()) != endPos) |
1994 | 52.6k | { |
1995 | 52.6k | long double val; |
1996 | 52.6k | bool isNaN; |
1997 | 52.6k | pos = m_input->tell(); |
1998 | 52.6k | if (pos > endPos) return false; |
1999 | 42.9k | auto wh = int(libwps::readU8(m_input)); |
2000 | 42.9k | int arity = 0; |
2001 | 42.9k | WKSContentListener::FormulaInstruction instr; |
2002 | 42.9k | switch (wh) |
2003 | 42.9k | { |
2004 | 8.99k | case 0x0: |
2005 | 8.99k | if (endPos-pos<9 || !libwps::readDouble8(m_input, val, isNaN)) |
2006 | 3.13k | { |
2007 | 3.13k | f.str(""); |
2008 | 3.13k | f << "###number"; |
2009 | 3.13k | error=f.str(); |
2010 | 3.13k | ok = false; |
2011 | 3.13k | break; |
2012 | 3.13k | } |
2013 | 5.86k | instr.m_type=WKSContentListener::FormulaInstruction::F_Double; |
2014 | 5.86k | instr.m_doubleValue=val; |
2015 | 5.86k | break; |
2016 | 778 | case 0x1: |
2017 | 778 | if (actCellId>=listCellsPos.size()) |
2018 | 149 | { |
2019 | 149 | f.str(""); |
2020 | 149 | f << "###unknCell" << actCellId; |
2021 | 149 | error=f.str(); |
2022 | 149 | ok = false; |
2023 | 149 | break; |
2024 | 149 | } |
2025 | 629 | instr=listCellsPos[actCellId++]; |
2026 | 629 | break; |
2027 | 2.50k | case 0x2: |
2028 | 2.50k | if (vers>=2) |
2029 | 2.36k | { |
2030 | 2.36k | if (actCellId>=listCellsPos.size()) |
2031 | 2.14k | { |
2032 | 2.14k | f.str(""); |
2033 | 2.14k | f << "###unknListCell" << actCellId; |
2034 | 2.14k | error=f.str(); |
2035 | 2.14k | ok = false; |
2036 | 2.14k | break; |
2037 | 2.14k | } |
2038 | 213 | instr=listCellsPos[actCellId++]; |
2039 | 213 | break; |
2040 | 2.36k | } |
2041 | 138 | if (actDualCellId+1>=listCellsPos.size()) |
2042 | 39 | { |
2043 | 39 | f.str(""); |
2044 | 39 | f << "###unknListCell" << actDualCellId; |
2045 | 39 | error=f.str(); |
2046 | 39 | ok = false; |
2047 | 39 | break; |
2048 | 39 | } |
2049 | 99 | instr=listCellsPos[actDualCellId++]; |
2050 | 99 | instr.m_type=WKSContentListener::FormulaInstruction::F_CellList; |
2051 | 99 | instr.m_position[1]=listCellsPos[actDualCellId].m_position[0]; |
2052 | 99 | instr.m_positionRelative[1]=listCellsPos[actDualCellId].m_positionRelative[0]; |
2053 | 99 | ++actDualCellId; |
2054 | 99 | break; |
2055 | 1.35k | case 0x5: |
2056 | 1.35k | instr.m_type=WKSContentListener::FormulaInstruction::F_Long; |
2057 | 1.35k | instr.m_longValue=long(libwps::read16(m_input)); |
2058 | 1.35k | break; |
2059 | 677 | case 0x6: |
2060 | 677 | instr.m_type=WKSContentListener::FormulaInstruction::F_Text; |
2061 | 8.40k | while (!m_input->isEnd()) |
2062 | 8.39k | { |
2063 | 8.39k | if (m_input->tell() >= endPos) |
2064 | 66 | { |
2065 | 66 | ok=false; |
2066 | 66 | break; |
2067 | 66 | } |
2068 | 8.33k | auto c = char(libwps::readU8(m_input)); |
2069 | 8.33k | if (c==0) break; |
2070 | 7.73k | instr.m_content += c; |
2071 | 7.73k | } |
2072 | 677 | break; |
2073 | 28.6k | default: |
2074 | 28.6k | if (wh >= 0x90 || QuattroDosSpreadsheetInternal::s_listFunctions[wh].m_arity == -2) |
2075 | 3.98k | { |
2076 | 3.98k | f.str(""); |
2077 | 3.98k | f << "##Funct" << std::hex << wh; |
2078 | 3.98k | error=f.str(); |
2079 | 3.98k | ok = false; |
2080 | 3.98k | break; |
2081 | 3.98k | } |
2082 | 24.6k | instr.m_type=WKSContentListener::FormulaInstruction::F_Function; |
2083 | 24.6k | instr.m_content=QuattroDosSpreadsheetInternal::s_listFunctions[wh].m_name; |
2084 | 24.6k | ok=!instr.m_content.empty(); |
2085 | 24.6k | arity = QuattroDosSpreadsheetInternal::s_listFunctions[wh].m_arity; |
2086 | 24.6k | if (arity == -1) arity = int(libwps::read8(m_input)); |
2087 | 24.6k | break; |
2088 | 42.9k | } |
2089 | | |
2090 | 42.9k | if (!ok) break; |
2091 | 33.4k | std::vector<WKSContentListener::FormulaInstruction> child; |
2092 | 33.4k | if (instr.m_type!=WKSContentListener::FormulaInstruction::F_Function) |
2093 | 8.76k | { |
2094 | 8.76k | child.push_back(instr); |
2095 | 8.76k | stack.push_back(child); |
2096 | 8.76k | continue; |
2097 | 8.76k | } |
2098 | 24.6k | size_t numElt = stack.size(); |
2099 | 24.6k | if (int(numElt) < arity) |
2100 | 374 | { |
2101 | 374 | f.str(""); |
2102 | 374 | f << instr.m_content << "[##" << arity << "]"; |
2103 | 374 | error=f.str(); |
2104 | 374 | ok = false; |
2105 | 374 | break; |
2106 | 374 | } |
2107 | | // |
2108 | | // first treat the special cases |
2109 | | // |
2110 | 24.2k | if (arity==3 && instr.m_type==WKSContentListener::FormulaInstruction::F_Function && instr.m_content=="TERM") |
2111 | 1.23k | { |
2112 | | // @TERM(pmt,pint,fv) -> NPER(pint,-pmt,pv=0,fv) |
2113 | 1.23k | stack.resize(size_t(++numElt)); |
2114 | 1.23k | std::swap(stack[size_t(int(numElt)-4)],stack[size_t(int(numElt)-3)]); |
2115 | 1.23k | std::swap(stack[size_t(int(numElt)-2)],stack[size_t(int(numElt)-1)]); // @TERM(pint,pmt,,fv) |
2116 | | // pv=0 |
2117 | 1.23k | instr.m_type=WKSContentListener::FormulaInstruction::F_Long; |
2118 | 1.23k | instr.m_longValue=0; |
2119 | 1.23k | stack[size_t(int(numElt)-2)].push_back(instr); // @TERM(pint,pmt,0,fv) |
2120 | | /// -pmt |
2121 | 1.23k | auto &pmt=stack[size_t(int(numElt)-3)]; |
2122 | 1.23k | WKSContentListener::FormulaInstruction::enclose(pmt,false); |
2123 | 1.23k | instr.m_type=WKSContentListener::FormulaInstruction::F_Operator; |
2124 | 1.23k | instr.m_content="-"; |
2125 | 1.23k | pmt.insert(pmt.begin(), instr); // @TERM(pint,-pmt,0,fv) |
2126 | | |
2127 | 1.23k | arity=4; |
2128 | 1.23k | instr.m_type=WKSContentListener::FormulaInstruction::F_Function; |
2129 | 1.23k | instr.m_content="NPER"; |
2130 | 1.23k | } |
2131 | 23.0k | else if (arity==3 && instr.m_type==WKSContentListener::FormulaInstruction::F_Function && instr.m_content=="CTERM") |
2132 | 1.50k | { |
2133 | | // @CTERM(pint,fv,pv) -> NPER(pint,pmt=0,-pv,fv) |
2134 | 1.50k | stack.resize(size_t(++numElt)); |
2135 | 1.50k | std::swap(stack[size_t(int(numElt)-1)],stack[size_t(int(numElt)-3)]); // @CTERM(pint,,pv,fv) |
2136 | | // pmt=0 |
2137 | 1.50k | instr.m_type=WKSContentListener::FormulaInstruction::F_Long; |
2138 | 1.50k | instr.m_longValue=0; |
2139 | 1.50k | stack[size_t(int(numElt)-3)].push_back(instr); // @CTERM(pint,0,pv,fv) |
2140 | | // -pv |
2141 | 1.50k | auto &pv=stack[size_t(int(numElt)-2)]; |
2142 | 1.50k | WKSContentListener::FormulaInstruction::enclose(pv,false); |
2143 | 1.50k | instr.m_type=WKSContentListener::FormulaInstruction::F_Operator; |
2144 | 1.50k | instr.m_content="-"; |
2145 | 1.50k | pv.insert(pv.begin(), instr); // @CTERM(pint,0,-pv,fv) |
2146 | | |
2147 | 1.50k | arity=4; |
2148 | 1.50k | instr.m_type=WKSContentListener::FormulaInstruction::F_Function; |
2149 | 1.50k | instr.m_content="NPER"; |
2150 | 1.50k | } |
2151 | 21.5k | else if (arity==3 && instr.m_type==WKSContentListener::FormulaInstruction::F_Function && (instr.m_content=="VLookUp" || instr.m_content=="HLookUp")) |
2152 | 992 | WKSContentListener::FormulaInstruction::add(stack[size_t(int(numElt)-1)],1); |
2153 | | |
2154 | 24.2k | if ((instr.m_content[0] >= 'A' && instr.m_content[0] <= 'Z') || instr.m_content[0] == '(') |
2155 | 19.4k | { |
2156 | 19.4k | if (instr.m_content[0] != '(') |
2157 | 18.2k | child.push_back(instr); |
2158 | | |
2159 | 19.4k | instr.m_type=WKSContentListener::FormulaInstruction::F_Operator; |
2160 | 19.4k | instr.m_content="("; |
2161 | 19.4k | child.push_back(instr); |
2162 | 65.2k | for (int i = 0; i < arity; i++) |
2163 | 45.7k | { |
2164 | 45.7k | if (i) |
2165 | 31.7k | { |
2166 | 31.7k | instr.m_content=";"; |
2167 | 31.7k | child.push_back(instr); |
2168 | 31.7k | } |
2169 | 45.7k | auto const &node=stack[size_t(int(numElt)-arity+i)]; |
2170 | 45.7k | child.insert(child.end(), node.begin(), node.end()); |
2171 | 45.7k | } |
2172 | 19.4k | instr.m_content=")"; |
2173 | 19.4k | child.push_back(instr); |
2174 | | |
2175 | 19.4k | stack.resize(size_t(int(numElt)-arity+1)); |
2176 | 19.4k | stack[size_t(int(numElt)-arity)] = child; |
2177 | 19.4k | continue; |
2178 | 19.4k | } |
2179 | 4.82k | if (arity==1) |
2180 | 2.22k | { |
2181 | 2.22k | instr.m_type=WKSContentListener::FormulaInstruction::F_Operator; |
2182 | 2.22k | stack[numElt-1].insert(stack[numElt-1].begin(), instr); |
2183 | 2.22k | if (wh==3) |
2184 | 533 | break; |
2185 | 1.68k | continue; |
2186 | 2.22k | } |
2187 | 2.59k | if (arity==2) |
2188 | 2.59k | { |
2189 | 2.59k | instr.m_type=WKSContentListener::FormulaInstruction::F_Operator; |
2190 | 2.59k | stack[numElt-2].push_back(instr); |
2191 | 2.59k | stack[numElt-2].insert(stack[numElt-2].end(), stack[numElt-1].begin(), stack[numElt-1].end()); |
2192 | 2.59k | stack.resize(numElt-1); |
2193 | 2.59k | continue; |
2194 | 2.59k | } |
2195 | 0 | ok=false; |
2196 | 0 | error = "### unexpected arity"; |
2197 | 0 | break; |
2198 | 2.59k | } |
2199 | | |
2200 | 11.1k | if (!ok) ; |
2201 | 1.24k | else if (stack.size()==1 && stack[0].size()>1 && stack[0][0].m_content=="=") |
2202 | 518 | { |
2203 | 518 | formula.insert(formula.begin(),stack[0].begin()+1,stack[0].end()); |
2204 | 518 | if (m_input->tell()!=endPos) |
2205 | 309 | { |
2206 | 309 | WPS_DEBUG_MSG(("QuattroDosSpreadsheet::readFormula: find some extra data\n")); |
2207 | 309 | error="##extra data"; |
2208 | 309 | ascii().addDelimiter(m_input->tell(),'#'); |
2209 | 309 | } |
2210 | 518 | return true; |
2211 | 518 | } |
2212 | 728 | else |
2213 | 728 | error = "###stack problem"; |
2214 | | |
2215 | 10.6k | static bool first = true; |
2216 | 10.6k | if (first) |
2217 | 4 | { |
2218 | 4 | WPS_DEBUG_MSG(("QuattroDosSpreadsheet::readFormula: I can not read some formula\n")); |
2219 | 4 | first = false; |
2220 | 4 | } |
2221 | | |
2222 | 10.6k | f.str(""); |
2223 | 10.6k | for (auto const &i : stack) |
2224 | 228k | { |
2225 | 228k | for (auto const &j : i) |
2226 | 106k | f << j << ","; |
2227 | 228k | } |
2228 | 10.6k | f << error << "###"; |
2229 | 10.6k | error = f.str(); |
2230 | 10.6k | return false; |
2231 | 11.1k | } |
2232 | | |
2233 | | //////////////////////////////////////////////////////////// |
2234 | | // send data |
2235 | | //////////////////////////////////////////////////////////// |
2236 | | void QuattroDosSpreadsheet::sendSpreadsheet(int sId, std::map<Vec2i, Vec2i> const &chartPosMap) |
2237 | 66.1k | { |
2238 | 66.1k | if (!m_listener) |
2239 | 0 | { |
2240 | 0 | WPS_DEBUG_MSG(("QuattroDosSpreadsheet::sendSpreadsheet: I can not find the listener\n")); |
2241 | 0 | return; |
2242 | 0 | } |
2243 | 66.1k | auto sheet = m_state->getSheet(QuattroDosSpreadsheetInternal::Spreadsheet::T_Spreadsheet, sId); |
2244 | 66.1k | if (!sheet) |
2245 | 59.9k | { |
2246 | 59.9k | if (sId==0) |
2247 | 0 | { |
2248 | 0 | WPS_DEBUG_MSG(("QuattroDosSpreadsheet::sendSpreadsheet: oops can not find the actual sheet\n")); |
2249 | 0 | } |
2250 | 59.9k | sheet.reset(new QuattroDosSpreadsheetInternal::Spreadsheet); |
2251 | 59.9k | } |
2252 | 66.1k | sheet->insertChartPositions(chartPosMap, m_mainParser.getDefaultFontType()); |
2253 | 66.1k | m_listener->openSheet(sheet->getWidths(), m_state->getSheetName(sId)); |
2254 | 66.1k | sheet->compressRowHeights(); |
2255 | 66.1k | auto it = sheet->m_positionToCellMap.begin(); |
2256 | 66.1k | int prevRow = -1; |
2257 | 108k | while (it != sheet->m_positionToCellMap.end()) |
2258 | 41.9k | { |
2259 | 41.9k | int row=it->first[1]; |
2260 | 41.9k | auto const &cell=(it++)->second; |
2261 | 41.9k | if (row>prevRow+1) |
2262 | 10.2k | { |
2263 | 25.2k | while (row > prevRow+1) |
2264 | 14.9k | { |
2265 | 14.9k | if (prevRow != -1) m_listener->closeSheetRow(); |
2266 | 14.9k | int numRepeat; |
2267 | 14.9k | float h=sheet->getRowHeight(prevRow+1, numRepeat); |
2268 | 14.9k | if (row<prevRow+1+numRepeat) |
2269 | 10.2k | numRepeat=row-1-prevRow; |
2270 | 14.9k | m_listener->openSheetRow(WPSRowFormat(h), numRepeat); |
2271 | 14.9k | prevRow+=numRepeat; |
2272 | 14.9k | } |
2273 | 10.2k | } |
2274 | 41.9k | if (row!=prevRow) |
2275 | 17.3k | { |
2276 | 17.3k | if (prevRow != -1) m_listener->closeSheetRow(); |
2277 | 17.3k | m_listener->openSheetRow(WPSRowFormat(sheet->getRowHeight(++prevRow))); |
2278 | 17.3k | } |
2279 | 41.9k | auto cIt=chartPosMap.find(cell.position()); |
2280 | 41.9k | if (cIt==chartPosMap.end()) |
2281 | 38.8k | sendCellContent(cell, sId); |
2282 | 3.07k | else |
2283 | 3.07k | sendCellContent(cell, sId, sId, sheet->getZoneSize(cIt->first, cIt->second)); |
2284 | 41.9k | } |
2285 | 66.1k | if (prevRow!=-1) m_listener->closeSheetRow(); |
2286 | 66.1k | m_listener->closeSheet(); |
2287 | 66.1k | } |
2288 | | |
2289 | | void QuattroDosSpreadsheet::sendCellContent(QuattroDosSpreadsheetInternal::Cell const &cell, int sheetId, int cellChartSheetId, Vec2f const &chartSize) |
2290 | 41.9k | { |
2291 | 41.9k | if (m_listener.get() == nullptr) |
2292 | 0 | { |
2293 | 0 | WPS_DEBUG_MSG(("QuattroDosSpreadsheet::sendCellContent: I can not find the listener\n")); |
2294 | 0 | return; |
2295 | 0 | } |
2296 | | |
2297 | 41.9k | libwps_tools_win::Font::Type fontType = cell.m_fontType; |
2298 | 41.9k | m_listener->setFont(cell.getFont()); |
2299 | | |
2300 | 41.9k | QuattroDosSpreadsheetInternal::Cell finalCell(cell); |
2301 | 41.9k | auto &content=finalCell.m_content; |
2302 | 41.9k | for (auto &f : content.m_formula) |
2303 | 2.62k | { |
2304 | 2.62k | if (f.m_type==WKSContentListener::FormulaInstruction::F_Cell || |
2305 | 2.49k | f.m_type==WKSContentListener::FormulaInstruction::F_CellList) |
2306 | 170 | { |
2307 | 170 | int dim=f.m_type==WKSContentListener::FormulaInstruction::F_Cell ? 1 : 2; |
2308 | 375 | for (int i=0; i<dim; ++i) |
2309 | 205 | { |
2310 | 205 | if (f.m_sheetId[i]>=0 && f.m_sheetName[i].empty() && (f.m_sheetId[i]!=sheetId || !f.m_fileName.empty())) |
2311 | 87 | f.m_sheetName[i]=getSheetName(f.m_sheetId[i]); |
2312 | 205 | } |
2313 | 170 | continue; |
2314 | 170 | } |
2315 | 2.45k | if (f.m_type!=WKSContentListener::FormulaInstruction::F_Text) |
2316 | 2.37k | continue; |
2317 | 89 | std::string &text=f.m_content; |
2318 | 89 | auto finalText=libwps_tools_win::Font::unicodeString(text, fontType); |
2319 | 89 | if (finalText.empty()) |
2320 | 44 | text.clear(); |
2321 | 45 | else |
2322 | 45 | text=finalText.cstr(); |
2323 | 89 | } |
2324 | 41.9k | finalCell.updateFormat(); |
2325 | 41.9k | m_listener->openSheetCell(finalCell, content); |
2326 | | |
2327 | 41.9k | if (cell.m_content.m_textEntry.valid()) |
2328 | 11.3k | { |
2329 | 11.3k | m_input->seek(cell.m_content.m_textEntry.begin(), librevenge::RVNG_SEEK_SET); |
2330 | 11.3k | bool prevEOL=false; |
2331 | 11.3k | std::string text; |
2332 | 180k | while (m_input->tell()<=cell.m_content.m_textEntry.end()) |
2333 | 180k | { |
2334 | 180k | bool last=m_input->isEnd() || m_input->tell()>=cell.m_content.m_textEntry.end(); |
2335 | 180k | auto c=last ? '\0' : char(libwps::readU8(m_input)); |
2336 | 180k | if ((c==0 || c==0xa || c==0xd) && !text.empty()) |
2337 | 25.6k | { |
2338 | 25.6k | m_listener->insertUnicodeString(libwps_tools_win::Font::unicodeString(text, fontType)); |
2339 | 25.6k | text.clear(); |
2340 | 25.6k | } |
2341 | 180k | if (last) break; |
2342 | 168k | if (c==0xd) |
2343 | 1.40k | { |
2344 | 1.40k | m_listener->insertEOL(); |
2345 | 1.40k | prevEOL=true; |
2346 | 1.40k | } |
2347 | 167k | else if (c==0xa) |
2348 | 840 | { |
2349 | 840 | if (!prevEOL) |
2350 | 834 | { |
2351 | 834 | WPS_DEBUG_MSG(("QuattroDosSpreadsheet::sendCellContent: find 0xa without 0xd\n")); |
2352 | 834 | } |
2353 | 840 | prevEOL=false; |
2354 | 840 | } |
2355 | 166k | else |
2356 | 166k | { |
2357 | 166k | text.push_back(c); |
2358 | 166k | prevEOL=false; |
2359 | 166k | } |
2360 | 168k | } |
2361 | 11.3k | } |
2362 | 41.9k | if (cellChartSheetId>=0) |
2363 | 3.07k | m_mainParser.sendChart(cellChartSheetId, cell.position(), chartSize); |
2364 | 41.9k | m_listener->closeSheetCell(); |
2365 | 41.9k | } |
2366 | | |
2367 | | /* vim:set shiftwidth=4 softtabstop=4 noexpandtab: */ |