/src/libstaroffice/src/lib/STOFFOLEParser.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 | | /* libstaroffice |
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 | | /* |
35 | | * freely inspired from istorage : |
36 | | * ------------------------------------------------------------ |
37 | | * Generic OLE Zones furnished with a copy of the file header |
38 | | * |
39 | | * Compound Storage (32 bit version) |
40 | | * Storage implementation |
41 | | * |
42 | | * This file contains the compound file implementation |
43 | | * of the storage interface. |
44 | | * |
45 | | * Copyright 1999 Francis Beaudet |
46 | | * Copyright 1999 Sylvain St-Germain |
47 | | * Copyright 1999 Thuy Nguyen |
48 | | * Copyright 2005 Mike McCormack |
49 | | * |
50 | | * This library is free software; you can redistribute it and/or |
51 | | * modify it under the terms of the GNU Lesser General Public |
52 | | * License as published by the Free Software Foundation; either |
53 | | * version 2.1 of the License, or (at your option) any later version. |
54 | | * |
55 | | * This library is distributed in the hope that it will be useful, |
56 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
57 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
58 | | * Lesser General Public License for more details. |
59 | | * |
60 | | * You should have received a copy of the GNU Lesser General Public |
61 | | * License along with this library; if not, write to the Free Software |
62 | | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
63 | | * |
64 | | */ |
65 | | |
66 | | /* |
67 | | * NOTES |
68 | | * The compound file implementation of IStorage used for create |
69 | | * and manage substorages and streams within a storage object |
70 | | * residing in a compound file object. |
71 | | * |
72 | | * MSDN |
73 | | * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/stg/stg/istorage_compound_file_implementation.asp |
74 | | * ------------------------------------------------------------ |
75 | | */ |
76 | | |
77 | | #include <cstdlib> |
78 | | #include <cstring> |
79 | | #include <iostream> |
80 | | #include <map> |
81 | | #include <sstream> |
82 | | #include <string> |
83 | | |
84 | | #include <librevenge/librevenge.h> |
85 | | |
86 | | #include "STOFFPosition.hxx" |
87 | | #include "STOFFOLEParser.hxx" |
88 | | |
89 | | ////////////////////////////////////////////////// |
90 | | // internal structure |
91 | | ////////////////////////////////////////////////// |
92 | | /** Low level: namespace used to define/store the data used by STOFFOLEParser */ |
93 | | namespace STOFFOLEParserInternal |
94 | | { |
95 | | //! the state of a STOFFOLEParser |
96 | | struct State { |
97 | | //! constructor |
98 | | State() |
99 | 284k | : m_oleList() |
100 | 284k | , m_unknownOLEs() |
101 | 284k | , m_mapCls() |
102 | 284k | { |
103 | 284k | } |
104 | | //! returns a CLSName if knwon |
105 | | std::string getCLSName(unsigned long id) const |
106 | 138 | { |
107 | 138 | if (m_mapCls.empty()) |
108 | 138 | const_cast<State *>(this)->initCLSMap(); |
109 | 138 | if (m_mapCls.find(id) == m_mapCls.end()) return ""; |
110 | 45 | return m_mapCls.find(id)->second; |
111 | 138 | } |
112 | | //! the ole list |
113 | | std::vector<std::shared_ptr<STOFFOLEParser::OleDirectory> > m_oleList; |
114 | | //! list of ole which can not be parsed |
115 | | std::vector<std::string> m_unknownOLEs; |
116 | | protected: |
117 | | /** initialise a map CLSId <-> name */ |
118 | | void initCLSMap(); |
119 | | /** map CLSId <-> name */ |
120 | | std::map<unsigned long, char const *> m_mapCls; |
121 | | }; |
122 | | |
123 | | void State::initCLSMap() |
124 | 138 | { |
125 | | // source: binfilter/bf_so3/source/inplace/embobj.cxx |
126 | 138 | m_mapCls[0x00000319]="Picture"; // addon Enhanced Metafile ( find in some file) |
127 | | |
128 | 138 | m_mapCls[0x000212F0]="MSWordArt"; // or MSWordArt.2 |
129 | 138 | m_mapCls[0x00021302]="MSWorksWPDoc"; // addon |
130 | | |
131 | | // MS Apps |
132 | 138 | m_mapCls[0x00030000]= "ExcelWorksheet"; |
133 | 138 | m_mapCls[0x00030001]= "ExcelChart"; |
134 | 138 | m_mapCls[0x00030002]= "ExcelMacrosheet"; |
135 | 138 | m_mapCls[0x00030003]= "WordDocument"; |
136 | 138 | m_mapCls[0x00030004]= "MSPowerPoint"; |
137 | 138 | m_mapCls[0x00030005]= "MSPowerPointSho"; |
138 | 138 | m_mapCls[0x00030006]= "MSGraph"; |
139 | 138 | m_mapCls[0x00030007]= "MSDraw"; // find also with ca003 ? |
140 | 138 | m_mapCls[0x00030008]= "Note-It"; |
141 | 138 | m_mapCls[0x00030009]= "WordArt"; |
142 | 138 | m_mapCls[0x0003000a]= "PBrush"; |
143 | 138 | m_mapCls[0x0003000b]= "Equation"; // "Microsoft Equation Editor" |
144 | 138 | m_mapCls[0x0003000c]= "Package"; |
145 | 138 | m_mapCls[0x0003000d]= "SoundRec"; |
146 | 138 | m_mapCls[0x0003000e]= "MPlayer"; |
147 | | // MS Demos |
148 | 138 | m_mapCls[0x0003000f]= "ServerDemo"; // "OLE 1.0 Server Demo" |
149 | 138 | m_mapCls[0x00030010]= "Srtest"; // "OLE 1.0 Test Demo" |
150 | 138 | m_mapCls[0x00030011]= "SrtInv"; // "OLE 1.0 Inv Demo" |
151 | 138 | m_mapCls[0x00030012]= "OleDemo"; //"OLE 1.0 Demo" |
152 | | |
153 | | // Coromandel / Dorai Swamy / 718-793-7963 |
154 | 138 | m_mapCls[0x00030013]= "CoromandelIntegra"; |
155 | 138 | m_mapCls[0x00030014]= "CoromandelObjServer"; |
156 | | |
157 | | // 3-d Visions Corp / Peter Hirsch / 310-325-1339 |
158 | 138 | m_mapCls[0x00030015]= "StanfordGraphics"; |
159 | | |
160 | | // Deltapoint / Nigel Hearne / 408-648-4000 |
161 | 138 | m_mapCls[0x00030016]= "DGraphCHART"; |
162 | 138 | m_mapCls[0x00030017]= "DGraphDATA"; |
163 | | |
164 | | // Corel / Richard V. Woodend / 613-728-8200 x1153 |
165 | 138 | m_mapCls[0x00030018]= "PhotoPaint"; // "Corel PhotoPaint" |
166 | 138 | m_mapCls[0x00030019]= "CShow"; // "Corel Show" |
167 | 138 | m_mapCls[0x0003001a]= "CorelChart"; |
168 | 138 | m_mapCls[0x0003001b]= "CDraw"; // "Corel Draw" |
169 | | |
170 | | // Inset Systems / Mark Skiba / 203-740-2400 |
171 | 138 | m_mapCls[0x0003001c]= "HJWIN1.0"; // "Inset Systems" |
172 | | |
173 | | // Mark V Systems / Mark McGraw / 818-995-7671 |
174 | 138 | m_mapCls[0x0003001d]= "ObjMakerOLE"; // "MarkV Systems Object Maker" |
175 | | |
176 | | // IdentiTech / Mike Gilger / 407-951-9503 |
177 | 138 | m_mapCls[0x0003001e]= "FYI"; // "IdentiTech FYI" |
178 | 138 | m_mapCls[0x0003001f]= "FYIView"; // "IdentiTech FYI Viewer" |
179 | | |
180 | | // Inventa Corporation / Balaji Varadarajan / 408-987-0220 |
181 | 138 | m_mapCls[0x00030020]= "Stickynote"; |
182 | | |
183 | | // ShapeWare Corp. / Lori Pearce / 206-467-6723 |
184 | 138 | m_mapCls[0x00030021]= "ShapewareVISIO10"; |
185 | 138 | m_mapCls[0x00030022]= "ImportServer"; // "Spaheware Import Server" |
186 | | |
187 | | // test app SrTest |
188 | 138 | m_mapCls[0x00030023]= "SrvrTest"; // "OLE 1.0 Server Test" |
189 | | |
190 | | // test app ClTest. Doesn't really work as a server but is in reg db |
191 | 138 | m_mapCls[0x00030025]= "Cltest"; // "OLE 1.0 Client Test" |
192 | | |
193 | | // Microsoft ClipArt Gallery Sherry Larsen-Holmes |
194 | 138 | m_mapCls[0x00030026]= "MS_ClipArt_Gallery"; |
195 | | // Microsoft Project Cory Reina |
196 | 138 | m_mapCls[0x00030027]= "MSProject"; |
197 | | |
198 | | // Microsoft Works Chart |
199 | 138 | m_mapCls[0x00030028]= "MSWorksChart"; |
200 | | |
201 | | // Microsoft Works Spreadsheet |
202 | 138 | m_mapCls[0x00030029]= "MSWorksSpreadsheet"; |
203 | | |
204 | | // AFX apps - Dean McCrory |
205 | 138 | m_mapCls[0x0003002A]= "MinSvr"; // "AFX Mini Server" |
206 | 138 | m_mapCls[0x0003002B]= "HierarchyList"; // "AFX Hierarchy List" |
207 | 138 | m_mapCls[0x0003002C]= "BibRef"; // "AFX BibRef" |
208 | 138 | m_mapCls[0x0003002D]= "MinSvrMI"; // "AFX Mini Server MI" |
209 | 138 | m_mapCls[0x0003002E]= "TestServ"; // "AFX Test Server" |
210 | | |
211 | | // Ami Pro |
212 | 138 | m_mapCls[0x0003002F]= "AmiProDocument"; |
213 | | |
214 | | // WordPerfect Presentations For Windows |
215 | 138 | m_mapCls[0x00030030]= "WPGraphics"; |
216 | 138 | m_mapCls[0x00030031]= "WPCharts"; |
217 | | |
218 | | // MicroGrafx Charisma |
219 | 138 | m_mapCls[0x00030032]= "Charisma"; |
220 | 138 | m_mapCls[0x00030033]= "Charisma_30"; // v 3.0 |
221 | 138 | m_mapCls[0x00030034]= "CharPres_30"; // v 3.0 Pres |
222 | | // MicroGrafx Draw |
223 | 138 | m_mapCls[0x00030035]= "Draw"; //"MicroGrafx Draw" |
224 | | // MicroGrafx Designer |
225 | 138 | m_mapCls[0x00030036]= "Designer_40"; // "MicroGrafx Designer 4.0" |
226 | | |
227 | | // STAR DIVISION |
228 | | //m_mapCls[0x000424CA]= "StarMath"; // "StarMath 1.0" |
229 | 138 | m_mapCls[0x00043AD2]= "FontWork"; // "Star FontWork" |
230 | | //m_mapCls[0x000456EE]= "StarMath2"; // "StarMath 2.0" |
231 | 138 | } |
232 | | |
233 | | } |
234 | | |
235 | | // constructor/destructor |
236 | | STOFFOLEParser::STOFFOLEParser() |
237 | 207k | : m_state(new STOFFOLEParserInternal::State) |
238 | 207k | { |
239 | 207k | } |
240 | | |
241 | | STOFFOLEParser::~STOFFOLEParser() |
242 | 207k | { |
243 | 207k | } |
244 | | |
245 | | std::vector<std::shared_ptr<STOFFOLEParser::OleDirectory> > &STOFFOLEParser::getDirectoryList() |
246 | 0 | { |
247 | 0 | return m_state->m_oleList; |
248 | 0 | } |
249 | | |
250 | | std::shared_ptr<STOFFOLEParser::OleDirectory> STOFFOLEParser::getDirectory(std::string const &dir) |
251 | 85.8k | { |
252 | 85.8k | std::string dirName(dir); |
253 | 85.8k | if (!dir.empty() && *dir.rbegin()=='/') |
254 | 76.5k | dirName=dir.substr(0, dir.size()-1); |
255 | 100k | for (auto &ole : m_state->m_oleList) { |
256 | 100k | if (ole && ole->m_dir==dirName) |
257 | 83.4k | return ole; |
258 | 100k | } |
259 | 2.41k | return std::shared_ptr<STOFFOLEParser::OleDirectory>(); |
260 | 85.8k | } |
261 | | |
262 | | // parsing |
263 | | bool STOFFOLEParser::parse(STOFFInputStreamPtr file) |
264 | 76.4k | { |
265 | 76.4k | m_state.reset(new STOFFOLEParserInternal::State); |
266 | | |
267 | 76.4k | if (!file.get()) return false; |
268 | | |
269 | 76.4k | if (!file->isStructured()) return false; |
270 | | |
271 | 76.4k | unsigned numSubStreams = file->subStreamCount(); |
272 | | // |
273 | | // we begin by grouping the Ole by their potential main id |
274 | | // |
275 | 76.4k | std::map<std::string, std::shared_ptr<STOFFOLEParser::OleDirectory> > listsByDir; |
276 | 571k | for (unsigned i = 0; i < numSubStreams; ++i) { |
277 | 494k | std::string const &name = file->subStreamName(i); |
278 | 494k | if (name.empty() || name[name.length()-1]=='/') continue; |
279 | | |
280 | | // separated the directory and the name |
281 | | // MatOST/MatadorObject1/Ole10Native |
282 | | // -> dir="MatOST/MatadorObject1", base="Ole10Native" |
283 | 409k | auto pos = name.find_last_of('/'); |
284 | | |
285 | 409k | std::string dir(""), base; |
286 | 409k | if (pos == std::string::npos) base = name; |
287 | 69.3k | else if (pos == 0) base = name.substr(1); |
288 | 67.9k | else { |
289 | 67.9k | dir = name.substr(0,pos); |
290 | 67.9k | base = name.substr(pos+1); |
291 | 67.9k | } |
292 | | |
293 | 409k | #define PRINT_OLE_NAME |
294 | 409k | #if defined(PRINT_OLE_NAME) |
295 | 409k | STOFF_DEBUG_MSG(("OLEName=%s\n", name.c_str())); |
296 | 409k | #endif |
297 | 409k | if (listsByDir.find(dir)==listsByDir.end() || !listsByDir.find(dir)->second) { |
298 | 92.2k | std::shared_ptr<STOFFOLEParser::OleDirectory> newDir(new STOFFOLEParser::OleDirectory(file, dir)); |
299 | 92.2k | listsByDir[dir]=newDir; |
300 | 92.2k | m_state->m_oleList.push_back(newDir); |
301 | 92.2k | } |
302 | 409k | listsByDir.find(dir)->second->addNewBase(base); |
303 | 409k | } |
304 | 92.2k | for (auto &dOle : m_state->m_oleList) { |
305 | 92.2k | if (!dOle) continue; |
306 | 92.2k | if (dOle->m_hasCompObj) { |
307 | 36.5k | auto ole = file->getSubStreamByName(dOle->m_dir+"/CompObj"); |
308 | 36.5k | if (!ole.get()) { |
309 | 1.94k | STOFF_DEBUG_MSG(("STOFFOLEParser::parse: error: can not find CompObj in directory: \"%s\"\n", dOle->m_dir.c_str())); |
310 | 1.94k | } |
311 | 34.5k | else |
312 | 34.5k | readCompObj(ole, *dOle); |
313 | 36.5k | } |
314 | 372k | for (auto &content : dOle->m_contentList) { |
315 | 372k | std::string base=content.getBaseName(); |
316 | 372k | std::string oleName=content.getOleName(); |
317 | 372k | auto ole = file->getSubStreamByName(oleName); |
318 | 372k | if (!ole.get()) { |
319 | 64.0k | STOFF_DEBUG_MSG(("STOFFOLEParser::parse: error: can not find OLE part: \"%s\"\n", oleName.c_str())); |
320 | 64.0k | continue; |
321 | 64.0k | } |
322 | | |
323 | 308k | ole->setReadInverted(true); |
324 | 308k | if (isOlePres(ole, base) && readOlePres(ole, content)) |
325 | 1.37k | continue; |
326 | 306k | if (isOle10Native(ole, base) && readOle10Native(ole, content)) |
327 | | // small size can be a symptom that this is a link |
328 | 37 | continue; |
329 | 306k | if (readContents(ole, content) || readCONTENTS(ole, content)) |
330 | 4.04k | continue; |
331 | 302k | libstoff::DebugFile asciiFile(ole); |
332 | 302k | asciiFile.open(oleName); |
333 | | |
334 | 302k | bool ok = true; |
335 | 302k | try { |
336 | 302k | if (readObjInfo(ole, base, asciiFile)); |
337 | 302k | else if (readOle(ole, base, asciiFile)); |
338 | 286k | else if (readSummaryInformation(ole, base, asciiFile)); |
339 | 266k | else |
340 | 266k | ok = false; |
341 | 302k | } |
342 | 302k | catch (...) { |
343 | 0 | ok = false; |
344 | 0 | } |
345 | 302k | content.setParsed(ok); |
346 | 302k | asciiFile.reset(); |
347 | 302k | if (ok) continue; |
348 | | |
349 | 266k | m_state->m_unknownOLEs.push_back(oleName); |
350 | 266k | if (base.compare(0,4,"Star")==0) { |
351 | | // times to update the |
352 | 89.9k | if (base=="StarCalcDocument") |
353 | 33.6k | dOle->m_kind=STOFFDocument::STOFF_K_SPREADSHEET; |
354 | 56.3k | else if (base=="StarChartDocument") |
355 | 2.73k | dOle->m_kind=STOFFDocument::STOFF_K_CHART; |
356 | 53.5k | else if (base=="StarDrawDocument" || base=="StarDrawDocument3") |
357 | 46.6k | dOle->m_kind=STOFFDocument::STOFF_K_DRAW; |
358 | 6.91k | else if (base=="StarImageDocument") |
359 | 82 | dOle->m_kind=STOFFDocument::STOFF_K_BITMAP; |
360 | 6.83k | else if (base=="StarMathDocument") |
361 | 2.15k | dOle->m_kind=STOFFDocument::STOFF_K_MATH; |
362 | 4.68k | else if (base=="StarWriterDocument") |
363 | 727 | dOle->m_kind=STOFFDocument::STOFF_K_TEXT; |
364 | 89.9k | } |
365 | 266k | } |
366 | 92.2k | } |
367 | | |
368 | 76.4k | return true; |
369 | 76.4k | } |
370 | | |
371 | | |
372 | | bool STOFFOLEParser::getCompObjName(STOFFInputStreamPtr file, std::string &programName) |
373 | 131k | { |
374 | 131k | if (!file.get() || !file->isStructured()) return false; |
375 | 131k | auto ole = file->getSubStreamByName("/CompObj"); |
376 | 131k | if (!ole) return false; |
377 | 81.1k | STOFFOLEParser::OleDirectory oleDir(file,""); |
378 | 81.1k | if (!readCompObj(ole, oleDir) || oleDir.m_clipName.empty()) return false; |
379 | 69.6k | programName=oleDir.m_clipName; |
380 | 69.6k | return true; |
381 | 81.1k | } |
382 | | |
383 | | //////////////////////////////////////// |
384 | | // |
385 | | // small structure |
386 | | // |
387 | | //////////////////////////////////////// |
388 | | bool STOFFOLEParser::readOle(STOFFInputStreamPtr ip, std::string const &oleName, |
389 | | libstoff::DebugFile &ascii) |
390 | 302k | { |
391 | 302k | if (!ip.get()) return false; |
392 | | |
393 | 302k | if (oleName!="Ole") return false; |
394 | | |
395 | 21.5k | if (ip->seek(20, librevenge::RVNG_SEEK_SET) != 0 || ip->tell() != 20) return false; |
396 | | |
397 | 21.3k | ip->seek(0, librevenge::RVNG_SEEK_SET); |
398 | | |
399 | 21.3k | int val[20]; |
400 | 364k | for (int &i : val) { |
401 | 364k | i = int(ip->readLong(1)); |
402 | 364k | if (i < -10 || i > 10) return false; |
403 | 364k | } |
404 | | |
405 | 16.7k | libstoff::DebugStream f; |
406 | 16.7k | f << "Entries(OleSimp): "; |
407 | | // always 1, 0, 2, 0* |
408 | 352k | for (int i = 0; i < 20; i++) |
409 | 335k | if (val[i]) f << "f" << i << "=" << val[i] << ","; |
410 | 16.7k | ascii.addPos(0); |
411 | 16.7k | ascii.addNote(f.str().c_str()); |
412 | | |
413 | 16.7k | if (!ip->isEnd()) { |
414 | 144 | ascii.addPos(20); |
415 | 144 | ascii.addNote("@@OleSimp:###"); |
416 | 144 | } |
417 | | |
418 | 16.7k | return true; |
419 | 21.3k | } |
420 | | |
421 | | bool STOFFOLEParser::readSummaryInformation(STOFFInputStreamPtr input, std::string const &oleName, |
422 | | libstoff::DebugFile &ascii) |
423 | 286k | { |
424 | 286k | if (oleName!="SummaryInformation") return false; |
425 | 19.4k | input->seek(0, librevenge::RVNG_SEEK_SET); |
426 | 19.4k | libstoff::DebugStream f; |
427 | 19.4k | f << "Entries(SumInfo):"; |
428 | 19.4k | auto val=int(input->readULong(2)); |
429 | 19.4k | if (val==0xfeff) { |
430 | 30 | input->setReadInverted(false); |
431 | 30 | val=0xfffe; |
432 | 30 | } |
433 | 19.4k | if (input->size()<48 || val!=0xfffe) { |
434 | 7.55k | STOFF_DEBUG_MSG(("STOFFOLEParser::readSummaryInformation: header seems bad\n")); |
435 | 7.55k | f << "###"; |
436 | 7.55k | ascii.addPos(0); |
437 | 7.55k | ascii.addNote(f.str().c_str()); |
438 | 7.55k | return true; |
439 | 7.55k | } |
440 | 143k | for (int i=0; i<11; ++i) { // f1=1, f2=0-2 |
441 | 131k | val=int(input->readULong(2)); |
442 | 131k | if (val) f << "f" << i << "=" << val << ","; |
443 | 131k | } |
444 | 11.9k | val=int(input->readULong(4)); |
445 | 11.9k | if (val!=1) { |
446 | 653 | STOFF_DEBUG_MSG(("STOFFOLEParser::readSummaryInformation: summary info is bad\n")); |
447 | 653 | f << "###sumInfo=" << val << ","; |
448 | 653 | ascii.addPos(0); |
449 | 653 | ascii.addNote(f.str().c_str()); |
450 | 653 | return true; |
451 | 653 | } |
452 | 54.9k | for (int i=0; i<4; ++i) { |
453 | 44.2k | val=int(input->readULong(4)); |
454 | 44.2k | static int const expected[]= {int(0xf29f85e0),0x10684ff9,0x891ab,int(0xd9b3272b)}; |
455 | 44.2k | if (val==expected[i]) continue; |
456 | 591 | STOFF_DEBUG_MSG(("STOFFOLEParser::readSummaryInformation: fmid is bad\n")); |
457 | 591 | f << "###fmid" << i << "=" << std::hex << val << std::dec << ","; |
458 | 591 | ascii.addPos(0); |
459 | 591 | ascii.addNote(f.str().c_str()); |
460 | 591 | return true; |
461 | 44.2k | } |
462 | 10.6k | auto decal=int(input->readULong(4)); |
463 | 10.6k | if (decal<0x30 || input->size()<decal) { |
464 | 127 | STOFF_DEBUG_MSG(("STOFFOLEParser::readSummaryInformation: decal is bad\n")); |
465 | 127 | f << "decal=" << val << ","; |
466 | 127 | ascii.addPos(0); |
467 | 127 | ascii.addNote(f.str().c_str()); |
468 | 127 | return true; |
469 | | |
470 | 127 | } |
471 | 10.5k | ascii.addPos(0); |
472 | 10.5k | ascii.addNote(f.str().c_str()); |
473 | 10.5k | if (decal!=0x30) { |
474 | 398 | ascii.addPos(0x30); |
475 | 398 | ascii.addNote("_"); |
476 | 398 | input->seek(decal, librevenge::RVNG_SEEK_SET); |
477 | 398 | } |
478 | | |
479 | 10.5k | long pos=input->tell(); |
480 | 10.5k | f.str(""); |
481 | 10.5k | f << "SumInfo-A:"; |
482 | 10.5k | auto pSetSize=long(input->readULong(4)); |
483 | 10.5k | auto N=int(input->readULong(4)); |
484 | 10.5k | f << "N=" << N << ","; |
485 | 10.5k | if (pSetSize<0 || input->size()-pos<pSetSize || (pSetSize-8)/8<N) { |
486 | 1.95k | STOFF_DEBUG_MSG(("STOFFOLEParser::readSummaryInformation: psetstruct is bad\n")); |
487 | 1.95k | f << "###"; |
488 | 1.95k | ascii.addPos(pos); |
489 | 1.95k | ascii.addNote(f.str().c_str()); |
490 | 1.95k | return true; |
491 | 1.95k | } |
492 | 8.59k | f << "["; |
493 | 8.59k | std::map<long,int> posToTypeMap; |
494 | 86.8k | for (int i=0; i<N; ++i) { |
495 | 78.2k | auto type=int(input->readULong(4)); |
496 | 78.2k | auto depl=int(input->readULong(4)); |
497 | 78.2k | if (depl==0) continue; |
498 | 77.8k | f << std::hex << depl << std::dec << ":" << type << ","; |
499 | 77.8k | if (depl<8+8*N || depl>pSetSize-4 || posToTypeMap.find(pos+depl)!=posToTypeMap.end()) { |
500 | 5.01k | f << "###"; |
501 | 5.01k | continue; |
502 | 5.01k | } |
503 | 72.8k | posToTypeMap[pos+depl]=type; |
504 | 72.8k | } |
505 | 8.59k | f << "],"; |
506 | 8.59k | ascii.addPos(pos); |
507 | 8.59k | ascii.addNote(f.str().c_str()); |
508 | | |
509 | 72.8k | for (auto const &posToType : posToTypeMap) { |
510 | 72.8k | pos=posToType.first; |
511 | 72.8k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
512 | 72.8k | f.str(""); |
513 | 72.8k | f << "SumInfo-B" << posToType.second << ":"; |
514 | 72.8k | auto type=int(input->readULong(4)); |
515 | 72.8k | if (type==0x1e) { |
516 | 55.0k | auto sSz=long(input->readULong(4)); |
517 | 55.0k | if (sSz<0 || (input->size()-pos-8)<sSz || pos+8+sSz>input->size()) { |
518 | 526 | STOFF_DEBUG_MSG(("STOFFOLEParser::readSummaryInformation: string size is bad\n")); |
519 | 526 | f << "##stringSz=" << sSz << ","; |
520 | 526 | ascii.addPos(pos); |
521 | 526 | ascii.addNote(f.str().c_str()); |
522 | 526 | continue; |
523 | 526 | } |
524 | 54.5k | std::string text(""); |
525 | 320k | for (long c=0; c < sSz; ++c) text+=char(input->readULong(1)); |
526 | 54.5k | f << text; |
527 | 54.5k | } |
528 | 17.7k | else if (type==0x40) { |
529 | 13.3k | f << "dateTime,"; // readme 8 byte |
530 | 13.3k | } |
531 | 4.47k | else { |
532 | 4.47k | STOFF_DEBUG_MSG(("STOFFOLEParser::readSummaryInformation: find unknown type\n")); |
533 | 4.47k | f << "#type=" << std::hex << type << std::dec << ","; |
534 | 4.47k | } |
535 | 72.3k | ascii.addPos(pos); |
536 | 72.3k | ascii.addNote(f.str().c_str()); |
537 | 72.3k | } |
538 | 8.59k | return true; |
539 | 10.5k | } |
540 | | |
541 | | bool STOFFOLEParser::readObjInfo(STOFFInputStreamPtr input, std::string const &oleName, |
542 | | libstoff::DebugFile &ascii) |
543 | 302k | { |
544 | 302k | if (oleName!="ObjInfo") return false; |
545 | | |
546 | 9 | if (input->size()!=6) return false; |
547 | | |
548 | 3 | input->seek(0, librevenge::RVNG_SEEK_SET); |
549 | 3 | libstoff::DebugStream f; |
550 | 3 | f << "Entries(ObjInfo):"; |
551 | | |
552 | | // always 0, 3, 4 ? |
553 | 12 | for (int i = 0; i < 3; i++) f << input->readLong(2) << ","; |
554 | | |
555 | 3 | ascii.addPos(0); |
556 | 3 | ascii.addNote(f.str().c_str()); |
557 | | |
558 | 3 | return true; |
559 | 9 | } |
560 | | |
561 | | bool STOFFOLEParser::readCompObj(STOFFInputStreamPtr ip, STOFFOLEParser::OleDirectory &directory) |
562 | 115k | { |
563 | 115k | libstoff::DebugFile ascii(ip); |
564 | 115k | if (directory.m_dir.empty()) |
565 | 107k | ascii.open("CompObj"); |
566 | 7.83k | else |
567 | 7.83k | ascii.open(directory.m_dir+"/CompObj"); |
568 | | |
569 | | // check minimal size |
570 | 115k | ip->setReadInverted(true); |
571 | 115k | const int minSize = 12 + 14+ 16 + 12; // size of header, clsid, footer, 3 string size |
572 | 115k | if (ip->seek(minSize,librevenge::RVNG_SEEK_SET) != 0 || ip->tell() != minSize) return false; |
573 | | |
574 | 115k | libstoff::DebugStream f; |
575 | 115k | f << "Entries(CompObj)(Header): "; |
576 | 115k | ip->seek(0,librevenge::RVNG_SEEK_SET); |
577 | | |
578 | 805k | for (int i = 0; i < 6; i++) { |
579 | 690k | auto val = int(ip->readLong(2)); |
580 | 690k | f << val << ", "; |
581 | 690k | } |
582 | | |
583 | 115k | ascii.addPos(0); |
584 | 115k | ascii.addNote(f.str().c_str()); |
585 | | |
586 | 115k | ascii.addPos(12); |
587 | | // the clsid |
588 | 115k | unsigned long clsData[4]; // ushort n1, n2, n3, b8, ... b15 |
589 | 115k | for (unsigned long &i : clsData) |
590 | 460k | i = ip->readULong(4); |
591 | | |
592 | 115k | f.str(""); |
593 | 115k | f << "@@CompObj(CLSID):"; |
594 | 115k | if (clsData[1] == 0 && clsData[2] == 0xC0 && clsData[3] == 0x46000000L) { |
595 | | // normally, a referenced object |
596 | 138 | directory.m_clsName = m_state->getCLSName(clsData[0]); |
597 | 138 | if (!directory.m_clsName.empty()) |
598 | 45 | f << "'" << directory.m_clsName << "'"; |
599 | 93 | else { |
600 | 93 | STOFF_DEBUG_MSG(("STOFFOLEParser::readCompObj: unknown clsid=%ld\n", long(clsData[0]))); |
601 | 93 | f << "unknCLSID='" << std::hex << clsData[0] << "'"; |
602 | 93 | } |
603 | 138 | } |
604 | 114k | else { |
605 | | /* I found: |
606 | | c1dbcd28e20ace11a29a00aa004a1a72 for MSWorks.Table |
607 | | c2dbcd28e20ace11a29a00aa004a1a72 for Microsoft Works/MSWorksWPDoc |
608 | | a3bcb394c2bd1b10a18306357c795b37 for Microsoft Drawing 1.01/MSDraw.1.01 |
609 | | b25aa40e0a9ed111a40700c04fb932ba for Quill96 Story Group Class ( basic MSWorks doc?) |
610 | | 796827ed8bc9d111a75f00c04fb9667b for MSWorks4Sheet |
611 | | */ |
612 | 114k | f << "data0=(" << std::hex << clsData[0] << "," << clsData[1] << "), " |
613 | 114k | << "data1=(" << clsData[2] << "," << clsData[3] << ")"; |
614 | 114k | } |
615 | 115k | ascii.addNote(f.str().c_str()); |
616 | 115k | f << std::dec; |
617 | 441k | for (int ch = 0; ch < 3; ch++) { |
618 | 335k | long actPos = ip->tell(); |
619 | 335k | long sz = ip->readLong(4); |
620 | 335k | bool waitNumber = sz == -1; |
621 | 335k | if (waitNumber || sz == -2) sz = 4; |
622 | 335k | if (sz < 0 || !ip->checkPosition(actPos+4+sz)) return false; |
623 | | |
624 | 326k | std::string st; |
625 | 326k | if (waitNumber) { |
626 | 2.74k | f.str(""); |
627 | 2.74k | f << ip->readLong(4) << "[val*]"; |
628 | 2.74k | st = f.str(); |
629 | 2.74k | } |
630 | 324k | else { |
631 | 5.93M | for (long i = 0; i < sz; i++) |
632 | 5.61M | st += char(ip->readULong(1)); |
633 | 324k | } |
634 | | |
635 | 326k | f.str(""); |
636 | 326k | f << "@@CompObj:"; |
637 | 326k | switch (ch) { |
638 | 110k | case 0: |
639 | 110k | f << "UserType="; |
640 | 110k | break; |
641 | 109k | case 1: |
642 | 109k | f << "ClipName="; |
643 | 109k | directory.m_clipName=st; |
644 | 109k | break; |
645 | 106k | case 2: |
646 | 106k | f << "ProgIdName="; |
647 | 106k | break; |
648 | 0 | default: |
649 | 0 | break; |
650 | 326k | } |
651 | 326k | f << st; |
652 | 326k | ascii.addPos(actPos); |
653 | 326k | ascii.addNote(f.str().c_str()); |
654 | 326k | } |
655 | | |
656 | 106k | if (ip->isEnd()) return true; |
657 | | |
658 | 56.8k | long actPos = ip->tell(); |
659 | 56.8k | long nbElt = 4; |
660 | 56.8k | if (ip->seek(actPos+16,librevenge::RVNG_SEEK_SET) != 0 || |
661 | 56.8k | ip->tell() != actPos+16) { |
662 | 39.5k | if ((ip->tell()-actPos)%4) |
663 | 170 | return false; |
664 | 39.3k | nbElt = (ip->tell()-actPos)/4; |
665 | 39.3k | } |
666 | | |
667 | 56.7k | f.str(""); |
668 | 56.7k | f << "@@CompObj(Footer): " << std::hex; |
669 | 56.7k | ip->seek(actPos,librevenge::RVNG_SEEK_SET); |
670 | 166k | for (long i = 0; i < nbElt; i++) |
671 | 109k | f << ip->readULong(4) << ","; |
672 | 56.7k | ascii.addPos(actPos); |
673 | 56.7k | ascii.addNote(f.str().c_str()); |
674 | | |
675 | 56.7k | ascii.addPos(ip->tell()); |
676 | | |
677 | 56.7k | return true; |
678 | 56.8k | } |
679 | | |
680 | | ////////////////////////////////////////////////// |
681 | | // |
682 | | // OlePres001 seems to contained standart picture file and size |
683 | | // extract the picture if it is possible |
684 | | // |
685 | | ////////////////////////////////////////////////// |
686 | | |
687 | | bool STOFFOLEParser::isOlePres(STOFFInputStreamPtr ip, std::string const &oleName) |
688 | 309k | { |
689 | 309k | if (!ip.get()) return false; |
690 | | |
691 | 309k | if (strncmp("OlePres",oleName.c_str(),7) != 0) return false; |
692 | | |
693 | 4.45k | if (ip->seek(40, librevenge::RVNG_SEEK_SET) != 0 || ip->tell() != 40) return false; |
694 | | |
695 | 4.18k | ip->seek(0, librevenge::RVNG_SEEK_SET); |
696 | 11.7k | for (int i= 0; i < 2; i++) { |
697 | 7.95k | long val = ip->readLong(4); |
698 | 7.95k | if (val < -10 || val > 10) { |
699 | 4.02k | if (i!=1 && val != 0x50494354) |
700 | 408 | return false; |
701 | 4.02k | } |
702 | 7.95k | } |
703 | | |
704 | 3.77k | long actPos = ip->tell(); |
705 | 3.77k | long hSize = ip->readLong(4); |
706 | 3.77k | if (hSize < 4) return false; |
707 | 3.57k | if (ip->seek(actPos+hSize+28, librevenge::RVNG_SEEK_SET) != 0 |
708 | 3.57k | || ip->tell() != actPos+hSize+28) |
709 | 306 | return false; |
710 | | |
711 | 3.26k | ip->seek(actPos+hSize, librevenge::RVNG_SEEK_SET); |
712 | 15.4k | for (int i= 3; i < 7; i++) { |
713 | 12.5k | long val = ip->readLong(4); |
714 | 12.5k | if (val < -10 || val > 10) { |
715 | 3.17k | if (i != 5 || val > 256) return false; |
716 | 3.17k | } |
717 | 12.5k | } |
718 | | |
719 | 2.94k | ip->seek(8, librevenge::RVNG_SEEK_CUR); |
720 | 2.94k | long size = ip->readLong(4); |
721 | | |
722 | 2.94k | if (size <= 0) return ip->isEnd(); |
723 | | |
724 | 2.68k | actPos = ip->tell(); |
725 | 2.68k | if (ip->seek(actPos+size, librevenge::RVNG_SEEK_SET) != 0 |
726 | 2.68k | || ip->tell() != actPos+size) |
727 | 120 | return false; |
728 | | |
729 | 2.56k | return true; |
730 | 2.68k | } |
731 | | |
732 | | bool STOFFOLEParser::readOlePres(STOFFInputStreamPtr ip, STOFFOLEParser::OleContent &content) |
733 | 1.37k | { |
734 | 1.37k | if (!isOlePres(ip, "OlePres")) return false; |
735 | 1.37k | content.setParsed(true); |
736 | 1.37k | libstoff::DebugFile ascii(ip); |
737 | 1.37k | ascii.open(content.getOleName()); |
738 | 1.37k | libstoff::DebugStream f; |
739 | 1.37k | f << "Entries(OlePress)(header): "; |
740 | 1.37k | ip->seek(0,librevenge::RVNG_SEEK_SET); |
741 | 4.11k | for (int i = 0; i < 2; i++) { |
742 | 2.74k | long val = ip->readLong(4); |
743 | 2.74k | f << val << ", "; |
744 | 2.74k | } |
745 | | |
746 | 1.37k | long actPos = ip->tell(); |
747 | 1.37k | long hSize = ip->readLong(4); |
748 | 1.37k | if (hSize < 4) return false; |
749 | 1.37k | f << "hSize = " << hSize; |
750 | 1.37k | ascii.addPos(0); |
751 | 1.37k | ascii.addNote(f.str().c_str()); |
752 | | |
753 | 1.37k | long endHPos = actPos+hSize; |
754 | 1.37k | if (!ip->checkPosition(endHPos+28)) return true; |
755 | 1.37k | if (hSize!=4) { |
756 | 1.36k | bool ok = true; |
757 | 1.36k | f.str(""); |
758 | 1.36k | f << "@@OlePress(headerA): "; |
759 | 1.36k | if (hSize < 14) ok = false; |
760 | 136 | else { |
761 | | // 12,21,32|48,0 |
762 | 680 | for (int i = 0; i < 4; i++) f << ip->readLong(2) << ","; |
763 | | // 3 name of creator |
764 | 447 | for (int ch=0; ch < 3; ch++) { |
765 | 390 | std::string str; |
766 | 390 | bool find = false; |
767 | 3.58k | while (ip->tell() < endHPos) { |
768 | 3.50k | auto c = static_cast<unsigned char>(ip->readULong(1)); |
769 | 3.50k | if (c == 0) { |
770 | 311 | find = true; |
771 | 311 | break; |
772 | 311 | } |
773 | 3.19k | str += char(c); |
774 | 3.19k | } |
775 | 390 | if (!find) { |
776 | 79 | ok = false; |
777 | 79 | break; |
778 | 79 | } |
779 | 311 | f << ", name" << ch << "=" << str; |
780 | 311 | } |
781 | 136 | if (ok) ok = ip->tell() == endHPos; |
782 | 136 | } |
783 | | // FIXME, normally they remain only a few bits (size unknown) |
784 | 1.36k | if (!ok) f << "###"; |
785 | 1.36k | ascii.addPos(actPos); |
786 | 1.36k | ascii.addNote(f.str().c_str()); |
787 | 1.36k | } |
788 | | |
789 | 1.37k | if (!ip->checkPosition(endHPos+28)) |
790 | 0 | return true; |
791 | | |
792 | 1.37k | ip->seek(endHPos, librevenge::RVNG_SEEK_SET); |
793 | | |
794 | 1.37k | actPos = ip->tell(); |
795 | 1.37k | f.str(""); |
796 | 1.37k | f << "@@OlePress(headerB): "; |
797 | 6.85k | for (int i = 3; i < 7; i++) { |
798 | 5.48k | long val = ip->readLong(4); |
799 | 5.48k | f << val << ", "; |
800 | 5.48k | } |
801 | | // dim in TWIP ? |
802 | 1.37k | auto extendX = long(ip->readULong(4)); |
803 | 1.37k | auto extendY = long(ip->readULong(4)); |
804 | 1.37k | if (extendX > 0 && extendY > 0) { |
805 | 1.17k | STOFFPosition pos; |
806 | 1.17k | pos.m_anchorTo=STOFFPosition::Char; |
807 | 1.17k | pos.setSize(STOFFVec2f(float(extendX)/20.f, float(extendY)/20.f)); |
808 | 1.17k | content.setPosition(pos); |
809 | 1.17k | } |
810 | 1.37k | long fSize = ip->readLong(4); |
811 | 1.37k | f << "extendX="<< extendX << ", extendY=" << extendY << ", fSize=" << fSize; |
812 | | |
813 | 1.37k | ascii.addPos(actPos); |
814 | 1.37k | ascii.addNote(f.str().c_str()); |
815 | | |
816 | 1.37k | if (fSize == 0) return true; |
817 | | |
818 | 1.35k | librevenge::RVNGBinaryData data; |
819 | 1.35k | if (!ip->readDataBlock(fSize, data)) return true; |
820 | 1.28k | content.setImageData(data,"object/ole"); |
821 | | #ifdef DEBUG_WITH_FILES |
822 | | libstoff::Debug::dumpFile(data, content.getOleName().c_str()); |
823 | | #endif |
824 | | |
825 | 1.28k | if (!ip->isEnd()) { |
826 | 1.23k | ascii.addPos(ip->tell()); |
827 | 1.23k | ascii.addNote("@@OlePress###"); |
828 | 1.23k | } |
829 | | |
830 | 1.28k | ascii.skipZone(36+hSize,36+hSize+fSize-1); |
831 | 1.28k | return true; |
832 | 1.35k | } |
833 | | |
834 | | ////////////////////////////////////////////////// |
835 | | // |
836 | | // Ole10Native: basic Windows picture, with no size |
837 | | // - in general used to store a bitmap |
838 | | // - may also store some Math StarOffice document |
839 | | // |
840 | | ////////////////////////////////////////////////// |
841 | | |
842 | | bool STOFFOLEParser::isOle10Native(STOFFInputStreamPtr ip, std::string const &oleName) |
843 | 306k | { |
844 | 306k | if (strncmp("Ole10Native",oleName.c_str(),11) != 0) return false; |
845 | | |
846 | 285 | if (ip->seek(4, librevenge::RVNG_SEEK_SET) != 0 || ip->tell() != 4) return false; |
847 | | |
848 | 256 | ip->seek(0, librevenge::RVNG_SEEK_SET); |
849 | 256 | long size = ip->readLong(4); |
850 | | |
851 | 256 | if (size <= 0) return false; |
852 | 167 | if (ip->seek(4+size, librevenge::RVNG_SEEK_SET) != 0 || ip->tell() != 4+size) |
853 | 93 | return false; |
854 | | |
855 | 74 | return true; |
856 | 167 | } |
857 | | |
858 | | bool STOFFOLEParser::readOle10Native(STOFFInputStreamPtr ip, STOFFOLEParser::OleContent &content) |
859 | 37 | { |
860 | 37 | if (!isOle10Native(ip, "Ole10Native")) return false; |
861 | | |
862 | 37 | content.setParsed(true); |
863 | 37 | libstoff::DebugFile ascii(ip); |
864 | 37 | ascii.open(content.getOleName()); |
865 | 37 | libstoff::DebugStream f; |
866 | 37 | f << "Entries(Ole10Native)(Header): "; |
867 | 37 | ip->seek(0,librevenge::RVNG_SEEK_SET); |
868 | 37 | long fSize = ip->readLong(4); |
869 | 37 | f << "fSize=" << fSize; |
870 | 37 | if (ip->readULong(4)==0x10001) { // TODO: check if the OLE is a old StarMathDocument 2.0 |
871 | 0 | STOFF_DEBUG_MSG(("STOFFOLEParser::readOle10Native: find an OLE which can be a StarMathDocument\n")); |
872 | 0 | } |
873 | 37 | ascii.addPos(0); |
874 | 37 | ascii.addNote(f.str().c_str()); |
875 | | |
876 | 37 | librevenge::RVNGBinaryData data; |
877 | 37 | ip->seek(4, librevenge::RVNG_SEEK_SET); |
878 | 37 | if (!ip->readDataBlock(fSize, data)) return false; |
879 | 37 | content.setImageData(data,"object/ole"); |
880 | | #ifdef DEBUG_WITH_FILES |
881 | | libstoff::Debug::dumpFile(data, content.getOleName().c_str()); |
882 | | #endif |
883 | | |
884 | 37 | if (!ip->isEnd()) { |
885 | 30 | ascii.addPos(ip->tell()); |
886 | 30 | ascii.addNote("@@Ole10Native###"); |
887 | 30 | } |
888 | 37 | ascii.skipZone(4,4+fSize-1); |
889 | 37 | return true; |
890 | 37 | } |
891 | | |
892 | | //////////////////////////////////////////////////////////////// |
893 | | // |
894 | | // In general a picture : a PNG, an JPEG, a basic metafile, |
895 | | // find also a MSDraw.1.01 picture (with first bytes 0x78563412="xV4") or WordArt, |
896 | | // ( with first bytes "WordArt" ) which are not sucefull read |
897 | | // (can probably contain a list of data, but do not know how to |
898 | | // detect that) |
899 | | // |
900 | | // To check: does this is related to MSO_BLIPTYPE ? |
901 | | // or OO/filter/sources/msfilter/msdffimp.cxx ? |
902 | | // |
903 | | //////////////////////////////////////////////////////////////// |
904 | | bool STOFFOLEParser::readContents(STOFFInputStreamPtr input, STOFFOLEParser::OleContent &content) |
905 | 306k | { |
906 | 306k | if (content.getBaseName()!="Contents") return false; |
907 | | |
908 | 3.66k | content.setParsed(true); |
909 | 3.66k | libstoff::DebugFile ascii(input); |
910 | 3.66k | ascii.open(content.getOleName()); |
911 | 3.66k | libstoff::DebugStream f; |
912 | 3.66k | input->seek(0, librevenge::RVNG_SEEK_SET); |
913 | 3.66k | f << "Entries(Contents):"; |
914 | | |
915 | 3.66k | bool ok = true; |
916 | | // bdbox 0 : size in the file ? |
917 | 3.66k | long dim[2]; |
918 | 3.66k | dim[0] = input->readLong(4); |
919 | 3.66k | dim[1] = input->readLong(4); |
920 | 3.66k | f << "bdbox0=(" << dim[0] << "," << dim[1]<<"),"; |
921 | 14.6k | for (int i = 0; i < 3; i++) { |
922 | | /* 0,{10|21|75|101|116}x2 */ |
923 | 10.9k | auto val = long(input->readULong(4)); |
924 | 10.9k | if (val < 1000) |
925 | 4.01k | f << val << ","; |
926 | 6.98k | else |
927 | 6.98k | f << std::hex << "0x" << val << std::dec << ","; |
928 | 10.9k | if (val > 0x10000) ok=false; |
929 | 10.9k | } |
930 | | // new bdbox : size of the picture ? |
931 | 3.66k | long naturalSize[2]; |
932 | 3.66k | naturalSize[0] = input->readLong(4); |
933 | 3.66k | naturalSize[1] = input->readLong(4); |
934 | 3.66k | f << std::dec << "bdbox1=(" << naturalSize[0] << "," << naturalSize[1]<<"),"; |
935 | 3.66k | f << "unk=" << input->readULong(4) << ","; // 24 or 32 |
936 | 3.66k | if (input->isEnd()) { |
937 | 93 | STOFF_DEBUG_MSG(("STOFFOLEParser: warning: Contents header length\n")); |
938 | 93 | return false; |
939 | 93 | } |
940 | 3.57k | STOFFPosition pos; |
941 | 3.57k | pos.m_anchorTo=STOFFPosition::Char; |
942 | 3.57k | bool sizeSet=false; |
943 | 3.57k | if (dim[0] > 0 && dim[0] < 3000 && |
944 | 1.37k | dim[1] > 0 && dim[1] < 3000) { |
945 | 742 | pos.setSize(STOFFVec2f(float(dim[0]),float(dim[1]))); |
946 | 742 | sizeSet=true; |
947 | 742 | } |
948 | 2.83k | else { |
949 | 2.83k | STOFF_DEBUG_MSG(("STOFFOLEParser: warning: Contents odd size : %ld %ld\n", dim[0], dim[1])); |
950 | 2.83k | } |
951 | 3.57k | if (naturalSize[0] > 0 && naturalSize[0] < 5000 && |
952 | 1.79k | naturalSize[1] > 0 && naturalSize[1] < 5000) { |
953 | 792 | if (!sizeSet) |
954 | 280 | pos.setSize(STOFFVec2f(float(naturalSize[0]),float(naturalSize[1]))); |
955 | 792 | } |
956 | 2.78k | else { |
957 | 2.78k | STOFF_DEBUG_MSG(("STOFFOLEParser: warning: Contents odd naturalsize : %ld %ld\n", naturalSize[0], naturalSize[1])); |
958 | 2.78k | } |
959 | 3.57k | content.setPosition(pos); |
960 | | |
961 | 3.57k | long actPos = input->tell(); |
962 | 3.57k | auto size = long(input->readULong(4)); |
963 | 3.57k | if (size <= 0) ok = false; |
964 | 3.57k | if (ok) { |
965 | 909 | input->seek(actPos+size+4, librevenge::RVNG_SEEK_SET); |
966 | 909 | if (input->tell() != actPos+size+4 || !input->isEnd()) { |
967 | 744 | ok = false; |
968 | 744 | STOFF_DEBUG_MSG(("STOFFOLEParser: warning: Contents unexpected file size=%ld\n", |
969 | 744 | size)); |
970 | 744 | } |
971 | 909 | } |
972 | | |
973 | 3.57k | if (!ok) f << "###"; |
974 | 3.57k | f << "dataSize=" << size; |
975 | | |
976 | 3.57k | ascii.addPos(0); |
977 | 3.57k | ascii.addNote(f.str().c_str()); |
978 | | |
979 | 3.57k | input->seek(actPos+4, librevenge::RVNG_SEEK_SET); |
980 | | |
981 | 3.57k | if (ok) { |
982 | 165 | librevenge::RVNGBinaryData pict; |
983 | 165 | if (input->readDataBlock(size, pict)) { |
984 | 165 | content.setImageData(pict,"object/ole"); |
985 | | #ifdef DEBUG_WITH_FILES |
986 | | libstoff::Debug::dumpFile(pict, content.getOleName().c_str()); |
987 | | #endif |
988 | 165 | ascii.skipZone(actPos+4, actPos+size+4-1); |
989 | 165 | } |
990 | 0 | else { |
991 | 0 | input->seek(actPos+4, librevenge::RVNG_SEEK_SET); |
992 | 0 | ok = false; |
993 | 0 | } |
994 | 165 | } |
995 | | |
996 | 3.57k | if (!input->isEnd()) { |
997 | 3.39k | ascii.addPos(actPos); |
998 | 3.39k | ascii.addNote("@@Contents:###"); |
999 | 3.39k | } |
1000 | | |
1001 | 3.57k | if (!ok) { |
1002 | 3.40k | STOFF_DEBUG_MSG(("STOFFOLEParser: warning: read ole Contents: failed\n")); |
1003 | 3.40k | } |
1004 | 3.57k | return true; |
1005 | 3.66k | } |
1006 | | |
1007 | | //////////////////////////////////////////////////////////////// |
1008 | | // |
1009 | | // Another different type of contents (this time in majuscule) |
1010 | | // we seem to contain the header of a EMF and then the EMF file |
1011 | | // |
1012 | | //////////////////////////////////////////////////////////////// |
1013 | | bool STOFFOLEParser::readCONTENTS(STOFFInputStreamPtr input, STOFFOLEParser::OleContent &content) |
1014 | 303k | { |
1015 | 303k | if (content.getBaseName()!="CONTENTS") return false; |
1016 | | |
1017 | 747 | content.setParsed(true); |
1018 | 747 | libstoff::DebugFile ascii(input); |
1019 | 747 | ascii.open(content.getOleName()); |
1020 | 747 | libstoff::DebugStream f; |
1021 | | |
1022 | 747 | input->seek(0, librevenge::RVNG_SEEK_SET); |
1023 | 747 | f << "Entries(CONTMAJ):"; |
1024 | | |
1025 | 747 | auto hSize = long(input->readULong(4)); |
1026 | 747 | if (input->isEnd()) return false; |
1027 | 715 | f << "hSize=" << std::hex << hSize << std::dec; |
1028 | | |
1029 | 715 | if (hSize <= 52 || input->seek(hSize+8,librevenge::RVNG_SEEK_SET) != 0 |
1030 | 676 | || input->tell() != hSize+8) { |
1031 | 160 | STOFF_DEBUG_MSG(("STOFFOLEParser: warning: CONTENTS headerSize=%ld\n", |
1032 | 160 | hSize)); |
1033 | 160 | return false; |
1034 | 160 | } |
1035 | | |
1036 | | // minimal checking of the "copied" header |
1037 | 555 | input->seek(4, librevenge::RVNG_SEEK_SET); |
1038 | 555 | auto type = long(input->readULong(4)); |
1039 | 555 | if (type < 0 || type > 4) return false; |
1040 | 512 | auto newSize = long(input->readULong(4)); |
1041 | | |
1042 | 512 | f << ", type=" << type; |
1043 | 512 | if (newSize < 8) return false; |
1044 | | |
1045 | 471 | if (newSize != hSize) // can sometimes happen, pb after a conversion ? |
1046 | 468 | f << ", ###newSize=" << std::hex << newSize << std::dec; |
1047 | | |
1048 | | // checkme: two bdbox, in document then data : units ? |
1049 | | // Maybe first in POINT, second in TWIP ? |
1050 | 471 | STOFFPosition pos; |
1051 | 471 | pos.m_anchorTo=STOFFPosition::Char; |
1052 | 1.41k | for (int st = 0; st < 2 ; st++) { |
1053 | 942 | long dim[4]; |
1054 | 3.76k | for (long &i : dim) i = input->readLong(4); |
1055 | | |
1056 | 942 | bool ok = dim[0] >= 0 && dim[2] > dim[0] && dim[1] >= 0 && dim[3] > dim[2]; |
1057 | 942 | if (ok && st==0) pos.setSize(STOFFVec2f(float(dim[2]-dim[0]), float(dim[3]-dim[1]))); |
1058 | 942 | if (st==0) f << ", bdbox(Text)"; |
1059 | 471 | else f << ", bdbox(Data)"; |
1060 | 942 | if (!ok) f << "###"; |
1061 | 942 | f << "=(" << dim[0] << "x" << dim[1] << "<->" << dim[2] << "x" << dim[3] << ")"; |
1062 | 942 | } |
1063 | 471 | content.setPosition(pos); |
1064 | 471 | char dataType[5]; |
1065 | 2.35k | for (int i = 0; i < 4; i++) dataType[i] = char(input->readULong(1)); |
1066 | 471 | dataType[4] = '\0'; |
1067 | 471 | f << ",typ=\""<<dataType<<"\""; // always " EMF" ? |
1068 | | |
1069 | 1.41k | for (int i = 0; i < 2; i++) { // always id0=0, id1=1 ? |
1070 | 942 | auto val = int(input->readULong(2)); |
1071 | 942 | if (val) f << ",id"<< i << "=" << val; |
1072 | 942 | } |
1073 | 471 | auto dataLength = long(input->readULong(4)); |
1074 | 471 | f << ",length=" << dataLength+hSize; |
1075 | | |
1076 | 471 | ascii.addPos(0); |
1077 | 471 | ascii.addNote(f.str().c_str()); |
1078 | | |
1079 | 471 | ascii.addPos(input->tell()); |
1080 | 471 | f.str(""); |
1081 | 471 | f << "@@CONTMAJ(2)"; |
1082 | 3.19k | for (int i = 0; i < 12 && 4*i+52 < hSize; i++) { |
1083 | | // f0=7,f1=1,f5=500,f6=320,f7=1c4,f8=11a |
1084 | | // or f0=a,f1=1,f2=2,f3=6c,f5=480,f6=360,f7=140,f8=f0 |
1085 | | // or f0=61,f1=1,f2=2,f3=58,f5=280,f6=1e0,f7=a9,f8=7f |
1086 | | // f3=some header sub size ? f5/f6 and f7/f8 two other bdbox ? |
1087 | 2.72k | auto val = long(input->readULong(4)); |
1088 | 2.72k | if (val) f << std::hex << ",f" << i << "=" << val; |
1089 | 2.72k | } |
1090 | 14.5k | for (int i = 0; 2*i+100 < hSize; i++) { |
1091 | | // g0=e3e3,g1=6,g2=4e6e,g3=4 |
1092 | | // g0=e200,g1=4,g2=a980,g3=3,g4=4c,g5=50 |
1093 | | // --- |
1094 | 14.1k | auto val = long(input->readULong(2)); |
1095 | 14.1k | if (val) f << std::hex << ",g" << i << "=" << val; |
1096 | 14.1k | } |
1097 | 471 | ascii.addNote(f.str().c_str()); |
1098 | | |
1099 | 471 | if (dataLength <= 0 || input->seek(hSize+4+dataLength,librevenge::RVNG_SEEK_SET) != 0 |
1100 | 468 | || input->tell() != hSize+4+dataLength || !input->isEnd()) { |
1101 | 468 | STOFF_DEBUG_MSG(("STOFFOLEParser: warning: CONTENTS unexpected file length=%ld\n", |
1102 | 468 | dataLength)); |
1103 | 468 | return true; |
1104 | 468 | } |
1105 | | |
1106 | 3 | input->seek(4+hSize, librevenge::RVNG_SEEK_SET); |
1107 | 3 | librevenge::RVNGBinaryData pict; |
1108 | 3 | if (!input->readEndDataBlock(pict)) return true; |
1109 | 3 | content.setImageData(pict,"object/ole"); |
1110 | | #ifdef DEBUG_WITH_FILES |
1111 | | libstoff::Debug::dumpFile(pict, content.getOleName().c_str()); |
1112 | | #endif |
1113 | | |
1114 | 3 | ascii.skipZone(hSize+4, input->tell()-1); |
1115 | 3 | return true; |
1116 | 3 | } |
1117 | | // vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: |