/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 | 18.2k | : m_bitmap() |
59 | 18.2k | { |
60 | 18.2k | } |
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 | 8.60k | : MWAWGraphicParser(input, rsrcParser, header) |
72 | 8.60k | , m_state() |
73 | 8.60k | { |
74 | 8.60k | init(); |
75 | 8.60k | } |
76 | | |
77 | | MacPaintParser::~MacPaintParser() |
78 | 8.60k | { |
79 | 8.60k | } |
80 | | |
81 | | void MacPaintParser::init() |
82 | 8.60k | { |
83 | 8.60k | resetGraphicListener(); |
84 | 8.60k | setAsciiName("main-1"); |
85 | | |
86 | 8.60k | m_state.reset(new MacPaintParserInternal::State); |
87 | | |
88 | 8.60k | getPageSpan().setMargins(0.1); |
89 | 8.60k | } |
90 | | |
91 | | //////////////////////////////////////////////////////////// |
92 | | // the parser |
93 | | //////////////////////////////////////////////////////////// |
94 | | void MacPaintParser::parse(librevenge::RVNGDrawingInterface *docInterface) |
95 | 1.07k | { |
96 | 1.07k | if (!getInput().get() || !checkHeader(nullptr)) throw(libmwaw::ParseException()); |
97 | 1.07k | bool ok = false; |
98 | 1.07k | try { |
99 | | // create the asciiFile |
100 | 1.07k | ascii().setStream(getInput()); |
101 | 1.07k | ascii().open(asciiName()); |
102 | 1.07k | checkHeader(nullptr); |
103 | 1.07k | ok = createZones(); |
104 | 1.07k | if (ok) { |
105 | 59 | createDocument(docInterface); |
106 | 59 | sendBitmap(); |
107 | 59 | } |
108 | 1.07k | ascii().reset(); |
109 | 1.07k | } |
110 | 1.07k | catch (...) { |
111 | 0 | MWAW_DEBUG_MSG(("MacPaintParser::parse: exception catched when parsing\n")); |
112 | 0 | ok = false; |
113 | 0 | } |
114 | | |
115 | 1.07k | resetGraphicListener(); |
116 | 1.07k | if (!ok) throw(libmwaw::ParseException()); |
117 | 1.07k | } |
118 | | |
119 | | //////////////////////////////////////////////////////////// |
120 | | // create the document |
121 | | //////////////////////////////////////////////////////////// |
122 | | void MacPaintParser::createDocument(librevenge::RVNGDrawingInterface *documentInterface) |
123 | 59 | { |
124 | 59 | if (!documentInterface) return; |
125 | 59 | 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 | 59 | MWAWPageSpan ps(getPageSpan()); |
132 | 59 | ps.setPageSpan(1); |
133 | 59 | std::vector<MWAWPageSpan> pageList(1,ps); |
134 | 59 | MWAWGraphicListenerPtr listen(new MWAWGraphicListener(*getParserState(), pageList, documentInterface)); |
135 | 59 | setGraphicListener(listen); |
136 | 59 | listen->startDocument(); |
137 | 59 | } |
138 | | |
139 | | |
140 | | //////////////////////////////////////////////////////////// |
141 | | // |
142 | | // Intermediate level |
143 | | // |
144 | | //////////////////////////////////////////////////////////// |
145 | | bool MacPaintParser::createZones() |
146 | 1.07k | { |
147 | 1.07k | MWAWInputStreamPtr input = getInput(); |
148 | 1.07k | 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 | 1.07k | if (!readBitmap()) return false; |
162 | 59 | if (!input->isEnd()) { |
163 | 51 | MWAW_DEBUG_MSG(("MacPaintParser::createZones: find some extra data\n")); |
164 | 51 | ascii().addPos(input->tell()); |
165 | 51 | ascii().addNote("Entries(End):###"); |
166 | 51 | } |
167 | 59 | return true; |
168 | 1.07k | } |
169 | | |
170 | | //////////////////////////////////////////////////////////// |
171 | | // send data |
172 | | //////////////////////////////////////////////////////////// |
173 | | bool MacPaintParser::sendBitmap() |
174 | 59 | { |
175 | 59 | MWAWGraphicListenerPtr listener=getGraphicListener(); |
176 | 59 | if (!listener) { |
177 | 0 | MWAW_DEBUG_MSG(("MacPaintParser::sendBitmap: can not find the listener\n")); |
178 | 0 | return false; |
179 | 0 | } |
180 | | |
181 | 59 | MWAWEmbeddedObject picture; |
182 | 59 | if (!m_state->m_bitmap || !m_state->m_bitmap->getBinary(picture)) return false; |
183 | | |
184 | 59 | MWAWPageSpan const &page=getPageSpan(); |
185 | 59 | MWAWPosition pos(MWAWVec2f(float(page.getMarginLeft()),float(page.getMarginRight())), |
186 | 59 | MWAWVec2f(float(page.getPageWidth()),float(page.getPageLength())), librevenge::RVNG_INCH); |
187 | 59 | pos.setRelativePosition(MWAWPosition::Page); |
188 | 59 | pos.m_wrapping = MWAWPosition::WNone; |
189 | 59 | listener->insertPicture(pos, picture); |
190 | 59 | return true; |
191 | 59 | } |
192 | | |
193 | | bool MacPaintParser::readBitmap(bool onlyCheck) |
194 | 6.01k | { |
195 | 6.01k | MWAWInputStreamPtr input = getInput(); |
196 | 6.01k | long endPos=input->size(); |
197 | 6.01k | input->seek(512, librevenge::RVNG_SEEK_SET); |
198 | | |
199 | 6.01k | libmwaw::DebugStream f; |
200 | | // a bitmap is composed of 720 rows of (72x8bytes) |
201 | 6.01k | std::shared_ptr<MWAWPictBitmapIndexed> pict; |
202 | 6.01k | if (!onlyCheck) { |
203 | 1.07k | pict.reset(new MWAWPictBitmapIndexed(MWAWVec2i(576,720))); |
204 | 1.07k | std::vector<MWAWColor> colors(2); |
205 | 1.07k | colors[0]=MWAWColor::white(); |
206 | 1.07k | colors[1]=MWAWColor::black(); |
207 | 1.07k | pict->setColors(colors); |
208 | 1.07k | } |
209 | | |
210 | 486k | for (int r=0; r<720; ++r) { |
211 | 486k | long rowPos=input->tell(); |
212 | 486k | f.str(""); |
213 | 486k | f << "Entries(Bitmap)-" << r << ":"; |
214 | 486k | int col=0; |
215 | 24.7M | while (col<72*8) { // UnpackBits |
216 | 24.2M | if (input->tell()+2>endPos) { |
217 | 330 | MWAW_DEBUG_MSG(("MacPaintParser::readBitmap: can not read row %d\n", r)); |
218 | 330 | f << "###"; |
219 | 330 | ascii().addPos(rowPos); |
220 | 330 | ascii().addNote(f.str().c_str()); |
221 | 330 | return false; |
222 | 330 | } |
223 | 24.2M | auto wh=static_cast<int>(input->readULong(1)); |
224 | 24.2M | if (wh>=0x81) { |
225 | 704k | auto color=static_cast<int>(input->readULong(1)); |
226 | 704k | if (onlyCheck) { |
227 | 572k | col+=8*(0x101-wh); |
228 | 572k | if (col>72*8) |
229 | 1.62k | return false; |
230 | 571k | continue; |
231 | 572k | } |
232 | 1.94M | for (int j=0; j < 0x101-wh; ++j) { |
233 | 1.81M | if (col>=72*8) { |
234 | 444 | MWAW_DEBUG_MSG(("MacPaintParser::readBitmap: can not read row %d\n", r)); |
235 | 444 | f << "###"; |
236 | 444 | ascii().addPos(rowPos); |
237 | 444 | ascii().addNote(f.str().c_str()); |
238 | 444 | return false; |
239 | 444 | } |
240 | 16.3M | for (int b=7; b>=0; --b) |
241 | 14.5M | pict->set(col++, r, (color>>b)&1); |
242 | 1.81M | } |
243 | 131k | } |
244 | 23.5M | else { // checkme normally 0x80 is reserved and almost nobody used it (for ending the compression) |
245 | 23.5M | if (input->tell()+wh+1>endPos) { |
246 | 142 | MWAW_DEBUG_MSG(("MacPaintParser::readBitmap: can not read row %d\n", r)); |
247 | 142 | f << "###"; |
248 | 142 | ascii().addPos(rowPos); |
249 | 142 | ascii().addNote(f.str().c_str()); |
250 | 142 | return false; |
251 | 142 | } |
252 | 51.3M | for (int j=0; j < wh+1; ++j) { |
253 | 27.7M | auto color=static_cast<int>(input->readULong(1)); |
254 | 27.7M | if (col>=72*8) { |
255 | 3.16k | MWAW_DEBUG_MSG(("MacPaintParser::readBitmap: can not read row %d\n", r)); |
256 | 3.16k | f << "###"; |
257 | 3.16k | ascii().addPos(rowPos); |
258 | 3.16k | ascii().addNote(f.str().c_str()); |
259 | 3.16k | return false; |
260 | 3.16k | } |
261 | 27.7M | if (onlyCheck) { |
262 | 22.3M | col+=8; |
263 | 22.3M | continue; |
264 | 22.3M | } |
265 | 49.2M | for (int b=7; b>=0; --b) |
266 | 43.7M | pict->set(col++, r, (color>>b)&1); |
267 | 5.47M | } |
268 | 23.5M | } |
269 | 24.2M | } |
270 | 480k | ascii().addPos(rowPos); |
271 | 480k | ascii().addNote(f.str().c_str()); |
272 | 480k | } |
273 | 303 | if (!onlyCheck) |
274 | 59 | m_state->m_bitmap=pict; |
275 | 303 | return true; |
276 | 6.01k | } |
277 | | |
278 | | //////////////////////////////////////////////////////////// |
279 | | // read the header |
280 | | //////////////////////////////////////////////////////////// |
281 | | bool MacPaintParser::checkHeader(MWAWHeader *header, bool strict) |
282 | 9.67k | { |
283 | 9.67k | *m_state = MacPaintParserInternal::State(); |
284 | 9.67k | MWAWInputStreamPtr input = getInput(); |
285 | 9.67k | if (!input || !input->hasDataFork() || !input->checkPosition(512+720*2)) |
286 | 75 | return false; |
287 | | |
288 | 9.60k | MWAWDocument::Type type=MWAWDocument::MWAW_T_MACPAINT; |
289 | 9.60k | std::string fType, fCreator; |
290 | 9.60k | if (input->getFinderInfo(fType, fCreator) && fCreator=="PANT") |
291 | 57 | type=MWAWDocument::MWAW_T_FULLPAINT; |
292 | | |
293 | 9.60k | int const vers=1; |
294 | 9.60k | 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.94k | input->seek(512, librevenge::RVNG_SEEK_SET); |
302 | 4.94k | if (!readBitmap(true) || input->tell()==512+720*144 || input->checkPosition(input->tell()+512)) |
303 | 4.88k | return false; |
304 | 4.94k | } |
305 | 4.72k | setVersion(vers); |
306 | 4.72k | if (header) |
307 | 2.57k | header->reset(type, vers, MWAWDocument::MWAW_K_PAINT); |
308 | | |
309 | 4.72k | return true; |
310 | 9.60k | } |
311 | | |
312 | | // vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: |