/src/libwps/src/lib/WPSOLEParser.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) 2009, 2011 Alonso Laurent (alonso@loria.fr) |
11 | | * Copyright (C) 2006, 2007 Andrew Ziem |
12 | | * Copyright (C) 2004-2006 Fridrich Strba (fridrich.strba@bluewin.ch) |
13 | | * Copyright (C) 2004 Marc Maurer (uwog@uwog.net) |
14 | | * Copyright (C) 2003-2005 William Lachance (william.lachance@sympatico.ca) |
15 | | * |
16 | | * For minor contributions see the git repository. |
17 | | * |
18 | | * Alternatively, the contents of this file may be used under the terms |
19 | | * of the GNU Lesser General Public License Version 2.1 or later |
20 | | * (LGPLv2.1+), in which case the provisions of the LGPLv2.1+ are |
21 | | * applicable instead of those above. |
22 | | * |
23 | | * For further information visit http://libwps.sourceforge.net |
24 | | */ |
25 | | |
26 | | /* |
27 | | * freely inspired from istorage : |
28 | | * ------------------------------------------------------------ |
29 | | * Generic OLE Zones furnished with a copy of the file header |
30 | | * |
31 | | * Compound Storage (32 bit version) |
32 | | * Storage implementation |
33 | | * |
34 | | * This file contains the compound file implementation |
35 | | * of the storage interface. |
36 | | * |
37 | | * Copyright 1999 Francis Beaudet |
38 | | * Copyright 1999 Sylvain St-Germain |
39 | | * Copyright 1999 Thuy Nguyen |
40 | | * Copyright 2005 Mike McCormack |
41 | | * |
42 | | * This library is free software; you can redistribute it and/or |
43 | | * modify it under the terms of the GNU Lesser General Public |
44 | | * License as published by the Free Software Foundation; either |
45 | | * version 2.1 of the License, or (at your option) any later version. |
46 | | * |
47 | | * This library is distributed in the hope that it will be useful, |
48 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
49 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
50 | | * Lesser General Public License for more details. |
51 | | * |
52 | | * You should have received a copy of the GNU Lesser General Public |
53 | | * License along with this library; if not, write to the Free Software |
54 | | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
55 | | * |
56 | | */ |
57 | | |
58 | | /* |
59 | | * NOTES |
60 | | * The compound file implementation of IStorage used for create |
61 | | * and manage substorages and streams within a storage object |
62 | | * residing in a compound file object. |
63 | | * |
64 | | * ------------------------------------------------------------ |
65 | | */ |
66 | | |
67 | | #include <cstdlib> |
68 | | #include <cstring> |
69 | | #include <map> |
70 | | #include <sstream> |
71 | | #include <string> |
72 | | |
73 | | #include <librevenge/librevenge.h> |
74 | | |
75 | | #include "WPSHeader.h" |
76 | | #include "WPSPosition.h" |
77 | | |
78 | | #include "WPSOLEParser.h" |
79 | | |
80 | | using namespace libwps; |
81 | | |
82 | | ////////////////////////////////////////////////// |
83 | | // internal structure |
84 | | ////////////////////////////////////////////////// |
85 | | namespace WPSOLEParserInternal |
86 | | { |
87 | | /** Internal: internal method to compobj definition */ |
88 | | class CompObj |
89 | | { |
90 | | public: |
91 | | //! the constructor |
92 | | CompObj() |
93 | 27.9k | : m_mapCls() |
94 | 27.9k | { |
95 | 27.9k | initCLSMap(); |
96 | 27.9k | } |
97 | | |
98 | | /** return the CLS Name corresponding to an identifier */ |
99 | | char const *getCLSName(unsigned long v) |
100 | 61 | { |
101 | 61 | if (m_mapCls.find(v) == m_mapCls.end()) return nullptr; |
102 | 50 | return m_mapCls[v]; |
103 | 61 | } |
104 | | |
105 | | protected: |
106 | | /** map CLSId <-> name */ |
107 | | std::map<unsigned long, char const *> m_mapCls; |
108 | | |
109 | | /** initialise a map CLSId <-> name */ |
110 | | void initCLSMap() |
111 | 27.9k | { |
112 | | // source: binfilter/bf_so3/source/inplace/embobj.cxx |
113 | 27.9k | m_mapCls[0x00000319]="Picture"; // addon Enhanced Metafile ( find in some file) |
114 | | |
115 | 27.9k | m_mapCls[0x00021290]="MSClipArtGalley2"; |
116 | 27.9k | m_mapCls[0x000212F0]="MSWordArt"; // or MSWordArt.2 |
117 | 27.9k | m_mapCls[0x00021302]="MSWorksREVENGEoc"; // addon |
118 | | |
119 | | // MS Apps |
120 | 27.9k | m_mapCls[0x00030000]= "ExcelWorksheet"; |
121 | 27.9k | m_mapCls[0x00030001]= "ExcelChart"; |
122 | 27.9k | m_mapCls[0x00030002]= "ExcelMacrosheet"; |
123 | 27.9k | m_mapCls[0x00030003]= "WordDocument"; |
124 | 27.9k | m_mapCls[0x00030004]= "MSPowerPoint"; |
125 | 27.9k | m_mapCls[0x00030005]= "MSPowerPointSho"; |
126 | 27.9k | m_mapCls[0x00030006]= "MSGraph"; |
127 | 27.9k | m_mapCls[0x00030007]= "MSDraw"; // find also ca003 ? |
128 | 27.9k | m_mapCls[0x00030008]= "Note-It"; |
129 | 27.9k | m_mapCls[0x00030009]= "WordArt"; |
130 | 27.9k | m_mapCls[0x0003000a]= "PBrush"; |
131 | 27.9k | m_mapCls[0x0003000b]= "Equation"; // "Microsoft Equation Editor" |
132 | 27.9k | m_mapCls[0x0003000c]= "Package"; |
133 | 27.9k | m_mapCls[0x0003000d]= "SoundRec"; |
134 | 27.9k | m_mapCls[0x0003000e]= "MPlayer"; |
135 | | // MS Demos |
136 | 27.9k | m_mapCls[0x0003000f]= "ServerDemo"; // "OLE 1.0 Server Demo" |
137 | 27.9k | m_mapCls[0x00030010]= "Srtest"; // "OLE 1.0 Test Demo" |
138 | 27.9k | m_mapCls[0x00030011]= "SrtInv"; // "OLE 1.0 Inv Demo" |
139 | 27.9k | m_mapCls[0x00030012]= "OleDemo"; //"OLE 1.0 Demo" |
140 | | |
141 | | // Coromandel / Dorai Swamy / 718-793-7963 |
142 | 27.9k | m_mapCls[0x00030013]= "CoromandelIntegra"; |
143 | 27.9k | m_mapCls[0x00030014]= "CoromandelObjServer"; |
144 | | |
145 | | // 3-d Visions Corp / Peter Hirsch / 310-325-1339 |
146 | 27.9k | m_mapCls[0x00030015]= "StanfordGraphics"; |
147 | | |
148 | | // Deltapoint / Nigel Hearne / 408-648-4000 |
149 | 27.9k | m_mapCls[0x00030016]= "DGraphCHART"; |
150 | 27.9k | m_mapCls[0x00030017]= "DGraphDATA"; |
151 | | |
152 | | // Corel / Richard V. Woodend / 613-728-8200 x1153 |
153 | 27.9k | m_mapCls[0x00030018]= "PhotoPaint"; // "Corel PhotoPaint" |
154 | 27.9k | m_mapCls[0x00030019]= "CShow"; // "Corel Show" |
155 | 27.9k | m_mapCls[0x0003001a]= "CorelChart"; |
156 | 27.9k | m_mapCls[0x0003001b]= "CDraw"; // "Corel Draw" |
157 | | |
158 | | // Inset Systems / Mark Skiba / 203-740-2400 |
159 | 27.9k | m_mapCls[0x0003001c]= "HJWIN1.0"; // "Inset Systems" |
160 | | |
161 | | // Mark V Systems / Mark McGraw / 818-995-7671 |
162 | 27.9k | m_mapCls[0x0003001d]= "ObjMakerOLE"; // "MarkV Systems Object Maker" |
163 | | |
164 | | // IdentiTech / Mike Gilger / 407-951-9503 |
165 | 27.9k | m_mapCls[0x0003001e]= "FYI"; // "IdentiTech FYI" |
166 | 27.9k | m_mapCls[0x0003001f]= "FYIView"; // "IdentiTech FYI Viewer" |
167 | | |
168 | | // Inventa Corporation / Balaji Varadarajan / 408-987-0220 |
169 | 27.9k | m_mapCls[0x00030020]= "Stickynote"; |
170 | | |
171 | | // ShapeWare Corp. / Lori Pearce / 206-467-6723 |
172 | 27.9k | m_mapCls[0x00030021]= "ShapewareVISIO10"; |
173 | 27.9k | m_mapCls[0x00030022]= "ImportServer"; // "Spaheware Import Server" |
174 | | |
175 | | // test app SrTest |
176 | 27.9k | m_mapCls[0x00030023]= "SrvrTest"; // "OLE 1.0 Server Test" |
177 | | |
178 | | // test app ClTest. Doesn't really work as a server but is in reg db |
179 | 27.9k | m_mapCls[0x00030025]= "Cltest"; // "OLE 1.0 Client Test" |
180 | | |
181 | | // Microsoft ClipArt Gallery Sherry Larsen-Holmes |
182 | 27.9k | m_mapCls[0x00030026]= "MS_ClipArt_Gallery"; |
183 | | // Microsoft Project Cory Reina |
184 | 27.9k | m_mapCls[0x00030027]= "MSProject"; |
185 | | |
186 | | // Microsoft Works Chart |
187 | 27.9k | m_mapCls[0x00030028]= "MSWorksChart"; |
188 | | |
189 | | // Microsoft Works Spreadsheet |
190 | 27.9k | m_mapCls[0x00030029]= "MSWorksSpreadsheet"; |
191 | | |
192 | | // AFX apps - Dean McCrory |
193 | 27.9k | m_mapCls[0x0003002A]= "MinSvr"; // "AFX Mini Server" |
194 | 27.9k | m_mapCls[0x0003002B]= "HierarchyList"; // "AFX Hierarchy List" |
195 | 27.9k | m_mapCls[0x0003002C]= "BibRef"; // "AFX BibRef" |
196 | 27.9k | m_mapCls[0x0003002D]= "MinSvrMI"; // "AFX Mini Server MI" |
197 | 27.9k | m_mapCls[0x0003002E]= "TestServ"; // "AFX Test Server" |
198 | | |
199 | | // Ami Pro |
200 | 27.9k | m_mapCls[0x0003002F]= "AmiProDocument"; |
201 | | |
202 | | // WordPerfect Presentations For Windows |
203 | 27.9k | m_mapCls[0x00030030]= "WPGraphics"; |
204 | 27.9k | m_mapCls[0x00030031]= "WPCharts"; |
205 | | |
206 | | // MicroGrafx Charisma |
207 | 27.9k | m_mapCls[0x00030032]= "Charisma"; |
208 | 27.9k | m_mapCls[0x00030033]= "Charisma_30"; // v 3.0 |
209 | 27.9k | m_mapCls[0x00030034]= "CharPres_30"; // v 3.0 Pres |
210 | | // MicroGrafx Draw |
211 | 27.9k | m_mapCls[0x00030035]= "Draw"; //"MicroGrafx Draw" |
212 | | // MicroGrafx Designer |
213 | 27.9k | m_mapCls[0x00030036]= "Designer_40"; // "MicroGrafx Designer 4.0" |
214 | | |
215 | | // STAR DIVISION |
216 | | //m_mapCls[0x000424CA]= "StarMath"; // "StarMath 1.0" |
217 | 27.9k | m_mapCls[0x00043AD2]= "FontWork"; // "Star FontWork" |
218 | | //m_mapCls[0x000456EE]= "StarMath2"; // "StarMath 2.0" |
219 | 27.9k | } |
220 | | }; |
221 | | |
222 | | /** Internal: internal method to keep ole definition */ |
223 | | struct OleDef |
224 | | { |
225 | | OleDef() |
226 | 52.2k | : m_id(-1) |
227 | 52.2k | , m_base("") |
228 | 52.2k | , m_dir("") |
229 | 52.2k | , m_name("") { } |
230 | | int m_id /**main id*/; |
231 | | std::string m_base/** the base name*/, m_dir/**the directory*/, m_name/**the complete name*/; |
232 | | }; |
233 | | |
234 | | /** Internal: the state of a WPSOLEParser */ |
235 | | struct State |
236 | | { |
237 | | //! constructor |
238 | | State(libwps_tools_win::Font::Type fontType, std::function<int(std::string const &)> const &dirToIdFunc) |
239 | 27.9k | : m_fontType(fontType) |
240 | 27.9k | , m_directoryToIdFunction(dirToIdFunc) |
241 | 27.9k | , m_metaData() |
242 | 27.9k | , m_unknownOLEs() |
243 | 27.9k | , m_idToObjectMap() |
244 | 27.9k | , m_compObjIdName() |
245 | 27.9k | { |
246 | 27.9k | } |
247 | | //! the default font type |
248 | | libwps_tools_win::Font::Type m_fontType; |
249 | | //! the function used to convert a directory name in a id |
250 | | std::function<int(std::string const &)> m_directoryToIdFunction; |
251 | | //! the meta data |
252 | | librevenge::RVNGPropertyList m_metaData; |
253 | | //! list of ole which can not be parsed |
254 | | std::vector<std::string> m_unknownOLEs; |
255 | | //! map id to object |
256 | | std::map<int, WPSEmbeddedObject> m_idToObjectMap; |
257 | | |
258 | | //! a smart ptr used to stored the list of compobj id->name |
259 | | std::shared_ptr<WPSOLEParserInternal::CompObj> m_compObjIdName; |
260 | | }; |
261 | | } |
262 | | |
263 | | // constructor/destructor |
264 | | WPSOLEParser::WPSOLEParser(const std::string &mainName, libwps_tools_win::Font::Type fontType, |
265 | | std::function<int(std::string const &)> const &dirToIdFunc) |
266 | 27.9k | : m_avoidOLE(mainName) |
267 | 27.9k | , m_state(new WPSOLEParserInternal::State(fontType, dirToIdFunc)) |
268 | 27.9k | { |
269 | 27.9k | } |
270 | | |
271 | | WPSOLEParser::~WPSOLEParser() |
272 | 27.9k | { |
273 | 27.9k | } |
274 | | |
275 | | |
276 | | std::vector<std::string> const &WPSOLEParser::getNotParse() const |
277 | 0 | { |
278 | 0 | return m_state->m_unknownOLEs; |
279 | 0 | } |
280 | | //! returns the list of data positions which have been read |
281 | | std::map<int,WPSEmbeddedObject> const &WPSOLEParser::getObjectsMap() const |
282 | 27.9k | { |
283 | 27.9k | return m_state->m_idToObjectMap; |
284 | 27.9k | } |
285 | | void WPSOLEParser::updateMetaData(librevenge::RVNGPropertyList &metaData) const |
286 | 18.1k | { |
287 | 18.1k | librevenge::RVNGPropertyList::Iter i(m_state->m_metaData); |
288 | 18.4k | for (i.rewind(); i.next();) |
289 | 290 | { |
290 | 290 | if (!metaData[i.key()]) |
291 | 290 | metaData.insert(i.key(),i()->clone()); |
292 | 290 | } |
293 | 18.1k | } |
294 | | // parsing |
295 | | int WPSOLEParser::getIdFromDirectory(std::string const &dirName) |
296 | 34.9k | { |
297 | | // try to retrieve the identificator stored in the directory |
298 | | // MatOST/MatadorObject1/ -> 1, -1 |
299 | | // Object 2/ -> 2, -1 |
300 | 34.9k | auto dir=dirName+'/'; |
301 | 34.9k | auto pos = dir.find('/'); |
302 | 70.1k | while (pos != std::string::npos) |
303 | 39.2k | { |
304 | 39.2k | if (pos >= 1 && dir[pos-1] >= '0' && dir[pos-1] <= '9') |
305 | 4.05k | { |
306 | 4.05k | auto idP = pos-1; |
307 | 8.24k | while (idP >=1 && dir[idP-1] >= '0' && dir[idP-1] <= '9') |
308 | 4.18k | idP--; |
309 | 4.05k | int val = std::atoi(dir.substr(idP, idP-pos).c_str()); |
310 | 4.05k | return val; |
311 | 4.05k | } |
312 | 35.2k | pos = dir.find('/', pos+1); |
313 | 35.2k | } |
314 | 30.9k | WPS_DEBUG_MSG(("WPSOLEParser::getIdFromDirectory: can not find id for %s\n", dirName.c_str())); |
315 | 30.9k | return -1; |
316 | 34.9k | } |
317 | | |
318 | | bool WPSOLEParser::parse(RVNGInputStreamPtr file) |
319 | 27.9k | { |
320 | 27.9k | if (!m_state->m_compObjIdName) |
321 | 27.9k | m_state->m_compObjIdName.reset(new WPSOLEParserInternal::CompObj); |
322 | | |
323 | 27.9k | m_state->m_unknownOLEs.resize(0); |
324 | 27.9k | m_state->m_idToObjectMap.clear(); |
325 | | |
326 | 27.9k | if (!file || !file->isStructured()) return false; |
327 | | |
328 | | // |
329 | | // we begin by grouping the Ole by their potential main id |
330 | | // |
331 | 27.9k | std::multimap<int, WPSOLEParserInternal::OleDef> listsById; |
332 | 27.9k | std::vector<int> listIds; |
333 | 27.9k | unsigned numSubStreams = file->subStreamCount(); |
334 | 139k | for (unsigned i = 0; i < numSubStreams; ++i) |
335 | 111k | { |
336 | 111k | char const *nm=file->subStreamName(i); |
337 | 111k | if (!nm) continue; |
338 | 111k | std::string name(nm); |
339 | 111k | if (name.empty() || name[name.length()-1]=='/') continue; |
340 | | // separated the directory and the name |
341 | | // MatOST/MatadorObject1/Ole10Native |
342 | | // -> dir="MatOST/MatadorObject1", base="Ole10Native" |
343 | 76.3k | auto pos = name.find_last_of('/'); |
344 | | |
345 | 76.3k | std::string dir, base; |
346 | 76.3k | if (pos == std::string::npos) base = name; |
347 | 20.0k | else if (pos == 0) base = name.substr(1); |
348 | 19.7k | else |
349 | 19.7k | { |
350 | 19.7k | dir = name.substr(0,pos); |
351 | 19.7k | base = name.substr(pos+1); |
352 | 19.7k | } |
353 | 76.3k | if (dir == "" && base == m_avoidOLE) continue; |
354 | | |
355 | 52.2k | #define PRINT_OLE_NAME |
356 | 52.2k | #ifdef PRINT_OLE_NAME |
357 | 52.2k | WPS_DEBUG_MSG(("WPSOLEParser::parse: find OLEName=%s\n", name.c_str())); |
358 | 52.2k | #endif |
359 | 52.2k | WPSOLEParserInternal::OleDef data; |
360 | 52.2k | data.m_name = name; |
361 | 52.2k | data.m_base = base; |
362 | 52.2k | data.m_dir = dir; |
363 | 52.2k | data.m_id = m_state->m_directoryToIdFunction(dir); |
364 | 52.2k | if (listsById.find(data.m_id) == listsById.end()) |
365 | 19.2k | listIds.push_back(data.m_id); |
366 | 52.2k | listsById.insert(std::multimap<int, WPSOLEParserInternal::OleDef>::value_type(data.m_id, data)); |
367 | 52.2k | } |
368 | | |
369 | 27.9k | for (auto id : listIds) |
370 | 19.2k | { |
371 | 19.2k | auto pos = listsById.lower_bound(id); |
372 | | |
373 | | // try to find a representation for each id |
374 | | // FIXME: maybe we must also find some for each subid |
375 | 19.2k | WPSEmbeddedObject pict; |
376 | | |
377 | 71.4k | while (pos != listsById.end()) |
378 | 55.0k | { |
379 | 55.0k | auto const &dOle = pos->second; |
380 | 55.0k | if (pos->first != id) break; |
381 | 52.2k | ++pos; |
382 | | |
383 | 52.2k | RVNGInputStreamPtr ole(file->getSubStreamByName(dOle.m_name.c_str())); |
384 | 52.2k | if (!ole) |
385 | 20.3k | { |
386 | 20.3k | WPS_DEBUG_MSG(("WPSOLEParser: error: can not find OLE part: \"%s\"\n", dOle.m_name.c_str())); |
387 | 20.3k | continue; |
388 | 20.3k | } |
389 | | |
390 | 31.8k | libwps::DebugFile asciiFile(ole); |
391 | 31.8k | asciiFile.open(dOle.m_name); |
392 | 31.8k | bool ok = true; |
393 | | |
394 | 31.8k | try |
395 | 31.8k | { |
396 | 31.8k | librevenge::RVNGPropertyList pList; |
397 | 31.8k | if (readMM(ole, dOle.m_base, asciiFile)); |
398 | 31.7k | else if (readSummaryInformation(ole, dOle.m_base, dOle.m_dir.empty() ? m_state->m_metaData : pList, asciiFile)); |
399 | 28.0k | else if (readObjInfo(ole, dOle.m_base, asciiFile)); |
400 | 28.0k | else if (readOle(ole, dOle.m_base, asciiFile)); |
401 | 26.8k | else if (readMN0AndCheckWKS(ole, dOle.m_base, pict, asciiFile)); |
402 | 26.5k | else if (isOlePres(ole, dOle.m_base) && readOlePres(ole, pict, asciiFile)); |
403 | 25.9k | else if (isOle10Native(ole, dOle.m_base) && readOle10Native(ole, pict, asciiFile)); |
404 | 25.7k | else if (readCompObj(ole, dOle.m_base, asciiFile)); |
405 | 22.4k | else if (readContents(ole, dOle.m_base, pict, asciiFile)); |
406 | 22.4k | else if (readCONTENTS(ole, dOle.m_base, pict, asciiFile)); |
407 | 22.4k | else |
408 | 22.4k | ok = false; |
409 | 31.8k | } |
410 | 31.8k | catch (...) |
411 | 31.8k | { |
412 | 0 | ok = false; |
413 | 0 | } |
414 | 31.8k | if (!ok) |
415 | 22.4k | m_state->m_unknownOLEs.push_back(dOle.m_name); |
416 | 31.8k | asciiFile.reset(); |
417 | 31.8k | } |
418 | | |
419 | 19.2k | if (!pict.isEmpty()) |
420 | 868 | m_state->m_idToObjectMap[id]=pict; |
421 | 19.2k | } |
422 | | |
423 | 27.9k | return true; |
424 | 27.9k | } |
425 | | |
426 | | |
427 | | |
428 | | //////////////////////////////////////// |
429 | | // |
430 | | // small structure |
431 | | // |
432 | | //////////////////////////////////////// |
433 | | bool WPSOLEParser::readOle(RVNGInputStreamPtr &ip, std::string const &oleName, |
434 | | libwps::DebugFile &ascii) |
435 | 28.0k | { |
436 | 28.0k | if (!ip.get()) return false; |
437 | | |
438 | 28.0k | if (strcmp("Ole",oleName.c_str()) != 0) return false; |
439 | | |
440 | 2.51k | if (ip->seek(20, librevenge::RVNG_SEEK_SET) != 0 || ip->tell() != 20) return false; |
441 | | |
442 | 2.25k | ip->seek(0, librevenge::RVNG_SEEK_SET); |
443 | | |
444 | 2.25k | int val[20]; |
445 | 2.25k | for (int &i : val) |
446 | 31.8k | { |
447 | 31.8k | i = libwps::read8(ip); |
448 | 31.8k | if (i < -10 || i > 10) return false; |
449 | 31.8k | } |
450 | | |
451 | 1.23k | libwps::DebugStream f; |
452 | 1.23k | f << "@@Ole: "; |
453 | | // always 1, 0, 2, 0* |
454 | 25.8k | for (int i = 0; i < 20; i++) |
455 | 24.6k | if (val[i]) f << "f" << i << "=" << val[i] << ","; |
456 | 1.23k | ascii.addPos(0); |
457 | 1.23k | ascii.addNote(f.str().c_str()); |
458 | | |
459 | 1.23k | if (!ip->isEnd()) |
460 | 189 | { |
461 | 189 | ascii.addPos(20); |
462 | 189 | ascii.addNote("@@Ole:###"); |
463 | 189 | } |
464 | | |
465 | 1.23k | return true; |
466 | 2.25k | } |
467 | | |
468 | | bool WPSOLEParser::readObjInfo(RVNGInputStreamPtr &input, std::string const &oleName, |
469 | | libwps::DebugFile &ascii) |
470 | 28.0k | { |
471 | 28.0k | if (strcmp(oleName.c_str(),"ObjInfo") != 0) return false; |
472 | | |
473 | 0 | input->seek(14, librevenge::RVNG_SEEK_SET); |
474 | 0 | if (input->tell() != 6 || !input->isEnd()) return false; |
475 | | |
476 | 0 | input->seek(0, librevenge::RVNG_SEEK_SET); |
477 | 0 | libwps::DebugStream f; |
478 | 0 | f << "@@ObjInfo:"; |
479 | | |
480 | | // always 0, 3, 4 ? |
481 | 0 | for (int i = 0; i < 3; i++) f << libwps::read16(input) << ","; |
482 | |
|
483 | 0 | ascii.addPos(0); |
484 | 0 | ascii.addNote(f.str().c_str()); |
485 | |
|
486 | 0 | return true; |
487 | 0 | } |
488 | | |
489 | | bool WPSOLEParser::readMM(RVNGInputStreamPtr &input, std::string const &oleName, |
490 | | libwps::DebugFile &ascii) |
491 | 31.8k | { |
492 | 31.8k | if (strcmp(oleName.c_str(),"MM") != 0) return false; |
493 | | |
494 | 755 | input->seek(14, librevenge::RVNG_SEEK_SET); |
495 | 755 | if (input->tell() != 14 || !input->isEnd()) return false; |
496 | | |
497 | 241 | input->seek(0, librevenge::RVNG_SEEK_SET); |
498 | 241 | int entete = libwps::readU16(input); |
499 | 241 | if (entete != 0x444e) |
500 | 147 | { |
501 | 147 | if (entete == 0x4e44) |
502 | 0 | { |
503 | 0 | WPS_DEBUG_MSG(("WPSOLEParser::readMM: ERROR: endian mode probably bad, potentially bad PC/Mac mode detection.\n")); |
504 | 0 | } |
505 | 147 | return false; |
506 | 147 | } |
507 | 94 | libwps::DebugStream f; |
508 | 94 | f << "@@MM:"; |
509 | | |
510 | 94 | int val[6]; |
511 | 94 | for (int &i : val) |
512 | 564 | i = libwps::read16(input); |
513 | | |
514 | 94 | switch (val[5]) |
515 | 94 | { |
516 | 3 | case 0: |
517 | 3 | f << "conversion,"; |
518 | 3 | break; |
519 | 5 | case 2: |
520 | 5 | f << "Works3,"; |
521 | 5 | break; |
522 | 71 | case 4: |
523 | 71 | f << "Works4,"; |
524 | 71 | break; |
525 | 15 | default: |
526 | 15 | f << "version=unknown,"; |
527 | 15 | break; |
528 | 94 | } |
529 | | |
530 | | // 1, 0, 0, 0, 0 : Mac file |
531 | | // 0, 1, 0, [0,1,2,4,6], 0 : Pc file |
532 | 564 | for (int i = 0; i < 5; i++) |
533 | 470 | { |
534 | 470 | if ((i%2)!=1 && val[i]) f << "###"; |
535 | 470 | f << val[i] << ","; |
536 | 470 | } |
537 | | |
538 | 94 | ascii.addPos(0); |
539 | 94 | ascii.addNote(f.str().c_str()); |
540 | | |
541 | 94 | return true; |
542 | 94 | } |
543 | | |
544 | | |
545 | | bool WPSOLEParser::readCompObj(RVNGInputStreamPtr &ip, std::string const &oleName, libwps::DebugFile &ascii) |
546 | 25.7k | { |
547 | 25.7k | if (strncmp(oleName.c_str(), "CompObj", 7) != 0) return false; |
548 | | |
549 | | // check minimal size |
550 | 5.68k | const int minSize = 12 + 14+ 16 + 12; // size of header, clsid, footer, 3 string size |
551 | 5.68k | if (ip->seek(minSize,librevenge::RVNG_SEEK_SET) != 0 || ip->tell() != minSize) return false; |
552 | | |
553 | 5.30k | libwps::DebugStream f; |
554 | 5.30k | f << "@@CompObj(Header): "; |
555 | 5.30k | ip->seek(0,librevenge::RVNG_SEEK_SET); |
556 | | |
557 | 37.1k | for (int i = 0; i < 6; i++) |
558 | 31.8k | { |
559 | 31.8k | auto val = long(libwps::readU16(ip)); |
560 | 31.8k | f << val << ", "; |
561 | 31.8k | } |
562 | | |
563 | 5.30k | ascii.addPos(0); |
564 | 5.30k | ascii.addNote(f.str().c_str()); |
565 | | |
566 | 5.30k | ascii.addPos(12); |
567 | | // the clsid |
568 | 5.30k | unsigned long clsData[4]; // ushort n1, n2, n3, b8, ... b15 |
569 | 5.30k | for (unsigned long &i : clsData) |
570 | 21.2k | i = libwps::readU32(ip); |
571 | | |
572 | 5.30k | f.str(""); |
573 | 5.30k | f << "@@CompObj(CLSID):"; |
574 | 5.30k | if (clsData[1] == 0 && clsData[2] == 0xC0 && clsData[3] == 0x46000000L) |
575 | 61 | { |
576 | | // normally, a referenced object |
577 | 61 | char const *clsName = m_state->m_compObjIdName->getCLSName(clsData[0]); |
578 | 61 | if (clsName) |
579 | 50 | f << "'" << clsName << "'"; |
580 | 11 | else |
581 | 11 | { |
582 | 11 | WPS_DEBUG_MSG(("WPSOLEParser::readCompObj: unknown clsid=%lx\n", clsData[0])); |
583 | 11 | f << "unknCLSID='" << std::hex << clsData[0] << "'"; |
584 | 11 | } |
585 | 61 | } |
586 | 5.24k | else |
587 | 5.24k | { |
588 | | /* I found: |
589 | | c1dbcd28e20ace11a29a00aa004a1a72 for MSWorks.Table |
590 | | c2dbcd28e20ace11a29a00aa004a1a72 for Microsoft Works/MSWorksREVENGEoc |
591 | | a3bcb394c2bd1b10a18306357c795b37 for Microsoft Drawing 1.01/MSDraw.1.01 |
592 | | b25aa40e0a9ed111a40700c04fb932ba for Quill96 Story Group Class ( basic MSWorks doc?) |
593 | | 796827ed8bc9d111a75f00c04fb9667b for MSWorks4Sheet |
594 | | */ |
595 | 5.24k | f << "data0=(" << std::hex << clsData[0] << "," << clsData[1] << "), " |
596 | 5.24k | << "data1=(" << clsData[2] << "," << clsData[3] << ")"; |
597 | 5.24k | } |
598 | 5.30k | ascii.addNote(f.str().c_str()); |
599 | 5.30k | f << std::dec; |
600 | 16.6k | for (int ch = 0; ch < 3; ch++) |
601 | 13.2k | { |
602 | 13.2k | long actPos = ip->tell(); |
603 | 13.2k | long sz = libwps::read32(ip); |
604 | 13.2k | bool waitNumber = sz == -1; |
605 | 13.2k | if (waitNumber) sz = 4; |
606 | 13.2k | if (sz < 0 || ip->seek(actPos+4+sz,librevenge::RVNG_SEEK_SET) != 0 || |
607 | 11.3k | ip->tell() != actPos+4+sz) return false; |
608 | 11.3k | ip->seek(actPos+4,librevenge::RVNG_SEEK_SET); |
609 | | |
610 | 11.3k | std::string st; |
611 | 11.3k | if (waitNumber) |
612 | 989 | { |
613 | 989 | f.str(""); |
614 | 989 | f << libwps::read32(ip) << "[val*]"; |
615 | 989 | st = f.str(); |
616 | 989 | } |
617 | 10.3k | else |
618 | 10.3k | { |
619 | 89.2k | for (int i = 0; i < sz; i++) |
620 | 78.9k | st += char(libwps::readU8(ip)); |
621 | 10.3k | } |
622 | | |
623 | 11.3k | f.str(""); |
624 | 11.3k | f << "@@CompObj:"; |
625 | 11.3k | switch (ch) |
626 | 11.3k | { |
627 | 4.18k | case 0: |
628 | 4.18k | f << "UserType="; |
629 | 4.18k | break; |
630 | 3.77k | case 1: |
631 | 3.77k | f << "ClipName="; |
632 | 3.77k | break; |
633 | 3.40k | case 2: |
634 | 3.40k | f << "ProgIdName="; |
635 | 3.40k | break; |
636 | 0 | default: |
637 | 0 | break; |
638 | 11.3k | } |
639 | 11.3k | f << st; |
640 | 11.3k | ascii.addPos(actPos); |
641 | 11.3k | ascii.addNote(f.str().c_str()); |
642 | 11.3k | } |
643 | | |
644 | 3.40k | if (ip->isEnd()) return true; |
645 | | |
646 | 3.25k | long actPos = ip->tell(); |
647 | 3.25k | long nbElt = 4; |
648 | 3.25k | if (ip->seek(actPos+16,librevenge::RVNG_SEEK_SET) != 0 || |
649 | 2.95k | ip->tell() != actPos+16) |
650 | 298 | { |
651 | 298 | if ((ip->tell()-actPos)%4) return false; |
652 | 154 | nbElt = (ip->tell()-actPos)/4; |
653 | 154 | } |
654 | | |
655 | 3.10k | f.str(""); |
656 | 3.10k | f << "@@CompObj(Footer): " << std::hex; |
657 | 3.10k | ip->seek(actPos,librevenge::RVNG_SEEK_SET); |
658 | 15.2k | for (int i = 0; i < nbElt; i++) |
659 | 12.1k | f << libwps::readU32(ip) << ","; |
660 | 3.10k | ascii.addPos(actPos); |
661 | 3.10k | ascii.addNote(f.str().c_str()); |
662 | | |
663 | 3.10k | ascii.addPos(ip->tell()); |
664 | | |
665 | 3.10k | return true; |
666 | 3.25k | } |
667 | | |
668 | | ////////////////////////////////////////////////// |
669 | | // |
670 | | // OlePres001 seems to contained standart picture file and size |
671 | | // extract the picture if it is possible |
672 | | // |
673 | | ////////////////////////////////////////////////// |
674 | | |
675 | | bool WPSOLEParser::isOlePres(RVNGInputStreamPtr &ip, std::string const &oleName) |
676 | 27.0k | { |
677 | 27.0k | if (!ip.get()) return false; |
678 | | |
679 | 27.0k | if (strncmp("OlePres",oleName.c_str(),7) != 0) return false; |
680 | | |
681 | 1.93k | if (ip->seek(40, librevenge::RVNG_SEEK_SET) != 0 || ip->tell() != 40) return false; |
682 | | |
683 | 1.90k | ip->seek(0, librevenge::RVNG_SEEK_SET); |
684 | 5.40k | for (int i= 0; i < 2; i++) |
685 | 3.67k | { |
686 | 3.67k | long val = libwps::read32(ip); |
687 | 3.67k | if (val < -10 || val > 10) return false; |
688 | 3.67k | } |
689 | | |
690 | 1.73k | long actPos = ip->tell(); |
691 | 1.73k | int hSize = libwps::read32(ip); |
692 | 1.73k | if (hSize < 4) return false; |
693 | 1.61k | if (ip->seek(actPos+hSize+28, librevenge::RVNG_SEEK_SET) != 0 |
694 | 1.53k | || ip->tell() != actPos+hSize+28) |
695 | 78 | return false; |
696 | | |
697 | 1.53k | ip->seek(actPos+hSize, librevenge::RVNG_SEEK_SET); |
698 | 7.30k | for (int i= 3; i < 7; i++) |
699 | 5.92k | { |
700 | 5.92k | long val = libwps::read32(ip); |
701 | 5.92k | if (val < -10 || val > 10) |
702 | 454 | { |
703 | 454 | if (i != 5 || val > 256) return false; |
704 | 454 | } |
705 | 5.92k | } |
706 | | |
707 | 1.38k | ip->seek(8, librevenge::RVNG_SEEK_CUR); |
708 | 1.38k | long size = libwps::read32(ip); |
709 | | |
710 | 1.38k | if (size <= 0) return ip->isEnd(); |
711 | | |
712 | 1.30k | actPos = ip->tell(); |
713 | 1.30k | if (ip->seek(actPos+size, librevenge::RVNG_SEEK_SET) != 0 |
714 | 1.14k | || ip->tell() != actPos+size) |
715 | 162 | return false; |
716 | | |
717 | 1.14k | return true; |
718 | 1.30k | } |
719 | | |
720 | | bool WPSOLEParser::readOlePres(RVNGInputStreamPtr &ip, WPSEmbeddedObject &obj, libwps::DebugFile &ascii) |
721 | 573 | { |
722 | 573 | if (!isOlePres(ip, "OlePres")) return false; |
723 | | |
724 | 573 | libwps::DebugStream f; |
725 | 573 | f << "@@OlePress(header): "; |
726 | 573 | ip->seek(0,librevenge::RVNG_SEEK_SET); |
727 | 1.71k | for (int i = 0; i < 2; i++) |
728 | 1.14k | { |
729 | 1.14k | long val = libwps::read32(ip); |
730 | 1.14k | f << val << ", "; |
731 | 1.14k | } |
732 | | |
733 | 573 | long actPos = ip->tell(); |
734 | 573 | int hSize = libwps::read32(ip); |
735 | 573 | if (hSize < 4) return false; |
736 | 573 | f << "hSize = " << hSize; |
737 | 573 | ascii.addPos(0); |
738 | 573 | ascii.addNote(f.str().c_str()); |
739 | | |
740 | 573 | long endHPos = actPos+hSize; |
741 | 573 | if (hSize > 4) // CHECKME |
742 | 209 | { |
743 | 209 | bool ok = true; |
744 | 209 | f.str(""); |
745 | 209 | f << "@@OlePress(headerA): "; |
746 | 209 | if (hSize < 14) ok = false; |
747 | 208 | else |
748 | 208 | { |
749 | | // 12,21,32|48,0 |
750 | 1.04k | for (int i = 0; i < 4; i++) f << libwps::read16(ip) << ","; |
751 | | // 3 name of creator |
752 | 738 | for (int ch=0; ch < 3; ch++) |
753 | 580 | { |
754 | 580 | std::string str; |
755 | 580 | bool find = false; |
756 | 8.92k | while (ip->tell() < endHPos) |
757 | 8.87k | { |
758 | 8.87k | unsigned char c = libwps::readU8(ip); |
759 | 8.87k | if (c == 0) |
760 | 530 | { |
761 | 530 | find = true; |
762 | 530 | break; |
763 | 530 | } |
764 | 8.34k | str += char(c); |
765 | 8.34k | } |
766 | 580 | if (!find) |
767 | 50 | { |
768 | 50 | ok = false; |
769 | 50 | break; |
770 | 50 | } |
771 | 530 | f << ", name" << ch << "=" << str; |
772 | 530 | } |
773 | 208 | if (ok) ok = ip->tell() == endHPos; |
774 | 208 | } |
775 | | // FIXME, normally they remain only a few bits (size unknown) |
776 | 209 | if (!ok) f << "###"; |
777 | 209 | ascii.addPos(actPos); |
778 | 209 | ascii.addNote(f.str().c_str()); |
779 | 209 | } |
780 | 573 | if (ip->seek(endHPos+28, librevenge::RVNG_SEEK_SET) != 0 |
781 | 573 | || ip->tell() != endHPos+28) |
782 | 0 | return false; |
783 | | |
784 | 573 | ip->seek(endHPos, librevenge::RVNG_SEEK_SET); |
785 | | |
786 | 573 | actPos = ip->tell(); |
787 | 573 | f.str(""); |
788 | 573 | f << "@@OlePress(headerB): "; |
789 | 2.86k | for (int i = 3; i < 7; i++) |
790 | 2.29k | { |
791 | 2.29k | long val = libwps::read32(ip); |
792 | 2.29k | f << val << ", "; |
793 | 2.29k | } |
794 | | // dim in TWIP ? |
795 | 573 | auto extendX = long(libwps::readU32(ip)); |
796 | 573 | auto extendY = long(libwps::readU32(ip)); |
797 | 573 | if (extendX > 0 && extendY > 0 && obj.m_size!=Vec2f()) |
798 | 0 | obj.m_size=Vec2f(float(extendX)/1440.f, float(extendY)/1440.f); |
799 | 573 | long fSize = libwps::read32(ip); |
800 | 573 | f << "extendX="<< extendX << ", extendY=" << extendY << ", fSize=" << fSize; |
801 | | |
802 | 573 | ascii.addPos(actPos); |
803 | 573 | ascii.addNote(f.str().c_str()); |
804 | | |
805 | 573 | if (fSize == 0) return ip->isEnd(); |
806 | | |
807 | 573 | librevenge::RVNGBinaryData data; |
808 | 573 | if (!libwps::readData(ip, static_cast<unsigned long>(fSize), data)) return false; |
809 | 573 | obj.add(data); |
810 | | #ifdef DEBUG_WITH_FILES |
811 | | std::stringstream s; |
812 | | static int num=0; |
813 | | s << "OlePress" << num++; |
814 | | libwps::Debug::dumpFile(data, s.str().c_str()); |
815 | | #endif |
816 | 573 | if (!ip->isEnd()) |
817 | 343 | { |
818 | 343 | ascii.addPos(ip->tell()); |
819 | 343 | ascii.addNote("@@OlePress###"); |
820 | 343 | } |
821 | | |
822 | 573 | ascii.skipZone(36+hSize,36+hSize+fSize-1); |
823 | 573 | return true; |
824 | 573 | } |
825 | | |
826 | | ////////////////////////////////////////////////// |
827 | | // |
828 | | // Ole10Native: basic Windows picture, with no size |
829 | | // - in general used to store a bitmap |
830 | | // |
831 | | ////////////////////////////////////////////////// |
832 | | |
833 | | bool WPSOLEParser::isOle10Native(RVNGInputStreamPtr &ip, std::string const &oleName) |
834 | 26.1k | { |
835 | 26.1k | if (strncmp("Ole10Native",oleName.c_str(),11) != 0) return false; |
836 | | |
837 | 674 | if (ip->seek(4, librevenge::RVNG_SEEK_SET) != 0 || ip->tell() != 4) return false; |
838 | | |
839 | 619 | ip->seek(0, librevenge::RVNG_SEEK_SET); |
840 | 619 | long size = libwps::read32(ip); |
841 | | |
842 | 619 | if (size <= 0) return false; |
843 | 527 | if (ip->seek(4+size, librevenge::RVNG_SEEK_SET) != 0 || ip->tell() != 4+size) |
844 | 95 | return false; |
845 | | |
846 | 432 | return true; |
847 | 527 | } |
848 | | |
849 | | bool WPSOLEParser::readOle10Native(RVNGInputStreamPtr &ip, WPSEmbeddedObject &obj, libwps::DebugFile &ascii) |
850 | 216 | { |
851 | 216 | if (!isOle10Native(ip, "Ole10Native")) return false; |
852 | | |
853 | 216 | libwps::DebugStream f; |
854 | 216 | f << "@@Ole10Native(Header): "; |
855 | 216 | ip->seek(0,librevenge::RVNG_SEEK_SET); |
856 | 216 | long fSize = libwps::read32(ip); |
857 | 216 | f << "fSize=" << fSize; |
858 | | |
859 | 216 | ascii.addPos(0); |
860 | 216 | ascii.addNote(f.str().c_str()); |
861 | | |
862 | 216 | librevenge::RVNGBinaryData data; |
863 | 216 | if (!libwps::readData(ip, static_cast<unsigned long>(fSize), data)) return false; |
864 | 216 | obj.add(data); |
865 | | #ifdef DEBUG_WITH_FILES |
866 | | std::stringstream s; |
867 | | static int num=0; |
868 | | s << "Ole10_" << num++ << ".bmp"; |
869 | | libwps::Debug::dumpFile(data, s.str().c_str()); |
870 | | #endif |
871 | | |
872 | 216 | if (!ip->isEnd()) |
873 | 99 | { |
874 | 99 | ascii.addPos(ip->tell()); |
875 | 99 | ascii.addNote("@@Ole10Native###"); |
876 | 99 | } |
877 | 216 | ascii.skipZone(4,4+fSize-1); |
878 | 216 | return true; |
879 | 216 | } |
880 | | |
881 | | //////////////////////////////////////////////////////////////// |
882 | | // |
883 | | // In general a picture : a PNG, an JPEG, a basic metafile, |
884 | | // find also a MSDraw.1.01 picture (with first bytes 0x78563412="xV4") or WordArt, |
885 | | // ( with first bytes "WordArt" ) which are not sucefull read |
886 | | // (can probably contain a list of data, but do not know how to |
887 | | // detect that) |
888 | | // |
889 | | // To check: does this is related to MSO_BLIPTYPE ? |
890 | | // or OO/filter/sources/msfilter/msdffimp.cxx ? |
891 | | // |
892 | | //////////////////////////////////////////////////////////////// |
893 | | bool WPSOLEParser::readContents(RVNGInputStreamPtr &input, |
894 | | std::string const &oleName, |
895 | | WPSEmbeddedObject &obj, |
896 | | libwps::DebugFile &ascii) |
897 | 22.4k | { |
898 | 22.4k | if (strcmp(oleName.c_str(),"Contents") != 0) return false; |
899 | | |
900 | 1.72k | libwps::DebugStream f; |
901 | 1.72k | input->seek(0, librevenge::RVNG_SEEK_SET); |
902 | 1.72k | f << "@@Contents:"; |
903 | | |
904 | 1.72k | bool ok = true; |
905 | | // bdbox 0 : size in the file ? |
906 | 1.72k | int dim[2]; |
907 | 1.72k | dim[0] = libwps::read32(input); |
908 | 1.72k | if (dim[0]==0x12345678) |
909 | 0 | { |
910 | 0 | WPS_DEBUG_MSG(("WPSOLEParser: warning: find a MSDraw picture, ignored\n")); |
911 | 0 | ascii.addPos(0); |
912 | 0 | ascii.addNote("Entries(MSDraw):"); |
913 | 0 | return false; |
914 | 0 | } |
915 | 1.72k | dim[1] = libwps::read32(input); |
916 | 1.72k | f << "bdbox0=(" << dim[0] << "," << dim[1]<<"),"; |
917 | 6.90k | for (int i = 0; i < 3; i++) |
918 | 5.18k | { |
919 | | /* 0,{10|21|75|101|116}x2 */ |
920 | 5.18k | auto val = long(libwps::readU32(input)); |
921 | 5.18k | if (val < 1000) |
922 | 2.16k | f << val << ","; |
923 | 3.01k | else |
924 | 3.01k | f << std::hex << "0x" << val << std::dec << ","; |
925 | 5.18k | if (val > 0x10000) ok=false; |
926 | 5.18k | } |
927 | | // new bdbox : size of the picture ? |
928 | 1.72k | int naturalSize[2]; |
929 | 1.72k | naturalSize[0] = libwps::read32(input); |
930 | 1.72k | naturalSize[1] = libwps::read32(input); |
931 | 1.72k | f << std::dec << "bdbox1=(" << naturalSize[0] << "," << naturalSize[1]<<"),"; |
932 | 1.72k | f << "unk=" << libwps::readU32(input) << ","; // 24 or 32 |
933 | 1.72k | if (input->isEnd()) |
934 | 684 | { |
935 | 684 | WPS_DEBUG_MSG(("WPSOLEParser: warning: Contents header length\n")); |
936 | 684 | return false; |
937 | 684 | } |
938 | 1.04k | long actPos = input->tell(); |
939 | 1.04k | auto size = long(libwps::readU32(input)); |
940 | 1.04k | if (size <= 0) ok = false; |
941 | 1.04k | if (ok) |
942 | 180 | { |
943 | 180 | input->seek(actPos+size+4, librevenge::RVNG_SEEK_SET); |
944 | 180 | if (input->tell() != actPos+size+4 || !input->isEnd()) |
945 | 144 | { |
946 | 144 | ok = false; |
947 | 144 | WPS_DEBUG_MSG(("WPSOLEParser: warning: Contents unexpected file size=%ld\n", |
948 | 144 | size)); |
949 | 144 | } |
950 | 180 | } |
951 | | |
952 | 1.04k | if (!ok) f << "###"; |
953 | 1.04k | f << "dataSize=" << size; |
954 | | |
955 | 1.04k | ascii.addPos(0); |
956 | 1.04k | ascii.addNote(f.str().c_str()); |
957 | | |
958 | 1.04k | input->seek(actPos+4, librevenge::RVNG_SEEK_SET); |
959 | | |
960 | 1.04k | if (ok) |
961 | 36 | { |
962 | 36 | librevenge::RVNGBinaryData data; |
963 | 36 | if (libwps::readData(input,static_cast<unsigned long>(size), data)) |
964 | 36 | { |
965 | 36 | obj.add(data); |
966 | 36 | ascii.skipZone(actPos+4, actPos+size+4-1); |
967 | | #ifdef DEBUG_WITH_FILES |
968 | | std::stringstream s; |
969 | | static int fileId=0; |
970 | | s << oleName << ++fileId << "cntents.pict"; |
971 | | libwps::Debug::dumpFile(data, s.str().c_str()); |
972 | | #endif |
973 | 36 | } |
974 | 0 | else |
975 | 0 | { |
976 | 0 | input->seek(actPos+4, librevenge::RVNG_SEEK_SET); |
977 | 0 | ok = false; |
978 | 0 | } |
979 | 36 | } |
980 | 1.04k | if (ok) |
981 | 36 | { |
982 | 36 | if (dim[0] > 0 && dim[0] < 3000 && dim[1] > 0 && dim[1] < 3000 && obj.m_size!=Vec2f()) |
983 | 0 | obj.m_size=Vec2f(float(dim[0])/72.f,float(dim[1])/72.f); |
984 | 36 | else |
985 | 36 | { |
986 | 36 | WPS_DEBUG_MSG(("WPSOLEParser: warning: Contents odd size : %d %d\n", dim[0], dim[1])); |
987 | 36 | } |
988 | 36 | if (naturalSize[0] > 0 && naturalSize[0] < 5000 && |
989 | 21 | naturalSize[1] > 0 && naturalSize[1] < 5000 && obj.m_size!=Vec2f()) |
990 | 0 | obj.m_size=Vec2f(float(dim[0])/72.f,float(dim[1])/72.f); |
991 | 36 | else |
992 | 36 | { |
993 | 36 | WPS_DEBUG_MSG(("WPSOLEParser: warning: Contents odd naturalsize : %d %d\n", naturalSize[0], naturalSize[1])); |
994 | 36 | } |
995 | 36 | } |
996 | 1.04k | if (!input->isEnd()) |
997 | 1.00k | { |
998 | 1.00k | ascii.addPos(actPos); |
999 | 1.00k | ascii.addNote("@@Contents:###"); |
1000 | 1.00k | } |
1001 | | |
1002 | 1.04k | if (!ok) |
1003 | 1.00k | { |
1004 | 1.00k | WPS_DEBUG_MSG(("WPSOLEParser: warning: read ole Contents: failed\n")); |
1005 | 1.00k | } |
1006 | 1.04k | return ok; |
1007 | 1.72k | } |
1008 | | |
1009 | | //////////////////////////////////////////////////////////////// |
1010 | | // |
1011 | | // Another different type of contents (this time in majuscule) |
1012 | | // we seem to contain the header of a EMF and then the EMF file |
1013 | | // |
1014 | | //////////////////////////////////////////////////////////////// |
1015 | | bool WPSOLEParser::readCONTENTS(RVNGInputStreamPtr &input, |
1016 | | std::string const &oleName, |
1017 | | WPSEmbeddedObject &obj, |
1018 | | libwps::DebugFile &ascii) |
1019 | 22.4k | { |
1020 | 22.4k | if (strcmp(oleName.c_str(),"CONTENTS") != 0) return false; |
1021 | | |
1022 | 85 | libwps::DebugStream f; |
1023 | | |
1024 | 85 | input->seek(0, librevenge::RVNG_SEEK_SET); |
1025 | 85 | f << "@@CONTENTS:"; |
1026 | | |
1027 | 85 | auto hSize = long(libwps::readU32(input)); |
1028 | 85 | if (input->isEnd()) return false; |
1029 | 83 | f << "hSize=" << std::hex << hSize << std::dec; |
1030 | | |
1031 | 83 | if (hSize <= 52 || input->seek(hSize+8,librevenge::RVNG_SEEK_SET) != 0 |
1032 | 63 | || input->tell() != hSize+8) |
1033 | 20 | { |
1034 | 20 | WPS_DEBUG_MSG(("WPSOLEParser: warning: CONTENTS headerSize=%ld\n", |
1035 | 20 | hSize)); |
1036 | 20 | return false; |
1037 | 20 | } |
1038 | | |
1039 | | // minimal checking of the "copied" header |
1040 | 63 | input->seek(4, librevenge::RVNG_SEEK_SET); |
1041 | 63 | auto type = long(libwps::readU32(input)); |
1042 | 63 | if (type < 0 || type > 4) return false; |
1043 | 59 | auto newSize = long(libwps::readU32(input)); |
1044 | | |
1045 | 59 | f << ", type=" << type; |
1046 | 59 | if (newSize < 8) return false; |
1047 | | |
1048 | 56 | if (newSize != hSize) // can sometimes happen, pb after a conversion ? |
1049 | 56 | f << ", ###newSize=" << std::hex << newSize << std::dec; |
1050 | | |
1051 | | // checkme: two bdbox, in document then data : units ? |
1052 | | // Maybe first in POINT, second in TWIP ? |
1053 | 168 | for (int st = 0; st < 2 ; st++) |
1054 | 112 | { |
1055 | 112 | int dim[4]; |
1056 | 448 | for (int &i : dim) i = libwps::read32(input); |
1057 | | |
1058 | 112 | bool ok = dim[0] >= 0 && dim[2] > dim[0] && dim[1] >= 0 && dim[3] > dim[2]; |
1059 | 112 | if (ok && st==0 && obj.m_size==Vec2f()) |
1060 | 33 | obj.m_size=Vec2f(float(dim[2]-dim[0])/72.f, float(dim[3]-dim[1])/72.f); |
1061 | 112 | if (st==0) f << ", bdbox(Text)"; |
1062 | 56 | else f << ", bdbox(Data)"; |
1063 | 112 | if (!ok) f << "###"; |
1064 | 112 | f << "=(" << dim[0] << "x" << dim[1] << "<->" << dim[2] << "x" << dim[3] << ")"; |
1065 | 112 | } |
1066 | 56 | char dataType[5]; |
1067 | 280 | for (int i = 0; i < 4; i++) dataType[i] = char(libwps::readU8(input)); |
1068 | 56 | dataType[4] = '\0'; |
1069 | 56 | f << ",typ=\""<<dataType<<"\""; // always " EMF" ? |
1070 | | |
1071 | 168 | for (int i = 0; i < 2; i++) // always id0=0, id1=1 ? |
1072 | 112 | { |
1073 | 112 | int val = libwps::readU16(input); |
1074 | 112 | if (val) f << ",id"<< i << "=" << val; |
1075 | 112 | } |
1076 | 56 | auto dataLength = long(libwps::readU32(input)); |
1077 | 56 | f << ",length=" << dataLength+hSize; |
1078 | | |
1079 | 56 | ascii.addPos(0); |
1080 | 56 | ascii.addNote(f.str().c_str()); |
1081 | | |
1082 | 56 | ascii.addPos(input->tell()); |
1083 | 56 | f.str(""); |
1084 | 56 | f << "@@CONTENTS(2)"; |
1085 | 426 | for (int i = 0; i < 12 && 4*i+52 < hSize; i++) |
1086 | 370 | { |
1087 | | // f0=7,f1=1,f5=500,f6=320,f7=1c4,f8=11a |
1088 | | // or f0=a,f1=1,f2=2,f3=6c,f5=480,f6=360,f7=140,f8=f0 |
1089 | | // or f0=61,f1=1,f2=2,f3=58,f5=280,f6=1e0,f7=a9,f8=7f |
1090 | | // f3=some header sub size ? f5/f6 and f7/f8 two other bdbox ? |
1091 | 370 | auto val = long(libwps::readU32(input)); |
1092 | 370 | if (val) f << std::hex << ",f" << i << "=" << val; |
1093 | 370 | } |
1094 | 21.7k | for (int i = 0; 2*i+100 < hSize; i++) |
1095 | 21.7k | { |
1096 | | // g0=e3e3,g1=6,g2=4e6e,g3=4 |
1097 | | // g0=e200,g1=4,g2=a980,g3=3,g4=4c,g5=50 |
1098 | | // --- |
1099 | 21.7k | long val = libwps::readU16(input); |
1100 | 21.7k | if (val) f << std::hex << ",g" << i << "=" << val; |
1101 | 21.7k | } |
1102 | 56 | ascii.addNote(f.str().c_str()); |
1103 | | |
1104 | 56 | if (dataLength <= 0 || input->seek(hSize+4+dataLength,librevenge::RVNG_SEEK_SET) != 0 |
1105 | 17 | || input->tell() != hSize+4+dataLength || !input->isEnd()) |
1106 | 47 | { |
1107 | 47 | WPS_DEBUG_MSG(("WPSOLEParser: warning: CONTENTS unexpected file length=%ld\n", |
1108 | 47 | dataLength)); |
1109 | 47 | return false; |
1110 | 47 | } |
1111 | | |
1112 | 9 | input->seek(4+hSize, librevenge::RVNG_SEEK_SET); |
1113 | 9 | librevenge::RVNGBinaryData data; |
1114 | 9 | if (!libwps::readDataToEnd(input, data)) return false; |
1115 | 9 | obj.add(data); |
1116 | | #ifdef DEBUG_WITH_FILES |
1117 | | std::stringstream s; |
1118 | | static int fileId=0; |
1119 | | s << oleName << ++fileId << "Contents.pict"; |
1120 | | libwps::Debug::dumpFile(data, s.str().c_str()); |
1121 | | #endif |
1122 | | |
1123 | 9 | ascii.skipZone(hSize+4, input->tell()-1); |
1124 | 9 | return true; |
1125 | 9 | } |
1126 | | |
1127 | | //////////////////////////////////////////////////////////////// |
1128 | | // |
1129 | | // the MN0 subdirectory |
1130 | | // |
1131 | | //////////////////////////////////////////////////////////////// |
1132 | | bool WPSOLEParser::readMN0AndCheckWKS(RVNGInputStreamPtr &input, std::string const &oleName, |
1133 | | WPSEmbeddedObject &obj, libwps::DebugFile &/*ascii*/) |
1134 | 26.8k | { |
1135 | 26.8k | if (strcmp(oleName.c_str(),"MN0") != 0) return false; |
1136 | 5.97k | std::unique_ptr<WPSHeader> header(WPSHeader::constructHeader(input)); |
1137 | 5.97k | if (!header) return false; |
1138 | 518 | bool ok=header->getKind()==WPS_SPREADSHEET; |
1139 | 518 | if (!ok) return false; |
1140 | | |
1141 | 321 | input->seek(0, librevenge::RVNG_SEEK_SET); |
1142 | 321 | librevenge::RVNGBinaryData data; |
1143 | 321 | if (!libwps::readDataToEnd(input, data)) |
1144 | 0 | return false; |
1145 | 321 | obj.add(data,"image/wks-ods"); |
1146 | | #ifdef DEBUG_WITH_FILES |
1147 | | std::stringstream s; |
1148 | | static int fileId=0; |
1149 | | s << oleName << ++fileId << ".wks"; |
1150 | | libwps::Debug::dumpFile(data, s.str().c_str()); |
1151 | | #endif |
1152 | 321 | return true; |
1153 | 321 | } |
1154 | | |
1155 | | //////////////////////////////////////////////////////////// |
1156 | | // |
1157 | | // Summary function |
1158 | | // |
1159 | | //////////////////////////////////////////////////////////// |
1160 | | bool WPSOLEParser::readSummaryInformation(RVNGInputStreamPtr input, std::string const &oleName, |
1161 | | librevenge::RVNGPropertyList &pList, libwps::DebugFile &ascii) const |
1162 | 31.7k | { |
1163 | 31.7k | if (oleName!="SummaryInformation") return false; |
1164 | 3.71k | input->seek(0, librevenge::RVNG_SEEK_END); |
1165 | 3.71k | long endPos=input->tell(); |
1166 | 3.71k | input->seek(0, librevenge::RVNG_SEEK_SET); |
1167 | 3.71k | libwps::DebugStream f; |
1168 | 3.71k | f << "Entries(SumInfo):"; |
1169 | 3.71k | auto val=int(libwps::readU16(input)); |
1170 | 3.71k | if (endPos<48 || val!=0xfffe) |
1171 | 2.89k | { |
1172 | 2.89k | WPS_DEBUG_MSG(("WPSOLEParser::readSummaryInformation: header seems bad\n")); |
1173 | 2.89k | f << "###"; |
1174 | 2.89k | ascii.addPos(0); |
1175 | 2.89k | ascii.addNote(f.str().c_str()); |
1176 | 2.89k | return true; |
1177 | 2.89k | } |
1178 | 9.86k | for (int i=0; i<11; ++i) // f1=1, f2=0-2 |
1179 | 9.04k | { |
1180 | 9.04k | val=int(libwps::readU16(input)); |
1181 | 9.04k | if (val) f << "f" << i << "=" << val << ","; |
1182 | 9.04k | } |
1183 | 822 | unsigned long lVal=libwps::readU32(input); |
1184 | 822 | if (lVal==0 || lVal>15) // find 1 or 2 sections, unsure about the maximum numbers |
1185 | 25 | { |
1186 | 25 | WPS_DEBUG_MSG(("WPSOLEParser::readSummaryInformation: summary info is bad\n")); |
1187 | 25 | f << "###sumInfo=" << std::hex << lVal << std::dec << ","; |
1188 | 25 | ascii.addPos(0); |
1189 | 25 | ascii.addNote(f.str().c_str()); |
1190 | 25 | return true; |
1191 | 25 | } |
1192 | 797 | auto numSection=int(lVal); |
1193 | 797 | if (numSection!=1) |
1194 | 92 | f << "num[section]=" << numSection << ","; |
1195 | 3.98k | for (int i=0; i<4; ++i) |
1196 | 3.18k | { |
1197 | 3.18k | val=int(libwps::readU32(input)); |
1198 | 3.18k | static int const expected[]= {int(0xf29f85e0),0x10684ff9,0x891ab,int(0xd9b3272b)}; |
1199 | 3.18k | if (val==expected[i]) continue; |
1200 | 377 | f << "#fmid" << i << "=" << std::hex << val << std::dec << ","; |
1201 | 377 | static bool first=true; |
1202 | 377 | if (first) |
1203 | 4 | { |
1204 | 4 | WPS_DEBUG_MSG(("WPSOLEParser::readSummaryInformation: fmid is bad\n")); |
1205 | 4 | first=false; |
1206 | 4 | } |
1207 | 377 | } |
1208 | 797 | auto decal=int(libwps::readU32(input)); |
1209 | 797 | if (decal<0x30 || endPos<decal) |
1210 | 25 | { |
1211 | 25 | WPS_DEBUG_MSG(("WPSOLEParser::readSummaryInformation: decal is bad\n")); |
1212 | 25 | f << "decal=" << val << ","; |
1213 | 25 | ascii.addPos(0); |
1214 | 25 | ascii.addNote(f.str().c_str()); |
1215 | 25 | return true; |
1216 | | |
1217 | 25 | } |
1218 | 772 | ascii.addPos(0); |
1219 | 772 | ascii.addNote(f.str().c_str()); |
1220 | 772 | if (decal!=0x30) |
1221 | 23 | { |
1222 | 23 | ascii.addPos(0x30); |
1223 | 23 | ascii.addNote("_"); |
1224 | 23 | input->seek(decal, librevenge::RVNG_SEEK_SET); |
1225 | 23 | } |
1226 | | |
1227 | 1.62k | for (int sect=0; sect<numSection; ++sect) |
1228 | 948 | { |
1229 | 948 | long pos=input->tell(); |
1230 | 948 | f.str(""); |
1231 | 948 | f << "SumInfo-A:"; |
1232 | 948 | auto pSectSize=long(libwps::readU32(input)); |
1233 | 948 | long endSect=pos+pSectSize; |
1234 | 948 | auto N=int(libwps::readU32(input)); |
1235 | 948 | f << "N=" << N << ","; |
1236 | 948 | if (pSectSize<0 || endPos-pos<pSectSize || (pSectSize-8)/8<N) |
1237 | 96 | { |
1238 | 96 | WPS_DEBUG_MSG(("WPSOLEParser::readSummaryInformation: psetstruct is bad\n")); |
1239 | 96 | f << "###"; |
1240 | 96 | ascii.addPos(pos); |
1241 | 96 | ascii.addNote(f.str().c_str()); |
1242 | 96 | return true; |
1243 | 96 | } |
1244 | 852 | f << "["; |
1245 | 852 | std::map<long,int> posToTypeMap; |
1246 | 8.74k | for (int i=0; i<N; ++i) |
1247 | 7.89k | { |
1248 | 7.89k | auto type=int(libwps::readU32(input)); |
1249 | 7.89k | auto depl=int(libwps::readU32(input)); |
1250 | 7.89k | if (depl<=0) continue; |
1251 | 6.91k | f << std::hex << depl << std::dec << ":" << type << ","; |
1252 | 6.91k | if ((depl-8)/8<N || depl>pSectSize-4 || posToTypeMap.find(pos+depl)!=posToTypeMap.end()) |
1253 | 2.56k | { |
1254 | 2.56k | f << "###"; |
1255 | 2.56k | continue; |
1256 | 2.56k | } |
1257 | 4.35k | posToTypeMap[pos+depl]=type; |
1258 | 4.35k | } |
1259 | 852 | f << "],"; |
1260 | 852 | ascii.addPos(pos); |
1261 | 852 | ascii.addNote(f.str().c_str()); |
1262 | | |
1263 | 5.20k | for (auto it=posToTypeMap.begin(); it!=posToTypeMap.end(); ++it) |
1264 | 4.35k | { |
1265 | 4.35k | pos=it->first; |
1266 | 4.35k | auto nextIt=it; |
1267 | 4.35k | long endPropPos=endSect; |
1268 | 4.35k | if (++nextIt!=posToTypeMap.end()) endPropPos=nextIt->first; |
1269 | 4.35k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
1270 | 4.35k | f.str(""); |
1271 | 4.35k | f << "SumInfo-B" << it->second << ":"; |
1272 | 4.35k | auto type=int(libwps::readU32(input)); |
1273 | 4.35k | if (sect==0 && it->second==1 && type==2) |
1274 | 18 | { |
1275 | 18 | long value=-1; |
1276 | 18 | if (readSummaryPropertyLong(input,endPropPos,type,value,f) && value>=0 && value<10000) // 10000 is mac |
1277 | 6 | f << "encoding,"; // USEME: never seems actually |
1278 | 18 | } |
1279 | 4.33k | else if (sect==0 && type==0x1e && ((it->second>=2 && it->second<=6) || it->second==8)) |
1280 | 779 | { |
1281 | 779 | librevenge::RVNGString text; |
1282 | 779 | if (readSummaryPropertyString(input, endPropPos, type, text, f) && !text.empty()) |
1283 | 316 | { |
1284 | 316 | static char const* const attribNames[] = |
1285 | 316 | { |
1286 | 316 | "", "", "dc:title", "dc:subject", "meta:initial-creator", |
1287 | 316 | "meta:keywords", "dc:description"/*comment*/, "", "dc:creator" |
1288 | 316 | }; |
1289 | 316 | pList.insert(attribNames[it->second], text); |
1290 | 316 | } |
1291 | 779 | } |
1292 | 3.56k | else if (!readSummaryProperty(input, endPropPos, type, ascii, f)) |
1293 | 2.51k | { |
1294 | 2.51k | WPS_DEBUG_MSG(("WPSOLEParser::readSummaryInformation: find unknown type\n")); |
1295 | 2.51k | f << "##type=" << std::hex << type << std::dec << ","; |
1296 | 2.51k | } |
1297 | 4.35k | if (input->tell()!=endPropPos && input->tell()!=pos) |
1298 | 3.74k | ascii.addDelimiter(input->tell(),'|'); |
1299 | 4.35k | ascii.addPos(pos); |
1300 | 4.35k | ascii.addNote(f.str().c_str()); |
1301 | 4.35k | } |
1302 | 852 | input->seek(endSect, librevenge::RVNG_SEEK_SET); |
1303 | 852 | } |
1304 | 676 | return true; |
1305 | 772 | } |
1306 | | |
1307 | | bool WPSOLEParser::readSummaryPropertyString(RVNGInputStreamPtr input, long endPos, int type, |
1308 | | librevenge::RVNGString &string, libwps::DebugStream &f) const |
1309 | 1.97k | { |
1310 | 1.97k | if (!input) return false; |
1311 | 1.97k | long pos=input->tell(); |
1312 | 1.97k | string.clear(); |
1313 | 1.97k | auto sSz=long(libwps::readU32(input)); |
1314 | 1.97k | if (sSz<0 || (endPos-pos-4)<sSz || pos+4+sSz>endPos) |
1315 | 262 | { |
1316 | 262 | WPS_DEBUG_MSG(("WPSOLEParser::readSummaryPropertyString: string size is bad\n")); |
1317 | 262 | f << "##stringSz=" << sSz << ","; |
1318 | 262 | return false; |
1319 | 262 | } |
1320 | 1.71k | std::string text(""); |
1321 | 6.40k | for (long c=0; c < sSz; ++c) |
1322 | 4.68k | { |
1323 | 4.68k | auto ch=static_cast<unsigned char>(libwps::readU8(input)); |
1324 | 4.68k | if (ch) |
1325 | 2.86k | text+=char(ch); |
1326 | 1.82k | else if (c+1!=sSz) |
1327 | 1.07k | text+="##"; |
1328 | 4.68k | } |
1329 | 1.71k | f << text; |
1330 | 1.71k | if (!text.empty()) |
1331 | 515 | string=libwps_tools_win::Font::unicodeString(text, m_state->m_fontType); |
1332 | 1.71k | if (type==0x1f && (sSz%4)) |
1333 | 55 | input->seek(sSz%4, librevenge::RVNG_SEEK_CUR); |
1334 | 1.71k | return true; |
1335 | 1.97k | } |
1336 | | |
1337 | | bool WPSOLEParser::readSummaryPropertyLong(RVNGInputStreamPtr input, long endPos, int type, long &value, |
1338 | | libwps::DebugStream &f) |
1339 | 18 | { |
1340 | 18 | if (!input) return false; |
1341 | 18 | long pos=input->tell(); |
1342 | 18 | switch (type) |
1343 | 18 | { |
1344 | 18 | case 2: // int |
1345 | 18 | case 0x12: // uint |
1346 | 18 | if (pos+2>endPos) |
1347 | 5 | return false; |
1348 | 13 | value=type==2 ? long(libwps::read16(input)) : long(libwps::readU16(input)); |
1349 | 13 | break; |
1350 | 0 | case 3: // int |
1351 | 0 | case 9: // uint |
1352 | 0 | if (pos+4>endPos) |
1353 | 0 | return false; |
1354 | 0 | value=type==3 ? long(libwps::read32(input)) : long(libwps::readU32(input)); |
1355 | 0 | break; |
1356 | 0 | default: |
1357 | 0 | return false; |
1358 | 18 | } |
1359 | 13 | f << "val=" << value << ","; |
1360 | 13 | return true; |
1361 | 18 | } |
1362 | | |
1363 | | bool WPSOLEParser::readSummaryProperty(RVNGInputStreamPtr input, long endPos, int type, |
1364 | | libwps::DebugFile &ascii, libwps::DebugStream &f) const |
1365 | 10.7k | { |
1366 | 10.7k | if (!input) return false; |
1367 | 10.7k | long pos=input->tell(); |
1368 | | // see propread.cxx |
1369 | 10.7k | if (type&0x1000) |
1370 | 1.21k | { |
1371 | 1.21k | auto N=int(libwps::readU32(input)); |
1372 | 1.21k | f << "N=" << N << ","; |
1373 | 1.21k | f << "["; |
1374 | 7.51k | for (int n=0; n<N; ++n) |
1375 | 7.13k | { |
1376 | 7.13k | pos=input->tell(); |
1377 | 7.13k | f << "["; |
1378 | 7.13k | if (!readSummaryProperty(input, endPos, type&0xFFF, ascii, f)) |
1379 | 833 | { |
1380 | 833 | input->seek(pos, librevenge::RVNG_SEEK_SET); |
1381 | 833 | return false; |
1382 | 833 | } |
1383 | 6.29k | f << "],"; |
1384 | 6.29k | } |
1385 | 386 | f << "],"; |
1386 | 386 | return true; |
1387 | 1.21k | } |
1388 | 9.49k | switch (type) |
1389 | 9.49k | { |
1390 | 1.80k | case 0x10: // int1 |
1391 | 2.63k | case 0x11: // uint1 |
1392 | 2.63k | if (pos+1>endPos) |
1393 | 118 | return false; |
1394 | 2.51k | f << "val=" << char(libwps::readU8(input)); |
1395 | 2.51k | break; |
1396 | 348 | case 2: // int |
1397 | 723 | case 0xb: // bool |
1398 | 1.04k | case 0x12: // uint |
1399 | 1.04k | if (pos+2>endPos) |
1400 | 57 | return false; |
1401 | 984 | if (type==2) |
1402 | 334 | f << "val=" << int(libwps::read16(input)) << ","; |
1403 | 650 | else if (type==0x12) |
1404 | 298 | f << "val=" << int(libwps::readU16(input)) << ","; |
1405 | 352 | else if (libwps::readU16(input)) |
1406 | 202 | f << "true,"; |
1407 | 984 | break; |
1408 | 304 | case 3: // int |
1409 | 599 | case 4: // float |
1410 | 874 | case 9: // uint |
1411 | 874 | if (pos+4>endPos) |
1412 | 84 | return false; |
1413 | 790 | if (type==3) |
1414 | 279 | f << "val=" << int(libwps::read32(input)) << ","; |
1415 | 511 | else if (type==9) |
1416 | 251 | f << "val=" << int(libwps::readU32(input)) << ","; |
1417 | 260 | else |
1418 | 260 | f << "val[fl4]=" << std::hex << libwps::readU32(input) << std::dec << ","; |
1419 | 790 | break; |
1420 | 123 | case 5: // double |
1421 | 264 | case 6: |
1422 | 395 | case 7: |
1423 | 521 | case 20: |
1424 | 641 | case 21: |
1425 | 882 | case 0x40: |
1426 | 882 | if (pos+8>endPos) |
1427 | 99 | return false; |
1428 | 783 | ascii.addDelimiter(input->tell(),'|'); |
1429 | 783 | if (type==5) |
1430 | 106 | f << "double,"; |
1431 | 677 | else if (type==6) |
1432 | 122 | f << "cy,"; |
1433 | 555 | else if (type==7) |
1434 | 117 | f << "date,"; |
1435 | 438 | else if (type==20) |
1436 | 110 | f << "long,"; |
1437 | 328 | else if (type==21) |
1438 | 105 | f << "ulong,"; |
1439 | 223 | else |
1440 | 223 | f << "fileTime,"; // readme 8 byte |
1441 | 783 | input->seek(pos+8, librevenge::RVNG_SEEK_SET); |
1442 | 783 | break; |
1443 | 26 | case 0xc: // variant |
1444 | 26 | if (pos+4>endPos) |
1445 | 5 | return false; |
1446 | 21 | type=int(libwps::readU32(input)); |
1447 | 21 | return readSummaryProperty(input, endPos, type, ascii, f); |
1448 | | // case 20: int64 |
1449 | | // case 21: uint64 |
1450 | 299 | case 8: |
1451 | 840 | case 0x1e: |
1452 | 1.19k | case 0x1f: |
1453 | 1.19k | { |
1454 | 1.19k | librevenge::RVNGString string; |
1455 | 1.19k | if (!readSummaryPropertyString(input, endPos, type, string, f)) |
1456 | 129 | return false; |
1457 | 1.06k | break; |
1458 | 1.19k | } |
1459 | 1.06k | case 0x41: |
1460 | 608 | case 0x46: |
1461 | 929 | case 0x47: |
1462 | 929 | { |
1463 | 929 | if (pos+4>endPos) |
1464 | 48 | return false; |
1465 | 881 | f << (type==0x41 ? "blob" : type==0x46 ? "blob[object]" : "clipboard") << ","; |
1466 | 881 | auto dSz=long(libwps::readU32(input)); |
1467 | 881 | if (dSz<0 || pos+4+dSz>endPos) |
1468 | 65 | return false; |
1469 | 816 | if (dSz) |
1470 | 56 | { |
1471 | 56 | ascii.skipZone(pos+4, pos+4+dSz-1); |
1472 | 56 | input->seek(dSz, librevenge::RVNG_SEEK_CUR); |
1473 | 56 | } |
1474 | 816 | break; |
1475 | 881 | } |
1476 | | /* todo type==0x47, vtcf clipboard */ |
1477 | 1.91k | default: |
1478 | 1.91k | return false; |
1479 | 9.49k | } |
1480 | 6.95k | return true; |
1481 | 9.49k | } |
1482 | | /* vim:set shiftwidth=4 softtabstop=4 noexpandtab: */ |