/src/libmwaw/src/lib/PixelPaintParser.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 <limits> |
37 | | #include <set> |
38 | | #include <sstream> |
39 | | |
40 | | #include <librevenge/librevenge.h> |
41 | | |
42 | | #include "MWAWGraphicListener.hxx" |
43 | | #include "MWAWHeader.hxx" |
44 | | #include "MWAWPictBitmap.hxx" |
45 | | #include "MWAWPictData.hxx" |
46 | | #include "MWAWPosition.hxx" |
47 | | |
48 | | #include "PixelPaintParser.hxx" |
49 | | |
50 | | /** Internal: the structures of a PixelPaintParser */ |
51 | | namespace PixelPaintParserInternal |
52 | | { |
53 | | //////////////////////////////////////// |
54 | | //! Internal: the state of a PixelPaintParser |
55 | | struct State { |
56 | | //! constructor |
57 | | State() |
58 | 29.8k | : m_bitmapSize(0,0) |
59 | 29.8k | , m_colorList() |
60 | 29.8k | , m_bitmap() |
61 | 29.8k | { |
62 | 29.8k | } |
63 | | //! the bitmap size(v1) |
64 | | MWAWVec2i m_bitmapSize; |
65 | | //! the color map |
66 | | std::vector<MWAWColor> m_colorList; |
67 | | /// the bitmap |
68 | | std::shared_ptr<MWAWPict> m_bitmap; |
69 | | }; |
70 | | |
71 | | } |
72 | | |
73 | | //////////////////////////////////////////////////////////// |
74 | | // constructor/destructor, ... |
75 | | //////////////////////////////////////////////////////////// |
76 | | PixelPaintParser::PixelPaintParser(MWAWInputStreamPtr const &input, MWAWRSRCParserPtr const &rsrcParser, MWAWHeader *header) |
77 | 14.3k | : MWAWGraphicParser(input, rsrcParser, header) |
78 | 14.3k | , m_state() |
79 | 14.3k | { |
80 | 14.3k | init(); |
81 | 14.3k | } |
82 | | |
83 | | PixelPaintParser::~PixelPaintParser() |
84 | 14.3k | { |
85 | 14.3k | } |
86 | | |
87 | | void PixelPaintParser::init() |
88 | 14.3k | { |
89 | 14.3k | resetGraphicListener(); |
90 | 14.3k | setAsciiName("main-1"); |
91 | | |
92 | 14.3k | m_state.reset(new PixelPaintParserInternal::State); |
93 | | |
94 | 14.3k | getPageSpan().setMargins(0.1); |
95 | 14.3k | } |
96 | | |
97 | | //////////////////////////////////////////////////////////// |
98 | | // the parser |
99 | | //////////////////////////////////////////////////////////// |
100 | | void PixelPaintParser::parse(librevenge::RVNGDrawingInterface *docInterface) |
101 | 1.19k | { |
102 | 1.19k | if (!getInput().get() || !checkHeader(nullptr)) throw(libmwaw::ParseException()); |
103 | 1.19k | bool ok = false; |
104 | 1.19k | try { |
105 | | // create the asciiFile |
106 | 1.19k | ascii().setStream(getInput()); |
107 | 1.19k | ascii().open(asciiName()); |
108 | 1.19k | checkHeader(nullptr); |
109 | 1.19k | ok = createZones(); |
110 | 1.19k | if (ok) { |
111 | 179 | createDocument(docInterface); |
112 | 179 | sendBitmap(); |
113 | 179 | } |
114 | 1.19k | ascii().reset(); |
115 | 1.19k | } |
116 | 1.19k | catch (...) { |
117 | 0 | MWAW_DEBUG_MSG(("PixelPaintParser::parse: exception catched when parsing\n")); |
118 | 0 | ok = false; |
119 | 0 | } |
120 | | |
121 | 1.19k | resetGraphicListener(); |
122 | 1.19k | if (!ok) throw(libmwaw::ParseException()); |
123 | 1.19k | } |
124 | | |
125 | | //////////////////////////////////////////////////////////// |
126 | | // create the document |
127 | | //////////////////////////////////////////////////////////// |
128 | | void PixelPaintParser::createDocument(librevenge::RVNGDrawingInterface *documentInterface) |
129 | 179 | { |
130 | 179 | if (!documentInterface) return; |
131 | 179 | if (getGraphicListener()) { |
132 | 0 | MWAW_DEBUG_MSG(("PixelPaintParser::createDocument: listener already exist\n")); |
133 | 0 | return; |
134 | 0 | } |
135 | | |
136 | | // create the page list |
137 | 179 | MWAWPageSpan ps(getPageSpan()); |
138 | 179 | ps.setPageSpan(1); |
139 | 179 | std::vector<MWAWPageSpan> pageList(1,ps); |
140 | 179 | MWAWGraphicListenerPtr listen(new MWAWGraphicListener(*getParserState(), pageList, documentInterface)); |
141 | 179 | setGraphicListener(listen); |
142 | 179 | listen->startDocument(); |
143 | 179 | } |
144 | | |
145 | | |
146 | | //////////////////////////////////////////////////////////// |
147 | | // |
148 | | // Intermediate level |
149 | | // |
150 | | //////////////////////////////////////////////////////////// |
151 | | bool PixelPaintParser::createZones() |
152 | 1.19k | { |
153 | 1.19k | MWAWInputStreamPtr input = getInput(); |
154 | 1.19k | int const vers=version(); |
155 | 1.19k | if (input->size()<512) return false; |
156 | 1.19k | libmwaw::DebugStream f; |
157 | 1.19k | f << "FileHeader:"; |
158 | 1.19k | input->seek(0, librevenge::RVNG_SEEK_SET); // seek file def |
159 | 1.19k | ascii().addPos(0); |
160 | 1.19k | ascii().addNote(f.str().c_str()); |
161 | | |
162 | 1.19k | long pos; |
163 | 1.19k | if ((vers<=1&&!readFileHeaderV1()) || (vers>=2&&!readFileHeaderV2())) |
164 | 0 | return false; |
165 | | |
166 | 1.19k | pos=input->tell(); |
167 | 1.19k | if (!readColorMap()) { |
168 | 0 | ascii().addPos(pos); |
169 | 0 | ascii().addNote("Entries(ColorMap):###"); |
170 | 0 | return false; |
171 | 0 | } |
172 | | |
173 | 1.19k | pos=input->tell(); |
174 | 1.19k | if (!readPatternMap()) { |
175 | 0 | ascii().addPos(pos); |
176 | 0 | ascii().addNote("Entries(PatternMap):###"); |
177 | 0 | return false; |
178 | 0 | } |
179 | 1.19k | if ((vers==1 && !readBitmapV1()) || (vers==2 && !readBitmapV2())) |
180 | 1.01k | return false; |
181 | 179 | if (!input->isEnd()) { |
182 | 169 | if (!input->checkPosition(input->tell()+8)) { |
183 | 23 | ascii().addPos(input->tell()); |
184 | 23 | ascii().addNote("Entries(Unused):"); |
185 | 23 | } |
186 | 146 | else { |
187 | 146 | MWAW_DEBUG_MSG(("PixelPaintParser::createZones: find some extra data\n")); |
188 | 146 | ascii().addPos(input->tell()); |
189 | 146 | ascii().addNote("Entries(Unused):###"); |
190 | 146 | } |
191 | 169 | } |
192 | 179 | return m_state->m_bitmap.get()!=nullptr; |
193 | 1.19k | } |
194 | | |
195 | | bool PixelPaintParser::readFileHeaderV1(bool onlyCheck) |
196 | 4.68k | { |
197 | 4.68k | MWAWInputStreamPtr input = getInput(); |
198 | 4.68k | if (!input->checkPosition(0x426)) { |
199 | 102 | MWAW_DEBUG_MSG(("PixelPaintParser::readFileHeaderV1: file is too short\n")); |
200 | 102 | return false; |
201 | 102 | } |
202 | 4.58k | libmwaw::DebugStream f; |
203 | 4.58k | f << "Entries(Zone0):"; |
204 | 4.58k | input->seek(4, librevenge::RVNG_SEEK_SET); // seek file def |
205 | 4.58k | long pos=4; |
206 | 664k | for (int i=0; i<144; ++i) { // always 0 |
207 | 659k | auto val=static_cast<int>(input->readULong(2)); |
208 | 659k | if (val) f << "f" << i << "=" << val << ","; |
209 | 659k | } |
210 | 4.58k | if (!onlyCheck) { |
211 | 518 | ascii().addPos(pos); |
212 | 518 | ascii().addNote(f.str().c_str()); |
213 | 518 | } |
214 | | |
215 | 8.72k | for (int z=0; z<8; ++z) { |
216 | 8.20k | pos=input->tell(); |
217 | 8.20k | f.str(""); |
218 | 8.20k | f << "Zone0-A" << z << ":"; |
219 | 8.20k | int val; |
220 | 8.20k | val=static_cast<int>(input->readULong(2)); |
221 | 8.20k | if (onlyCheck && z==0 && (val<1 || val>4)) return false; |
222 | 7.94k | switch (val) { |
223 | 1.49k | case 0: |
224 | 1.49k | break; |
225 | 1.85k | case 1: |
226 | 1.85k | f << "image=512x512,"; |
227 | 1.85k | if (z==0) |
228 | 1.69k | m_state->m_bitmapSize=MWAWVec2i(512,512); |
229 | 1.85k | break; |
230 | 1.41k | case 2: |
231 | 1.41k | f << "image=720x576,"; |
232 | 1.41k | if (z==0) |
233 | 1.31k | m_state->m_bitmapSize=MWAWVec2i(720,576); |
234 | 1.41k | break; |
235 | 972 | case 3: |
236 | 972 | f << "image=1024x768,"; |
237 | 972 | if (z==0) |
238 | 886 | m_state->m_bitmapSize=MWAWVec2i(1024,768); |
239 | 972 | break; |
240 | 445 | case 4: |
241 | 445 | f << "image=1024x1024,"; |
242 | 445 | if (z==0) |
243 | 422 | m_state->m_bitmapSize=MWAWVec2i(1024,1024); |
244 | 445 | break; |
245 | 1.75k | default: |
246 | 1.75k | MWAW_DEBUG_MSG(("PixelPaintParser::readFileHeaderV1: unknown image size\n")); |
247 | 1.75k | f << "###image=" << val << ","; |
248 | 1.75k | break; |
249 | 7.94k | } |
250 | 39.7k | for (int i=0; i<4; ++i) { |
251 | 31.7k | val=static_cast<int>(input->readULong(2)); |
252 | 31.7k | if (val) |
253 | 17.3k | f << "f" << i << "=" << val << ","; |
254 | 31.7k | } |
255 | 7.94k | val=static_cast<int>(input->readULong(2)); |
256 | 7.94k | if (val!=5) // always 5 |
257 | 6.38k | f << "f5=" << val << ","; |
258 | 7.94k | int dim[4]; |
259 | 31.7k | for (auto &d : dim) d=static_cast<int>(input->readULong(2)); |
260 | 7.94k | if (dim[0]||dim[1]||dim[2]||dim[3]) |
261 | 6.37k | f << "windows[dim]=" << MWAWBox2i(MWAWVec2i(dim[1],dim[0]), MWAWVec2i(dim[3],dim[2])) << ","; |
262 | 7.94k | val=static_cast<int>(input->readULong(2)); |
263 | 7.94k | if (val) // always 0 |
264 | 3.61k | f << "f6=" << val << ","; |
265 | 31.7k | for (auto &d : dim) d=static_cast<int>(input->readULong(2)); |
266 | 7.94k | if (dim[0]||dim[1]||dim[2]||dim[3]) |
267 | 6.31k | f << "screen1[dim]=" << MWAWBox2i(MWAWVec2i(dim[1],dim[0]), MWAWVec2i(dim[3],dim[2])) << ","; |
268 | 71.4k | for (int i=0; i<8; ++i) { // always 0 |
269 | 63.5k | val=static_cast<int>(input->readULong(2)); |
270 | 63.5k | if (val) |
271 | 31.1k | f << "f" << i+7 << "=" << val << ","; |
272 | 63.5k | } |
273 | 31.7k | for (auto &d : dim) d=static_cast<int>(input->readULong(2)); |
274 | 7.94k | if (dim[0]||dim[1]||dim[2]||dim[3]) |
275 | 6.01k | f << "screen1[sz]=" << MWAWBox2i(MWAWVec2i(dim[1],dim[0]), MWAWVec2i(dim[3],dim[2])) << ","; |
276 | 23.8k | for (int i=0; i<2; ++i) { // f15=1|8, f16=0|69 |
277 | 15.8k | val=static_cast<int>(input->readULong(2)); |
278 | 15.8k | if (val) |
279 | 9.70k | f << "f" << i+15 << "=" << val << ","; |
280 | 15.8k | } |
281 | 23.8k | for (int i=0; i<2; ++i) dim[i]=static_cast<int>(input->readULong(2)); |
282 | 7.94k | if (dim[0]||dim[1]) f << "width=[" << dim[0] << "," << dim[1] << "],"; |
283 | 39.7k | for (int i=0; i<4; ++i) { // g2=1|3 |
284 | 31.7k | val=static_cast<int>(input->readULong(2)); |
285 | 31.7k | if (val) |
286 | 16.4k | f << "g" << i << "=" << val << ","; |
287 | 31.7k | } |
288 | 31.7k | for (int i=0; i<3; ++i) { |
289 | 23.8k | val=static_cast<int>(input->readULong(4)); |
290 | 23.8k | if (val) |
291 | 17.0k | f << "ID" << i << "=" << std::hex << val << std::dec << ","; |
292 | 23.8k | } |
293 | 7.94k | val=static_cast<int>(input->readULong(2)); // always 0? |
294 | 7.94k | if (val) f << "g2=" << val << ","; |
295 | 31.7k | for (auto &d : dim) d=static_cast<int>(input->readULong(2)); |
296 | 7.94k | if (dim[0]||dim[1]||dim[2]||dim[3]) |
297 | 6.17k | f << "screen2[dim]=" << MWAWBox2i(MWAWVec2i(dim[1],dim[0]), MWAWVec2i(dim[3],dim[2])) << ","; |
298 | 7.94k | if (onlyCheck) { |
299 | 3.79k | input->seek(0x426, librevenge::RVNG_SEEK_SET); |
300 | 3.79k | return true; |
301 | 3.79k | } |
302 | 4.14k | ascii().addPos(pos); |
303 | 4.14k | ascii().addNote(f.str().c_str()); |
304 | 4.14k | input->seek(pos+92, librevenge::RVNG_SEEK_SET); |
305 | 4.14k | } |
306 | 518 | pos=input->tell(); |
307 | 518 | f.str(""); |
308 | 518 | f << "Zone0-Prefs:"; |
309 | 518 | int val; |
310 | 3.10k | for (int i=0; i<5; ++i) { // always 0? |
311 | 2.59k | val=static_cast<int>(input->readULong(2)); |
312 | 2.59k | if (val) |
313 | 1.31k | f << "f" << i << "=" << val << ","; |
314 | 2.59k | } |
315 | 3.62k | for (int i=0; i<6; ++i) { |
316 | 3.10k | val=static_cast<int>(input->readULong(2)); |
317 | 3.10k | static int const expected[]= {1, 0x28, 0xaa, 3, 0xff, 9}; |
318 | 3.10k | if (val==expected[i]) continue; |
319 | 2.66k | if (i==4) |
320 | 513 | f << "font[sz]=" << val << ","; |
321 | 2.15k | else |
322 | 2.15k | f << "f" << i+5 << "=" << val << ","; |
323 | | |
324 | 2.66k | } |
325 | 3.62k | for (int i=0; i<6; ++i) { |
326 | 3.10k | val=static_cast<int>(input->readULong(1)); |
327 | 3.10k | if (!val) continue; |
328 | 1.45k | static char const* const wh[]= {"setForAllTools", "noFullScreen[zoom]","fl2","autoscroll[fatbits]","center[createObject]","remap[color]"}; |
329 | 1.45k | f << wh[i]; |
330 | 1.45k | if (val!=1) |
331 | 1.12k | f << "=" << val; |
332 | 1.45k | f << ","; |
333 | 1.45k | } |
334 | 518 | val=static_cast<int>(input->readLong(2)); |
335 | 518 | if (val<0) { |
336 | 159 | f << "option[first]=invertPattern,"; |
337 | 159 | val*=-1; |
338 | 159 | } |
339 | 518 | switch (val) { |
340 | 24 | case 1: |
341 | 24 | break; |
342 | 6 | case 2: |
343 | 6 | f << "option[effect]=transp,"; |
344 | 6 | break; |
345 | 7 | case 3: |
346 | 7 | f << "option[effect]=invert,"; |
347 | 7 | break; |
348 | 78 | case 4: |
349 | 78 | f << "option[effect]=erase,"; |
350 | 78 | break; |
351 | 403 | default: |
352 | 403 | f << "###option[effect]=" << val << ","; |
353 | 403 | break; |
354 | 518 | } |
355 | 518 | val=static_cast<int>(input->readLong(2)); // numColors? |
356 | 518 | if (val!=0x100) f << "g0=" << val << ","; |
357 | 518 | val=static_cast<int>(input->readLong(2)); |
358 | 518 | if (val!=0x80) f << "g1=" << val << ","; |
359 | 518 | ascii().addPos(pos); |
360 | 518 | ascii().addNote(f.str().c_str()); |
361 | 518 | input->seek(0x426, librevenge::RVNG_SEEK_SET); |
362 | 518 | return true; |
363 | 518 | } |
364 | | |
365 | | bool PixelPaintParser::readFileHeaderV2(bool onlyCheck) |
366 | 6.01k | { |
367 | 6.01k | MWAWInputStreamPtr input = getInput(); |
368 | 6.01k | if (!input->checkPosition(58)) { |
369 | 0 | MWAW_DEBUG_MSG(("PixelPaintParser::readFileHeaderV2: file is too short\n")); |
370 | 0 | return false; |
371 | 0 | } |
372 | 6.01k | input->seek(4, librevenge::RVNG_SEEK_SET); // seek file def |
373 | 6.01k | libmwaw::DebugStream f; |
374 | 6.01k | f << "Entries(Zone0):"; |
375 | 6.01k | long pos=4; |
376 | 6.01k | int val; |
377 | 18.0k | for (int i=0; i<2; ++i) { |
378 | 12.0k | val=static_cast<int>(input->readULong(2)); |
379 | 12.0k | if (val) |
380 | 7.73k | f << "f" << i << "=" << val << ","; |
381 | 12.0k | } |
382 | 6.01k | int dim[2]; |
383 | 12.0k | for (auto &d : dim) d=static_cast<int>(input->readULong(2)); |
384 | 6.01k | if (dim[0]<=0||dim[0]>1024 || dim[1]<=0 || dim[1]>1024) |
385 | 1.59k | return false; |
386 | 4.42k | if (onlyCheck) { |
387 | 3.74k | input->seek(58, librevenge::RVNG_SEEK_SET); |
388 | 3.74k | return true; |
389 | 3.74k | } |
390 | 679 | m_state->m_bitmapSize=MWAWVec2i(dim[1], dim[0]); |
391 | 679 | f << "sz=" << m_state->m_bitmapSize << ","; |
392 | 4.07k | for (int i=0; i<5; ++i) { |
393 | 3.39k | val=static_cast<int>(input->readULong(2)); |
394 | 3.39k | static int const expected[]= {8, 0, 0, 0, 0xff }; |
395 | 3.39k | if (val==expected[i]) continue; |
396 | 3.15k | if (i==0) // checkme |
397 | 650 | f << "font[sz]=" << val << ","; |
398 | 2.50k | else |
399 | 2.50k | f << "f" << i << "=" << val << ","; |
400 | 3.15k | } |
401 | 12.9k | for (int i=0; i<18; ++i) { // g9=256 : numColor? |
402 | 12.2k | val=static_cast<int>(input->readULong(2)); |
403 | 12.2k | if (val) |
404 | 9.89k | f << "g" << i << "=" << val << ","; |
405 | 12.2k | } |
406 | 679 | input->seek(58, librevenge::RVNG_SEEK_SET); |
407 | 679 | ascii().addPos(pos); |
408 | 679 | ascii().addNote(f.str().c_str()); |
409 | 679 | return true; |
410 | 4.42k | } |
411 | | |
412 | | bool PixelPaintParser::readColorMap(bool onlyCheck) |
413 | 8.73k | { |
414 | 8.73k | MWAWInputStreamPtr input = getInput(); |
415 | 8.73k | long pos=input->tell(); |
416 | 8.73k | if (!input->checkPosition(pos+2048)) { |
417 | 435 | MWAW_DEBUG_MSG(("PixelPaintParser::readColorMap: file is too short\n")); |
418 | 435 | return false; |
419 | 435 | } |
420 | 8.30k | if (onlyCheck) { |
421 | 7.10k | input->seek(pos+2048, librevenge::RVNG_SEEK_SET); |
422 | 7.10k | return true; |
423 | 7.10k | } |
424 | 1.19k | libmwaw::DebugStream f; |
425 | 1.19k | f << "Entries(ColorMap):"; |
426 | 1.19k | m_state->m_colorList.resize(256); |
427 | 306k | for (auto &color : m_state->m_colorList) { |
428 | 306k | unsigned char c[4]; |
429 | 1.22M | for (auto &col : c) col=static_cast<unsigned char>(input->readULong(2)>>8); |
430 | 306k | color=MWAWColor(c[1],c[2],c[3],static_cast<unsigned char>(255-c[0])); |
431 | 306k | f << color << ","; |
432 | 306k | } |
433 | 1.19k | ascii().addPos(pos); |
434 | 1.19k | ascii().addNote(f.str().c_str()); |
435 | 1.19k | return true; |
436 | 8.30k | } |
437 | | |
438 | | bool PixelPaintParser::readPatternMap(bool onlyCheck) |
439 | 8.30k | { |
440 | 8.30k | MWAWInputStreamPtr input = getInput(); |
441 | 8.30k | long pos=input->tell(); |
442 | 8.30k | if (!input->checkPosition(pos+144*8)) { |
443 | 137 | MWAW_DEBUG_MSG(("PixelPaintParser::readPatternMap: file is too short\n")); |
444 | 137 | return false; |
445 | 137 | } |
446 | 8.16k | if (onlyCheck) { |
447 | 6.96k | input->seek(pos+144*8, librevenge::RVNG_SEEK_SET); |
448 | 6.96k | return true; |
449 | 6.96k | } |
450 | 1.19k | libmwaw::DebugStream f; |
451 | 1.19k | f << "Entries(PatternMap):"; |
452 | 1.19k | ascii().addPos(pos); |
453 | 1.19k | ascii().addNote(f.str().c_str()); |
454 | 173k | for (int i=0; i<144; ++i) { |
455 | 172k | pos=input->tell(); |
456 | 172k | f.str(""); |
457 | 172k | f << "PatternMap-" << i << ":"; |
458 | 172k | input->seek(pos+8, librevenge::RVNG_SEEK_SET); |
459 | 172k | ascii().addPos(pos); |
460 | 172k | ascii().addNote(f.str().c_str()); |
461 | 172k | } |
462 | 1.19k | return true; |
463 | 8.16k | } |
464 | | |
465 | | |
466 | | //////////////////////////////////////////////////////////// |
467 | | // send data |
468 | | //////////////////////////////////////////////////////////// |
469 | | bool PixelPaintParser::sendBitmap() |
470 | 179 | { |
471 | 179 | MWAWGraphicListenerPtr listener=getGraphicListener(); |
472 | 179 | if (!listener) { |
473 | 0 | MWAW_DEBUG_MSG(("PixelPaintParser::sendBitmap: can not find the listener\n")); |
474 | 0 | return false; |
475 | 0 | } |
476 | | |
477 | 179 | MWAWEmbeddedObject picture; |
478 | 179 | if (!m_state->m_bitmap || !m_state->m_bitmap->getBinary(picture)) return false; |
479 | | |
480 | 179 | MWAWPageSpan const &page=getPageSpan(); |
481 | 179 | MWAWPosition pos(MWAWVec2f(float(page.getMarginLeft()),float(page.getMarginRight())), |
482 | 179 | MWAWVec2f(float(page.getPageWidth()),float(page.getPageLength())), librevenge::RVNG_INCH); |
483 | 179 | pos.setRelativePosition(MWAWPosition::Page); |
484 | 179 | pos.m_wrapping = MWAWPosition::WNone; |
485 | 179 | listener->insertPicture(pos, picture); |
486 | 179 | return true; |
487 | 179 | } |
488 | | |
489 | | bool PixelPaintParser::readBitmapV1(bool onlyCheck) |
490 | 1.77k | { |
491 | 1.77k | MWAWInputStreamPtr input = getInput(); |
492 | 1.77k | long pos=input->tell(); |
493 | | |
494 | 1.77k | libmwaw::DebugStream f; |
495 | 1.77k | f << "Entries(Bitmap):"; |
496 | 1.77k | std::shared_ptr<MWAWPictBitmapIndexed> pict; |
497 | 1.77k | int numColors=256; |
498 | 1.77k | if (!onlyCheck) { |
499 | 518 | ascii().addPos(pos); |
500 | 518 | ascii().addNote(f.str().c_str()); |
501 | | |
502 | 518 | if (m_state->m_bitmapSize[0]<=0||m_state->m_bitmapSize[0]>1024 || |
503 | 518 | m_state->m_bitmapSize[1]<=0||m_state->m_bitmapSize[1]>1024) { |
504 | 0 | MWAW_DEBUG_MSG(("PixelPaintParser::readBitmapV1: argh can not find the bitmap size\n")); |
505 | 0 | return false; |
506 | 0 | } |
507 | 518 | if (m_state->m_colorList.empty()) { |
508 | 0 | MWAW_DEBUG_MSG(("PixelPaintParser::readBitmapV1: argh can not find the color list\n")); |
509 | 0 | return false; |
510 | 0 | } |
511 | 518 | pict.reset(new MWAWPictBitmapIndexed(m_state->m_bitmapSize)); |
512 | 518 | numColors=static_cast<int>(m_state->m_colorList.size()); |
513 | 518 | pict->setColors(m_state->m_colorList); |
514 | 518 | } |
515 | 1.67M | for (int i=0; i<16*1024; ++i) { |
516 | 1.67M | pos=input->tell(); |
517 | 1.67M | auto sz=long(input->readULong(4)); |
518 | 1.67M | long endPos=pos+4+sz; |
519 | 1.67M | if (sz<2 || !input->checkPosition(endPos)) { |
520 | 799 | input->seek(pos, librevenge::RVNG_SEEK_SET); |
521 | 799 | return false; |
522 | 799 | } |
523 | 1.67M | int row=i/16; |
524 | 1.67M | int col=(i%16)*64; |
525 | 1.67M | f.str(""); |
526 | 1.67M | f << "Bitmap[R" << row << "C" << col << "]:"; |
527 | 1.67M | int nPixel=0; |
528 | 3.81M | while (input->tell()+2<=endPos) { // UnpackBits |
529 | 2.14M | auto n=static_cast<int>(input->readULong(1)); |
530 | 2.14M | if (n>=0x81) { |
531 | 1.85M | auto color=static_cast<int>(input->readULong(1)); |
532 | 1.85M | if (color>=numColors) { |
533 | 0 | static bool first=true; |
534 | 0 | if (first) { |
535 | 0 | MWAW_DEBUG_MSG(("PixelPaintParser::readBitmapV1: find some bad index\n")); |
536 | 0 | first=false; |
537 | 0 | } |
538 | 0 | f << "###id=" << color << ","; |
539 | 0 | color=0; |
540 | 0 | } |
541 | 23.0M | for (int c=0; c<0x101-n; ++c) { |
542 | 22.7M | if (!pict || row >= m_state->m_bitmapSize[1] || col >= m_state->m_bitmapSize[0]) |
543 | 1.49M | break; |
544 | 21.2M | pict->set(col++, row, color); |
545 | 21.2M | } |
546 | 1.85M | nPixel+=0x101-n; |
547 | 1.85M | } |
548 | 287k | else { // checkme normally 0x80 is reserved and almost nobody used it (for ending the compression) |
549 | 287k | if (input->tell()+n+1>endPos) { |
550 | 684 | input->seek(-1, librevenge::RVNG_SEEK_CUR); |
551 | 684 | break; |
552 | 684 | } |
553 | 286k | nPixel+=n+1; |
554 | 1.82M | for (int c=0; c<=n; ++c) { |
555 | 1.54M | auto color=static_cast<int>(input->readULong(1)); |
556 | 1.54M | if (color>=numColors) { |
557 | 0 | static bool first=true; |
558 | 0 | if (first) { |
559 | 0 | MWAW_DEBUG_MSG(("PixelPaintParser::readBitmapV1: find some bad index\n")); |
560 | 0 | first=false; |
561 | 0 | } |
562 | 0 | f << "###id=" << color << ","; |
563 | 0 | color=0; |
564 | 0 | } |
565 | 1.54M | if (!pict || row >= m_state->m_bitmapSize[1] || col >= m_state->m_bitmapSize[0]) |
566 | 1.44M | continue; |
567 | 91.7k | pict->set(col++, row, color); |
568 | 91.7k | } |
569 | 286k | } |
570 | 2.14M | } |
571 | 1.67M | f << nPixel; |
572 | 1.67M | if (onlyCheck) { |
573 | 1.07M | if (nPixel!=64) return false; |
574 | 1.07M | } |
575 | 597k | else { |
576 | 597k | if (input->tell()!=endPos) { |
577 | 482 | ascii().addDelimiter(input->tell(),'|'); |
578 | 482 | f << "###"; |
579 | 482 | } |
580 | 597k | ascii().addPos(pos); |
581 | 597k | ascii().addNote(f.str().c_str()); |
582 | 597k | } |
583 | 1.67M | input->seek(endPos, librevenge::RVNG_SEEK_SET); |
584 | 1.67M | } |
585 | 15 | m_state->m_bitmap=pict; |
586 | 15 | return true; |
587 | 1.77k | } |
588 | | |
589 | | bool PixelPaintParser::readBitmapV2(bool onlyCheck) |
590 | 2.01k | { |
591 | 2.01k | MWAWInputStreamPtr input = getInput(); |
592 | 2.01k | long pos=input->tell(); |
593 | 2.01k | auto dataSz=static_cast<int>(input->readULong(2)); |
594 | 2.01k | if (dataSz<136+2048 || !input->checkPosition(pos+dataSz)) |
595 | 146 | return false; |
596 | 1.86k | libmwaw::DebugStream f; |
597 | 1.86k | f << "Entries(Bitmap)[header]:"; |
598 | 1.86k | int val; |
599 | 5.60k | for (int i=0; i<2; ++i) { // always 0 |
600 | 3.73k | val=static_cast<int>(input->readULong(2)); |
601 | 3.73k | if (val) |
602 | 2.36k | f << "f" << i << "=" << val << ","; |
603 | 3.73k | } |
604 | 1.86k | int dim[4]; |
605 | 5.60k | for (int i=0; i<2; ++i) dim[i]=static_cast<int>(input->readULong(2)); |
606 | 1.86k | if (dim[0]<=0||dim[0]>1024 || dim[1]<=0 || dim[1]>1024) |
607 | 210 | return false; |
608 | 1.65k | m_state->m_bitmapSize=MWAWVec2i(dim[1], dim[0]); |
609 | 1.65k | f << "sz=" << m_state->m_bitmapSize << ","; |
610 | 9.94k | for (int i=0; i<5; ++i) { // always 0 |
611 | 8.29k | val=static_cast<int>(input->readULong(2)); |
612 | 8.29k | if (val) |
613 | 5.50k | f << "f" << i+2 << "=" << val << ","; |
614 | 8.29k | } |
615 | 16.5k | for (int i=0; i<9; ++i) { // always 0 |
616 | 14.9k | val=static_cast<int>(input->readULong(2)); |
617 | 14.9k | if (val) |
618 | 11.2k | f << "f" << i+7 << "=" << val << ","; |
619 | 14.9k | } |
620 | 9.94k | for (int i=0; i<5; ++i) { |
621 | 8.29k | val=static_cast<int>(input->readLong(2)); |
622 | 8.29k | static int const expected[]= {0x11, 0x2ff, 0xc00, -1, -1}; |
623 | 8.29k | if (val!=expected[i]) |
624 | 7.84k | f << "g" << i << "=" << val << ","; |
625 | 8.29k | } |
626 | 8.29k | for (int i=0; i<4; ++i) { // always 0 |
627 | 6.63k | val=static_cast<int>(input->readULong(2)); |
628 | 6.63k | if (val) |
629 | 4.19k | f << "g" << i+4 << "=" << val << ","; |
630 | 6.63k | } |
631 | 1.65k | if (!onlyCheck) { |
632 | 619 | ascii().addPos(pos); |
633 | 619 | ascii().addNote(f.str().c_str()); |
634 | 619 | } |
635 | 1.65k | pos=input->tell(); |
636 | 1.65k | f.str(""); |
637 | 1.65k | f << "Bitmap[headerA]:"; |
638 | 4.97k | for (int i=0; i<2; ++i) { |
639 | 3.31k | val=static_cast<int>(input->readLong(2)); |
640 | 3.31k | if (val!=m_state->m_bitmapSize[i]) |
641 | 3.08k | f << "##dim" << i << "=" << val << ","; |
642 | 3.31k | val=static_cast<int>(input->readLong(2)); |
643 | 3.31k | if (val) |
644 | 2.00k | f << "dim" << i << "[low]=" << val << ","; |
645 | 3.31k | } |
646 | 16.5k | for (int i=0; i<9; ++i) { |
647 | 14.9k | val=static_cast<int>(input->readLong(2)); |
648 | 14.9k | static int const expected[]= {0, 0, 1, 0xa, 0, 0, 0x400, 0x400, 0x98 }; |
649 | 14.9k | if (val!=expected[i]) |
650 | 13.3k | f << "f" << i << "=" << val << ","; |
651 | 14.9k | } |
652 | 1.65k | val=static_cast<int>(input->readULong(2)); // 8248|8400 |
653 | 1.65k | if (val) f << "fl?=" << std::hex << val << std::dec << ","; |
654 | 4.97k | for (int i=0; i<2; ++i) { |
655 | 3.31k | val=static_cast<int>(input->readLong(2)); |
656 | 3.31k | if (val) |
657 | 2.46k | f << "g" << i << "=" << val << ","; |
658 | 3.31k | } |
659 | 4.97k | for (int i=0; i<2; ++i) dim[i]=static_cast<int>(input->readULong(2)); |
660 | 1.65k | if (MWAWVec2i(dim[1], dim[0])!=m_state->m_bitmapSize) |
661 | 1.62k | f << "sz2=" << MWAWVec2i(dim[1], dim[0]) << ","; |
662 | | |
663 | 8.29k | for (int i=0; i<4; ++i) { |
664 | 6.63k | val=static_cast<int>(input->readLong(2)); |
665 | 6.63k | if (val) |
666 | 4.29k | f << "g" << i+2 << "=" << val << ","; |
667 | 6.63k | } |
668 | 26.5k | for (int i=0; i<15; ++i) { |
669 | 24.8k | val=static_cast<int>(input->readLong(2)); |
670 | 24.8k | static int const expected[]= {0x48, 0, 0x48, 0, 0, 8, 1, 8, 0, 0, 0, 0x1f10, 0, 0, 0 }; |
671 | 24.8k | if (val!=expected[i]) |
672 | 19.4k | f << "g" << i+6 << "=" << val << ","; |
673 | 24.8k | } |
674 | 4.97k | for (int i=0; i<2; ++i) { // fl2=bc5|7bb9|bccc, fl3=8000 |
675 | 3.31k | val=static_cast<int>(input->readULong(2)); |
676 | 3.31k | if (val) f << "fl" << i+1 << "=" << std::hex << val << std::dec << ","; |
677 | 3.31k | } |
678 | 1.65k | val=static_cast<int>(input->readULong(2)); |
679 | 1.65k | if (val!=255) f << "h0=" << val << ","; |
680 | 1.65k | if (!onlyCheck) { |
681 | 619 | ascii().addPos(pos); |
682 | 619 | ascii().addNote(f.str().c_str()); |
683 | 619 | } |
684 | | |
685 | 1.65k | pos=input->tell(); |
686 | 1.65k | if (onlyCheck) |
687 | 1.03k | input->seek(pos+2048, librevenge::RVNG_SEEK_SET); |
688 | 619 | else { |
689 | 619 | f.str(""); |
690 | 619 | f << "Bitmap[color]:"; |
691 | | // CHECKME: does we want to use this color list or the main color list ? |
692 | 619 | m_state->m_colorList.resize(256); |
693 | 158k | for (auto &color : m_state->m_colorList) { |
694 | 158k | val=static_cast<int>(input->readULong(2)); |
695 | 158k | unsigned char c[3]; |
696 | 475k | for (auto &col : c) col=static_cast<unsigned char>(input->readULong(2)>>8); |
697 | 158k | color=MWAWColor(c[0],c[1],c[2]); |
698 | 158k | f << color; |
699 | 158k | if (val!=0x800) |
700 | 151k | f << "[" << std::hex << val << std::dec << "],"; |
701 | 7.04k | else |
702 | 7.04k | f << ","; |
703 | 158k | } |
704 | | |
705 | 619 | ascii().addPos(pos); |
706 | 619 | ascii().addNote(f.str().c_str()); |
707 | | |
708 | 619 | input->seek(pos+2048, librevenge::RVNG_SEEK_SET); |
709 | 619 | } |
710 | | |
711 | 1.65k | pos=input->tell(); |
712 | 1.65k | if (!input->checkPosition(pos+18)) |
713 | 0 | return false; |
714 | 1.65k | if (!onlyCheck) { |
715 | 619 | f.str(""); |
716 | 619 | f << "Bitmap[headerB]:"; |
717 | 1.85k | for (int i=0; i<2; ++i) { |
718 | 4.95k | for (auto &d : dim) d=static_cast<int>(input->readULong(2)); |
719 | 1.23k | if (dim[0]||dim[1]||m_state->m_bitmapSize!=MWAWVec2i(dim[3],dim[2])) |
720 | 1.19k | f << "dim" << i << "=" << MWAWBox2i(MWAWVec2i(dim[1],dim[0]), MWAWVec2i(dim[3],dim[2])) << ","; |
721 | 1.23k | } |
722 | 619 | val=static_cast<int>(input->readLong(2)); // always 0 ? |
723 | 619 | if (val) f << "f0=" << val << ","; |
724 | 619 | ascii().addPos(pos); |
725 | 619 | ascii().addNote(f.str().c_str()); |
726 | 619 | } |
727 | | |
728 | 1.65k | input->seek(pos+18, librevenge::RVNG_SEEK_SET); |
729 | 1.65k | int numColors=0; |
730 | 1.65k | std::shared_ptr<MWAWPictBitmapIndexed> pict; |
731 | 1.65k | if (!onlyCheck) { |
732 | 619 | ascii().addPos(input->tell()); |
733 | 619 | ascii().addNote(f.str().c_str()); |
734 | | |
735 | 619 | if (m_state->m_bitmapSize[0]<=0||m_state->m_bitmapSize[0]>1024 || |
736 | 619 | m_state->m_bitmapSize[1]<=0||m_state->m_bitmapSize[1]>1024) { |
737 | 0 | MWAW_DEBUG_MSG(("PixelPaintParser::readBitmapV2: argh can not find the bitmap size\n")); |
738 | 0 | return false; |
739 | 0 | } |
740 | 619 | if (m_state->m_colorList.empty()) { |
741 | 0 | MWAW_DEBUG_MSG(("PixelPaintParser::readBitmapV2: argh can not find the color list\n")); |
742 | 0 | return false; |
743 | 0 | } |
744 | 619 | pict.reset(new MWAWPictBitmapIndexed(m_state->m_bitmapSize)); |
745 | 619 | numColors=static_cast<int>(m_state->m_colorList.size()); |
746 | 619 | pict->setColors(m_state->m_colorList); |
747 | 619 | } |
748 | | |
749 | 47.2k | for (int row=0; row<m_state->m_bitmapSize[1]; ++row) { |
750 | 46.7k | pos=input->tell(); |
751 | 46.7k | dataSz=static_cast<int>(input->readULong(2)); |
752 | 46.7k | long endPos=pos+2+dataSz; |
753 | 46.7k | if (dataSz<2 || !input->checkPosition(endPos)) { |
754 | 1.20k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
755 | 1.20k | return false; |
756 | 1.20k | } |
757 | 45.5k | if (onlyCheck) { |
758 | 28.1k | input->seek(endPos, librevenge::RVNG_SEEK_SET); |
759 | 28.1k | continue; |
760 | 28.1k | } |
761 | 17.4k | f.str(""); |
762 | 17.4k | f << "Bitmap[R" << row << "]:"; |
763 | 17.4k | int col=0, nPixel=0; |
764 | 2.39M | while (input->tell()+2<=endPos) { // UnpackBits |
765 | 2.38M | auto n=static_cast<int>(input->readULong(1)); |
766 | 2.38M | if (n>=0x81) { |
767 | 474k | auto color=static_cast<int>(input->readULong(1)); |
768 | 474k | if (color>=numColors) { |
769 | 0 | static bool first=true; |
770 | 0 | if (first) { |
771 | 0 | MWAW_DEBUG_MSG(("PixelPaintParser::readBitmapV2: find some bad index\n")); |
772 | 0 | first=false; |
773 | 0 | } |
774 | 0 | f << "###id=" << color << ","; |
775 | 0 | color=0; |
776 | 0 | } |
777 | 4.95M | for (int c=0; c<0x101-n; ++c) { |
778 | 4.90M | if (!pict || col >= m_state->m_bitmapSize[0]) |
779 | 424k | break; |
780 | 4.48M | pict->set(col++, row, color); |
781 | 4.48M | } |
782 | 474k | nPixel+=0x101-n; |
783 | 474k | } |
784 | 1.91M | else { // checkme normally 0x80 is reserved and almost nobody used it (for ending the compression) |
785 | 1.91M | if (input->tell()+n+1>endPos) { |
786 | 7.82k | input->seek(-1, librevenge::RVNG_SEEK_CUR); |
787 | 7.82k | break; |
788 | 7.82k | } |
789 | 1.90M | nPixel+=n+1; |
790 | 11.8M | for (int c=0; c<=n; ++c) { |
791 | 9.89M | auto color=static_cast<int>(input->readULong(1)); |
792 | 9.89M | if (color>=numColors) { |
793 | 0 | static bool first=true; |
794 | 0 | if (first) { |
795 | 0 | MWAW_DEBUG_MSG(("PixelPaintParser::readBitmapV2: find some bad index\n")); |
796 | 0 | first=false; |
797 | 0 | } |
798 | 0 | f << "###id=" << color << ","; |
799 | 0 | color=0; |
800 | 0 | } |
801 | 9.89M | if (!pict || col >= m_state->m_bitmapSize[0]) |
802 | 7.92M | continue; |
803 | 1.97M | pict->set(col++, row, color); |
804 | 1.97M | } |
805 | 1.90M | } |
806 | 2.38M | } |
807 | 17.4k | if (nPixel<m_state->m_bitmapSize[0] || nPixel>m_state->m_bitmapSize[0]+32) { |
808 | 10.6k | static bool first=true; |
809 | 10.6k | if (first) { |
810 | 13 | MWAW_DEBUG_MSG(("PixelPaintParser::readBitmapV2: find row with odd number of pixel\n")); |
811 | 13 | first=false; |
812 | 13 | } |
813 | 10.6k | f << "###numPixel=" << nPixel << ","; |
814 | 10.6k | } |
815 | 17.4k | if (input->tell()!=endPos) { |
816 | 9.03k | ascii().addDelimiter(input->tell(),'|'); |
817 | 9.03k | f << "###"; |
818 | 9.03k | } |
819 | 17.4k | ascii().addPos(pos); |
820 | 17.4k | ascii().addNote(f.str().c_str()); |
821 | 17.4k | input->seek(endPos, librevenge::RVNG_SEEK_SET); |
822 | 17.4k | } |
823 | 454 | m_state->m_bitmap=pict; |
824 | 454 | return true; |
825 | 1.65k | } |
826 | | |
827 | | //////////////////////////////////////////////////////////// |
828 | | // read the header |
829 | | //////////////////////////////////////////////////////////// |
830 | | bool PixelPaintParser::checkHeader(MWAWHeader *header, bool strict) |
831 | 15.5k | { |
832 | 15.5k | *m_state = PixelPaintParserInternal::State(); |
833 | 15.5k | MWAWInputStreamPtr input = getInput(); |
834 | 15.5k | if (!input || !input->hasDataFork() || !input->checkPosition(512)) |
835 | 5.89k | return false; |
836 | 9.64k | input->seek(0, librevenge::RVNG_SEEK_SET); |
837 | 9.64k | if (input->readULong(2)) |
838 | 72 | return false; |
839 | 9.57k | int vers=1; |
840 | 9.57k | auto val=static_cast<int>(input->readULong(2)); |
841 | 9.57k | if (val==0x7fff) |
842 | 4.16k | ; |
843 | 5.40k | else if (val==0x8000) |
844 | 5.33k | vers=2; |
845 | 73 | else |
846 | 73 | return false; |
847 | 9.49k | if ((vers==1&&!readFileHeaderV1(true)) || (vers==2&&!readFileHeaderV2(true))) |
848 | 1.96k | return false; |
849 | 7.53k | if (!readColorMap(true) || !readPatternMap(true)) |
850 | 572 | return false; |
851 | 6.96k | if (strict) { |
852 | 2.59k | if ((vers==1 && !readBitmapV1(true)) || (vers==2 && !readBitmapV2(true))) |
853 | 2.30k | return false; |
854 | 2.59k | } |
855 | 4.66k | setVersion(vers); |
856 | 4.66k | if (header) |
857 | 2.27k | header->reset(MWAWDocument::MWAW_T_PIXELPAINT, vers, MWAWDocument::MWAW_K_PAINT); |
858 | | |
859 | 4.66k | return true; |
860 | 6.96k | } |
861 | | |
862 | | // vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: |