/src/libmwaw/src/lib/MacPaintParser.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 "MacPaintParser.hxx" |
49 | | |
50 | | /** Internal: the structures of a MacPaintParser */ |
51 | | namespace MacPaintParserInternal |
52 | | { |
53 | | //////////////////////////////////////// |
54 | | //! Internal: the state of a MacPaintParser |
55 | | struct State { |
56 | | //! constructor |
57 | | State() |
58 | 16.1k | : m_bitmap() |
59 | 16.1k | { |
60 | 16.1k | } |
61 | | /// the bitmap (v1) |
62 | | std::shared_ptr<MWAWPict> m_bitmap; |
63 | | }; |
64 | | |
65 | | } |
66 | | |
67 | | //////////////////////////////////////////////////////////// |
68 | | // constructor/destructor, ... |
69 | | //////////////////////////////////////////////////////////// |
70 | | MacPaintParser::MacPaintParser(MWAWInputStreamPtr const &input, MWAWRSRCParserPtr const &rsrcParser, MWAWHeader *header) |
71 | 7.64k | : MWAWGraphicParser(input, rsrcParser, header) |
72 | 7.64k | , m_state() |
73 | 7.64k | { |
74 | 7.64k | init(); |
75 | 7.64k | } |
76 | | |
77 | | MacPaintParser::~MacPaintParser() |
78 | 7.64k | { |
79 | 7.64k | } |
80 | | |
81 | | void MacPaintParser::init() |
82 | 7.64k | { |
83 | 7.64k | resetGraphicListener(); |
84 | 7.64k | setAsciiName("main-1"); |
85 | | |
86 | 7.64k | m_state.reset(new MacPaintParserInternal::State); |
87 | | |
88 | 7.64k | getPageSpan().setMargins(0.1); |
89 | 7.64k | } |
90 | | |
91 | | //////////////////////////////////////////////////////////// |
92 | | // the parser |
93 | | //////////////////////////////////////////////////////////// |
94 | | void MacPaintParser::parse(librevenge::RVNGDrawingInterface *docInterface) |
95 | 877 | { |
96 | 877 | if (!getInput().get() || !checkHeader(nullptr)) throw(libmwaw::ParseException()); |
97 | 877 | bool ok = false; |
98 | 877 | try { |
99 | | // create the asciiFile |
100 | 877 | ascii().setStream(getInput()); |
101 | 877 | ascii().open(asciiName()); |
102 | 877 | checkHeader(nullptr); |
103 | 877 | ok = createZones(); |
104 | 877 | if (ok) { |
105 | 47 | createDocument(docInterface); |
106 | 47 | sendBitmap(); |
107 | 47 | } |
108 | 877 | ascii().reset(); |
109 | 877 | } |
110 | 877 | catch (...) { |
111 | 0 | MWAW_DEBUG_MSG(("MacPaintParser::parse: exception catched when parsing\n")); |
112 | 0 | ok = false; |
113 | 0 | } |
114 | | |
115 | 877 | resetGraphicListener(); |
116 | 877 | if (!ok) throw(libmwaw::ParseException()); |
117 | 877 | } |
118 | | |
119 | | //////////////////////////////////////////////////////////// |
120 | | // create the document |
121 | | //////////////////////////////////////////////////////////// |
122 | | void MacPaintParser::createDocument(librevenge::RVNGDrawingInterface *documentInterface) |
123 | 47 | { |
124 | 47 | if (!documentInterface) return; |
125 | 47 | if (getGraphicListener()) { |
126 | 0 | MWAW_DEBUG_MSG(("MacPaintParser::createDocument: listener already exist\n")); |
127 | 0 | return; |
128 | 0 | } |
129 | | |
130 | | // create the page list |
131 | 47 | MWAWPageSpan ps(getPageSpan()); |
132 | 47 | ps.setPageSpan(1); |
133 | 47 | std::vector<MWAWPageSpan> pageList(1,ps); |
134 | 47 | MWAWGraphicListenerPtr listen(new MWAWGraphicListener(*getParserState(), pageList, documentInterface)); |
135 | 47 | setGraphicListener(listen); |
136 | 47 | listen->startDocument(); |
137 | 47 | } |
138 | | |
139 | | |
140 | | //////////////////////////////////////////////////////////// |
141 | | // |
142 | | // Intermediate level |
143 | | // |
144 | | //////////////////////////////////////////////////////////// |
145 | | bool MacPaintParser::createZones() |
146 | 877 | { |
147 | 877 | MWAWInputStreamPtr input = getInput(); |
148 | 877 | if (input->size()<512) return false; |
149 | | #ifdef DEBUG |
150 | | libmwaw::DebugStream f; |
151 | | f << "FileHeader:"; |
152 | | input->seek(0, librevenge::RVNG_SEEK_SET); |
153 | | for (int i=0; i<256; i++) { // normally 0, but can be a list of patter |
154 | | auto val=static_cast<int>(input->readLong(2)); |
155 | | if (val) |
156 | | f << "f" << i << "=" << val << ","; |
157 | | } |
158 | | ascii().addPos(0); |
159 | | ascii().addNote(f.str().c_str()); |
160 | | #endif |
161 | 877 | if (!readBitmap()) return false; |
162 | 47 | if (!input->isEnd()) { |
163 | 37 | MWAW_DEBUG_MSG(("MacPaintParser::createZones: find some extra data\n")); |
164 | 37 | ascii().addPos(input->tell()); |
165 | 37 | ascii().addNote("Entries(End):###"); |
166 | 37 | } |
167 | 47 | return true; |
168 | 877 | } |
169 | | |
170 | | //////////////////////////////////////////////////////////// |
171 | | // send data |
172 | | //////////////////////////////////////////////////////////// |
173 | | bool MacPaintParser::sendBitmap() |
174 | 47 | { |
175 | 47 | MWAWGraphicListenerPtr listener=getGraphicListener(); |
176 | 47 | if (!listener) { |
177 | 0 | MWAW_DEBUG_MSG(("MacPaintParser::sendBitmap: can not find the listener\n")); |
178 | 0 | return false; |
179 | 0 | } |
180 | | |
181 | 47 | MWAWEmbeddedObject picture; |
182 | 47 | if (!m_state->m_bitmap || !m_state->m_bitmap->getBinary(picture)) return false; |
183 | | |
184 | 47 | MWAWPageSpan const &page=getPageSpan(); |
185 | 47 | MWAWPosition pos(MWAWVec2f(float(page.getMarginLeft()),float(page.getMarginRight())), |
186 | 47 | MWAWVec2f(float(page.getPageWidth()),float(page.getPageLength())), librevenge::RVNG_INCH); |
187 | 47 | pos.setRelativePosition(MWAWPosition::Page); |
188 | 47 | pos.m_wrapping = MWAWPosition::WNone; |
189 | 47 | listener->insertPicture(pos, picture); |
190 | 47 | return true; |
191 | 47 | } |
192 | | |
193 | | bool MacPaintParser::readBitmap(bool onlyCheck) |
194 | 5.26k | { |
195 | 5.26k | MWAWInputStreamPtr input = getInput(); |
196 | 5.26k | long endPos=input->size(); |
197 | 5.26k | input->seek(512, librevenge::RVNG_SEEK_SET); |
198 | | |
199 | 5.26k | libmwaw::DebugStream f; |
200 | | // a bitmap is composed of 720 rows of (72x8bytes) |
201 | 5.26k | std::shared_ptr<MWAWPictBitmapIndexed> pict; |
202 | 5.26k | if (!onlyCheck) { |
203 | 877 | pict.reset(new MWAWPictBitmapIndexed(MWAWVec2i(576,720))); |
204 | 877 | std::vector<MWAWColor> colors(2); |
205 | 877 | colors[0]=MWAWColor::white(); |
206 | 877 | colors[1]=MWAWColor::black(); |
207 | 877 | pict->setColors(colors); |
208 | 877 | } |
209 | | |
210 | 398k | for (int r=0; r<720; ++r) { |
211 | 397k | long rowPos=input->tell(); |
212 | 397k | f.str(""); |
213 | 397k | f << "Entries(Bitmap)-" << r << ":"; |
214 | 397k | int col=0; |
215 | 17.3M | while (col<72*8) { // UnpackBits |
216 | 16.9M | if (input->tell()+2>endPos) { |
217 | 317 | MWAW_DEBUG_MSG(("MacPaintParser::readBitmap: can not read row %d\n", r)); |
218 | 317 | f << "###"; |
219 | 317 | ascii().addPos(rowPos); |
220 | 317 | ascii().addNote(f.str().c_str()); |
221 | 317 | return false; |
222 | 317 | } |
223 | 16.9M | auto wh=static_cast<int>(input->readULong(1)); |
224 | 16.9M | if (wh>=0x81) { |
225 | 720k | auto color=static_cast<int>(input->readULong(1)); |
226 | 720k | if (onlyCheck) { |
227 | 589k | col+=8*(0x101-wh); |
228 | 589k | if (col>72*8) |
229 | 1.38k | return false; |
230 | 587k | continue; |
231 | 589k | } |
232 | 2.16M | for (int j=0; j < 0x101-wh; ++j) { |
233 | 2.03M | if (col>=72*8) { |
234 | 303 | MWAW_DEBUG_MSG(("MacPaintParser::readBitmap: can not read row %d\n", r)); |
235 | 303 | f << "###"; |
236 | 303 | ascii().addPos(rowPos); |
237 | 303 | ascii().addNote(f.str().c_str()); |
238 | 303 | return false; |
239 | 303 | } |
240 | 18.3M | for (int b=7; b>=0; --b) |
241 | 16.2M | pict->set(col++, r, (color>>b)&1); |
242 | 2.03M | } |
243 | 130k | } |
244 | 16.2M | else { // checkme normally 0x80 is reserved and almost nobody used it (for ending the compression) |
245 | 16.2M | if (input->tell()+wh+1>endPos) { |
246 | 139 | MWAW_DEBUG_MSG(("MacPaintParser::readBitmap: can not read row %d\n", r)); |
247 | 139 | f << "###"; |
248 | 139 | ascii().addPos(rowPos); |
249 | 139 | ascii().addNote(f.str().c_str()); |
250 | 139 | return false; |
251 | 139 | } |
252 | 36.1M | for (int j=0; j < wh+1; ++j) { |
253 | 19.8M | auto color=static_cast<int>(input->readULong(1)); |
254 | 19.8M | if (col>=72*8) { |
255 | 2.90k | MWAW_DEBUG_MSG(("MacPaintParser::readBitmap: can not read row %d\n", r)); |
256 | 2.90k | f << "###"; |
257 | 2.90k | ascii().addPos(rowPos); |
258 | 2.90k | ascii().addNote(f.str().c_str()); |
259 | 2.90k | return false; |
260 | 2.90k | } |
261 | 19.8M | if (onlyCheck) { |
262 | 15.6M | col+=8; |
263 | 15.6M | continue; |
264 | 15.6M | } |
265 | 37.9M | for (int b=7; b>=0; --b) |
266 | 33.7M | pict->set(col++, r, (color>>b)&1); |
267 | 4.21M | } |
268 | 16.2M | } |
269 | 16.9M | } |
270 | 392k | ascii().addPos(rowPos); |
271 | 392k | ascii().addNote(f.str().c_str()); |
272 | 392k | } |
273 | 216 | if (!onlyCheck) |
274 | 47 | m_state->m_bitmap=pict; |
275 | 216 | return true; |
276 | 5.26k | } |
277 | | |
278 | | //////////////////////////////////////////////////////////// |
279 | | // read the header |
280 | | //////////////////////////////////////////////////////////// |
281 | | bool MacPaintParser::checkHeader(MWAWHeader *header, bool strict) |
282 | 8.52k | { |
283 | 8.52k | *m_state = MacPaintParserInternal::State(); |
284 | 8.52k | MWAWInputStreamPtr input = getInput(); |
285 | 8.52k | if (!input || !input->hasDataFork() || !input->checkPosition(512+720*2)) |
286 | 103 | return false; |
287 | | |
288 | 8.42k | MWAWDocument::Type type=MWAWDocument::MWAW_T_MACPAINT; |
289 | 8.42k | std::string fType, fCreator; |
290 | 8.42k | if (input->getFinderInfo(fType, fCreator) && fCreator=="PANT") |
291 | 69 | type=MWAWDocument::MWAW_T_FULLPAINT; |
292 | | |
293 | 8.42k | int const vers=1; |
294 | 8.42k | if (strict) { |
295 | | /* check : |
296 | | - if we can read the bitmap, |
297 | | - if the data have been packed: ie. if the bitmap size is 720x144 |
298 | | the bitmap's creator clearly creates the worst possible data, |
299 | | - and if after reading the bitmap we are at the end of the file |
300 | | (up to 512 char) */ |
301 | 4.38k | input->seek(512, librevenge::RVNG_SEEK_SET); |
302 | 4.38k | if (!readBitmap(true) || input->tell()==512+720*144 || input->checkPosition(input->tell()+512)) |
303 | 4.31k | return false; |
304 | 4.38k | } |
305 | 4.11k | setVersion(vers); |
306 | 4.11k | if (header) |
307 | 2.35k | header->reset(type, vers, MWAWDocument::MWAW_K_PAINT); |
308 | | |
309 | 4.11k | return true; |
310 | 8.42k | } |
311 | | |
312 | | // vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: |