/src/libmwaw/src/lib/MsWksTable.cxx
Line | Count | Source |
1 | | /* -*- Mode: C++; c-default-style: "k&r"; indent-tabs-mode: nil; tab-width: 2; c-basic-offset: 2 -*- */ |
2 | | |
3 | | /* libmwaw |
4 | | * Version: MPL 2.0 / LGPLv2+ |
5 | | * |
6 | | * The contents of this file are subject to the Mozilla Public License Version |
7 | | * 2.0 (the "License"); you may not use this file except in compliance with |
8 | | * the License or as specified alternatively below. You may obtain a copy of |
9 | | * the License at http://www.mozilla.org/MPL/ |
10 | | * |
11 | | * Software distributed under the License is distributed on an "AS IS" basis, |
12 | | * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License |
13 | | * for the specific language governing rights and limitations under the |
14 | | * License. |
15 | | * |
16 | | * Major Contributor(s): |
17 | | * Copyright (C) 2002 William Lachance (wrlach@gmail.com) |
18 | | * Copyright (C) 2002,2004 Marc Maurer (uwog@uwog.net) |
19 | | * Copyright (C) 2004-2006 Fridrich Strba (fridrich.strba@bluewin.ch) |
20 | | * Copyright (C) 2006, 2007 Andrew Ziem |
21 | | * Copyright (C) 2011, 2012 Alonso Laurent (alonso@loria.fr) |
22 | | * |
23 | | * |
24 | | * All Rights Reserved. |
25 | | * |
26 | | * For minor contributions see the git repository. |
27 | | * |
28 | | * Alternatively, the contents of this file may be used under the terms of |
29 | | * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"), |
30 | | * in which case the provisions of the LGPLv2+ are applicable |
31 | | * instead of those above. |
32 | | */ |
33 | | |
34 | | #include <iomanip> |
35 | | #include <iostream> |
36 | | #include <map> |
37 | | #include <sstream> |
38 | | |
39 | | #include "libmwaw_internal.hxx" |
40 | | |
41 | | #include "MWAWCell.hxx" |
42 | | #include "MWAWListener.hxx" |
43 | | #include "MWAWFont.hxx" |
44 | | #include "MWAWFontConverter.hxx" |
45 | | #include "MWAWGraphicStyle.hxx" |
46 | | #include "MWAWParagraph.hxx" |
47 | | #include "MWAWPictData.hxx" |
48 | | #include "MWAWSubDocument.hxx" |
49 | | #include "MWAWTable.hxx" |
50 | | |
51 | | #include "MsWksGraph.hxx" |
52 | | #include "MsWksDocument.hxx" |
53 | | |
54 | | #include "MsWksTable.hxx" |
55 | | |
56 | | /** Internal: the structures of a MsWksTable */ |
57 | | namespace MsWksTableInternal |
58 | | { |
59 | | //////////////////////////////////////// |
60 | | //! Internal: the chart of a MsWksTable |
61 | | struct Chart { |
62 | | //! constructor |
63 | | explicit Chart(MsWksGraph::Style const &style) |
64 | 5.64M | : m_style(style) |
65 | 5.64M | , m_backgroundEntry() |
66 | 5.64M | , m_zoneId(-1) |
67 | 5.64M | { |
68 | 16.9M | for (auto &id : m_textZonesId) id=-1; |
69 | 5.64M | } |
70 | | //! empty constructor |
71 | | Chart() |
72 | 862 | : m_style() |
73 | 862 | , m_backgroundEntry() |
74 | 862 | , m_zoneId(-1) |
75 | 862 | { |
76 | 2.58k | for (auto &id : m_textZonesId) id=-1; |
77 | 862 | } |
78 | | |
79 | | //! the graphic style |
80 | | MWAWGraphicStyle m_style; |
81 | | //! the three text pictures |
82 | | int m_textZonesId[3]; |
83 | | //! the background entry |
84 | | MWAWEntry m_backgroundEntry; |
85 | | //! the chart zone id (in the graph parser ) |
86 | | int m_zoneId; |
87 | | }; |
88 | | |
89 | | |
90 | | //////////////////////////////////////// |
91 | | //! Internal: the table of a MsWksTable |
92 | | struct Table { |
93 | | //! the cell content |
94 | | struct Cell { |
95 | | Cell() |
96 | 37.0k | : m_pos(-1,-1) |
97 | 37.0k | , m_font() |
98 | 37.0k | , m_text("") |
99 | 37.0k | { |
100 | 37.0k | } |
101 | | //! the cell position |
102 | | MWAWVec2i m_pos; |
103 | | //! the font |
104 | | MWAWFont m_font; |
105 | | //! the text |
106 | | std::string m_text; |
107 | | }; |
108 | | //! constructor |
109 | | explicit Table(MsWksGraph::Style const &style) |
110 | 206k | : m_style(style) |
111 | 206k | , m_numRows(0) |
112 | 206k | , m_numCols(0) |
113 | 206k | , m_rowsDim() |
114 | 206k | , m_colsDim() |
115 | 206k | , m_font() |
116 | 206k | , m_cellsList() |
117 | 206k | { |
118 | 206k | m_style.m_surfaceColor = style.m_baseSurfaceColor; |
119 | 206k | } |
120 | | //! empty constructor |
121 | | Table() |
122 | 112k | : m_style() |
123 | 112k | , m_numRows(0) |
124 | 112k | , m_numCols(0) |
125 | 112k | , m_rowsDim() |
126 | 112k | , m_colsDim() |
127 | 112k | , m_font() |
128 | 112k | , m_cellsList() |
129 | 112k | { |
130 | 112k | } |
131 | | |
132 | | //! try to find a cell |
133 | | Cell const *getCell(MWAWVec2i const &pos) const |
134 | 0 | { |
135 | 0 | for (auto &cell : m_cellsList) { |
136 | 0 | if (cell.m_pos == pos) |
137 | 0 | return &cell; |
138 | 0 | } |
139 | 0 | return nullptr; |
140 | 0 | } |
141 | | |
142 | | //! the graphic style |
143 | | MWAWGraphicStyle m_style; |
144 | | int m_numRows /** the number of rows*/, m_numCols/** the number of columns*/; |
145 | | std::vector<int> m_rowsDim/**the rows dimensions*/, m_colsDim/*the columns dimensions*/; |
146 | | //! the default font |
147 | | MWAWFont m_font; |
148 | | //! the list of cell |
149 | | std::vector<Cell> m_cellsList; |
150 | | }; |
151 | | |
152 | | //////////////////////////////////////// |
153 | | //! Internal: the state of a MsWksTable |
154 | | struct State { |
155 | | //! constructor |
156 | | State() |
157 | 244k | : m_version(-1) |
158 | 244k | , m_idChartMap() |
159 | 244k | , m_idTableMap() |
160 | 244k | { |
161 | 244k | } |
162 | | |
163 | | //! the version |
164 | | int m_version; |
165 | | |
166 | | //! the map id->chart |
167 | | std::map<int, Chart> m_idChartMap; |
168 | | //! the map id->table |
169 | | std::map<int, Table> m_idTableMap; |
170 | | }; |
171 | | |
172 | | } |
173 | | |
174 | | //////////////////////////////////////////////////////////// |
175 | | // constructor/destructor, ... |
176 | | //////////////////////////////////////////////////////////// |
177 | | MsWksTable::MsWksTable(MWAWParser &parser, MsWksDocument &zone, MsWksGraph &graph) |
178 | 244k | : m_parserState(parser.getParserState()) |
179 | 244k | , m_state(new MsWksTableInternal::State) |
180 | 244k | , m_mainParser(&parser) |
181 | 244k | , m_graphParser(&graph) |
182 | 244k | , m_zone(zone) |
183 | 244k | { |
184 | 244k | } |
185 | | |
186 | | MsWksTable::~MsWksTable() |
187 | 244k | { } |
188 | | |
189 | | int MsWksTable::version() const |
190 | 6.61M | { |
191 | 6.61M | if (m_state->m_version < 0) |
192 | 3.03k | m_state->m_version = m_parserState->m_version; |
193 | 6.61M | return m_state->m_version; |
194 | 6.61M | } |
195 | | |
196 | | //////////////////////////////////////////////////////////// |
197 | | // table |
198 | | //////////////////////////////////////////////////////////// |
199 | | bool MsWksTable::sendTable(int zoneId) |
200 | 4.47k | { |
201 | 4.47k | MWAWListenerPtr listener=m_parserState->getMainListener(); |
202 | 4.47k | if (!listener) return false; |
203 | | |
204 | 4.47k | if (m_state->m_idTableMap.find(zoneId)==m_state->m_idTableMap.end()) { |
205 | 0 | MWAW_DEBUG_MSG(("MsWksTable::sendTable: can not find textbox %d\n", zoneId)); |
206 | 0 | return false; |
207 | 0 | } |
208 | 4.47k | if (m_parserState->m_type==MWAWParserState::Spreadsheet) { |
209 | | /* inserting a table may cause problem when there happens in some |
210 | | ods file, so... */ |
211 | 3 | MWAW_DEBUG_MSG(("MsWksTable::sendTable: inserting a table in a spreadsheet is not implemented\n")); |
212 | 3 | return false; |
213 | 3 | } |
214 | | |
215 | 4.47k | auto &table = m_state->m_idTableMap.find(zoneId)->second; |
216 | | |
217 | | // open the table |
218 | 4.47k | size_t nCols = table.m_colsDim.size(); |
219 | 4.47k | size_t nRows = table.m_rowsDim.size(); |
220 | 4.47k | if (!nCols || !nRows) { |
221 | 4.47k | MWAW_DEBUG_MSG(("MsWksTable::sendTable: problem with dimensions\n")); |
222 | 4.47k | return false; |
223 | 4.47k | } |
224 | 0 | std::vector<float> colsDims(nCols); |
225 | 0 | for (size_t c = 0; c < nCols; c++) colsDims[c] = float(table.m_colsDim[c]); |
226 | 0 | MWAWTable theTable(MWAWTable::TableDimBit); |
227 | 0 | theTable.setColsSize(colsDims); |
228 | 0 | listener->openTable(theTable); |
229 | |
|
230 | 0 | int const borderPos = libmwaw::TopBit | libmwaw::RightBit | |
231 | 0 | libmwaw::BottomBit | libmwaw::LeftBit; |
232 | 0 | MWAWBorder border, internBorder; |
233 | 0 | internBorder.m_width=0.5; |
234 | 0 | internBorder.m_color=MWAWColor(0xC0,0xC0,0xC0); |
235 | 0 | MWAWParagraph para; |
236 | 0 | para.m_justify=MWAWParagraph::JustificationCenter; |
237 | 0 | for (size_t row = 0; row < nRows; row++) { |
238 | 0 | listener->openTableRow(float(table.m_rowsDim[row]), librevenge::RVNG_POINT); |
239 | |
|
240 | 0 | for (size_t col = 0; col < nCols; col++) { |
241 | 0 | MWAWCell cell; |
242 | 0 | MWAWVec2i cellPosition(MWAWVec2i(static_cast<int>(col),static_cast<int>(row))); |
243 | 0 | cell.setPosition(cellPosition); |
244 | 0 | cell.setBorders(borderPos, border); |
245 | 0 | int internWhat=0; |
246 | 0 | if (col!=0) internWhat|=libmwaw::LeftBit; |
247 | 0 | if (col+1!=nCols) internWhat|=libmwaw::RightBit; |
248 | 0 | if (row!=0) internWhat|=libmwaw::TopBit; |
249 | 0 | if (row+1!=nRows) internWhat|=libmwaw::BottomBit; |
250 | 0 | cell.setBorders(internWhat, internBorder); |
251 | 0 | if (!table.m_style.m_surfaceColor.isWhite()) |
252 | 0 | cell.setBackgroundColor(table.m_style.m_surfaceColor); |
253 | 0 | listener->openTableCell(cell); |
254 | 0 | listener->setParagraph(para); |
255 | |
|
256 | 0 | auto const *tCell=table.getCell(cellPosition); |
257 | 0 | if (tCell) { |
258 | 0 | listener->setFont(tCell->m_font); |
259 | 0 | size_t nChar = tCell->m_text.size(); |
260 | 0 | for (size_t ch = 0; ch < nChar; ch++) { |
261 | 0 | auto c = static_cast<unsigned char>(tCell->m_text[ch]); |
262 | 0 | switch (c) { |
263 | 0 | case 0x9: |
264 | 0 | MWAW_DEBUG_MSG(("MsWksTable::sendTable: find a tab\n")); |
265 | 0 | listener->insertChar(' '); |
266 | 0 | break; |
267 | 0 | case 0xd: |
268 | 0 | listener->insertEOL(); |
269 | 0 | break; |
270 | 0 | default: |
271 | 0 | listener->insertCharacter(c); |
272 | 0 | break; |
273 | 0 | } |
274 | 0 | } |
275 | 0 | } |
276 | | |
277 | 0 | listener->closeTableCell(); |
278 | 0 | } |
279 | 0 | listener->closeTableRow(); |
280 | 0 | } |
281 | | |
282 | | // close the table |
283 | 0 | listener->closeTable(); |
284 | 0 | return true; |
285 | 0 | } |
286 | | |
287 | | bool MsWksTable::readTable(int numCol, int numRow, int zoneId, MsWksGraph::Style const &style) |
288 | 206k | { |
289 | 206k | int vers=version(); |
290 | 206k | MWAWInputStreamPtr input=m_zone.getInput(); |
291 | 206k | long actPos = input->tell(); |
292 | 206k | libmwaw::DebugFile &ascFile = m_zone.ascii(); |
293 | 206k | libmwaw::DebugStream f, f2; |
294 | 206k | f << "Entries(Table): "; |
295 | | |
296 | 206k | MsWksTableInternal::Table table(style); |
297 | 206k | table.m_numRows=numRow; |
298 | 206k | table.m_numCols=numCol; |
299 | | // first we read the dim |
300 | 543k | for (int i = 0; i < 2; i++) { |
301 | 393k | auto &dim = i==0 ? table.m_rowsDim : table.m_colsDim; |
302 | 393k | dim.resize(0); |
303 | 393k | auto sz = static_cast<int>(input->readLong(4)); |
304 | 393k | if (i == 0 && sz != 2*table.m_numRows) return false; |
305 | 374k | if (i == 1 && sz != 2*table.m_numCols) return false; |
306 | | |
307 | 340k | if (i == 0) f << "rowS=("; |
308 | 152k | else f << "colS=("; |
309 | | |
310 | 410k | for (int j = 0; j < sz/2; j++) { |
311 | 73.5k | auto val = static_cast<int>(input->readLong(2)); |
312 | | |
313 | 73.5k | if (val < -10) return false; |
314 | | |
315 | 70.4k | dim.push_back(val); |
316 | 70.4k | f << val << ","; |
317 | 70.4k | } |
318 | 336k | f << "), "; |
319 | 336k | } |
320 | | |
321 | 149k | long sz = input->readLong(4); |
322 | 149k | f << "szOfCells=" << sz; |
323 | 149k | ascFile.addPos(actPos); |
324 | 149k | ascFile.addNote(f.str().c_str()); |
325 | | |
326 | 149k | actPos = input->tell(); |
327 | 149k | long endPos = actPos+sz; |
328 | | // now we read the data for each size |
329 | 149k | while (input->tell() != endPos) { |
330 | 37.0k | f.str(""); |
331 | 37.0k | actPos = input->tell(); |
332 | 37.0k | MsWksTableInternal::Table::Cell cell; |
333 | 37.0k | auto y = static_cast<int>(input->readLong(2)); |
334 | 37.0k | auto x = static_cast<int>(input->readLong(2)); |
335 | 37.0k | cell.m_pos = MWAWVec2i(x,y); |
336 | 37.0k | if (x < 0 || y < 0 || |
337 | 37.0k | x >= table.m_numCols || y >= table.m_numRows) return false; |
338 | | |
339 | 0 | f << "Table:("<< cell.m_pos << "):"; |
340 | 0 | auto nbChar = static_cast<int>(input->readLong(1)); |
341 | 0 | if (nbChar < 0 || actPos+5+nbChar > endPos) return false; |
342 | | |
343 | 0 | std::string fName(""); |
344 | 0 | for (int c = 0; c < nbChar; c++) |
345 | 0 | fName +=char(input->readLong(1)); |
346 | |
|
347 | 0 | input->seek(actPos+34, librevenge::RVNG_SEEK_SET); |
348 | 0 | f << std::hex << "unk=" << input->readLong(2) << ", "; // 0|827 |
349 | 0 | auto v = static_cast<int>(input->readLong(2)); |
350 | 0 | if (v) f << "f0=" << v << ", "; |
351 | 0 | auto fSize = static_cast<int>(input->readLong(2)); |
352 | 0 | v = static_cast<int>(input->readLong(2)); |
353 | 0 | if (v) f2 << "unkn0=" << v << ", "; |
354 | 0 | auto fFlags = static_cast<int>(input->readLong(2)); |
355 | |
|
356 | 0 | nbChar = static_cast<int>(input->readLong(4)); |
357 | 0 | if (nbChar <= 0 || input->tell()+nbChar > endPos) return false; |
358 | | |
359 | 0 | v = static_cast<int>(input->readLong(2)); |
360 | 0 | if (v) f << "f1=" << v << ", "; |
361 | 0 | auto fColors = static_cast<int>(input->readLong(2)); |
362 | 0 | v = static_cast<int>(input->readLong(2)); |
363 | 0 | if (v) f << "f2=" << v << ", "; |
364 | 0 | auto bgColors = static_cast<int>(input->readLong(2)); |
365 | 0 | if (bgColors) |
366 | 0 | f2 << std::dec << "bgColorId(?)=" << bgColors << ", "; // indexed |
367 | |
|
368 | 0 | cell.m_font=MWAWFont(m_parserState->m_fontConverter->getId(fName), float(fSize)); |
369 | 0 | uint32_t flags = 0; |
370 | 0 | if (fFlags & 0x1) flags |= MWAWFont::boldBit; |
371 | 0 | if (fFlags & 0x2) flags |= MWAWFont::italicBit; |
372 | 0 | if (fFlags & 0x4) cell.m_font.setUnderlineStyle(MWAWFont::Line::Simple); |
373 | 0 | if (fFlags & 0x8) flags |= MWAWFont::embossBit; |
374 | 0 | if (fFlags & 0x10) flags |= MWAWFont::shadowBit; |
375 | 0 | if (fFlags & 0x20) { |
376 | 0 | if (vers==1) |
377 | 0 | cell.m_font.set(MWAWFont::Script(20,librevenge::RVNG_PERCENT,80)); |
378 | 0 | else |
379 | 0 | cell.m_font.set(MWAWFont::Script::super100()); |
380 | 0 | } |
381 | 0 | if (fFlags & 0x40) { |
382 | 0 | if (vers==1) |
383 | 0 | cell.m_font.set(MWAWFont::Script(-20,librevenge::RVNG_PERCENT,80)); |
384 | 0 | else |
385 | 0 | cell.m_font.set(MWAWFont::Script::sub100()); |
386 | 0 | } |
387 | 0 | cell.m_font.setFlags(flags); |
388 | |
|
389 | 0 | if (fColors != 0xFF) { |
390 | 0 | MWAWColor col; |
391 | 0 | if (m_zone.getColor(fColors,col,3)) |
392 | 0 | cell.m_font.setColor(col); |
393 | 0 | else |
394 | 0 | f << "#colId=" << fColors << ","; |
395 | 0 | } |
396 | 0 | f << "[" << cell.m_font.getDebugString(m_parserState->m_fontConverter) << "," << f2.str()<< "],"; |
397 | | // check what happens, if the size of text is greater than 4 |
398 | 0 | for (int c = 0; c < nbChar; c++) |
399 | 0 | cell.m_text+=char(input->readLong(1)); |
400 | 0 | f << cell.m_text; |
401 | |
|
402 | 0 | table.m_cellsList.push_back(cell); |
403 | |
|
404 | 0 | ascFile.addPos(actPos); |
405 | 0 | ascFile.addNote(f.str().c_str()); |
406 | 0 | } |
407 | 112k | if (m_state->m_idTableMap.find(zoneId)!=m_state->m_idTableMap.end()) { |
408 | 0 | MWAW_DEBUG_MSG(("MsWksTable::readTable: oops a table with id=%d already exists\n", zoneId)); |
409 | 0 | } |
410 | 112k | else |
411 | 112k | m_state->m_idTableMap[zoneId]=table; |
412 | 112k | return true; |
413 | 149k | } |
414 | | |
415 | | //////////////////////////////////////////////////////////// |
416 | | // chart |
417 | | //////////////////////////////////////////////////////////// |
418 | | |
419 | | void MsWksTable::setChartZoneId(int chartId, int zoneId) |
420 | 862 | { |
421 | 862 | if (m_state->m_idChartMap.find(chartId)==m_state->m_idChartMap.end()) { |
422 | 0 | MWAW_DEBUG_MSG(("MsWksTable::setChartZoneId: can not find chart %d\n", chartId)); |
423 | 0 | return; |
424 | 0 | } |
425 | 862 | auto &chart = m_state->m_idChartMap.find(chartId)->second; |
426 | 862 | chart.m_zoneId = zoneId; |
427 | 862 | } |
428 | | |
429 | | bool MsWksTable::sendChart(int chartId) |
430 | 4 | { |
431 | 4 | MWAWListenerPtr listener=m_parserState->getMainListener(); |
432 | 4 | if (!listener) { |
433 | 0 | MWAW_DEBUG_MSG(("MsWksTable::sendChart: can not find a listener\n")); |
434 | 0 | return false; |
435 | 0 | } |
436 | 4 | if (m_state->m_idChartMap.find(chartId)==m_state->m_idChartMap.end()) { |
437 | 0 | MWAW_DEBUG_MSG(("MsWksTable::sendChart: can not find chart %d\n", chartId)); |
438 | 0 | return false; |
439 | 0 | } |
440 | 4 | auto &chart = m_state->m_idChartMap.find(chartId)->second; |
441 | | |
442 | 4 | MWAWInputStreamPtr input=m_zone.getInput(); |
443 | 4 | MWAWPosition chartPos; |
444 | 4 | if (chart.m_zoneId < 0 || !m_graphParser->getZonePosition(chart.m_zoneId, MWAWPosition::Frame, chartPos)) { |
445 | 0 | MWAW_DEBUG_MSG(("MsWksTable::sendChart: oops can not find chart bdbox %d[%d]\n", chartId, chart.m_zoneId)); |
446 | 0 | return false; |
447 | 0 | } |
448 | 4 | MWAWPosition pictPos(MWAWVec2f(0,0), chartPos.size(),librevenge::RVNG_POINT); |
449 | 4 | pictPos.setRelativePosition(MWAWPosition::Frame, MWAWPosition::XLeft, MWAWPosition::YTop); |
450 | 4 | if (chart.m_backgroundEntry.valid()) { |
451 | 0 | long actPos = input->tell(); |
452 | | #ifdef DEBUG_WITH_FILES |
453 | | if (1) { |
454 | | librevenge::RVNGBinaryData file; |
455 | | input->seek(chart.m_backgroundEntry.begin(), librevenge::RVNG_SEEK_SET); |
456 | | input->readDataBlock(chart.m_backgroundEntry.length(), file); |
457 | | static int volatile pictName = 0; |
458 | | libmwaw::DebugStream f; |
459 | | f << "Pict-" << ++pictName << ".pct"; |
460 | | libmwaw::Debug::dumpFile(file, f.str().c_str()); |
461 | | } |
462 | | #endif |
463 | |
|
464 | 0 | input->seek(chart.m_backgroundEntry.begin(), librevenge::RVNG_SEEK_SET); |
465 | 0 | MWAWBox2f naturalBox; |
466 | 0 | auto res = MWAWPictData::check(input, static_cast<int>(chart.m_backgroundEntry.length()), naturalBox); |
467 | 0 | if (res == MWAWPict::MWAW_R_BAD) { |
468 | 0 | MWAW_DEBUG_MSG(("MsWksTable::sendChart: can not find the picture\n")); |
469 | 0 | } |
470 | 0 | else { |
471 | 0 | input->seek(chart.m_backgroundEntry.begin(), librevenge::RVNG_SEEK_SET); |
472 | 0 | std::shared_ptr<MWAWPict> pict(MWAWPictData::get(input, static_cast<int>(chart.m_backgroundEntry.length()))); |
473 | |
|
474 | 0 | MWAWEmbeddedObject picture; |
475 | 0 | if (pict && pict->getBinary(picture)) |
476 | 0 | listener->insertPicture(pictPos, picture); |
477 | 0 | } |
478 | 0 | input->seek(actPos, librevenge::RVNG_SEEK_SET); |
479 | 0 | } |
480 | 16 | for (int i=0; i < 3; i++) { |
481 | 12 | int cId=chart.m_textZonesId[i]; |
482 | 12 | MWAWPosition childPos; |
483 | 12 | if (!m_graphParser->getZonePosition(cId, MWAWPosition::Frame, childPos)) { |
484 | 0 | MWAW_DEBUG_MSG(("MsWksTable::sendChart: oops can not find chart bdbox for child %d[%d]\n", i, cId)); |
485 | 0 | continue; |
486 | 0 | } |
487 | 12 | MWAWPosition textPos(pictPos); |
488 | 12 | textPos.setOrigin(childPos.origin()-chartPos.origin()); |
489 | 12 | textPos.setSize(childPos.size()); |
490 | 12 | m_graphParser->send(cId, textPos); |
491 | 12 | } |
492 | | |
493 | 4 | return true; |
494 | 4 | } |
495 | | |
496 | | bool MsWksTable::readChart(int chartId, MsWksGraph::Style const &style) |
497 | 6.40M | { |
498 | | // checkme: works for some chart, but not sure that it can work for all chart... |
499 | 6.40M | MWAWInputStreamPtr input=m_zone.getInput(); |
500 | 6.40M | long pos = input->tell(); |
501 | 6.40M | int const vers=version(); |
502 | 6.40M | if (vers<=2 || (vers==3&&m_parserState->m_type!=MWAWParserState::Spreadsheet) || |
503 | 6.14M | !input->checkPosition(pos+306)) |
504 | 758k | return false; |
505 | | |
506 | 5.64M | libmwaw::DebugFile &ascFile = m_zone.ascii(); |
507 | 5.64M | libmwaw::DebugStream f; |
508 | 5.64M | f << "Entries(Chart):"; |
509 | | |
510 | 5.64M | MsWksTableInternal::Chart chart(style); |
511 | 5.64M | auto val = static_cast<int>(input->readLong(2)); |
512 | 5.64M | switch (val) { |
513 | 469k | case 1: |
514 | 469k | f << "bar,"; |
515 | 469k | break; |
516 | 19.1k | case 2: |
517 | 19.1k | f << "stacked,"; |
518 | 19.1k | break; |
519 | 725k | case 3: |
520 | 725k | f << "line,"; |
521 | 725k | break; // checkme |
522 | 171 | case 4: |
523 | 171 | f << "combo,"; |
524 | 171 | break; // checkme |
525 | 259 | case 5: |
526 | 259 | f << "pie,"; |
527 | 259 | break; // checkme |
528 | 50.2k | case 6: |
529 | 50.2k | f << "hi-lo-choose,"; |
530 | 50.2k | break; // checkme |
531 | 4.38M | default: |
532 | 4.38M | f << "#type=val"; |
533 | 4.38M | break; |
534 | 5.64M | } |
535 | 28.2M | for (int i = 0; i < 4; i++) { |
536 | 22.5M | val = static_cast<int>(input->readLong(2)); |
537 | 22.5M | if (val) f << "col" << i << "=" << val << ","; |
538 | 22.5M | } |
539 | 5.64M | f << "rows="; |
540 | 16.9M | for (int i = 0; i < 2; i++) { |
541 | 11.2M | val = static_cast<int>(input->readLong(2)); |
542 | 11.2M | f << val; |
543 | 11.2M | if (i==0) f << "-"; |
544 | 5.64M | else f << ","; |
545 | 11.2M | } |
546 | 5.64M | val = static_cast<int>(input->readLong(2)); |
547 | 5.64M | if (val) f << "colLabels=" << val << ","; |
548 | 5.64M | val = static_cast<int>(input->readLong(2)); |
549 | 5.64M | if (val) f << "rowLabels=" << val << ","; |
550 | 5.64M | std::string name(""); |
551 | 5.64M | auto sz = static_cast<int>(input->readULong(1)); |
552 | 5.64M | if (sz > 31) { |
553 | 305k | MWAW_DEBUG_MSG(("MsWksTable::readChart: string size is too long\n")); |
554 | 305k | return false; |
555 | 305k | } |
556 | 11.3M | for (int i = 0; i < sz; i++) { |
557 | 6.74M | auto c = char(input->readLong(1)); |
558 | 6.74M | if (!c) break; |
559 | 5.99M | name+=c; |
560 | 5.99M | } |
561 | 5.34M | f << name << ","; |
562 | 5.34M | input->seek(pos+50, librevenge::RVNG_SEEK_SET); |
563 | 689M | for (int i = 0; i < 128; i++) { // always 0 ? |
564 | 684M | val = static_cast<int>(input->readLong(2)); |
565 | 684M | if (val) f << "g" << i << "=" << val << std::dec << ","; |
566 | 684M | } |
567 | 5.34M | ascFile.addPos(pos); |
568 | 5.34M | ascFile.addNote(f.str().c_str()); |
569 | | |
570 | 5.34M | pos = input->tell(); |
571 | 5.34M | ascFile.addPos(pos); |
572 | 5.34M | ascFile.addNote("Chart(II)"); |
573 | 5.34M | input->seek(vers==3 ? 1992 : 2428, librevenge::RVNG_SEEK_CUR); |
574 | | |
575 | | // three textbox |
576 | 15.0M | for (int i = 0; i < 3; i++) { |
577 | 12.7M | pos = input->tell(); |
578 | 12.7M | MWAWEntry childZone; |
579 | 12.7M | chart.m_textZonesId[i] = m_graphParser->getEntryPicture(-9999, childZone, false, i+2); |
580 | 12.7M | if (chart.m_textZonesId[i]<0) { |
581 | 3.04M | MWAW_DEBUG_MSG(("MsWksTable::readChart: can not find textbox\n")); |
582 | 3.04M | input->seek(pos, librevenge::RVNG_SEEK_SET); |
583 | 3.04M | return false; |
584 | 3.04M | } |
585 | 12.7M | } |
586 | | // the background picture |
587 | 2.29M | pos = input->tell(); |
588 | 2.29M | auto dataSz = long(input->readULong(4)); |
589 | 2.29M | auto smDataSz = long(input->readULong(2)); |
590 | 2.29M | if (!dataSz || (dataSz&0xFFFF) != smDataSz || !input->checkPosition(pos+4+dataSz)) |
591 | | // background picture not always present ( at least in v3) |
592 | 2.17M | input->seek(pos, librevenge::RVNG_SEEK_SET); |
593 | 124k | else { |
594 | 124k | MWAWEntry &background=chart.m_backgroundEntry; |
595 | 124k | background.setBegin(pos+4); |
596 | 124k | background.setLength(dataSz); |
597 | 124k | ascFile.skipZone(background.begin(), background.end()-1); |
598 | | |
599 | 124k | ascFile.addPos(pos); |
600 | 124k | ascFile.addNote("Chart(picture)"); |
601 | 124k | input->seek(background.end(), librevenge::RVNG_SEEK_SET); |
602 | 124k | } |
603 | | // last the value ( by columns ? ) |
604 | 3.45M | for (int i = 0; i < 4; i++) { |
605 | 3.45M | pos = input->tell(); |
606 | 3.45M | dataSz = long(input->readULong(4)); |
607 | 3.45M | if (dataSz > input->size() - pos - 4) |
608 | 2.43M | dataSz = input->size() - pos - 4; |
609 | 3.45M | if (dataSz%0x10) { |
610 | 2.29M | MWAW_DEBUG_MSG(("MsWksTable::readChart: can not read end last zone\n")); |
611 | 2.29M | input->seek(pos, librevenge::RVNG_SEEK_SET); |
612 | 2.29M | return false; |
613 | 2.29M | } |
614 | 1.16M | f.str(""); |
615 | 1.16M | f << "Chart(A" << i << ")"; |
616 | 1.16M | ascFile.addPos(pos); |
617 | 1.16M | ascFile.addNote(f.str().c_str()); |
618 | 1.16M | auto numLine = int(dataSz/0x10); |
619 | 2.56M | for (int l = 0; l < numLine; l++) { |
620 | 1.40M | f.str(""); |
621 | 1.40M | f << "Chart(A" << i << "-" << l << ")"; |
622 | 1.40M | ascFile.addPos(pos+4+0x10*l); |
623 | 1.40M | ascFile.addNote(f.str().c_str()); |
624 | 1.40M | } |
625 | 1.16M | if (input->seek(pos+4+dataSz, librevenge::RVNG_SEEK_SET) != 0) { |
626 | 0 | MWAW_DEBUG_MSG(("MsWksTable::readChart: reading past the end\n")); |
627 | 0 | return false; |
628 | 0 | } |
629 | 1.16M | } |
630 | 862 | if (m_state->m_idChartMap.find(chartId)!=m_state->m_idChartMap.end()) { |
631 | 0 | MWAW_DEBUG_MSG(("MsWksTable::readChart: oops a chart with id=%d already exists\n", chartId)); |
632 | 0 | } |
633 | 862 | else |
634 | 862 | m_state->m_idChartMap[chartId]=chart; |
635 | 862 | return true; |
636 | 2.29M | } |
637 | | |
638 | | // vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: |