/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 | 481 | { |
45 | 481 | if (!stream) return false; |
46 | 481 | RVNGInputStreamPtr &input=stream->m_input; |
47 | 481 | libwps::DebugFile &ascFile=stream->m_ascii; |
48 | 481 | libwps::DebugStream f; |
49 | | |
50 | 481 | if (endPos<=0) endPos=stream->m_eof; |
51 | 481 | else if (endPos>stream->m_eof) endPos=stream->m_eof; |
52 | | |
53 | 481 | long pos = input->tell(); |
54 | 481 | if (pos+8+4>endPos) |
55 | 24 | return false; |
56 | 457 | f << "Entries(Metafile):"; |
57 | 457 | f << "type=" << libwps::readU16(input) << ","; |
58 | 457 | float fDim[2]; |
59 | 914 | for (auto &d : fDim) d=float(libwps::read16(input)/1440.); |
60 | 457 | if (fDim[0]<0||fDim[1]<0) |
61 | 76 | { |
62 | 76 | input->seek(pos, librevenge::RVNG_SEEK_SET); |
63 | 76 | return false; |
64 | 76 | } |
65 | 381 | if (object.m_size==Vec2f() && fDim[0]>0 && fDim[1]>0) |
66 | 133 | { |
67 | 133 | object.m_size=Vec2f(fDim[0],fDim[1]); |
68 | 133 | f << "sz=" << object.m_size << ","; |
69 | 133 | } |
70 | 381 | input->seek(2, librevenge::RVNG_SEEK_CUR); // seek handle |
71 | 381 | if (strict) |
72 | 276 | { |
73 | 276 | if (!checkIsWMF(stream, endPos)) |
74 | 154 | { |
75 | 154 | input->seek(pos, librevenge::RVNG_SEEK_SET); |
76 | 154 | return false; |
77 | 154 | } |
78 | 122 | input->seek(pos+8, librevenge::RVNG_SEEK_SET); |
79 | 122 | } |
80 | 227 | librevenge::RVNGBinaryData data; |
81 | 227 | 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 | 227 | 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 | 227 | input->seek(endPos, librevenge::RVNG_SEEK_SET); |
97 | 227 | ascFile.addPos(pos); |
98 | 227 | ascFile.addNote(f.str().c_str()); |
99 | 227 | return true; |
100 | 227 | } |
101 | | |
102 | | bool WPSOLEObject::readWMF(std::shared_ptr<WPSStream> stream, WPSEmbeddedObject &object,long endPos) |
103 | 13.2k | { |
104 | 13.2k | if (!stream) return false; |
105 | 13.2k | RVNGInputStreamPtr &input=stream->m_input; |
106 | 13.2k | libwps::DebugFile &ascFile=stream->m_ascii; |
107 | 13.2k | long pos=input->tell(); |
108 | | |
109 | 13.2k | long lastPos=endPos<=0 ? stream->m_eof : endPos; |
110 | 13.2k | if (lastPos>stream->m_eof) lastPos=stream->m_eof; |
111 | 13.2k | if (!checkIsWMF(stream,lastPos)) return false; |
112 | | |
113 | 1.28k | input->seek(pos+6, librevenge::RVNG_SEEK_SET); |
114 | 1.28k | auto fSize = long(libwps::read32(input)); |
115 | 1.28k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
116 | 1.28k | librevenge::RVNGBinaryData data; |
117 | 1.28k | 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.28k | 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.28k | if (endPos>0 && input->tell()!=endPos) |
131 | 61 | { |
132 | 61 | ascFile.addPos(input->tell()); |
133 | 61 | ascFile.addNote("_"); |
134 | 61 | input->seek(endPos, librevenge::RVNG_SEEK_SET); |
135 | 61 | } |
136 | 1.28k | return true; |
137 | 1.28k | } |
138 | | |
139 | | bool WPSOLEObject::readOLE(std::shared_ptr<WPSStream> stream, WPSEmbeddedObject &object, long endPos) |
140 | 14.0k | { |
141 | 14.0k | if (!stream) return false; |
142 | 14.0k | RVNGInputStreamPtr &input=stream->m_input; |
143 | 14.0k | libwps::DebugStream f; |
144 | | |
145 | 14.0k | if (endPos<=0) endPos=stream->m_eof; |
146 | 13.9k | else if (endPos>stream->m_eof) endPos=stream->m_eof; |
147 | | |
148 | 14.0k | long pos = input->tell(); |
149 | 14.0k | if (pos+24>endPos || libwps::read32(input)!=0x501) |
150 | 2.90k | { |
151 | 2.90k | WPS_DEBUG_MSG(("WPSOLEObject::readOLE: not a picture header\n")); |
152 | 2.90k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
153 | 2.90k | return false; |
154 | 2.90k | } |
155 | 11.1k | f.str(""); |
156 | 11.1k | f << "Entries(OLEObject):"; |
157 | 11.1k | auto type=int(readU32(input)); |
158 | 11.1k | f << "type=" << type << ","; |
159 | 11.1k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
160 | 11.1k | bool ok=false; |
161 | 11.1k | switch (type) |
162 | 11.1k | { |
163 | 0 | case 1: |
164 | 0 | WPS_DEBUG_MSG(("WPSOLEObject::readOLE: find a link ole\n")); |
165 | 0 | f << "link,"; |
166 | 0 | break; |
167 | 9.86k | case 2: |
168 | 9.86k | ok=readEmbeddedOLE(stream, object, endPos); |
169 | 9.86k | break; |
170 | 592 | case 3: |
171 | 782 | case 5: |
172 | 782 | ok=readStaticOLE(stream, object, endPos); |
173 | 782 | break; |
174 | 473 | default: |
175 | 473 | WPS_DEBUG_MSG(("WPSOLEObject::readOLE: find a unknown type\n")); |
176 | 473 | f << "unknown,"; |
177 | 473 | break; |
178 | 11.1k | } |
179 | 11.1k | if (!ok) |
180 | 10.3k | { |
181 | 10.3k | libwps::DebugFile &ascFile=stream->m_ascii; |
182 | 10.3k | f << "###"; |
183 | 10.3k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
184 | 10.3k | ascFile.addPos(pos); |
185 | 10.3k | ascFile.addNote(f.str().c_str()); |
186 | 10.3k | } |
187 | 11.1k | return true; |
188 | 11.1k | } |
189 | | |
190 | | bool WPSOLEObject::readEmbeddedOLE(std::shared_ptr<WPSStream> stream, WPSEmbeddedObject &object, long endPos) |
191 | 9.86k | { |
192 | 9.86k | if (!stream) return false; |
193 | 9.86k | RVNGInputStreamPtr &input=stream->m_input; |
194 | 9.86k | libwps::DebugFile &ascFile=stream->m_ascii; |
195 | 9.86k | libwps::DebugStream f; |
196 | | |
197 | 9.86k | long pos = input->tell(); |
198 | 9.86k | if (pos+24+4>endPos || libwps::readU32(input)!=0x501) |
199 | 262 | { |
200 | 262 | input->seek(pos, librevenge::RVNG_SEEK_SET); |
201 | 262 | return false; |
202 | 262 | } |
203 | 9.60k | auto type=int(libwps::readU32(input)); |
204 | 9.60k | if (type!=2) |
205 | 0 | { |
206 | 0 | input->seek(pos, librevenge::RVNG_SEEK_SET); |
207 | 0 | return false; |
208 | 0 | } |
209 | 9.60k | f << "Entries(OLEObject)[embedded]:"; |
210 | 9.60k | std::string names[3]; |
211 | 9.60k | for (auto &name : names) |
212 | 26.2k | { |
213 | 26.2k | if (!readString(stream, name, endPos) || input->tell()+4>endPos) |
214 | 2.28k | { |
215 | 2.28k | WPS_DEBUG_MSG(("WPSOLEObject::readEmbeddedOLE: can not read the name\n")); |
216 | 2.28k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
217 | 2.28k | return false; |
218 | 2.28k | } |
219 | 23.9k | if (name.empty()) continue; |
220 | 363 | f << name << ","; |
221 | 363 | } |
222 | | // find Paint.Picture, WangImage.Document |
223 | 7.32k | unsigned long dSz=libwps::readU32(input); |
224 | 7.32k | long actPos=input->tell(); |
225 | 7.32k | if (dSz>0x40000000 || dSz<10 || dSz>static_cast<unsigned long>(endPos-actPos)) |
226 | 6.77k | { |
227 | 6.77k | WPS_DEBUG_MSG(("WPSOLEObject::readOLE: pict size seems bad\n")); |
228 | 6.77k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
229 | 6.77k | return false; |
230 | 6.77k | } |
231 | | |
232 | 542 | bool ok=true; |
233 | 542 | if (names[0]=="METAFILEPICT") |
234 | 0 | ok=readMetafile(stream, object, actPos+long(dSz)); |
235 | 542 | else |
236 | 542 | { |
237 | 542 | librevenge::RVNGBinaryData data; |
238 | 542 | if (!libwps::readData(input, dSz, data)) |
239 | 0 | ok=false; |
240 | 542 | else |
241 | 542 | { |
242 | 542 | 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 | 542 | } |
251 | 542 | } |
252 | 542 | if (!ok) |
253 | 0 | { |
254 | 0 | WPS_DEBUG_MSG(("WPSOLEObject::readEmbeddedOLE: I can not find the picture\n")); |
255 | 0 | f << "###"; |
256 | 0 | } |
257 | 542 | input->seek(actPos+long(dSz), librevenge::RVNG_SEEK_SET); |
258 | 542 | ascFile.addPos(pos); |
259 | 542 | ascFile.addNote(f.str().c_str()); |
260 | 542 | if (input->tell()<endPos) // normally followed by a static OLE |
261 | 341 | readStaticOLE(stream, object, endPos); |
262 | 542 | return true; |
263 | 7.32k | } |
264 | | |
265 | | bool WPSOLEObject::readStaticOLE(std::shared_ptr<WPSStream> stream, WPSEmbeddedObject &object, long endPos) |
266 | 1.12k | { |
267 | 1.12k | if (!stream) return false; |
268 | 1.12k | RVNGInputStreamPtr &input=stream->m_input; |
269 | 1.12k | libwps::DebugFile &ascFile=stream->m_ascii; |
270 | 1.12k | libwps::DebugStream f; |
271 | | |
272 | 1.12k | long pos = input->tell(); |
273 | 1.12k | if (pos+24+4>endPos || libwps::readU32(input)!=0x501) |
274 | 307 | { |
275 | 307 | input->seek(pos, librevenge::RVNG_SEEK_SET); |
276 | 307 | return false; |
277 | 307 | } |
278 | 816 | auto type=int(libwps::readU32(input)); |
279 | 816 | if (type!=3 && type!=5) |
280 | 23 | { |
281 | 23 | input->seek(pos, librevenge::RVNG_SEEK_SET); |
282 | 23 | return false; |
283 | 23 | } |
284 | 793 | f << "Entries(OLEObject)[static]:"; |
285 | 793 | f << "type=" << type << ","; |
286 | 793 | std::string name; |
287 | 793 | if (!readString(stream, name, endPos) || input->tell()+12>endPos) |
288 | 249 | { |
289 | 249 | WPS_DEBUG_MSG(("WPSOLEObject::readStaticOLE: can not read the name\n")); |
290 | 249 | input->seek(pos, librevenge::RVNG_SEEK_SET); |
291 | 249 | return false; |
292 | 249 | } |
293 | | // find METAFILEPICT |
294 | 544 | f << name << ","; |
295 | 1.63k | for (int i=0; i<2; ++i) // g0+g1~0, some application id? |
296 | 1.08k | { |
297 | 1.08k | auto val=long(libwps::read32(input)); |
298 | 1.08k | if (val) f << "g" << i << "=" << val << ","; |
299 | 1.08k | } |
300 | 544 | unsigned long dSz=libwps::readU32(input); |
301 | 544 | long actPos=input->tell(); |
302 | 544 | if (dSz>0x40000000 || dSz<10 || dSz>static_cast<unsigned long>(endPos-actPos)) |
303 | 294 | { |
304 | 294 | WPS_DEBUG_MSG(("WPSOLEObject::readOLE: pict size seems bad\n")); |
305 | 294 | input->seek(pos, librevenge::RVNG_SEEK_SET); |
306 | 294 | return false; |
307 | 294 | } |
308 | | |
309 | 250 | bool ok=true; |
310 | 250 | if (name=="METAFILEPICT") |
311 | 41 | ok=readMetafile(stream, object, actPos+long(dSz)); |
312 | 209 | else |
313 | 209 | { |
314 | 209 | librevenge::RVNGBinaryData data; |
315 | 209 | if (!libwps::readData(input, dSz, data)) |
316 | 0 | ok=false; |
317 | 209 | else |
318 | 209 | { |
319 | 209 | 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 | 209 | } |
328 | 209 | } |
329 | 250 | if (!ok) |
330 | 2 | { |
331 | 2 | WPS_DEBUG_MSG(("WPSOLEObject::readStaticOLE: I can not find the picture\n")); |
332 | 2 | f << "###"; |
333 | 2 | } |
334 | 250 | input->seek(actPos+long(dSz), librevenge::RVNG_SEEK_SET); |
335 | 250 | ascFile.addPos(pos); |
336 | 250 | ascFile.addNote(f.str().c_str()); |
337 | 250 | return true; |
338 | 544 | } |
339 | | |
340 | | bool WPSOLEObject::readString(std::shared_ptr<WPSStream> stream, std::string &name, long endPos) |
341 | 27.0k | { |
342 | 27.0k | if (!stream) return false; |
343 | 27.0k | name=""; |
344 | 27.0k | RVNGInputStreamPtr &input=stream->m_input; |
345 | 27.0k | long pos=input->tell(); |
346 | 27.0k | if (pos+4>endPos) return false; |
347 | 27.0k | auto sSz=long(libwps::readU32(input)); |
348 | 27.0k | if (sSz<0 || sSz>endPos-pos-4) |
349 | 1.81k | { |
350 | 1.81k | WPS_DEBUG_MSG(("WPSOLEObject::readString: name size seems bad\n")); |
351 | 1.81k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
352 | 1.81k | return false; |
353 | 1.81k | } |
354 | 25.2k | if (sSz==0) return true; |
355 | 7.44k | for (long i=0; i+1<sSz; ++i) |
356 | 6.51k | { |
357 | 6.51k | auto c=char(libwps::readU8(input)); |
358 | 6.51k | if (c) |
359 | 6.13k | name+=c; |
360 | 381 | else |
361 | 381 | return false; |
362 | 6.51k | } |
363 | 926 | return libwps::readU8(input)==0; |
364 | 1.30k | } |
365 | | |
366 | | bool WPSOLEObject::checkIsWMF(std::shared_ptr<WPSStream> stream, long endPos) |
367 | 13.5k | { |
368 | 13.5k | RVNGInputStreamPtr &input=stream->m_input; |
369 | 13.5k | long pos=input->tell(); |
370 | 13.5k | if (pos+18>endPos) return false; |
371 | 8.23k | auto fType = int(libwps::read16(input)); |
372 | 8.23k | if ((fType!=1 && fType!=2) || libwps::read16(input)<9) |
373 | 2.32k | { |
374 | 2.32k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
375 | 2.32k | return false; |
376 | 2.32k | } |
377 | | // seek version |
378 | 5.90k | input->seek(2, librevenge::RVNG_SEEK_CUR); |
379 | 5.90k | auto fSize = long(libwps::read32(input)); // size in words |
380 | 5.90k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
381 | 5.90k | return (2*fSize>18 && 2*fSize<=endPos-pos); |
382 | 8.23k | } |
383 | | |
384 | | /* vim:set shiftwidth=4 softtabstop=4 noexpandtab: */ |