/src/libmwaw/src/lib/Canvas5Structure.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 <iomanip> |
35 | | #include <iostream> |
36 | | #include <set> |
37 | | #include <vector> |
38 | | |
39 | | #include "MWAWStringStream.hxx" |
40 | | #include "MWAWPictBitmap.hxx" |
41 | | |
42 | | #include "Canvas5Structure.hxx" |
43 | | |
44 | | namespace Canvas5Structure |
45 | | { |
46 | | |
47 | | std::string getString(unsigned val) |
48 | 0 | { |
49 | 0 | if (val<20) return std::to_string(val); |
50 | 0 | std::string res; |
51 | 0 | for (int dec=24; dec>=0; dec-=8) { |
52 | 0 | char c=char((val>>dec)&0xff); |
53 | 0 | if (!std::isprint(c)) |
54 | 0 | return std::to_string(val); |
55 | 0 | res+=c; |
56 | 0 | } |
57 | 0 | return res; |
58 | 0 | } |
59 | | |
60 | | bool readBitmap(Stream &stream, int version, MWAWEmbeddedObject &object, MWAWColor *avgColor) |
61 | 0 | { |
62 | 0 | object=MWAWEmbeddedObject(); |
63 | 0 | auto input=stream.input(); |
64 | 0 | long pos=input->tell(); |
65 | 0 | libmwaw::DebugStream f; |
66 | 0 | auto &ascFile=stream.ascii(); |
67 | 0 | f << "Entries(Bitmap):"; |
68 | 0 | int type0=int(input->readULong(4)); // found type0=5 in texture bw bitmap |
69 | 0 | if (type0!=6) f << "type0=" << type0 << ","; |
70 | 0 | if (!input->checkPosition(pos+64) || (type0!=5 && type0!=6)) { |
71 | 0 | MWAW_DEBUG_MSG(("Canvas5Structure::readBitmap: the zone beginning seems bad\n")); |
72 | 0 | f << "###"; |
73 | 0 | ascFile.addPos(pos); |
74 | 0 | ascFile.addNote(f.str().c_str()); |
75 | 0 | return false; |
76 | 0 | } |
77 | 0 | int type=int(input->readLong(2)); // 1-3 |
78 | 0 | switch (type) { |
79 | 0 | case 0: |
80 | 0 | f << "bw[indexed],"; // 1 bool by bytes |
81 | 0 | break; |
82 | 0 | case 1: |
83 | 0 | f << "bw[color],"; // 1 plane |
84 | 0 | break; |
85 | 0 | case 2: |
86 | 0 | f << "indexed,"; // 1 plane, color map |
87 | 0 | break; |
88 | 0 | case 3: |
89 | 0 | f << "color,"; // with 3 planes |
90 | 0 | break; |
91 | 0 | case 4: |
92 | 0 | f << "color4,"; // with 4 planes |
93 | 0 | break; |
94 | 0 | default: |
95 | 0 | f << "##type=" << type << ","; |
96 | 0 | MWAW_DEBUG_MSG(("Canvas5Structure::readBitmap: unexpected type\n")); |
97 | 0 | ascFile.addPos(pos); |
98 | 0 | ascFile.addNote(f.str().c_str()); |
99 | 0 | return false; |
100 | 0 | } |
101 | 0 | int numBytes=int(input->readLong(2)); // number of byte? |
102 | 0 | if (numBytes!=8) { |
103 | 0 | if (numBytes==1 && type==0) |
104 | 0 | f << "num[bytes]=1,"; |
105 | 0 | else { |
106 | 0 | MWAW_DEBUG_MSG(("Canvas5Structure::readBitmap: oops, find a number of bytes unexpected, unimplemented\n")); |
107 | 0 | f << "##num[bytes]=" << numBytes << ","; |
108 | 0 | } |
109 | 0 | } |
110 | 0 | int dim[2]; |
111 | 0 | for (auto &d : dim) d=int(input->readULong(4)); |
112 | 0 | MWAWVec2i dimension(dim[1], dim[0]); |
113 | 0 | f << "dim=" << dimension << ","; |
114 | 0 | int numPlanes=int(input->readLong(2)); // 1-4 |
115 | 0 | int val=int(input->readLong(2)); // val |
116 | 0 | if (numPlanes!=val) |
117 | 0 | f << "num[planes]=" << numPlanes << "x" << val << ","; |
118 | 0 | else if (numPlanes!=1) f << "f2=" << val << ","; |
119 | 0 | float fDim[2]; |
120 | 0 | for (auto &v : fDim) v=float(input->readULong(4))/65536.f; |
121 | 0 | if (MWAWVec2f(fDim[0],fDim[1])!=MWAWVec2f(72,72)) |
122 | 0 | f << "fDim=" << MWAWVec2f(fDim[0],fDim[1]) << ","; |
123 | 0 | for (int i=0; i<4; ++i) { // 0 |
124 | 0 | val=int(input->readLong(2)); |
125 | 0 | if (val) |
126 | 0 | f << "f" << i+3 << "=" << val << ","; |
127 | 0 | } |
128 | 0 | for (auto &d : dim) d=int(input->readULong(4)); |
129 | 0 | MWAWVec2i dim1(dim[1], dim[0]); |
130 | 0 | if (dimension!=dim1) |
131 | 0 | f << "dim1=" << dim1 << ","; |
132 | 0 | ascFile.addPos(pos); |
133 | 0 | ascFile.addNote(f.str().c_str()); |
134 | | |
135 | | // FIXME: find correctly the data, color positions |
136 | | // but only reconstruct correctly small bitmaps :-~ |
137 | 0 | std::shared_ptr<MWAWPictBitmapIndexed> bitmapIndexed; |
138 | 0 | std::shared_ptr<MWAWPictBitmapColor> bitmapColor; |
139 | 0 | switch (type) { |
140 | 0 | case 0: |
141 | 0 | case 2: |
142 | 0 | bitmapIndexed.reset(new MWAWPictBitmapIndexed(dimension)); |
143 | 0 | break; |
144 | 0 | case 1: |
145 | 0 | case 3: |
146 | 0 | case 4: |
147 | 0 | default: |
148 | 0 | bitmapColor.reset(new MWAWPictBitmapColor(dimension)); |
149 | 0 | break; |
150 | 0 | } |
151 | | |
152 | 0 | pos=input->tell(); |
153 | 0 | int const width=type==0 ? (dimension[0]+7)/8 : dimension[0]; |
154 | 0 | int const planeHeaderLength=(version<9 ? 20 : 40); |
155 | 0 | long dataLength=((type==3||type==4) ? numPlanes : 1)*(planeHeaderLength+width*dimension[1]); |
156 | 0 | if (width<=0 || dimension[1]<=0 || pos+dataLength<pos || !input->checkPosition(pos+dataLength)) { |
157 | 0 | MWAW_DEBUG_MSG(("Canvas5Structure::readBitmap: can not find the bitmap data\n")); |
158 | 0 | f << "###"; |
159 | 0 | ascFile.addPos(pos); |
160 | 0 | ascFile.addNote(f.str().c_str()); |
161 | 0 | return false; |
162 | 0 | } |
163 | | |
164 | 0 | long dataPos=pos; |
165 | | // first read the color map |
166 | 0 | input->seek(pos+dataLength, librevenge::RVNG_SEEK_SET); |
167 | 0 | pos=input->tell(); |
168 | 0 | long len=input->readLong(4); |
169 | 0 | if (pos+4+(len?4:0)+len<pos+4 || !input->checkPosition(pos+4+(len?4:0)+len)) { |
170 | 0 | MWAW_DEBUG_MSG(("Canvas5Structure::readBitmap: can not find the color block\n")); |
171 | 0 | ascFile.addPos(pos); |
172 | 0 | ascFile.addNote("Bitmap[color]:###"); |
173 | 0 | return false; |
174 | 0 | } |
175 | 0 | if (len==0) { |
176 | 0 | ascFile.addPos(pos); |
177 | 0 | ascFile.addNote("_"); |
178 | 0 | } |
179 | 0 | else { |
180 | 0 | input->seek(4, librevenge::RVNG_SEEK_CUR); |
181 | 0 | unsigned long numBytesRead; |
182 | 0 | auto *data=input->read(size_t(len), numBytesRead); |
183 | 0 | if (!data || long(numBytesRead)!=len) { |
184 | 0 | MWAW_DEBUG_MSG(("Canvas5Structure::readBitmap: can not find the color block\n")); |
185 | 0 | ascFile.addPos(pos); |
186 | 0 | ascFile.addNote("Bitmap[color]:###"); |
187 | 0 | return false; |
188 | 0 | } |
189 | 0 | size_t N=size_t(len/3); |
190 | 0 | std::vector<MWAWColor> colors(N); |
191 | 0 | for (size_t c=0; c<N; ++c) colors[c]=MWAWColor(data[c],data[c+N],data[c+2*N]); |
192 | 0 | if (type==2) |
193 | 0 | bitmapIndexed->setColors(colors); |
194 | 0 | ascFile.addPos(pos); |
195 | 0 | ascFile.addNote("Bitmap[color]:"); |
196 | 0 | ascFile.skipZone(pos+8, pos+8+len-1); |
197 | 0 | } |
198 | 0 | long endPos=input->tell(); |
199 | 0 | if (type==0) |
200 | 0 | bitmapIndexed->setColors({MWAWColor::black(), MWAWColor::white()}); |
201 | | // now read the bitmap data |
202 | 0 | input->seek(dataPos, librevenge::RVNG_SEEK_SET); |
203 | 0 | for (int plane=0; plane<((type==3||type==4) ? numPlanes : 1); ++plane) { |
204 | 0 | pos=input->tell(); |
205 | 0 | f.str(""); |
206 | 0 | f << "Bitmap-P" << plane << ":"; |
207 | 0 | for (int i=0; i<3; ++i) { |
208 | 0 | val=int(input->readLong(4)); |
209 | 0 | int const expected[]= {2 /* or 3*/,8,1}; |
210 | 0 | if (val==expected[i]) continue; |
211 | 0 | if (i==1) |
212 | 0 | f << "num[bytes]=" << val << ","; |
213 | 0 | else |
214 | 0 | f << "g" << i << "=" << val << ","; |
215 | 0 | } |
216 | 0 | for (auto &d : dim) d=int(input->readULong(4)); |
217 | 0 | dim1=MWAWVec2i(dim[1], dim[0]); |
218 | 0 | if (dimension!=dim1) |
219 | 0 | f << "dim2=" << dim1 << ","; |
220 | 0 | input->seek(pos+planeHeaderLength, librevenge::RVNG_SEEK_SET); |
221 | 0 | ascFile.addPos(pos); |
222 | 0 | ascFile.addNote(f.str().c_str()); |
223 | |
|
224 | 0 | if (type==0) { |
225 | | // checkme: is the picture decomposed by block if dim[0]>128*8 or dim[1]>128 ? |
226 | 0 | for (int y=0; y<dimension[1]; ++y) { |
227 | 0 | int x=0; |
228 | 0 | for (int w=0; w<width; ++w) { |
229 | 0 | val=int(input->readULong(1)); |
230 | 0 | for (int v=0, depl=0x80; v<8; ++v, depl>>=1) { |
231 | 0 | if (x>=dimension[0]) |
232 | 0 | break; |
233 | 0 | bitmapIndexed->set(x++,y, (val&depl) ? 0 : 1); |
234 | 0 | } |
235 | 0 | } |
236 | 0 | } |
237 | 0 | } |
238 | 0 | else { |
239 | 0 | for (int nY=0; nY<(dimension[1]+127)/128; ++nY) { |
240 | 0 | for (int nW=0; nW<(dimension[0]+127)/128; ++nW) { |
241 | 0 | for (int y=128*nY; y<std::min(dimension[1], 128*(nY+1)); ++y) { |
242 | 0 | for (int w=128*nW; w<std::min(dimension[0], 128*(nW+1)); ++w) { |
243 | 0 | unsigned char c=(unsigned char)input->readULong(1); |
244 | 0 | if (type==1) |
245 | 0 | bitmapColor->set(w,y, MWAWColor(c,c,c)); |
246 | 0 | else if (type==2) |
247 | 0 | bitmapIndexed->set(w,y,c); |
248 | 0 | else { |
249 | 0 | if (plane==0) |
250 | 0 | bitmapColor->set(w,y,MWAWColor(c,0,0)); |
251 | 0 | else { |
252 | 0 | int const decal=plane==3 ? 24 : (16-(8*plane)); |
253 | 0 | uint32_t finalValue=bitmapColor->get(w,y).value()|(uint32_t(c)<<decal); |
254 | 0 | bitmapColor->set(w,y,MWAWColor(finalValue)); |
255 | 0 | } |
256 | 0 | } |
257 | 0 | } |
258 | 0 | } |
259 | 0 | } |
260 | 0 | } |
261 | 0 | } |
262 | 0 | ascFile.skipZone(dataPos+20, dataPos+dataLength-1); |
263 | 0 | } |
264 | 0 | input->seek(endPos, librevenge::RVNG_SEEK_SET); |
265 | |
|
266 | 0 | bool ok=false; |
267 | 0 | if (type==0 || type==2) { |
268 | 0 | ok=bitmapIndexed->getBinary(object); |
269 | 0 | if (ok && avgColor) *avgColor=bitmapIndexed->getAverageColor(); |
270 | 0 | } |
271 | 0 | else if (type==1 || type==3 || type==4) { |
272 | 0 | ok=bitmapColor->getBinary(object); |
273 | 0 | if (ok && avgColor) *avgColor=bitmapColor->getAverageColor(); |
274 | 0 | } |
275 | | #ifdef DEBUG_WITH_FILES |
276 | | if (ok && !object.m_dataList.empty()) { |
277 | | std::stringstream s; |
278 | | static int index=0; |
279 | | s << "file" << ++index << ".png"; |
280 | | libmwaw::Debug::dumpFile(object.m_dataList[0], s.str().c_str()); |
281 | | } |
282 | | #endif |
283 | 0 | return ok && !object.m_dataList.empty(); |
284 | 0 | } |
285 | | |
286 | | bool readBitmapDAD58Bim(Stream &stream, int version, MWAWEmbeddedObject &object) |
287 | 0 | { |
288 | 0 | if (!readBitmap(stream, version, object)) |
289 | 0 | return false; |
290 | | |
291 | 0 | auto input=stream.input(); |
292 | 0 | long pos=input->tell(); |
293 | 0 | auto &ascFile=stream.ascii(); |
294 | | |
295 | | // DAD5 block |
296 | 0 | libmwaw::DebugStream f; |
297 | 0 | f << "Bitmap[DAD5]:"; |
298 | 0 | if (!input->checkPosition(pos+12)) { |
299 | 0 | MWAW_DEBUG_MSG(("Canvas5Structure::readBitmapDAD58Bim: can not find the DAD5 block\n")); |
300 | 0 | f << "###"; |
301 | 0 | ascFile.addPos(pos); |
302 | 0 | ascFile.addNote(f.str().c_str()); |
303 | 0 | return false; |
304 | 0 | } |
305 | 0 | int val=int(input->readLong(4)); |
306 | 0 | if (val!=1) // checkme: val=0 means probably no data |
307 | 0 | f << "f0=" << val << ","; |
308 | 0 | f << "len?=" << std::hex << input->readULong(4) << std::dec << ","; |
309 | 0 | int N=int(input->readULong(4)); // 1-3 |
310 | 0 | f << "N=" << N << ","; |
311 | 0 | if (N<0 || (input->size()-pos-12)/16<N || pos+12+16*N<pos+12 || !input->checkPosition(pos+12+16*N)) { |
312 | 0 | MWAW_DEBUG_MSG(("Canvas5Structure::readBitmapDAD58Bim[DAD5]: can not find the number of subblock\n")); |
313 | 0 | f << "###"; |
314 | 0 | ascFile.addPos(pos); |
315 | 0 | ascFile.addNote(f.str().c_str()); |
316 | 0 | return false; |
317 | 0 | } |
318 | 0 | ascFile.addPos(pos); |
319 | 0 | ascFile.addNote(f.str().c_str()); |
320 | |
|
321 | 0 | for (int j=0; j<N; ++j) { |
322 | 0 | pos=input->tell(); |
323 | 0 | f.str(""); |
324 | 0 | f << "Bitmap[DAD5-A" << j << "]:"; |
325 | 0 | if (!input->checkPosition(pos+16)) { |
326 | 0 | MWAW_DEBUG_MSG(("Canvas5Structure::readBitmapDAD58Bim[DAD5]: can not read subblock %d\n", j)); |
327 | 0 | f << "###"; |
328 | 0 | ascFile.addPos(pos); |
329 | 0 | ascFile.addNote(f.str().c_str()); |
330 | 0 | return false; |
331 | 0 | } |
332 | 0 | unsigned types[2]; |
333 | 0 | for (auto &t : types) t=unsigned(input->readULong(4)); |
334 | 0 | f << getString(types[0]) << ":" << getString(types[1]) << ","; |
335 | 0 | val=int(input->readLong(4)); |
336 | 0 | if (val!=1) f << "f0=" << val << ","; |
337 | 0 | long len=input->readLong(4); |
338 | 0 | if (len<0 || pos+16+len<pos+16 || !input->checkPosition(pos+16+len)) { |
339 | 0 | MWAW_DEBUG_MSG(("Canvas5Structure::readBitmapDAD58Bim[DAD5]: can not read subblock %d length\n", j)); |
340 | 0 | f << "###len=" << len << ","; |
341 | 0 | ascFile.addPos(pos); |
342 | 0 | ascFile.addNote(f.str().c_str()); |
343 | 0 | return false; |
344 | 0 | } |
345 | | // DAD5::VISM (size 8), DAD5::hack (size 8c) or DAD5::1 (size variable, ie end with a string) |
346 | 0 | if (types[0]==0x44414435) { |
347 | 0 | switch (types[1]) { |
348 | 0 | case 1: { |
349 | 0 | std::string name; |
350 | 0 | for (int k=0; k<len; ++k) { |
351 | 0 | char c=char(input->readULong(1)); |
352 | 0 | if (c==0) |
353 | 0 | break; |
354 | 0 | name+=c; |
355 | 0 | } |
356 | 0 | f << "path=" << name << ","; |
357 | 0 | break; |
358 | 0 | } |
359 | 0 | case 0x6861636b: { |
360 | 0 | if (len!=0x8c) { |
361 | 0 | MWAW_DEBUG_MSG(("Canvas5Structure::readBitmapDAD58Bim[DAD5,hack]: unexpected length\n")); |
362 | 0 | f << "###"; |
363 | 0 | break; |
364 | 0 | } |
365 | 0 | for (int k=0; k<2; ++k) { // 0 |
366 | 0 | val=int(input->readLong(4)); |
367 | 0 | if (val) |
368 | 0 | f << "f" << k+1 << "=" << val << ","; |
369 | 0 | } |
370 | 0 | int maxN=int(input->readLong(4)); |
371 | 0 | f << "maxN=" << maxN << ","; |
372 | 0 | f << "unkn=["; |
373 | 0 | for (int k=0; k<32; ++k) { // unsure where to stop |
374 | 0 | val=int(input->readLong(4)); |
375 | 0 | if (val<=0 || val>maxN) break; |
376 | 0 | f << val << ","; |
377 | 0 | } |
378 | 0 | f << "],"; |
379 | 0 | ascFile.addDelimiter(input->tell(),'|'); |
380 | 0 | break; |
381 | 0 | } |
382 | 0 | case 0x5649534d: // VISM |
383 | 0 | if (len!=8) { |
384 | 0 | MWAW_DEBUG_MSG(("Canvas5Structure::readBitmapDAD58Bim[DAD5,VISM]: unexpected length\n")); |
385 | 0 | f << "###"; |
386 | 0 | break; |
387 | 0 | } |
388 | 0 | val=int(input->readLong(4)); // 0-1 |
389 | 0 | if (val) |
390 | 0 | f << "f1=" << val << ","; |
391 | 0 | val=int(input->readLong(4)); |
392 | 0 | if (val!=-1) |
393 | 0 | f << "f2=" << val << ","; |
394 | 0 | break; |
395 | 0 | default: |
396 | 0 | MWAW_DEBUG_MSG(("Canvas5Structure::readBitmapDAD58Bim[DAD5]: unexpected type for sub zone\n")); |
397 | 0 | f << "###"; |
398 | 0 | break; |
399 | 0 | } |
400 | 0 | } |
401 | 0 | else { |
402 | 0 | MWAW_DEBUG_MSG(("Canvas5Structure::readBitmapDAD58Bim[DAD5]: find unknown type0 for subblock %d\n", j)); |
403 | 0 | f << "###"; |
404 | 0 | } |
405 | 0 | ascFile.addPos(pos); |
406 | 0 | ascFile.addNote(f.str().c_str()); |
407 | 0 | input->seek(pos+16+len, librevenge::RVNG_SEEK_SET); |
408 | 0 | } |
409 | | |
410 | | // last block: 8BIM |
411 | 0 | pos=input->tell(); |
412 | 0 | long len=input->readLong(4); |
413 | 0 | f.str(""); |
414 | 0 | f << "Bitmap[8bim]:"; |
415 | 0 | long endBimBlock=pos+4+len; |
416 | 0 | if (len<0 || endBimBlock<pos+4 || !input->checkPosition(endBimBlock)) { |
417 | 0 | MWAW_DEBUG_MSG(("Canvas5Structure::readBitmapDAD58Bim: can not read 8bim block\n")); |
418 | 0 | f << "###"; |
419 | 0 | ascFile.addPos(pos); |
420 | 0 | ascFile.addNote(f.str().c_str()); |
421 | 0 | return false; |
422 | 0 | } |
423 | 0 | ascFile.addPos(pos); |
424 | 0 | ascFile.addNote(f.str().c_str()); |
425 | 0 | while (input->tell()<endBimBlock) { |
426 | 0 | pos=input->tell(); |
427 | 0 | f.str(""); |
428 | 0 | f << "Bitmap[8bim]:"; |
429 | 0 | if (pos+12>endBimBlock) { |
430 | 0 | MWAW_DEBUG_MSG(("Canvas5Structure::readBitmapDAD58Bim: a 8bim block seems bad\n")); |
431 | 0 | f << "###"; |
432 | 0 | ascFile.addPos(pos); |
433 | 0 | ascFile.addNote(f.str().c_str()); |
434 | 0 | break; |
435 | 0 | } |
436 | 0 | unsigned type=unsigned(input->readULong(4)); |
437 | 0 | f << getString(type) << ","; // 8BIM |
438 | 0 | int id=int(input->readLong(2)); |
439 | 0 | f << "id=" << id << ","; |
440 | 0 | val=int(input->readLong(2)); |
441 | 0 | if (val) |
442 | 0 | f << "f0=" << val << ","; |
443 | 0 | len=input->readLong(4); |
444 | 0 | if (len<0 || pos+12+len>endBimBlock) { |
445 | 0 | MWAW_DEBUG_MSG(("Canvas5Structure::readBitmapDAD58Bim: a 8bim block len seems bad\n")); |
446 | 0 | f << "###"; |
447 | 0 | ascFile.addPos(pos); |
448 | 0 | ascFile.addNote(f.str().c_str()); |
449 | 0 | break; |
450 | 0 | } |
451 | 0 | switch (type) { |
452 | 0 | case 0x3842494d: |
453 | 0 | switch (id) { |
454 | 0 | case 1006: |
455 | 0 | if (len==0) |
456 | 0 | break; |
457 | 0 | else { |
458 | 0 | int sSz=int(input->readULong(1)); |
459 | 0 | if (1+sSz>len) { |
460 | 0 | MWAW_DEBUG_MSG(("Canvas5Structure::readBitmapDAD58Bim[8bim,1006]: can not find the string size\n")); |
461 | 0 | f << "###"; |
462 | 0 | break; |
463 | 0 | } |
464 | 0 | std::string name; |
465 | 0 | for (int k=0; k<sSz; ++k) { |
466 | 0 | char c=char(input->readULong(1)); |
467 | 0 | if (!c) |
468 | 0 | break; |
469 | 0 | name+=c; |
470 | 0 | } |
471 | 0 | f << name << ","; |
472 | 0 | } |
473 | 0 | break; |
474 | 0 | case 1007: { |
475 | 0 | if ((len%14)!=0) { |
476 | 0 | MWAW_DEBUG_MSG(("Canvas5Structure::readBitmapDAD58Bim[8bim,1007]: the size seems bad\n")); |
477 | 0 | f << "###"; |
478 | 0 | break; |
479 | 0 | } |
480 | 0 | int nUnkn=int(len/14); |
481 | 0 | f << "unkn=["; |
482 | 0 | for (int k=0; k<nUnkn; ++k) { |
483 | 0 | f << "["; |
484 | 0 | for (int l=0; l<7; ++l) { |
485 | 0 | val=int(input->readLong(2)); |
486 | 0 | int const expected[]= {0,0/* or 255*/,0,0,0,50 /* or 100 */, 0}; |
487 | 0 | if (val!=expected[l]) |
488 | 0 | f << "f" << l << "=" << val << ","; |
489 | 0 | } |
490 | 0 | f << "],"; |
491 | 0 | } |
492 | 0 | f << "],"; |
493 | 0 | break; |
494 | 0 | } |
495 | 0 | default: |
496 | 0 | MWAW_DEBUG_MSG(("Canvas5Structure::readBitmapDAD58Bim[8bim]: unknown id=%d\n", id)); |
497 | 0 | f << "###"; |
498 | 0 | break; |
499 | 0 | } |
500 | 0 | break; |
501 | 0 | default: |
502 | 0 | MWAW_DEBUG_MSG(("Canvas5Structure::readBitmapDAD58Bim[8bim]: unknown type=%s\n", getString(type).c_str())); |
503 | 0 | f << "###"; |
504 | 0 | } |
505 | 0 | if (input->tell()!=pos+12+len) |
506 | 0 | ascFile.addDelimiter(input->tell(),'|'); |
507 | 0 | input->seek(pos+12+len, librevenge::RVNG_SEEK_SET); |
508 | 0 | ascFile.addPos(pos); |
509 | 0 | ascFile.addNote(f.str().c_str()); |
510 | 0 | } |
511 | | |
512 | 0 | input->seek(endBimBlock, librevenge::RVNG_SEEK_SET); |
513 | |
|
514 | 0 | if (version<9) |
515 | 0 | return true; |
516 | | |
517 | 0 | if (input->isEnd()) // bitmap in cvi file ends here |
518 | 0 | return true; |
519 | | // last block: unknown |
520 | 0 | pos=input->tell(); |
521 | 0 | len=input->readLong(4); |
522 | 0 | f.str(""); |
523 | 0 | f << "Bitmap[unknown]:"; |
524 | 0 | long endUnknownBlock=pos+4+len; |
525 | 0 | if (len<0 || endUnknownBlock<pos+4 || !input->checkPosition(endUnknownBlock)) { |
526 | 0 | MWAW_DEBUG_MSG(("Canvas5Structure::readBitmapDAD58Bim: can not read unknown block\n")); |
527 | 0 | f << "###"; |
528 | 0 | ascFile.addPos(pos); |
529 | 0 | ascFile.addNote(f.str().c_str()); |
530 | 0 | return false; |
531 | 0 | } |
532 | 0 | if (len) { |
533 | 0 | MWAW_DEBUG_MSG(("Canvas5Structure::readBitmapDAD58Bim: find an unknown block\n")); |
534 | 0 | f << "###"; |
535 | 0 | ascFile.addPos(pos); |
536 | 0 | ascFile.addNote(f.str().c_str()); |
537 | 0 | input->seek(endUnknownBlock, librevenge::RVNG_SEEK_SET); |
538 | 0 | } |
539 | 0 | else { |
540 | 0 | ascFile.addPos(pos); |
541 | 0 | ascFile.addNote("_"); |
542 | 0 | } |
543 | 0 | return true; |
544 | 0 | } |
545 | | |
546 | | bool readPreview(Stream &stream, bool hasPreviewBitmap) |
547 | 0 | { |
548 | 0 | auto input=stream.input(); |
549 | 0 | if (!input) return false; |
550 | 0 | long pos=input->tell(); |
551 | 0 | if (!input->checkPosition(pos+12+(hasPreviewBitmap ? 12 : 0))) { |
552 | 0 | MWAW_DEBUG_MSG(("Canvas5Structure::readPreview: the zone is too short\n")); |
553 | 0 | return false; |
554 | 0 | } |
555 | 0 | libmwaw::DebugStream f; |
556 | 0 | auto &ascFile=stream.ascii(); |
557 | 0 | f << "Entries(Preview):"; |
558 | 0 | int dims[3]; |
559 | 0 | for (auto &d : dims) d=int(input->readLong(4)); |
560 | 0 | f << "dim=" << MWAWVec2i(dims[1], dims[0]) << "[" << dims[2] << "],"; |
561 | 0 | int width=hasPreviewBitmap ? int(input->readLong(4)) : 0; |
562 | 0 | if (width) f << "w=" << width << ","; |
563 | 0 | long endPos=pos+(hasPreviewBitmap ? 24 : 12)+long(width*dims[0]); |
564 | 0 | if (!hasPreviewBitmap || dims[0]<=0 || dims[1]<=0 || dims[2]!=3 || width<dims[1]*dims[2] || |
565 | 0 | endPos<=pos+24 || !input->checkPosition(endPos)) { |
566 | 0 | if (dims[0]==0 && dims[1]==0 && input->checkPosition(endPos)) { |
567 | 0 | ascFile.addPos(pos); |
568 | 0 | ascFile.addNote(f.str().c_str()); |
569 | 0 | input->seek(endPos, librevenge::RVNG_SEEK_SET); |
570 | 0 | ascFile.skipZone(input->tell(), endPos-1); |
571 | 0 | return true; |
572 | 0 | } |
573 | 0 | f << "###"; |
574 | 0 | MWAW_DEBUG_MSG(("Canvas5Structure::readPreview: the dimensions seems bad\n")); |
575 | 0 | ascFile.addPos(pos); |
576 | 0 | ascFile.addNote(f.str().c_str()); |
577 | 0 | return false; |
578 | 0 | } |
579 | 0 | for (int i=0; i<2; ++i) { |
580 | 0 | int val=int(input->readLong(4)); |
581 | 0 | int const expected[]= {3,1}; |
582 | 0 | if (val!=expected[i]) |
583 | 0 | f << "f" << i << "=" << val << ","; |
584 | 0 | } |
585 | 0 | ascFile.addPos(pos); |
586 | 0 | ascFile.addNote(f.str().c_str()); |
587 | |
|
588 | 0 | pos=input->tell(); |
589 | 0 | MWAWPictBitmapColor pict(MWAWVec2i(dims[1], dims[0]), dims[2]==4); |
590 | 0 | for (int y=0; y<dims[0]; ++y) { |
591 | 0 | long actPos=input->tell(); |
592 | 0 | unsigned char cols[4]= {0,0,0,0}; |
593 | 0 | for (int w=0; w<dims[1]; ++w) { |
594 | 0 | for (int c=0; c<dims[2]; ++c) cols[c]=(unsigned char)(input->readULong(1)); |
595 | 0 | if (dims[2]==4) |
596 | 0 | pict.set(w, y, MWAWColor(cols[1], cols[2], cols[3], (unsigned char)(255-cols[0]))); |
597 | 0 | else |
598 | 0 | pict.set(w, y, MWAWColor(cols[0], cols[1], cols[2])); |
599 | 0 | } |
600 | 0 | input->seek(actPos+width, librevenge::RVNG_SEEK_SET); |
601 | 0 | } |
602 | |
|
603 | 0 | input->seek(endPos, librevenge::RVNG_SEEK_SET); |
604 | 0 | ascFile.skipZone(pos, endPos-1); |
605 | | #ifdef DEBUG_WITH_FILES |
606 | | MWAWEmbeddedObject obj; |
607 | | if (pict.getBinary(obj) && !obj.m_dataList.empty()) |
608 | | libmwaw::Debug::dumpFile(obj.m_dataList[0], "file.png"); |
609 | | #endif |
610 | |
|
611 | 0 | return true; |
612 | 0 | } |
613 | | |
614 | | //////////////////////////////////////////////////////////// |
615 | | // decoder |
616 | | //////////////////////////////////////////////////////////// |
617 | | |
618 | | //! a basic Unpack decoder |
619 | | struct UnpackDecoder { |
620 | | //! constructor |
621 | | UnpackDecoder(unsigned char const *data, unsigned long len) |
622 | 268 | : m_data(data) |
623 | 268 | , m_len(len) |
624 | | |
625 | 268 | , m_pos(0) |
626 | 268 | { |
627 | 268 | } |
628 | | |
629 | | bool decode(unsigned long expectedLength, std::vector<unsigned char> &output) |
630 | 268 | { |
631 | 268 | output.clear(); |
632 | 268 | output.reserve(expectedLength > 0x8000 ? 0x8000 : expectedLength); |
633 | 41.7k | while (m_pos+2<=m_len) { |
634 | 41.5k | unsigned num=unsigned(m_data[m_pos++]); |
635 | 41.5k | unsigned char val=m_data[m_pos++]; |
636 | 41.5k | if (output.size()+num>expectedLength) |
637 | 68 | return false; |
638 | 3.05M | for (unsigned i=0; i<num; ++i) |
639 | 3.01M | output.push_back(val); |
640 | 41.5k | } |
641 | 200 | return output.size()==expectedLength; |
642 | 268 | } |
643 | | protected: |
644 | | |
645 | | unsigned char const *m_data; |
646 | | unsigned long m_len; |
647 | | mutable unsigned long m_pos; |
648 | | }; |
649 | | |
650 | | //! a basic NIB decoder |
651 | | struct NIBDecoder { |
652 | | //! constructor |
653 | | NIBDecoder(unsigned char const *data, unsigned long len) |
654 | 454 | : m_data(data) |
655 | 454 | , m_len(len) |
656 | | |
657 | 454 | , m_pos(0) |
658 | 454 | { |
659 | 454 | } |
660 | | |
661 | | bool decode(unsigned long expectedLength, std::vector<unsigned char> &output) |
662 | 454 | { |
663 | 454 | output.clear(); |
664 | 454 | output.reserve(expectedLength > 0x8000 ? 0x8000 : expectedLength); |
665 | 454 | unsigned char dict[30]; |
666 | 454 | std::set<unsigned char> dictKeys; |
667 | | |
668 | 454 | if (m_pos+30>m_len) { |
669 | 17 | MWAW_DEBUG_MSG(("Canvas5Structure::NIBDecoder::can not read a dictionary at pos=%lx\n", m_pos)); |
670 | 17 | return false; |
671 | 17 | } |
672 | 13.1k | for (auto &c : dict) c=m_data[m_pos++]; |
673 | 437 | dictKeys.clear(); |
674 | 13.1k | for (auto &c : dict) dictKeys.insert(c); |
675 | | |
676 | 437 | int newC=0; |
677 | 437 | bool readC=false; |
678 | 437 | unsigned char c; |
679 | 35.3k | while (m_pos<=m_len) { |
680 | 35.3k | bool ok=true; |
681 | 52.6k | for (int st=0; st<4; ++st) { |
682 | 49.2k | int val; |
683 | 49.2k | if (!readC) { |
684 | 24.6k | if (m_pos>m_len) { |
685 | 0 | ok=false; |
686 | 0 | break; |
687 | 0 | } |
688 | 24.6k | c=m_data[m_pos++]; |
689 | 24.6k | val=int(c>>4); |
690 | 24.6k | } |
691 | 24.5k | else |
692 | 24.5k | val=int(c&0xf); |
693 | 49.2k | readC=!readC; |
694 | | |
695 | 49.2k | if (val && st<2) { |
696 | 31.4k | output.push_back(dict[15*st+val-1]); |
697 | 31.4k | break; |
698 | 31.4k | } |
699 | 17.7k | newC=(newC<<4)|val; |
700 | 17.7k | if (st==3) { |
701 | 3.90k | if (dictKeys.find((unsigned char) newC)!=dictKeys.end()) { |
702 | 437 | ok=false; |
703 | 437 | break; |
704 | 437 | } |
705 | 3.47k | output.push_back((unsigned char) newC); |
706 | 3.47k | newC=0; |
707 | 3.47k | } |
708 | 17.7k | } |
709 | 35.3k | if (!ok) |
710 | 437 | break; |
711 | 34.9k | if (m_pos+1>=m_len && output.size()==expectedLength) |
712 | 0 | break; |
713 | 34.9k | } |
714 | 437 | return output.size()==expectedLength; |
715 | 454 | } |
716 | | protected: |
717 | | |
718 | | unsigned char const *m_data; |
719 | | unsigned long m_len; |
720 | | mutable unsigned long m_pos; |
721 | | }; |
722 | | |
723 | | /** a basic LWZ decoder |
724 | | |
725 | | \note this code is freely inspired from https://github.com/MichaelDipperstein/lzw GLP 3 |
726 | | */ |
727 | | struct LWZDecoder { |
728 | | static int const e_firstCode=(1<<8); |
729 | | static int const e_maxCodeLen=12; |
730 | | static int const e_maxCode=(1<<e_maxCodeLen); |
731 | | |
732 | | //! constructor |
733 | | LWZDecoder(unsigned char const *data, unsigned long len) |
734 | 243 | : m_data(data) |
735 | 243 | , m_len(len) |
736 | | |
737 | 243 | , m_pos(0) |
738 | 243 | , m_bit(0) |
739 | 243 | , m_dictionary() |
740 | 243 | { |
741 | 243 | initDictionary(); |
742 | 243 | } |
743 | | |
744 | | bool decode(std::vector<unsigned char> &output); |
745 | | |
746 | | protected: |
747 | | void initDictionary() |
748 | 399 | { |
749 | 399 | m_dictionary.resize(2); // 100 and 101 |
750 | 399 | m_dictionary.reserve(e_maxCode - e_firstCode); // max table 4000 |
751 | 399 | } |
752 | | |
753 | | unsigned getBit() const |
754 | 27.7k | { |
755 | 27.7k | if (m_pos>=m_len) |
756 | 29 | throw libmwaw::ParseException(); |
757 | 27.7k | unsigned val=(m_data[m_pos]>>(7-m_bit++))&1; |
758 | 27.7k | if (m_bit==8) { |
759 | 3.43k | ++m_pos; |
760 | 3.43k | m_bit=0; |
761 | 3.43k | } |
762 | 27.7k | return val; |
763 | 27.7k | } |
764 | | unsigned getCodeWord(unsigned codeLen) const |
765 | 6.95k | { |
766 | 6.95k | unsigned code=0; |
767 | 41.6k | for (unsigned i=0; i<codeLen;) { |
768 | 34.7k | if (m_bit==0 && (codeLen-i)>=8 && m_pos<m_len) { |
769 | 6.93k | code = (code<<8) | unsigned(m_data[m_pos++]); |
770 | 6.93k | i+=8; |
771 | 6.93k | continue; |
772 | 6.93k | } |
773 | 27.7k | code = (code<<1) | getBit(); |
774 | 27.7k | ++i; |
775 | 27.7k | } |
776 | 6.95k | return code; |
777 | 6.95k | } |
778 | | |
779 | | struct LWZEntry { |
780 | | //! constructor |
781 | | explicit LWZEntry(unsigned int prefixCode=0, unsigned char suffix=0) |
782 | 6.68k | : m_suffix(suffix) |
783 | 6.68k | , m_prefixCode(prefixCode) |
784 | 6.68k | { |
785 | 6.68k | } |
786 | | /** last char in encoded string */ |
787 | | unsigned char m_suffix; |
788 | | /** code for remaining chars in string */ |
789 | | unsigned int m_prefixCode; |
790 | | }; |
791 | | |
792 | | unsigned char decodeRec(unsigned int code, std::vector<unsigned char> &output) |
793 | 6.82k | { |
794 | 6.82k | unsigned char c; |
795 | 6.82k | unsigned char firstChar; |
796 | | |
797 | 6.82k | if (code >= e_firstCode) { |
798 | 168 | if (code-e_firstCode >= m_dictionary.size()) { |
799 | 101 | MWAW_DEBUG_MSG(("Canvas5Structure::LWZDecoder::decodeRec: bad id=%x/%x\n", code, unsigned(m_dictionary.size()))); |
800 | 101 | throw libmwaw::ParseException(); |
801 | 101 | } |
802 | | /* code word is string + c */ |
803 | 67 | c = m_dictionary[code - e_firstCode].m_suffix; |
804 | 67 | code = m_dictionary[code - e_firstCode].m_prefixCode; |
805 | | |
806 | | /* evaluate new code word for remaining string */ |
807 | 67 | firstChar = decodeRec(code, output); |
808 | 67 | } |
809 | 6.65k | else /* code word is just c */ |
810 | 6.65k | firstChar = c = (unsigned char)code; |
811 | | |
812 | 6.72k | output.push_back(c); |
813 | 6.72k | return firstChar; |
814 | 6.82k | } |
815 | | LWZDecoder(LWZDecoder const &)=delete; |
816 | | LWZDecoder &operator=(LWZDecoder const &)=delete; |
817 | | unsigned char const *m_data; |
818 | | unsigned long m_len; |
819 | | mutable unsigned long m_pos, m_bit; |
820 | | |
821 | | std::vector<LWZEntry> m_dictionary; |
822 | | }; |
823 | | |
824 | | bool LWZDecoder::decode(std::vector<unsigned char> &output) |
825 | 243 | try |
826 | 243 | { |
827 | 243 | output.reserve(0x8000); |
828 | | |
829 | 243 | unsigned int const currentCodeLen = 12; |
830 | 243 | unsigned lastCode=0; |
831 | 243 | unsigned char c=(unsigned char) 0; |
832 | 243 | bool first=true; |
833 | | |
834 | 7.08k | while (true) { |
835 | 6.95k | unsigned code=getCodeWord(currentCodeLen); |
836 | 6.95k | if (code==0x100) { |
837 | 156 | initDictionary(); |
838 | 156 | first=true; |
839 | 156 | continue; |
840 | 156 | } |
841 | 6.79k | if (code==0x101) // end of code |
842 | 12 | break; |
843 | 6.78k | if (code < e_firstCode+m_dictionary.size()) |
844 | | /* we have a known code. decode it */ |
845 | 6.40k | c = decodeRec(code, output); |
846 | 381 | else { |
847 | | /*************************************************************** |
848 | | * We got a code that's not in our dictionary. This must be due |
849 | | * to the string + char + string + char + string exception. |
850 | | * Build the decoded string using the last character + the |
851 | | * string from the last code. |
852 | | ***************************************************************/ |
853 | 381 | unsigned char tmp = c; |
854 | 381 | c = decodeRec(lastCode, output); |
855 | 381 | output.push_back(tmp); |
856 | 381 | } |
857 | | |
858 | | /* if room, add new code to the dictionary */ |
859 | 6.78k | if (!first && m_dictionary.size() < e_maxCode) { |
860 | 6.29k | if (lastCode>=e_firstCode+m_dictionary.size()) { |
861 | 101 | MWAW_DEBUG_MSG(("Canvas5Structure::LWZDecoder::decode: oops a loop with %x/%x\n", lastCode, unsigned(m_dictionary.size()))); |
862 | 101 | break; |
863 | 101 | } |
864 | 6.19k | m_dictionary.push_back(LWZEntry(lastCode, c)); |
865 | 6.19k | } |
866 | | |
867 | | /* save character and code for use in unknown code word case */ |
868 | 6.68k | lastCode = code; |
869 | 6.68k | first=false; |
870 | 6.68k | } |
871 | 243 | return true; |
872 | 243 | } |
873 | 243 | catch (...) |
874 | 243 | { |
875 | 130 | return false; |
876 | 130 | } |
877 | | |
878 | | |
879 | | bool decodeZone5(MWAWInputStreamPtr input, long endPos, int type, unsigned long finalLength, |
880 | | std::shared_ptr<MWAWStringStream> &stream) |
881 | 1.28k | { |
882 | 1.28k | if (type<0 || type>8) { |
883 | 0 | MWAW_DEBUG_MSG(("Canvas5Structure::decodeZone5: unknown type\n")); |
884 | 0 | return false; |
885 | 0 | } |
886 | 1.28k | std::vector<unsigned long> lengths; |
887 | 1.28k | lengths.push_back(finalLength); |
888 | | // checkme this code is only tested when type==0, 7, 8 |
889 | 1.28k | int const nExtraLength[]= { |
890 | 1.28k | 0, 0, 0, 0, 2, // _, _, Z, N, N+Z |
891 | 1.28k | 0, 0, 2, 3 // _, P, P+N, P+N+Z |
892 | 1.28k | }; |
893 | 1.28k | long pos=input->tell(); |
894 | 1.28k | if (pos+4*nExtraLength[type]>endPos) { |
895 | 11 | MWAW_DEBUG_MSG(("Canvas5Structure::decodeZone5: can not read the extra length\n")); |
896 | 11 | return false; |
897 | 11 | } |
898 | 1.26k | bool readInverted=input->readInverted(); |
899 | 1.26k | input->setReadInverted(false); |
900 | 1.64k | for (int n=0; n<nExtraLength[type]; ++n) |
901 | 374 | lengths.push_back(input->readULong(4)); |
902 | 1.26k | if (lengths.size()==1) |
903 | 1.09k | lengths.push_back((unsigned long)(endPos-pos)); |
904 | 1.26k | input->setReadInverted(readInverted); |
905 | | |
906 | 1.26k | auto l=lengths.back(); |
907 | 1.26k | lengths.pop_back(); |
908 | 1.29k | for (size_t i=lengths.size(); i>0 && l==0xFFFFFFFF; --i) l=lengths[i-1]; |
909 | | |
910 | 1.26k | pos=input->tell(); |
911 | 1.26k | unsigned long read; |
912 | 1.26k | unsigned char const *dt = l<=(unsigned long)(endPos-pos) ? input->read(l, read) : nullptr; |
913 | 1.26k | if (!dt || read != l) { |
914 | 97 | MWAW_DEBUG_MSG(("Canvas5Structure::decodeZone5: can not read some data\n")); |
915 | 97 | return false; |
916 | 97 | } |
917 | 1.17k | std::vector<unsigned char> data(dt, dt+l); |
918 | | |
919 | 1.17k | if (type==2 || type==4 || type==8) { // find with type==8 |
920 | 253 | l=lengths.back(); |
921 | 253 | lengths.pop_back(); |
922 | 257 | for (size_t i=lengths.size(); i>0 && l==0xFFFFFFFF; --i) l=lengths[i-1]; |
923 | 253 | if (l!=0xffffffff && l!=data.size()) { |
924 | 243 | Canvas5Structure::LWZDecoder decoder(data.data(), data.size()); |
925 | 243 | std::vector<unsigned char> data2; |
926 | 243 | if (!decoder.decode(data2) || data2.size()!=l) { |
927 | 243 | MWAW_DEBUG_MSG(("Canvas5Structure::decodeZone5[LWZ]: can not decode some data\n")); |
928 | 243 | return false; |
929 | 243 | } |
930 | 0 | std::swap(data, data2); |
931 | 0 | } |
932 | 253 | } |
933 | | |
934 | 929 | if (type==3 || type==4 || type==7 || type==8) { // find with type==7,8 |
935 | 466 | l=lengths.back(); |
936 | 466 | lengths.pop_back(); |
937 | 467 | for (size_t i=lengths.size(); i>0 && l==0xFFFFFFFF; --i) l=lengths[i-1]; |
938 | 466 | if (l!=0xffffffff && l!=data.size()) { |
939 | 454 | Canvas5Structure::NIBDecoder decoder(data.data(), data.size()); |
940 | 454 | std::vector<unsigned char> data2; |
941 | 454 | if (!decoder.decode(l, data2)) { |
942 | 452 | MWAW_DEBUG_MSG(("Canvas5Structure::decodeZone5[NIB]: can not decode some data\n")); |
943 | 452 | return false; |
944 | 452 | } |
945 | 2 | std::swap(data, data2); |
946 | 2 | } |
947 | 466 | } |
948 | | |
949 | 477 | if (type==6 || type==7 || type==8) { // find with type==7,8 |
950 | 276 | l=lengths.back(); |
951 | 276 | lengths.pop_back(); |
952 | 276 | for (size_t i=lengths.size(); i>0 && l==0xFFFFFFFF; --i) l=lengths[i-1]; |
953 | 276 | if (l!=0xffffffff && l!=data.size()) { |
954 | 268 | Canvas5Structure::UnpackDecoder decoder(data.data(), data.size()); |
955 | 268 | std::vector<unsigned char> data2; |
956 | 268 | if (!decoder.decode(l, data2)) { |
957 | 267 | MWAW_DEBUG_MSG(("Canvas5Structure::decodeZone5[pack]: can not decode some data\n")); |
958 | 267 | return false; |
959 | 267 | } |
960 | 1 | std::swap(data, data2); |
961 | 1 | } |
962 | 276 | } |
963 | | |
964 | 210 | if (data.size()!=finalLength) { |
965 | 62 | MWAW_DEBUG_MSG(("Canvas5Structure::decodeZone5[pack]: problem decoding data %lx/%lx\n", (unsigned long)data.size(), finalLength)); |
966 | 62 | return false; |
967 | 62 | } |
968 | | |
969 | 148 | stream->append(data.data(), unsigned(data.size())); |
970 | | |
971 | 148 | if (input->tell()!=endPos) { |
972 | 0 | MWAW_DEBUG_MSG(("Canvas5Structure::decodeZone5: find extra data\n")); |
973 | 0 | input->seek(endPos, librevenge::RVNG_SEEK_SET); |
974 | 0 | } |
975 | 148 | return true; |
976 | 210 | } |
977 | | |
978 | | } |
979 | | // vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: |
980 | | |