/src/libmwaw/src/lib/ClarisWksDatabase.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 <algorithm> |
35 | | #include <iomanip> |
36 | | #include <iostream> |
37 | | #include <limits> |
38 | | #include <map> |
39 | | #include <sstream> |
40 | | |
41 | | #include <librevenge/librevenge.h> |
42 | | |
43 | | #include "MWAWCell.hxx" |
44 | | #include "MWAWFont.hxx" |
45 | | #include "MWAWSpreadsheetListener.hxx" |
46 | | #include "MWAWParser.hxx" |
47 | | #include "MWAWTable.hxx" |
48 | | |
49 | | #include "ClarisWksDbaseContent.hxx" |
50 | | #include "ClarisWksDocument.hxx" |
51 | | #include "ClarisWksStruct.hxx" |
52 | | #include "ClarisWksStyleManager.hxx" |
53 | | |
54 | | #include "ClarisWksDatabase.hxx" |
55 | | |
56 | | /** Internal: the structures of a ClarisWksDatabase */ |
57 | | namespace ClarisWksDatabaseInternal |
58 | | { |
59 | | struct Field { |
60 | | // the type |
61 | | enum Type { F_Unknown, F_Text, F_Number, F_Date, F_Time, |
62 | | F_Formula, F_FormulaSum, |
63 | | F_Checkbox, F_PopupMenu, F_RadioButton, F_ValueList, |
64 | | F_Multimedia |
65 | | }; |
66 | | Field() |
67 | 1.09M | : m_type(F_Unknown) |
68 | 1.09M | , m_defType(-1) |
69 | 1.09M | , m_resType(0) |
70 | 1.09M | , m_name("") |
71 | 1.09M | , m_default("") |
72 | 1.09M | , m_valuesList() |
73 | 1.09M | , m_formula() |
74 | 1.09M | { |
75 | 1.09M | } |
76 | | |
77 | | //! operator<< |
78 | | friend std::ostream &operator<<(std::ostream &o, Field const &field) |
79 | 0 | { |
80 | 0 | switch (field.m_type) { |
81 | 0 | case F_Text : |
82 | 0 | o << "text,"; |
83 | 0 | break; |
84 | 0 | case F_Number : |
85 | 0 | o << "number,"; |
86 | 0 | break; |
87 | 0 | case F_Date : |
88 | 0 | o << "date,"; |
89 | 0 | break; |
90 | 0 | case F_Time : |
91 | 0 | o << "time,"; |
92 | 0 | break; |
93 | 0 | case F_Formula : |
94 | 0 | o << "formula,"; |
95 | 0 | break; |
96 | 0 | case F_FormulaSum : |
97 | 0 | o << "formula(summary),"; |
98 | 0 | break; |
99 | 0 | case F_Checkbox : |
100 | 0 | o << "checkbox,"; |
101 | 0 | break; |
102 | 0 | case F_PopupMenu : |
103 | 0 | o << "popupMenu,"; |
104 | 0 | break; |
105 | 0 | case F_RadioButton : |
106 | 0 | o << "radioButton,"; |
107 | 0 | break; |
108 | 0 | case F_ValueList: |
109 | 0 | o << "valueList,"; |
110 | 0 | break; |
111 | 0 | case F_Multimedia : |
112 | 0 | o << "multimedia,"; |
113 | 0 | break; |
114 | 0 | case F_Unknown : |
115 | 0 | #if !defined(__clang__) |
116 | 0 | default: |
117 | 0 | #endif |
118 | 0 | o << "type=#unknown,"; |
119 | 0 | break; |
120 | 0 | } |
121 | 0 | switch (field.m_resType) { |
122 | 0 | case 0: |
123 | 0 | o << "text[format],"; |
124 | 0 | break; |
125 | 0 | case 1: |
126 | 0 | o << "number[format],"; |
127 | 0 | break; |
128 | 0 | case 2: |
129 | 0 | o << "date[format],"; |
130 | 0 | break; |
131 | 0 | case 3: |
132 | 0 | o << "time[format],"; |
133 | 0 | break; |
134 | 0 | default: |
135 | 0 | o << "##res[format]=" << field.m_resType << ","; |
136 | 0 | break; |
137 | 0 | } |
138 | 0 | o << "'" << field.m_name << "',"; |
139 | 0 | switch (field.m_defType) { |
140 | 0 | case -1: |
141 | 0 | break; |
142 | 0 | case 0: |
143 | 0 | break; |
144 | 0 | case 3: |
145 | 0 | o << "recordInfo,"; |
146 | 0 | break; |
147 | 0 | case 7: |
148 | 0 | o << "serial"; |
149 | 0 | break; |
150 | 0 | case 8: |
151 | 0 | o << "hasDef,"; |
152 | 0 | break; // text with default |
153 | 0 | case 9: |
154 | 0 | o << "popup/radio/control,"; |
155 | 0 | break; // with default value ? |
156 | 0 | default: |
157 | 0 | o << "#defType=" << field.m_defType << ","; |
158 | 0 | break; |
159 | 0 | } |
160 | 0 | if (field.m_default.length()) |
161 | 0 | o << "defaultVal='" << field.m_default << "',"; |
162 | 0 | return o; |
163 | 0 | } |
164 | | |
165 | | bool isText() const |
166 | 163k | { |
167 | 163k | return m_type == F_Text; |
168 | 163k | } |
169 | | bool isFormula() const |
170 | 633k | { |
171 | 633k | return m_type == F_Formula || m_type == F_FormulaSum; |
172 | 633k | } |
173 | | |
174 | | int getNumDefault(int version) const |
175 | 633k | { |
176 | 633k | switch (m_type) { |
177 | 219k | case F_Text : |
178 | 219k | if (version >= 4) |
179 | 63.7k | return 1; |
180 | 155k | if (m_defType == 8) return 1; |
181 | 147k | return 0; |
182 | 41.1k | case F_Number : |
183 | 74.6k | case F_Date : |
184 | 110k | case F_Time : |
185 | 112k | case F_Multimedia : |
186 | 112k | return 0; |
187 | 32.7k | case F_Formula : |
188 | 76.6k | case F_FormulaSum : |
189 | 76.6k | return 1; |
190 | 15.6k | case F_Checkbox : |
191 | 15.6k | return 1; |
192 | 18.8k | case F_PopupMenu : |
193 | 76.8k | case F_RadioButton : |
194 | 76.8k | return 2; |
195 | 28.6k | case F_ValueList : |
196 | 28.6k | return (version >= 3) ? 2 : 1; |
197 | 103k | case F_Unknown : |
198 | | #if !defined(__clang__) |
199 | | default: |
200 | | #endif |
201 | 103k | break; |
202 | 633k | } |
203 | 103k | return 0; |
204 | 633k | } |
205 | | |
206 | | Type m_type; |
207 | | /** the local definition type */ |
208 | | int m_defType; |
209 | | /** the result type */ |
210 | | int m_resType; |
211 | | /** the field name */ |
212 | | std::string m_name; |
213 | | /** the default value */ |
214 | | std::string m_default; |
215 | | /** list of different value list */ |
216 | | std::vector<MWAWEntry> m_valuesList; |
217 | | /** the formula */ |
218 | | std::vector<MWAWCellContent::FormulaInstruction> m_formula; |
219 | | }; |
220 | | |
221 | | //////////////////////////////////////// |
222 | | //////////////////////////////////////// |
223 | | |
224 | | //! Internal: the database of a ClarisWksDatabase |
225 | | struct Database final : public ClarisWksStruct::DSET { |
226 | | //! constructor |
227 | | explicit Database(ClarisWksStruct::DSET const &dset = ClarisWksStruct::DSET()) |
228 | 664k | : ClarisWksStruct::DSET(dset) |
229 | 664k | , m_fields() |
230 | 664k | , m_content() |
231 | 664k | { |
232 | 664k | } |
233 | | //! destructor |
234 | | ~Database() final; |
235 | | //! operator<< |
236 | | friend std::ostream &operator<<(std::ostream &o, Database const &doc) |
237 | 0 | { |
238 | 0 | o << static_cast<ClarisWksStruct::DSET const &>(doc); |
239 | 0 | return o; |
240 | 0 | } |
241 | | //! the list of field |
242 | | std::vector<Field> m_fields; |
243 | | //! the data |
244 | | std::shared_ptr<ClarisWksDbaseContent> m_content; |
245 | | }; |
246 | | |
247 | | Database::~Database() |
248 | 664k | { |
249 | 664k | } |
250 | | |
251 | | //////////////////////////////////////// |
252 | | //! Internal: the state of a ClarisWksDatabase |
253 | | struct State { |
254 | | //! constructor |
255 | | State() |
256 | 402k | : m_databaseMap() |
257 | 402k | { |
258 | 402k | } |
259 | | |
260 | | std::map<int, std::shared_ptr<Database> > m_databaseMap; |
261 | | }; |
262 | | |
263 | | } |
264 | | |
265 | | //////////////////////////////////////////////////////////// |
266 | | // constructor/destructor, ... |
267 | | //////////////////////////////////////////////////////////// |
268 | | ClarisWksDatabase::ClarisWksDatabase(ClarisWksDocument &document) |
269 | 402k | : m_document(document) |
270 | 402k | , m_parserState(document.m_parserState) |
271 | 402k | , m_state(new ClarisWksDatabaseInternal::State) |
272 | 402k | , m_mainParser(&document.getMainParser()) |
273 | 402k | { |
274 | 402k | } |
275 | | |
276 | | ClarisWksDatabase::~ClarisWksDatabase() |
277 | 402k | { } |
278 | | |
279 | | int ClarisWksDatabase::version() const |
280 | 3.02M | { |
281 | 3.02M | return m_parserState->m_version; |
282 | 3.02M | } |
283 | | |
284 | | // fixme |
285 | | int ClarisWksDatabase::numPages() const |
286 | 135k | { |
287 | 135k | return 1; |
288 | 135k | } |
289 | | //////////////////////////////////////////////////////////// |
290 | | // Intermediate level |
291 | | //////////////////////////////////////////////////////////// |
292 | | |
293 | | //////////////////////////////////////////////////////////// |
294 | | // a document part |
295 | | //////////////////////////////////////////////////////////// |
296 | | std::shared_ptr<ClarisWksStruct::DSET> ClarisWksDatabase::readDatabaseZone |
297 | | (ClarisWksStruct::DSET const &zone, MWAWEntry const &entry, bool &complete) |
298 | 670k | { |
299 | 670k | complete = false; |
300 | 670k | if (!entry.valid() || zone.m_fileType != 3 || entry.length() < 32) |
301 | 6.09k | return std::shared_ptr<ClarisWksStruct::DSET>(); |
302 | 664k | long pos = entry.begin(); |
303 | 664k | MWAWInputStreamPtr &input= m_parserState->m_input; |
304 | 664k | input->seek(pos+8+16, librevenge::RVNG_SEEK_SET); // avoid header+8 generic number |
305 | 664k | libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile; |
306 | 664k | libmwaw::DebugStream f; |
307 | 664k | std::shared_ptr<ClarisWksDatabaseInternal::Database> |
308 | 664k | databaseZone(new ClarisWksDatabaseInternal::Database(zone)); |
309 | | |
310 | 664k | f << "Entries(DatabaseDef):" << *databaseZone << ","; |
311 | 664k | ascFile.addDelimiter(input->tell(), '|'); |
312 | 664k | ascFile.addPos(pos); |
313 | 664k | ascFile.addNote(f.str().c_str()); |
314 | | |
315 | | // read the last part |
316 | 664k | long data0Length = zone.m_dataSz; |
317 | 664k | long N = zone.m_numData; |
318 | 664k | if (entry.length() -8-12 != data0Length*N + zone.m_headerSz) { |
319 | 474k | if (data0Length == 0 && N) { |
320 | 14.5k | MWAW_DEBUG_MSG(("ClarisWksDatabase::readDatabaseZone: can not find definition size\n")); |
321 | 14.5k | input->seek(entry.end(), librevenge::RVNG_SEEK_SET); |
322 | 14.5k | return std::shared_ptr<ClarisWksStruct::DSET>(); |
323 | 14.5k | } |
324 | | |
325 | 459k | MWAW_DEBUG_MSG(("ClarisWksDatabase::readDatabaseZone: unexpected size for zone definition, try to continue\n")); |
326 | 459k | } |
327 | | |
328 | 649k | long dataEnd = entry.end()-N*data0Length; |
329 | 649k | int numLast = -1; |
330 | 649k | int const vers=version(); |
331 | 649k | switch (vers) { |
332 | 204k | case 1: |
333 | 344k | case 2: |
334 | 394k | case 3: |
335 | 437k | case 4: |
336 | 437k | numLast = 0; |
337 | 437k | break; |
338 | 161k | case 5: |
339 | 161k | numLast = 4; |
340 | 161k | break; |
341 | 50.4k | case 6: |
342 | 50.4k | numLast = 8; |
343 | 50.4k | break; |
344 | 0 | default: |
345 | 0 | MWAW_DEBUG_MSG(("ClarisWksDatabase::readDatabaseZone: unexpected version\n")); |
346 | 0 | break; |
347 | 649k | } |
348 | 649k | if (numLast >= 0 && long(input->tell()) + data0Length + numLast <= dataEnd) { |
349 | 505k | ascFile.addPos(dataEnd-data0Length-numLast); |
350 | 505k | ascFile.addNote("DatabaseDef-_"); |
351 | 505k | if (numLast) { |
352 | 163k | ascFile.addPos(dataEnd-numLast); |
353 | 163k | ascFile.addNote("DatabaseDef-extra"); |
354 | 163k | } |
355 | 505k | } |
356 | 649k | input->seek(dataEnd, librevenge::RVNG_SEEK_SET); |
357 | | |
358 | 1.31M | for (long i = 0; i < N; i++) { |
359 | 668k | pos = input->tell(); |
360 | | |
361 | 668k | f.str(""); |
362 | 668k | f << "DatabaseDef-" << i; |
363 | 668k | ascFile.addPos(pos); |
364 | 668k | ascFile.addNote(f.str().c_str()); |
365 | 668k | input->seek(pos+data0Length, librevenge::RVNG_SEEK_SET); |
366 | 668k | } |
367 | | |
368 | 649k | input->seek(entry.end(), librevenge::RVNG_SEEK_SET); |
369 | | |
370 | 649k | if (m_state->m_databaseMap.find(databaseZone->m_id) != m_state->m_databaseMap.end()) { |
371 | 585k | MWAW_DEBUG_MSG(("ClarisWksDatabase::readDatabaseZone: zone %d already exists!!!\n", databaseZone->m_id)); |
372 | | /* can only happen if we did not read completly the header, and so |
373 | | we have previously read some old saved part of the database, |
374 | | which has remained in the junk zones. */ |
375 | 585k | if (databaseZone->m_id==1) |
376 | 152k | m_state->m_databaseMap[databaseZone->m_id] = databaseZone; |
377 | 585k | } |
378 | 63.6k | else |
379 | 63.6k | m_state->m_databaseMap[databaseZone->m_id] = databaseZone; |
380 | | |
381 | 649k | databaseZone->m_otherChilds.push_back(databaseZone->m_id+1); |
382 | | |
383 | 649k | pos = input->tell(); |
384 | 649k | bool ok = readFields(*databaseZone); |
385 | | |
386 | 649k | if (ok) { |
387 | 481k | ok = readDefaults(*databaseZone); |
388 | 481k | pos = input->tell(); |
389 | 481k | } |
390 | 649k | if (ok) { |
391 | 402k | pos = input->tell(); |
392 | 402k | ok = ClarisWksStruct::readStructZone(*m_parserState, "DatabaseListUnkn0", false); |
393 | 402k | } |
394 | 649k | if (ok) { |
395 | 314k | pos = input->tell(); |
396 | | // probably: field number followed by 1 : increasing, 2 : decreasing |
397 | 314k | ok = ClarisWksStruct::readStructZone(*m_parserState, "DatabaseSortFunction", false); |
398 | 314k | } |
399 | 649k | if (ok) { |
400 | 275k | pos = input->tell(); |
401 | 275k | std::shared_ptr<ClarisWksDbaseContent> content(new ClarisWksDbaseContent(m_document, false)); |
402 | 275k | ok = content->readContent(); |
403 | 275k | if (ok) databaseZone->m_content=content; |
404 | 275k | } |
405 | 649k | std::vector<int> listLayout; |
406 | 649k | if (ok) { |
407 | 137k | pos = input->tell(); |
408 | 137k | ok = ClarisWksStruct::readIntZone(*m_parserState, "DatabaseLayout", false, 4, listLayout); |
409 | 137k | } |
410 | 649k | if (ok) { |
411 | 144k | for (size_t i=0; i<listLayout.size(); ++i) { |
412 | 46.9k | pos = input->tell(); |
413 | 46.9k | if (!readLayout(*databaseZone)) { |
414 | 33.9k | MWAW_DEBUG_MSG(("ClarisWksDatabase::readDatabaseZone: can not read some ListLayout data file\n")); |
415 | 33.9k | ok=false; |
416 | 33.9k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
417 | 33.9k | ascFile.addPos(pos); |
418 | 33.9k | ascFile.addNote("DatabaseLayout:###"); |
419 | 33.9k | break; |
420 | 33.9k | } |
421 | 46.9k | } |
422 | 131k | } |
423 | 649k | if (ok) { |
424 | 97.8k | pos = input->tell(); |
425 | | // in v1-v4 list of id block?, in v5-v6 list of block id+? |
426 | 97.8k | ok = ClarisWksStruct::readStructZone(*m_parserState, "DatabaseListUnkn3", false); |
427 | 97.8k | } |
428 | | |
429 | 649k | if (ok) { // never seems, |
430 | 92.1k | pos=input->tell(); |
431 | 92.1k | auto sz=long(input->readULong(4)); |
432 | 92.1k | if (input->checkPosition(pos+4+sz)) { |
433 | 53.7k | input->seek(pos+4+sz, librevenge::RVNG_SEEK_SET); |
434 | 53.7k | ascFile.addPos(pos); |
435 | 53.7k | if (sz) { |
436 | 26.9k | MWAW_DEBUG_MSG(("ClarisWksDatabase::readDatabaseZone: find a Unkn4 block\n")); |
437 | 26.9k | ascFile.addNote("Entries(DatabaseListUnkn4):"); |
438 | 26.9k | } |
439 | 26.7k | else |
440 | 26.7k | ascFile.addNote("_"); |
441 | 53.7k | } |
442 | 38.4k | else { |
443 | 38.4k | ok=false; |
444 | 38.4k | MWAW_DEBUG_MSG(("ClarisWksDatabase::readDatabaseZone: find a Unkn4 block does not know how to read it\n")); |
445 | 38.4k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
446 | 38.4k | } |
447 | 92.1k | } |
448 | 649k | if (ok && vers>1) { |
449 | 40.2k | pos=input->tell(); |
450 | 40.2k | std::vector<std::string> listString; |
451 | 40.2k | ok=m_document.readStringList("DatabaseListString", false, listString); |
452 | 40.2k | } |
453 | 649k | if (ok) { |
454 | 28.6k | pos = input->tell(); |
455 | 28.6k | ok = ClarisWksStruct::readStructZone(*m_parserState, "DatabaseUnkn5", false); |
456 | 28.6k | } |
457 | 649k | if (ok && vers>=4) { |
458 | | // version 4 can contains more block: list of int+flag? |
459 | 4.65k | pos=input->tell(); |
460 | 4.65k | ok = ClarisWksStruct::readStructZone(*m_parserState, "DatabaseUnkn6", false); |
461 | 4.65k | } |
462 | | // now the following seems to be different |
463 | 649k | if (!ok) |
464 | 636k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
465 | | |
466 | 649k | return databaseZone; |
467 | 649k | } |
468 | | |
469 | | //////////////////////////////////////////////////////////// |
470 | | // |
471 | | // Intermediate level |
472 | | // |
473 | | //////////////////////////////////////////////////////////// |
474 | | bool ClarisWksDatabase::readFields(ClarisWksDatabaseInternal::Database &dBase) |
475 | 649k | { |
476 | 649k | MWAWInputStreamPtr &input= m_parserState->m_input; |
477 | 649k | long pos = input->tell(); |
478 | 649k | ClarisWksStruct::Struct header; |
479 | 649k | if (!header.readHeader(input,true) || (header.m_size && header.m_dataSize<28)) { |
480 | 128k | MWAW_DEBUG_MSG(("ClarisWksDatabase::readFields: can not read the header\n")); |
481 | 128k | return false; |
482 | 128k | } |
483 | 521k | libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile; |
484 | 521k | libmwaw::DebugStream f; |
485 | 521k | if (header.m_size==0) { |
486 | 109k | ascFile.addPos(pos); |
487 | 109k | ascFile.addNote("Nop"); |
488 | 109k | return true; |
489 | 109k | } |
490 | 411k | long endPos = pos+4+header.m_size; |
491 | 411k | f << "Entries(DatabaseField):" << header; |
492 | 411k | if (header.m_headerSize) { |
493 | 2.42k | ascFile.addDelimiter(input->tell(),'|'); |
494 | 2.42k | input->seek(header.m_headerSize, librevenge::RVNG_SEEK_CUR); |
495 | 2.42k | } |
496 | 411k | ascFile.addPos(pos); |
497 | 411k | ascFile.addNote(f.str().c_str()); |
498 | | |
499 | 411k | dBase.m_fields.resize(size_t(header.m_numData)); |
500 | 411k | int n=0; |
501 | 1.05M | for (auto &field : dBase.m_fields) { |
502 | 1.05M | pos = input->tell(); |
503 | 1.05M | f.str(""); |
504 | 1.05M | f << "DatabaseField-" << n++ << ":"; |
505 | | |
506 | 1.05M | int const fNameMaxSz = 64; |
507 | 1.05M | std::string name(""); |
508 | 1.05M | auto sz = long(input->readULong(1)); |
509 | 1.05M | if (sz > fNameMaxSz-1 || sz > header.m_dataSize-1) { |
510 | 40.0k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
511 | 40.0k | MWAW_DEBUG_MSG(("ClarisWksDatabase::readFields: find odd field name\n")); |
512 | 40.0k | return false; |
513 | 40.0k | } |
514 | 5.75M | for (long j = 0; j < sz; j++) |
515 | 4.74M | name += char(input->readULong(1)); |
516 | 1.01M | field.m_name = name; |
517 | | |
518 | 1.01M | input->seek(pos+fNameMaxSz, librevenge::RVNG_SEEK_SET); |
519 | 1.01M | auto type = static_cast<int>(input->readULong(1)); |
520 | 1.01M | bool ok = true; |
521 | 1.01M | switch (type) { |
522 | | // or name |
523 | 389k | case 0: |
524 | 389k | field.m_type = ClarisWksDatabaseInternal::Field::F_Text; |
525 | 389k | break; |
526 | 52.8k | case 1: |
527 | 52.8k | field.m_type = ClarisWksDatabaseInternal::Field::F_Number; |
528 | 52.8k | break; |
529 | 77.9k | case 2: |
530 | 77.9k | field.m_type = ClarisWksDatabaseInternal::Field::F_Date; |
531 | 77.9k | break; |
532 | 79.1k | case 3: |
533 | 79.1k | field.m_type = ClarisWksDatabaseInternal::Field::F_Time; |
534 | 79.1k | break; |
535 | 51.7k | case 4: |
536 | 51.7k | if (version() <= 2) |
537 | 24.3k | field.m_type = ClarisWksDatabaseInternal::Field::F_Formula; |
538 | 27.4k | else |
539 | 27.4k | field.m_type = ClarisWksDatabaseInternal::Field::F_PopupMenu; |
540 | 51.7k | break; |
541 | 65.4k | case 5: |
542 | 65.4k | if (version() <= 2) |
543 | 42.2k | field.m_type = ClarisWksDatabaseInternal::Field::F_FormulaSum; |
544 | 23.1k | else |
545 | 23.1k | field.m_type = ClarisWksDatabaseInternal::Field::F_Checkbox; |
546 | 65.4k | break; |
547 | 64.2k | case 6: |
548 | 64.2k | field.m_type = ClarisWksDatabaseInternal::Field::F_RadioButton; |
549 | 64.2k | break; |
550 | 6.24k | case 7: |
551 | 6.24k | if (version() == 4) |
552 | 2.86k | field.m_type = ClarisWksDatabaseInternal::Field::F_Formula; |
553 | 3.37k | else |
554 | 3.37k | field.m_type = ClarisWksDatabaseInternal::Field::F_Multimedia; |
555 | 6.24k | break; |
556 | 25.7k | case 8: |
557 | 25.7k | if (version() == 4) |
558 | 5.43k | field.m_type = ClarisWksDatabaseInternal::Field::F_FormulaSum; |
559 | 20.3k | else |
560 | 20.3k | ok = false; |
561 | 25.7k | break; |
562 | 21.8k | case 10: |
563 | 21.8k | field.m_type = ClarisWksDatabaseInternal::Field::F_Formula; |
564 | 21.8k | break; |
565 | 10.2k | case 11: |
566 | 10.2k | field.m_type = ClarisWksDatabaseInternal::Field::F_FormulaSum; |
567 | 10.2k | break; |
568 | 165k | default: |
569 | 165k | ok = false; |
570 | 165k | break; |
571 | 1.01M | } |
572 | 1.01M | if (!ok) |
573 | 186k | f << "#type=" << type << ","; |
574 | 1.01M | auto val = static_cast<int>(input->readULong(1)); |
575 | 1.01M | if (val) |
576 | 358k | f << "#unkn=" << val << ","; |
577 | 1.01M | unsigned long ptr = input->readULong(4); |
578 | 1.01M | if (ptr) // set for formula |
579 | 502k | f << "ptr=" << std::hex << ptr << std::dec << ","; |
580 | 1.01M | field.m_resType=static_cast<int>(input->readLong(1)); |
581 | 1.01M | f << "fl?=[" << std::hex; |
582 | 1.01M | f << input->readULong(1) << ","; |
583 | 1.01M | f << input->readULong(1) << ","; |
584 | 7.07M | for (int j = 0; j < 6; j++) { |
585 | | // some int which seems constant on the database... |
586 | 6.06M | val = static_cast<int>(input->readULong(2)); |
587 | 6.06M | f << val << ","; |
588 | 6.06M | } |
589 | 1.01M | f << std::dec << "],"; |
590 | | |
591 | 1.01M | if (version() > 1) { |
592 | 12.4M | for (int j = 0; j < 16; j++) { |
593 | | /** find f1=600 for a number |
594 | | f16 = 0[checkbox, ... ], 2[number or text],3 [name field], 82[value list], |
595 | | f16 & 8: can not be empty |
596 | | */ |
597 | 11.7M | val = static_cast<int>(input->readLong(2)); |
598 | 11.7M | if (val) f << "f" << j << "=" << std::hex << val << std::dec << ","; |
599 | 11.7M | } |
600 | 733k | auto subType = static_cast<int>(input->readULong(2)); |
601 | 733k | if (version() == 2) { |
602 | 234k | if ((subType & 0x80) && field.m_type == ClarisWksDatabaseInternal::Field::F_Text) { |
603 | 21.7k | field.m_type = ClarisWksDatabaseInternal::Field::F_ValueList; |
604 | 21.7k | subType &= 0xFF7F; |
605 | 21.7k | } |
606 | 234k | if (subType) f << "f17=" << std::hex << subType << std::dec << ","; |
607 | 234k | } |
608 | 499k | else { |
609 | 499k | if ((subType & 0x80) && field.m_type == ClarisWksDatabaseInternal::Field::F_Text) { |
610 | 31.6k | field.m_type = ClarisWksDatabaseInternal::Field::F_ValueList; |
611 | 31.6k | subType &= 0xFF7F; |
612 | 31.6k | } |
613 | 499k | ok = true; |
614 | 499k | switch (subType) { |
615 | 138k | case 0: |
616 | 138k | ok = field.m_type == ClarisWksDatabaseInternal::Field::F_Checkbox || |
617 | 131k | field.m_type == ClarisWksDatabaseInternal::Field::F_PopupMenu || |
618 | 116k | field.m_type == ClarisWksDatabaseInternal::Field::F_RadioButton || |
619 | 113k | field.m_type == ClarisWksDatabaseInternal::Field::F_Multimedia; |
620 | 138k | break; |
621 | 156k | case 2: // basic |
622 | 156k | break; |
623 | 1.36k | case 3: |
624 | 1.36k | ok = field.m_type == ClarisWksDatabaseInternal::Field::F_Text; |
625 | 1.36k | if (ok) f << "name[field],"; |
626 | 1.36k | break; |
627 | 4.52k | case 6: |
628 | 4.52k | ok = version() == 4 && field.m_type == ClarisWksDatabaseInternal::Field::F_ValueList;; |
629 | 4.52k | break; |
630 | 199k | default: |
631 | 199k | ok = false; |
632 | 499k | } |
633 | 499k | if (!ok) f << "#unkSubType=" << std::hex << subType << std::dec << ","; |
634 | 499k | } |
635 | 733k | val = static_cast<int>(input->readULong(2)); |
636 | 733k | if (val==0x8000) |
637 | 4.15k | f << "recordInfo"; |
638 | 729k | else if (val) |
639 | 347k | f << "#unk1=" << std::hex << val << std::dec << ","; |
640 | 733k | field.m_defType = static_cast<int>(input->readULong(1)); |
641 | | // default, followed by a number/ptr/... : 7fff ( mean none) |
642 | 733k | } |
643 | 1.01M | f << field << ","; |
644 | 1.01M | long actPos = input->tell(); |
645 | 1.01M | if (actPos != pos && actPos != pos+header.m_dataSize) |
646 | 1.01M | ascFile.addDelimiter(actPos, '|'); |
647 | 1.01M | ascFile.addPos(pos); |
648 | 1.01M | ascFile.addNote(f.str().c_str()); |
649 | 1.01M | input->seek(pos+header.m_dataSize, librevenge::RVNG_SEEK_SET); |
650 | 1.01M | } |
651 | | |
652 | 371k | input->seek(endPos, librevenge::RVNG_SEEK_SET); |
653 | 371k | return true; |
654 | 411k | } |
655 | | |
656 | | bool ClarisWksDatabase::readDefaults(ClarisWksDatabaseInternal::Database &dBase) |
657 | 481k | { |
658 | 481k | int vers = version(); |
659 | 481k | MWAWInputStreamPtr &input= m_parserState->m_input; |
660 | 481k | libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile; |
661 | 481k | libmwaw::DebugStream f; |
662 | | |
663 | 481k | int n=0; |
664 | 633k | for (auto &field : dBase.m_fields) { |
665 | 633k | int numExpected = field.getNumDefault(vers); |
666 | | |
667 | 633k | bool formField = field.isFormula(); |
668 | 633k | bool valueList = field.m_type == ClarisWksDatabaseInternal::Field::F_ValueList; |
669 | 804k | for (int fi = 0; fi < numExpected; fi++) { |
670 | | // actually we guess which one are ok |
671 | 319k | long pos = input->tell(); |
672 | 319k | auto sz = long(input->readULong(4)); |
673 | | |
674 | 319k | long endPos = pos+4+sz; |
675 | 319k | if (!input->checkPosition(endPos)) { |
676 | 47.4k | MWAW_DEBUG_MSG(("ClarisWksDatabase::readDefaults: can not find value for field: %d\n", fi)); |
677 | 47.4k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
678 | 47.4k | return false; |
679 | 47.4k | } |
680 | 272k | long length = (vers <= 2 && field.isText()) ? sz : static_cast<int>(input->readULong(1)); |
681 | 272k | f.str(""); |
682 | 272k | f << "Entries(DatabaseDft)[" << n++ << "]:"; |
683 | 272k | if (formField) { |
684 | 60.0k | if (length != sz-1) { |
685 | 9.04k | MWAW_DEBUG_MSG(("ClarisWksDatabase::readDefaults: can not find formula for field: %ld\n", long(n))); |
686 | 9.04k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
687 | 9.04k | return false; |
688 | 9.04k | } |
689 | 50.9k | f << "formula,"; |
690 | 50.9k | std::vector<MWAWCellContent::FormulaInstruction> formula; |
691 | 50.9k | std::string error; |
692 | 50.9k | if (!dBase.m_content) |
693 | 50.7k | dBase.m_content.reset(new ClarisWksDbaseContent(m_document, false)); |
694 | 50.9k | if (!dBase.m_content->readFormula(MWAWVec2i(fi,0), endPos, formula, error)) { |
695 | 47.4k | MWAW_DEBUG_MSG(("ClarisWksDatabase::readDefaults: can not find formula for field: %ld\n", long(n))); |
696 | 47.4k | } |
697 | 3.47k | else |
698 | 3.47k | field.m_formula=formula; |
699 | 1.64M | for (auto const &fo : formula) f << fo; |
700 | 50.9k | f << error; |
701 | 50.9k | } |
702 | 212k | else { |
703 | 212k | bool listField = (valueList && fi == 1) || (!valueList && fi==0 && numExpected==2); |
704 | 212k | if (listField) |
705 | 74.1k | f << "listString,"; |
706 | 138k | else |
707 | 138k | f << "string,"; |
708 | 212k | if (vers > 2 && !listField && length != sz-1) { |
709 | 22.3k | MWAW_DEBUG_MSG(("ClarisWksDatabase::readDefaults: can not find strings for field: %ld\n", long(n))); |
710 | 22.3k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
711 | 22.3k | return false; |
712 | 22.3k | } |
713 | 2.21M | while (1) { |
714 | 2.21M | long actPos = input->tell(); |
715 | 2.21M | if (actPos+length > endPos) { |
716 | 69.1k | MWAW_DEBUG_MSG(("ClarisWksDatabase::readDefaults: can not find strings for field: %ld\n", long(n))); |
717 | 69.1k | ascFile.addPos(pos); |
718 | 69.1k | ascFile.addNote("DatabaseDft:###"); |
719 | | |
720 | 69.1k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
721 | 69.1k | return true; |
722 | 69.1k | } |
723 | 2.14M | if (listField) { |
724 | 1.89M | MWAWEntry entry; |
725 | 1.89M | entry.setBegin(actPos); |
726 | 1.89M | entry.setLength(length); |
727 | 1.89M | field.m_valuesList.push_back(entry); |
728 | 1.89M | } |
729 | 2.14M | std::string name(""); |
730 | 11.2M | for (long c = 0; c < length; c++) |
731 | 9.10M | name += char(input->readULong(1)); |
732 | 2.14M | f << "'" << name << "',"; |
733 | 2.14M | if (long(input->tell()) == endPos) |
734 | 120k | break; |
735 | 2.02M | length = long(input->readULong(1)); |
736 | 2.02M | } |
737 | 189k | } |
738 | 171k | ascFile.addPos(pos); |
739 | 171k | ascFile.addNote(f.str().c_str()); |
740 | 171k | input->seek(endPos, librevenge::RVNG_SEEK_SET); |
741 | 171k | } |
742 | 633k | } |
743 | 333k | return true; |
744 | 481k | } |
745 | | |
746 | | |
747 | | bool ClarisWksDatabase::readLayout(ClarisWksDatabaseInternal::Database &dBase) |
748 | 46.9k | { |
749 | 46.9k | MWAWInputStreamPtr &input= m_parserState->m_input; |
750 | 46.9k | long pos = input->tell(); |
751 | 46.9k | ClarisWksStruct::Struct header; |
752 | 46.9k | if (!header.readHeader(input,true) || header.m_headerSize<52 || header.m_dataSize<6) { |
753 | 21.9k | MWAW_DEBUG_MSG(("ClarisWksDatabase::readLayout: can not read the header\n")); |
754 | 21.9k | return false; |
755 | 21.9k | } |
756 | 25.0k | libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile; |
757 | 25.0k | libmwaw::DebugStream f; |
758 | 25.0k | if (header.m_size==0) { |
759 | 0 | ascFile.addPos(pos); |
760 | 0 | ascFile.addNote("Nop"); |
761 | 0 | return true; |
762 | 0 | } |
763 | 25.0k | f << "DatabaseLayout-Part:" << header; |
764 | 25.0k | auto val = static_cast<int>(input->readLong(2)); |
765 | 25.0k | if (val) f << "f3=" << val << ","; |
766 | 25.0k | auto childId=int(input->readULong(2)); |
767 | 25.0k | f << "childId=" << childId << ","; |
768 | 25.0k | dBase.m_otherChilds.push_back(childId); |
769 | 75.2k | for (int i = 0; i < 2; ++i) { // f4=1-3, f5=0|c6|12a |
770 | 50.1k | val = static_cast<int>(input->readLong(2)); |
771 | 50.1k | if (val) f << "f" << i+4 << "=" << val << ","; |
772 | 50.1k | } |
773 | 125k | for (int i = 0; i<4; ++i) { // always 0|1 |
774 | 100k | val = static_cast<int>(input->readLong(1)); |
775 | 100k | if (val==1) f << "fl" << i << ","; |
776 | 81.3k | else if (val) f << "#fl" << i << "=" << val << ","; |
777 | 100k | } |
778 | 25.0k | auto sSz=static_cast<int>(input->readULong(1)); |
779 | 25.0k | if (sSz>31) { |
780 | 4.44k | MWAW_DEBUG_MSG(("ClarisWksDatabase::readLayout: find odd string size\n")); |
781 | 4.44k | f << "#sSz=" << sSz << ","; |
782 | 4.44k | } |
783 | 20.6k | else { |
784 | 20.6k | std::string name(""); |
785 | 127k | for (int i=0; i<sSz; ++i) name+=char(input->readULong(1)); |
786 | 20.6k | f << "\"" << name << "\","; |
787 | 20.6k | } |
788 | 25.0k | input->seek(pos+60, librevenge::RVNG_SEEK_SET); |
789 | 25.0k | val = static_cast<int>(input->readLong(2)); // always 0 |
790 | 25.0k | if (val) f << "g0=" << val << ","; |
791 | 25.0k | childId=static_cast<int>(input->readULong(2)); |
792 | 25.0k | f << "childId2=" << childId << ","; |
793 | 25.0k | dBase.m_otherChilds.push_back(childId); |
794 | | |
795 | 25.0k | ascFile.addDelimiter(input->tell(),'|'); |
796 | 25.0k | ascFile.addPos(pos); |
797 | 25.0k | ascFile.addNote(f.str().c_str()); |
798 | | |
799 | 25.0k | input->seek(pos+4+12+header.m_headerSize, librevenge::RVNG_SEEK_SET); |
800 | 116k | for (long i = 0; i < header.m_numData; i++) { |
801 | 91.8k | pos=input->tell(); |
802 | 91.8k | f.str(""); |
803 | 91.8k | f << "DatabaseLayout-Part" << i << ":"; |
804 | | |
805 | 91.8k | ascFile.addPos(pos); |
806 | 91.8k | ascFile.addNote(f.str().c_str()); |
807 | 91.8k | input->seek(pos+header.m_dataSize, librevenge::RVNG_SEEK_SET); |
808 | 91.8k | } |
809 | | |
810 | 25.0k | pos=input->tell(); |
811 | 25.0k | if (!ClarisWksStruct::readStructZone(*m_parserState, "DatabaseLayout", false)) { |
812 | 12.0k | MWAW_DEBUG_MSG(("ClarisWksDatabase::readLayout: can not read the layout second part\n")); |
813 | 12.0k | ascFile.addPos(pos); |
814 | 12.0k | ascFile.addNote("DatabaseLayout-B:###"); |
815 | 12.0k | return false; |
816 | 12.0k | } |
817 | 13.0k | return true; |
818 | 25.0k | } |
819 | | |
820 | | //////////////////////////////////////////////////////////// |
821 | | // |
822 | | // send data |
823 | | // |
824 | | //////////////////////////////////////////////////////////// |
825 | | bool ClarisWksDatabase::sendDatabase(int zId, MWAWListenerPtr listener) |
826 | 35.4k | { |
827 | 35.4k | if (!listener) |
828 | 11.6k | listener=m_parserState->m_spreadsheetListener; |
829 | 35.4k | if (!listener) { |
830 | 8.98k | MWAW_DEBUG_MSG(("ClarisWksDatabase::sendDatabase: called without any listener\n")); |
831 | 8.98k | return false; |
832 | 8.98k | } |
833 | 26.5k | if (listener->getType()!=MWAWListener::Spreadsheet || |
834 | 24.1k | (m_parserState->m_kind==MWAWDocument::MWAW_K_DATABASE && zId!=1)) { |
835 | 24.1k | MWAW_DEBUG_MSG(("ClarisWksDatabase::sendDatabase: sending a database is not implemented\n")); |
836 | 24.1k | return false; |
837 | 24.1k | } |
838 | | |
839 | 2.35k | auto *sheetListener=static_cast<MWAWSpreadsheetListener *>(listener.get()); |
840 | 2.35k | auto it=m_state->m_databaseMap.find(zId); |
841 | 2.35k | if (it == m_state->m_databaseMap.end() || !it->second) { |
842 | 0 | MWAW_DEBUG_MSG(("ClarisWksDatabase::sendDatabase: can not find zone %d!!!\n", zId)); |
843 | 0 | return false; |
844 | 0 | } |
845 | 2.35k | auto &dbase=*it->second; |
846 | 2.35k | MWAWVec2i minData, maxData; |
847 | 2.35k | std::vector<int> recordsPos; |
848 | 2.35k | if (!dbase.m_content || !dbase.m_content->getExtrema(minData,maxData) || |
849 | 1.67k | !dbase.m_content->getRecordList(recordsPos)) { |
850 | 676 | MWAW_DEBUG_MSG(("ClarisWksDatabase::sendDatabase: can not find any content\n")); |
851 | 676 | return false; |
852 | 676 | } |
853 | 1.67k | size_t numDataFields=dbase.m_fields.size(); |
854 | 1.67k | int numFields = std::max(maxData[0]+1,int(numDataFields)); |
855 | 1.67k | std::vector<ClarisWksStyleManager::CellFormat> formats; |
856 | 1.67k | formats.resize(size_t(numFields), ClarisWksStyleManager::CellFormat()); |
857 | 1.67k | bool hasMultimedia=false; |
858 | 8.37k | for (size_t f=0; f < dbase.m_fields.size(); ++f) { |
859 | 6.70k | switch (dbase.m_fields[f].m_type) { |
860 | 845 | case ClarisWksDatabaseInternal::Field::F_Number: |
861 | 845 | formats[f].m_format=MWAWCell::F_NUMBER; |
862 | 845 | formats[f].m_numberFormat=MWAWCell::F_NUMBER_GENERIC; |
863 | 845 | break; |
864 | 1.55k | case ClarisWksDatabaseInternal::Field::F_Date: |
865 | 1.55k | formats[f].m_format=MWAWCell::F_DATE; |
866 | 1.55k | break; |
867 | 842 | case ClarisWksDatabaseInternal::Field::F_Time: |
868 | 842 | formats[f].m_format=MWAWCell::F_TIME; |
869 | 842 | break; |
870 | 0 | case ClarisWksDatabaseInternal::Field::F_Checkbox: |
871 | 0 | formats[f].m_format=MWAWCell::F_BOOLEAN; |
872 | 0 | break; |
873 | 1 | case ClarisWksDatabaseInternal::Field::F_Multimedia: |
874 | 1 | formats[f].m_format=MWAWCell::F_TEXT; |
875 | 1 | hasMultimedia=true; |
876 | 1 | break; |
877 | 42 | case ClarisWksDatabaseInternal::Field::F_Unknown: |
878 | 2.61k | case ClarisWksDatabaseInternal::Field::F_Text: |
879 | 2.69k | case ClarisWksDatabaseInternal::Field::F_Formula: |
880 | 2.69k | case ClarisWksDatabaseInternal::Field::F_FormulaSum: |
881 | 2.69k | case ClarisWksDatabaseInternal::Field::F_PopupMenu: |
882 | 2.69k | case ClarisWksDatabaseInternal::Field::F_RadioButton: |
883 | 3.45k | case ClarisWksDatabaseInternal::Field::F_ValueList: // ok, the text is stored |
884 | | #if !defined(__clang__) |
885 | | default: |
886 | | #endif |
887 | 3.45k | switch (dbase.m_fields[f].m_resType) { |
888 | 1.58k | case 1: |
889 | 1.58k | formats[f].m_format=MWAWCell::F_NUMBER; |
890 | 1.58k | formats[f].m_numberFormat=MWAWCell::F_NUMBER_GENERIC; |
891 | 1.58k | break; |
892 | 2 | case 2: |
893 | 2 | formats[f].m_format=MWAWCell::F_DATE; |
894 | 2 | break; |
895 | 0 | case 3: |
896 | 0 | formats[f].m_format=MWAWCell::F_TIME; |
897 | 0 | break; |
898 | 1.86k | default: |
899 | 1.86k | break; |
900 | 3.45k | } |
901 | 3.45k | break; |
902 | 6.70k | } |
903 | 6.70k | } |
904 | 1.67k | dbase.m_content->setDatabaseFormats(formats); |
905 | | |
906 | 1.67k | std::vector<float> colSize(size_t(numFields),72); |
907 | 1.67k | sheetListener->openSheet(colSize, librevenge::RVNG_POINT); |
908 | 1.67k | MWAWInputStreamPtr &input= m_parserState->m_input; |
909 | 1.67k | MWAWFont const defFont; |
910 | | // increase the row height, if we can have some picture |
911 | 1.67k | float const rowHeight=!hasMultimedia ? 14.f : 72.f; |
912 | 32.2k | for (size_t r=0; r < recordsPos.size(); ++r) { |
913 | 30.5k | sheetListener->openSheetRow(rowHeight, librevenge::RVNG_POINT); |
914 | 152k | for (int c=0; c < numFields; ++c) { |
915 | 122k | ClarisWksDbaseContent::Record rec; |
916 | 122k | if (!dbase.m_content->get(MWAWVec2i(c,recordsPos[r]),rec)) continue; |
917 | 40.2k | sheetListener->setFont(defFont); |
918 | 40.2k | MWAWCell cell; |
919 | 40.2k | cell.setPosition(MWAWVec2i(c,int(r))); |
920 | 40.2k | cell.setFormat(rec.m_format); |
921 | 40.2k | cell.setHAlignment(rec.m_hAlign); |
922 | 40.2k | bool isMultimedia=false; |
923 | 40.2k | if (c<int(numDataFields)) { |
924 | 40.2k | auto const &field=dbase.m_fields[size_t(c)]; |
925 | 40.2k | if (field.m_type==ClarisWksDatabaseInternal::Field::F_Multimedia) |
926 | 4 | isMultimedia=true; |
927 | 40.2k | else if (field.m_type==ClarisWksDatabaseInternal::Field::F_Formula && !field.m_formula.empty()) { |
928 | 0 | rec.m_content.m_formula=field.m_formula; |
929 | 0 | for (auto &d : rec.m_content.m_formula) { |
930 | 0 | if (d.m_type == MWAWCellContent::FormulaInstruction::F_Cell) |
931 | 0 | d.m_position[0][1]=int(r); |
932 | 0 | } |
933 | 0 | } |
934 | 40.2k | else if (field.m_type==ClarisWksDatabaseInternal::Field::F_PopupMenu || |
935 | 40.2k | field.m_type==ClarisWksDatabaseInternal::Field::F_RadioButton) { |
936 | 5 | if (rec.m_content.isValueSet()) { |
937 | 3 | auto enumId = int(rec.m_content.m_value+0.5); |
938 | | // checkme: if the enum list is a list of float, the enum value can be stored as value:-~ |
939 | 3 | if (enumId > 0 && enumId <= int(field.m_valuesList.size()) && |
940 | 0 | double(enumId)-0.01 < rec.m_content.m_value && |
941 | 0 | double(enumId)+0.01 > rec.m_content.m_value) { |
942 | 0 | rec.m_format.m_format=MWAWCell::F_TEXT; |
943 | 0 | rec.m_content.m_textEntry=field.m_valuesList[size_t(enumId-1)]; |
944 | 0 | rec.m_content.m_valueSet=false; |
945 | 0 | cell.setFormat(rec.m_format); |
946 | 0 | } |
947 | 3 | } |
948 | 5 | } |
949 | 40.2k | } |
950 | | // change the reference date from 1/1/1904 to 1/1/1900 |
951 | 40.2k | if (rec.m_format.m_format==MWAWCell::F_DATE && rec.m_content.isValueSet()) |
952 | 2.39k | rec.m_content.setValue(rec.m_content.m_value+1460); |
953 | 37.8k | else if (isMultimedia) // do not export the picture id |
954 | 4 | rec.m_content.m_valueSet=false; |
955 | 40.2k | sheetListener->openSheetCell(cell, rec.m_content); |
956 | 40.2k | if (isMultimedia) { |
957 | 4 | auto pictId = int(rec.m_content.m_value+0.5); // pictId is saved as float, converts it back to an int |
958 | 4 | if (pictId>0) { |
959 | 2 | MWAWPosition pos(MWAWVec2f(0,0), MWAWVec2f(72,72), librevenge::RVNG_POINT); |
960 | 2 | pos.m_anchorTo=MWAWPosition::Cell; |
961 | | // we have only one sheet, so compute the cell name by hand |
962 | 2 | std::string endCellName=std::string("Sheet0.")+MWAWCell::getBasicCellName(MWAWVec2i(int(c+1),int(r+1))); |
963 | 2 | pos.m_anchorCellName=endCellName.c_str(); |
964 | 2 | m_document.sendDatabasePictZone(pictId, listener, pos); |
965 | 2 | } |
966 | 4 | } |
967 | 40.2k | else if (rec.m_content.m_textEntry.valid()) { |
968 | 18.6k | long fPos = input->tell(); |
969 | 18.6k | input->seek(rec.m_content.m_textEntry.begin(), librevenge::RVNG_SEEK_SET); |
970 | 18.6k | long endPos = rec.m_content.m_textEntry.end(); |
971 | 18.6k | int cPos=0; |
972 | 4.67M | while (!input->isEnd() && input->tell() < endPos) { |
973 | 4.65M | if (rec.m_posToFontMap.find(cPos) != rec.m_posToFontMap.end()) |
974 | 9.50k | sheetListener->setFont(rec.m_posToFontMap.find(cPos)->second); |
975 | 4.65M | auto ch=static_cast<unsigned char>(input->readULong(1)); |
976 | 4.65M | if (ch==9) |
977 | 8.70k | sheetListener->insertTab(); |
978 | 4.64M | else if (ch==0xa || ch==0xd) |
979 | 58.3k | sheetListener->insertEOL(); |
980 | 4.58M | else |
981 | 4.58M | sheetListener->insertCharacter(ch, input, endPos); |
982 | 4.65M | ++cPos; |
983 | 4.65M | } |
984 | 18.6k | input->seek(fPos,librevenge::RVNG_SEEK_SET); |
985 | 18.6k | } |
986 | 40.2k | sheetListener->closeSheetCell(); |
987 | 40.2k | } |
988 | 30.5k | sheetListener->closeSheetRow(); |
989 | 30.5k | } |
990 | 1.67k | sheetListener->closeSheet(); |
991 | 1.67k | return true; |
992 | 1.67k | } |
993 | | // vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: |