/src/libwps/src/lib/WPSOLEObject.cpp
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ |
2 | | /* libwps |
3 | | * Version: MPL 2.0 / LGPLv2.1+ |
4 | | * |
5 | | * This Source Code Form is subject to the terms of the Mozilla Public |
6 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
7 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
8 | | * |
9 | | * Major Contributor(s): |
10 | | * Copyright (C) 2009, 2011 Alonso Laurent (alonso@loria.fr) |
11 | | * Copyright (C) 2006, 2007 Andrew Ziem |
12 | | * Copyright (C) 2004-2006 Fridrich Strba (fridrich.strba@bluewin.ch) |
13 | | * Copyright (C) 2004 Marc Maurer (uwog@uwog.net) |
14 | | * Copyright (C) 2003-2005 William Lachance (william.lachance@sympatico.ca) |
15 | | * |
16 | | * For minor contributions see the git repository. |
17 | | * |
18 | | * Alternatively, the contents of this file may be used under the terms |
19 | | * of the GNU Lesser General Public License Version 2.1 or later |
20 | | * (LGPLv2.1+), in which case the provisions of the LGPLv2.1+ are |
21 | | * applicable instead of those above. |
22 | | * |
23 | | * For further information visit http://libwps.sourceforge.net |
24 | | */ |
25 | | |
26 | | #include <sstream> |
27 | | #include <string> |
28 | | |
29 | | #include <librevenge/librevenge.h> |
30 | | |
31 | | #include "WPSOLEObject.h" |
32 | | |
33 | | #include "WPSDebug.h" |
34 | | #include "WPSStream.h" |
35 | | #include "WPSStringStream.h" |
36 | | |
37 | | using namespace libwps; |
38 | | |
39 | | |
40 | | //////////////////////////////////////////////////////////// |
41 | | // read the OLE object |
42 | | //////////////////////////////////////////////////////////// |
43 | | bool WPSOLEObject::readMetafile(std::shared_ptr<WPSStream> stream, WPSEmbeddedObject &object, long endPos, bool strict) |
44 | 411 | { |
45 | 411 | if (!stream) return false; |
46 | 411 | RVNGInputStreamPtr &input=stream->m_input; |
47 | 411 | libwps::DebugFile &ascFile=stream->m_ascii; |
48 | 411 | libwps::DebugStream f; |
49 | | |
50 | 411 | if (endPos<=0) endPos=stream->m_eof; |
51 | 411 | else if (endPos>stream->m_eof) endPos=stream->m_eof; |
52 | | |
53 | 411 | long pos = input->tell(); |
54 | 411 | if (pos+8+4>endPos) |
55 | 16 | return false; |
56 | 395 | f << "Entries(Metafile):"; |
57 | 395 | f << "type=" << libwps::readU16(input) << ","; |
58 | 395 | float fDim[2]; |
59 | 790 | for (auto &d : fDim) d=float(libwps::read16(input)/1440.); |
60 | 395 | if (fDim[0]<0||fDim[1]<0) |
61 | 51 | { |
62 | 51 | input->seek(pos, librevenge::RVNG_SEEK_SET); |
63 | 51 | return false; |
64 | 51 | } |
65 | 344 | if (object.m_size==Vec2f() && fDim[0]>0 && fDim[1]>0) |
66 | 116 | { |
67 | 116 | object.m_size=Vec2f(fDim[0],fDim[1]); |
68 | 116 | f << "sz=" << object.m_size << ","; |
69 | 116 | } |
70 | 344 | input->seek(2, librevenge::RVNG_SEEK_CUR); // seek handle |
71 | 344 | if (strict) |
72 | 250 | { |
73 | 250 | if (!checkIsWMF(stream, endPos)) |
74 | 135 | { |
75 | 135 | input->seek(pos, librevenge::RVNG_SEEK_SET); |
76 | 135 | return false; |
77 | 135 | } |
78 | 115 | input->seek(pos+8, librevenge::RVNG_SEEK_SET); |
79 | 115 | } |
80 | 209 | librevenge::RVNGBinaryData data; |
81 | 209 | if (!libwps::readData(input, static_cast<unsigned long>(endPos-pos-8), data)) |
82 | 0 | { |
83 | 0 | WPS_DEBUG_MSG(("WPSOLEObject::readMetafile: I can not find the picture\n")); |
84 | 0 | input->seek(pos, librevenge::RVNG_SEEK_SET); |
85 | 0 | return false; |
86 | 0 | } |
87 | 209 | object.add(data,"application/x-wmf"); |
88 | | #ifdef DEBUG_WITH_FILES |
89 | | ascFile.skipZone(pos+8, endPos-1); |
90 | | std::stringstream s; |
91 | | static int fileId=0; |
92 | | s << "PictMeta" << ++fileId << ".wmf"; |
93 | | libwps::Debug::dumpFile(data, s.str().c_str()); |
94 | | #endif |
95 | | |
96 | 209 | input->seek(endPos, librevenge::RVNG_SEEK_SET); |
97 | 209 | ascFile.addPos(pos); |
98 | 209 | ascFile.addNote(f.str().c_str()); |
99 | 209 | return true; |
100 | 209 | } |
101 | | |
102 | | bool WPSOLEObject::readWMF(std::shared_ptr<WPSStream> stream, WPSEmbeddedObject &object,long endPos) |
103 | 13.7k | { |
104 | 13.7k | if (!stream) return false; |
105 | 13.7k | RVNGInputStreamPtr &input=stream->m_input; |
106 | 13.7k | libwps::DebugFile &ascFile=stream->m_ascii; |
107 | 13.7k | long pos=input->tell(); |
108 | | |
109 | 13.7k | long lastPos=endPos<=0 ? stream->m_eof : endPos; |
110 | 13.7k | if (lastPos>stream->m_eof) lastPos=stream->m_eof; |
111 | 13.7k | if (!checkIsWMF(stream,lastPos)) return false; |
112 | | |
113 | 1.38k | input->seek(pos+6, librevenge::RVNG_SEEK_SET); |
114 | 1.38k | auto fSize = long(libwps::read32(input)); |
115 | 1.38k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
116 | 1.38k | librevenge::RVNGBinaryData data; |
117 | 1.38k | if (!libwps::readData(input, static_cast<unsigned long>(2*fSize), data)) |
118 | 0 | { |
119 | 0 | input->seek(pos, librevenge::RVNG_SEEK_SET); |
120 | 0 | return false; |
121 | 0 | } |
122 | 1.38k | object.add(data,"application/x-wmf"); |
123 | | #ifdef DEBUG_WITH_FILES |
124 | | std::stringstream f; |
125 | | static volatile int actPict = 0; |
126 | | f << "WMF" << actPict++ << ".wmf"; |
127 | | libwps::Debug::dumpFile(data, f.str().c_str()); |
128 | | ascFile.skipZone(pos,pos+2*fSize-1); |
129 | | #endif |
130 | 1.38k | if (endPos>0 && input->tell()!=endPos) |
131 | 71 | { |
132 | 71 | ascFile.addPos(input->tell()); |
133 | 71 | ascFile.addNote("_"); |
134 | 71 | input->seek(endPos, librevenge::RVNG_SEEK_SET); |
135 | 71 | } |
136 | 1.38k | return true; |
137 | 1.38k | } |
138 | | |
139 | | bool WPSOLEObject::readOLE(std::shared_ptr<WPSStream> stream, WPSEmbeddedObject &object, long endPos) |
140 | 15.5k | { |
141 | 15.5k | if (!stream) return false; |
142 | 15.5k | RVNGInputStreamPtr &input=stream->m_input; |
143 | 15.5k | libwps::DebugStream f; |
144 | | |
145 | 15.5k | if (endPos<=0) endPos=stream->m_eof; |
146 | 15.4k | else if (endPos>stream->m_eof) endPos=stream->m_eof; |
147 | | |
148 | 15.5k | long pos = input->tell(); |
149 | 15.5k | if (pos+24>endPos || libwps::read32(input)!=0x501) |
150 | 3.52k | { |
151 | 3.52k | WPS_DEBUG_MSG(("WPSOLEObject::readOLE: not a picture header\n")); |
152 | 3.52k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
153 | 3.52k | return false; |
154 | 3.52k | } |
155 | 11.9k | f.str(""); |
156 | 11.9k | f << "Entries(OLEObject):"; |
157 | 11.9k | auto type=int(readU32(input)); |
158 | 11.9k | f << "type=" << type << ","; |
159 | 11.9k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
160 | 11.9k | bool ok=false; |
161 | 11.9k | switch (type) |
162 | 11.9k | { |
163 | 0 | case 1: |
164 | 0 | WPS_DEBUG_MSG(("WPSOLEObject::readOLE: find a link ole\n")); |
165 | 0 | f << "link,"; |
166 | 0 | break; |
167 | 10.6k | case 2: |
168 | 10.6k | ok=readEmbeddedOLE(stream, object, endPos); |
169 | 10.6k | break; |
170 | 693 | case 3: |
171 | 882 | case 5: |
172 | 882 | ok=readStaticOLE(stream, object, endPos); |
173 | 882 | break; |
174 | 490 | default: |
175 | 490 | WPS_DEBUG_MSG(("WPSOLEObject::readOLE: find a unknown type\n")); |
176 | 490 | f << "unknown,"; |
177 | 490 | break; |
178 | 11.9k | } |
179 | 11.9k | if (!ok) |
180 | 11.0k | { |
181 | 11.0k | libwps::DebugFile &ascFile=stream->m_ascii; |
182 | 11.0k | f << "###"; |
183 | 11.0k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
184 | 11.0k | ascFile.addPos(pos); |
185 | 11.0k | ascFile.addNote(f.str().c_str()); |
186 | 11.0k | } |
187 | 11.9k | return true; |
188 | 11.9k | } |
189 | | |
190 | | bool WPSOLEObject::readEmbeddedOLE(std::shared_ptr<WPSStream> stream, WPSEmbeddedObject &object, long endPos) |
191 | 10.6k | { |
192 | 10.6k | if (!stream) return false; |
193 | 10.6k | RVNGInputStreamPtr &input=stream->m_input; |
194 | 10.6k | libwps::DebugFile &ascFile=stream->m_ascii; |
195 | 10.6k | libwps::DebugStream f; |
196 | | |
197 | 10.6k | long pos = input->tell(); |
198 | 10.6k | if (pos+24+4>endPos || libwps::readU32(input)!=0x501) |
199 | 283 | { |
200 | 283 | input->seek(pos, librevenge::RVNG_SEEK_SET); |
201 | 283 | return false; |
202 | 283 | } |
203 | 10.3k | auto type=int(libwps::readU32(input)); |
204 | 10.3k | if (type!=2) |
205 | 0 | { |
206 | 0 | input->seek(pos, librevenge::RVNG_SEEK_SET); |
207 | 0 | return false; |
208 | 0 | } |
209 | 10.3k | f << "Entries(OLEObject)[embedded]:"; |
210 | 10.3k | std::string names[3]; |
211 | 10.3k | for (auto &name : names) |
212 | 28.2k | { |
213 | 28.2k | if (!readString(stream, name, endPos) || input->tell()+4>endPos) |
214 | 2.51k | { |
215 | 2.51k | WPS_DEBUG_MSG(("WPSOLEObject::readEmbeddedOLE: can not read the name\n")); |
216 | 2.51k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
217 | 2.51k | return false; |
218 | 2.51k | } |
219 | 25.7k | if (name.empty()) continue; |
220 | 369 | f << name << ","; |
221 | 369 | } |
222 | | // find Paint.Picture, WangImage.Document |
223 | 7.80k | unsigned long dSz=libwps::readU32(input); |
224 | 7.80k | long actPos=input->tell(); |
225 | 7.80k | if (dSz>0x40000000 || dSz<10 || dSz>static_cast<unsigned long>(endPos-actPos)) |
226 | 7.21k | { |
227 | 7.21k | WPS_DEBUG_MSG(("WPSOLEObject::readOLE: pict size seems bad\n")); |
228 | 7.21k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
229 | 7.21k | return false; |
230 | 7.21k | } |
231 | | |
232 | 599 | bool ok=true; |
233 | 599 | if (names[0]=="METAFILEPICT") |
234 | 0 | ok=readMetafile(stream, object, actPos+long(dSz)); |
235 | 599 | else |
236 | 599 | { |
237 | 599 | librevenge::RVNGBinaryData data; |
238 | 599 | if (!libwps::readData(input, dSz, data)) |
239 | 0 | ok=false; |
240 | 599 | else |
241 | 599 | { |
242 | 599 | object.add(data); |
243 | | #ifdef DEBUG_WITH_FILES |
244 | | ascFile.skipZone(actPos, actPos+long(dSz)-1); |
245 | | std::stringstream s; |
246 | | static int fileId=0; |
247 | | s << "PictOLEEmbedded" << ++fileId << ".pct"; |
248 | | libwps::Debug::dumpFile(data, s.str().c_str()); |
249 | | #endif |
250 | 599 | } |
251 | 599 | } |
252 | 599 | if (!ok) |
253 | 0 | { |
254 | 0 | WPS_DEBUG_MSG(("WPSOLEObject::readEmbeddedOLE: I can not find the picture\n")); |
255 | 0 | f << "###"; |
256 | 0 | } |
257 | 599 | input->seek(actPos+long(dSz), librevenge::RVNG_SEEK_SET); |
258 | 599 | ascFile.addPos(pos); |
259 | 599 | ascFile.addNote(f.str().c_str()); |
260 | 599 | if (input->tell()<endPos) // normally followed by a static OLE |
261 | 396 | readStaticOLE(stream, object, endPos); |
262 | 599 | return true; |
263 | 7.80k | } |
264 | | |
265 | | bool WPSOLEObject::readStaticOLE(std::shared_ptr<WPSStream> stream, WPSEmbeddedObject &object, long endPos) |
266 | 1.27k | { |
267 | 1.27k | if (!stream) return false; |
268 | 1.27k | RVNGInputStreamPtr &input=stream->m_input; |
269 | 1.27k | libwps::DebugFile &ascFile=stream->m_ascii; |
270 | 1.27k | libwps::DebugStream f; |
271 | | |
272 | 1.27k | long pos = input->tell(); |
273 | 1.27k | if (pos+24+4>endPos || libwps::readU32(input)!=0x501) |
274 | 327 | { |
275 | 327 | input->seek(pos, librevenge::RVNG_SEEK_SET); |
276 | 327 | return false; |
277 | 327 | } |
278 | 951 | auto type=int(libwps::readU32(input)); |
279 | 951 | if (type!=3 && type!=5) |
280 | 48 | { |
281 | 48 | input->seek(pos, librevenge::RVNG_SEEK_SET); |
282 | 48 | return false; |
283 | 48 | } |
284 | 903 | f << "Entries(OLEObject)[static]:"; |
285 | 903 | f << "type=" << type << ","; |
286 | 903 | std::string name; |
287 | 903 | if (!readString(stream, name, endPos) || input->tell()+12>endPos) |
288 | 271 | { |
289 | 271 | WPS_DEBUG_MSG(("WPSOLEObject::readStaticOLE: can not read the name\n")); |
290 | 271 | input->seek(pos, librevenge::RVNG_SEEK_SET); |
291 | 271 | return false; |
292 | 271 | } |
293 | | // find METAFILEPICT |
294 | 632 | f << name << ","; |
295 | 1.89k | for (int i=0; i<2; ++i) // g0+g1~0, some application id? |
296 | 1.26k | { |
297 | 1.26k | auto val=long(libwps::read32(input)); |
298 | 1.26k | if (val) f << "g" << i << "=" << val << ","; |
299 | 1.26k | } |
300 | 632 | unsigned long dSz=libwps::readU32(input); |
301 | 632 | long actPos=input->tell(); |
302 | 632 | if (dSz>0x40000000 || dSz<10 || dSz>static_cast<unsigned long>(endPos-actPos)) |
303 | 305 | { |
304 | 305 | WPS_DEBUG_MSG(("WPSOLEObject::readOLE: pict size seems bad\n")); |
305 | 305 | input->seek(pos, librevenge::RVNG_SEEK_SET); |
306 | 305 | return false; |
307 | 305 | } |
308 | | |
309 | 327 | bool ok=true; |
310 | 327 | if (name=="METAFILEPICT") |
311 | 41 | ok=readMetafile(stream, object, actPos+long(dSz)); |
312 | 286 | else |
313 | 286 | { |
314 | 286 | librevenge::RVNGBinaryData data; |
315 | 286 | if (!libwps::readData(input, dSz, data)) |
316 | 0 | ok=false; |
317 | 286 | else |
318 | 286 | { |
319 | 286 | object.add(data); |
320 | | #ifdef DEBUG_WITH_FILES |
321 | | ascFile.skipZone(actPos, actPos+long(dSz)-1); |
322 | | std::stringstream s; |
323 | | static int fileId=0; |
324 | | s << "PictOLEStatic" << ++fileId << ".pct"; |
325 | | libwps::Debug::dumpFile(data, s.str().c_str()); |
326 | | #endif |
327 | 286 | } |
328 | 286 | } |
329 | 327 | if (!ok) |
330 | 2 | { |
331 | 2 | WPS_DEBUG_MSG(("WPSOLEObject::readStaticOLE: I can not find the picture\n")); |
332 | 2 | f << "###"; |
333 | 2 | } |
334 | 327 | input->seek(actPos+long(dSz), librevenge::RVNG_SEEK_SET); |
335 | 327 | ascFile.addPos(pos); |
336 | 327 | ascFile.addNote(f.str().c_str()); |
337 | 327 | return true; |
338 | 632 | } |
339 | | |
340 | | bool WPSOLEObject::readString(std::shared_ptr<WPSStream> stream, std::string &name, long endPos) |
341 | 29.1k | { |
342 | 29.1k | if (!stream) return false; |
343 | 29.1k | name=""; |
344 | 29.1k | RVNGInputStreamPtr &input=stream->m_input; |
345 | 29.1k | long pos=input->tell(); |
346 | 29.1k | if (pos+4>endPos) return false; |
347 | 29.1k | auto sSz=long(libwps::readU32(input)); |
348 | 29.1k | if (sSz<0 || sSz>endPos-pos-4) |
349 | 1.99k | { |
350 | 1.99k | WPS_DEBUG_MSG(("WPSOLEObject::readString: name size seems bad\n")); |
351 | 1.99k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
352 | 1.99k | return false; |
353 | 1.99k | } |
354 | 27.1k | if (sSz==0) return true; |
355 | 7.96k | for (long i=0; i+1<sSz; ++i) |
356 | 7.05k | { |
357 | 7.05k | auto c=char(libwps::readU8(input)); |
358 | 7.05k | if (c) |
359 | 6.61k | name+=c; |
360 | 448 | else |
361 | 448 | return false; |
362 | 7.05k | } |
363 | 905 | return libwps::readU8(input)==0; |
364 | 1.35k | } |
365 | | |
366 | | bool WPSOLEObject::checkIsWMF(std::shared_ptr<WPSStream> stream, long endPos) |
367 | 13.9k | { |
368 | 13.9k | RVNGInputStreamPtr &input=stream->m_input; |
369 | 13.9k | long pos=input->tell(); |
370 | 13.9k | if (pos+18>endPos) return false; |
371 | 8.50k | auto fType = int(libwps::read16(input)); |
372 | 8.50k | if ((fType!=1 && fType!=2) || libwps::read16(input)<9) |
373 | 2.40k | { |
374 | 2.40k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
375 | 2.40k | return false; |
376 | 2.40k | } |
377 | | // seek version |
378 | 6.09k | input->seek(2, librevenge::RVNG_SEEK_CUR); |
379 | 6.09k | auto fSize = long(libwps::read32(input)); // size in words |
380 | 6.09k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
381 | 6.09k | return (2*fSize>18 && 2*fSize<=endPos-pos); |
382 | 8.50k | } |
383 | | |
384 | | /* vim:set shiftwidth=4 softtabstop=4 noexpandtab: */ |