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