1 /* libwpg
2  * Copyright (C) 2006 Ariya Hidayat (ariya@kde.org)
3  * Copyright (C) 2005 Fridrich Strba (fridrich.strba@bluewin.ch)
4  * Copyright (C) 2004 Marc Oude Kotte (marc@solcon.nl)
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA  02111-1301 USA
20  *
21  * For further information visit http://libwpg.sourceforge.net
22  */
23 
24 /* "This product is not manufactured, approved, or supported by
25  * Corel Corporation or Corel Corporation Limited."
26  */
27 
28 #include "WPG1Parser.h"
29 #include "WPGPaintInterface.h"
30 #include "libwpg_utils.h"
31 
32 static const unsigned char defaultWPG1PaletteRed[] = {
33 	0x00, 0x00, 0x00, 0x00, 0x7F, 0x7F, 0x7F, 0x7F,
34 	0xC0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
35 	0x00, 0x14, 0x20, 0x2C, 0x38, 0x45, 0x51, 0x61,
36 	0x71, 0x82, 0x92, 0xA2, 0xB6, 0xCB, 0xE3, 0xFF,
37 	0x00, 0x41, 0x7D, 0xBE, 0xFF, 0xFF, 0xFF, 0xFF,
38 	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBE, 0x7D, 0x41,
39 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
40 	0x7D, 0x9E, 0xBE, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF,
41 	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xDF, 0xBE, 0x9E,
42 	0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D,
43 	0xB6, 0xC7, 0xDB, 0xEB, 0xFF, 0xFF, 0xFF, 0xFF,
44 	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEB, 0xDB, 0xC7,
45 	0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6,
46 	0x00, 0x1C, 0x38, 0x55, 0x71, 0x71, 0x71, 0x71,
47 	0x71, 0x71, 0x71, 0x71, 0x71, 0x55, 0x38, 0x1C,
48 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
49 	0x38, 0x45, 0x55, 0x61, 0x71, 0x71, 0x71, 0x71,
50 	0x71, 0x71, 0x71, 0x71, 0x71, 0x61, 0x55, 0x45,
51 	0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38,
52 	0x51, 0x59, 0x61, 0x69, 0x71, 0x71, 0x71, 0x71,
53 	0x71, 0x71, 0x71, 0x71, 0x71, 0x69, 0x61, 0x59,
54 	0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51,
55 	0x00, 0x10, 0x20, 0x30, 0x41, 0x41, 0x41, 0x41,
56 	0x41, 0x41, 0x41, 0x41, 0x41, 0x30, 0x20, 0x10,
57 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
58 	0x20, 0x28, 0x30, 0x38, 0x41, 0x41, 0x41, 0x41,
59 	0x41, 0x41, 0x41, 0x41, 0x41, 0x38, 0x30, 0x28,
60 	0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
61 	0x3C, 0x30, 0x34, 0x3C, 0x41, 0x41, 0x41, 0x41,
62 	0x41, 0x41, 0x41, 0x41, 0x41, 0x3C, 0x34, 0x30,
63 	0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C,
64 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
65 };
66 
67 static const unsigned char defaultWPG1PaletteGreen[] = {
68 	0x00, 0x00, 0x7F, 0x7F, 0x00, 0x00, 0x3F, 0x7F,
69 	0xC0, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF,
70 	0x00, 0x14, 0x20, 0x2C, 0x38, 0x45, 0x51, 0x61,
71 	0x71, 0x82, 0x92, 0xA2, 0xB6, 0xCB, 0xE3, 0xFF,
72 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
73 	0x00, 0x41, 0x7D, 0xBE, 0xFF, 0xFF, 0xFF, 0xFF,
74 	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBE, 0x7D, 0x41,
75 	0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D,
76 	0x7D, 0x9E, 0xBE, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF,
77 	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xDF, 0xBE, 0x9E,
78 	0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6,
79 	0xB6, 0xC7, 0xDB, 0xEB, 0xFF, 0xFF, 0xFF, 0xFF,
80 	0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEB, 0xDB, 0xC7,
81 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
82 	0x00, 0x1C, 0x38, 0x55, 0x71, 0x71, 0x71, 0x71,
83 	0x71, 0x71, 0x71, 0x71, 0x71, 0x55, 0x38, 0x1C,
84 	0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38,
85 	0x38, 0x45, 0x55, 0x61, 0x71, 0x71, 0x71, 0x71,
86 	0x71, 0x71, 0x71, 0x71, 0x71, 0x61, 0x55, 0x45,
87 	0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51,
88 	0x51, 0x59, 0x61, 0x69, 0x71, 0x71, 0x71, 0x71,
89 	0x71, 0x71, 0x71, 0x71, 0x71, 0x69, 0x61, 0x59,
90 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
91 	0x00, 0x10, 0x20, 0x30, 0x41, 0x41, 0x41, 0x41,
92 	0x41, 0x41, 0x41, 0x41, 0x41, 0x30, 0x20, 0x10,
93 	0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
94 	0x20, 0x28, 0x30, 0x38, 0x41, 0x41, 0x41, 0x41,
95 	0x41, 0x41, 0x41, 0x41, 0x41, 0x38, 0x30, 0x28,
96 	0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C,
97 	0x3C, 0x30, 0x34, 0x3C, 0x41, 0x41, 0x41, 0x41,
98 	0x41, 0x41, 0x41, 0x41, 0x41, 0x3C, 0x34, 0x30,
99 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
100 };
101 
102 static const unsigned char defaultWPG1PaletteBlue[] = {
103 	0x00, 0x7F, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x7F,
104 	0xC0, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
105 	0x00, 0x14, 0x20, 0x2C, 0x38, 0x45, 0x51, 0x61,
106 	0x71, 0x82, 0x92, 0xA2, 0xB6, 0xCB, 0xE3, 0xFF,
107 	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBE, 0x7D, 0x41,
108 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
109 	0x00, 0x41, 0x7D, 0xBE, 0xFF, 0xFF, 0xFF, 0xFF,
110 	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xDF, 0xBE, 0x9E,
111 	0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D,
112 	0x7D, 0x9E, 0xBE, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF,
113 	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEB, 0xDB, 0xC7,
114 	0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6,
115 	0xB6, 0xC7, 0xDB, 0xEB, 0xFF, 0xFF, 0xFF, 0xFF,
116 	0x71, 0x71, 0x71, 0x71, 0x71, 0x55, 0x38, 0x1C,
117 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
118 	0x00, 0x1C, 0x38, 0x55, 0x71, 0x71, 0x71, 0x71,
119 	0x71, 0x71, 0x71, 0x71, 0x71, 0x61, 0x55, 0x45,
120 	0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38,
121 	0x38, 0x45, 0x55, 0x61, 0x71, 0x71, 0x71, 0x71,
122 	0x71, 0x71, 0x71, 0x71, 0x71, 0x69, 0x61, 0x59,
123 	0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51,
124 	0x51, 0x59, 0x61, 0x69, 0x71, 0x71, 0x71, 0x71,
125 	0x41, 0x41, 0x41, 0x41, 0x41, 0x30, 0x20, 0x10,
126 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
127 	0x00, 0x10, 0x20, 0x30, 0x41, 0x41, 0x41, 0x41,
128 	0x41, 0x41, 0x41, 0x41, 0x41, 0x38, 0x30, 0x28,
129 	0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
130 	0x20, 0x28, 0x30, 0x38, 0x41, 0x41, 0x41, 0x41,
131 	0x41, 0x41, 0x41, 0x41, 0x41, 0x3C, 0x34, 0x30,
132 	0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C,
133 	0x2C, 0x30, 0x34, 0x3C, 0x41, 0x41, 0x41, 0x41,
134 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
135 };
136 
137 
WPG1Parser(WPXInputStream * input,libwpg::WPGPaintInterface * painter)138 WPG1Parser::WPG1Parser(WPXInputStream *input, libwpg::WPGPaintInterface* painter):
139 	WPGXParser(input, painter),
140 	m_recordLength(0), m_recordEnd(0),
141 	m_success(true), m_exit(false), m_graphicsStarted(false),
142 	m_width(0), m_height(0),
143 	m_pen(libwpg::WPGPen()), m_brush(libwpg::WPGBrush())
144 {
145 }
146 
parse()147 bool WPG1Parser::parse()
148 {
149 	typedef void (WPG1Parser::*Method)();
150 
151 	struct RecordHandler
152 	{
153 		int type;
154 		const char *name;
155 		Method handler;
156 	};
157 
158 	static const struct RecordHandler handlers[] =
159 	{
160 		{ 0x01, "Fill Attributes",           &WPG1Parser::handleFillAttributes },
161 		{ 0x02, "Line Attributes",           &WPG1Parser::handleLineAttributes },
162 		{ 0x03, "Marker Atttibutes",         nullptr },
163 		{ 0x04, "Polymarker",                nullptr },
164 		{ 0x05, "Line",                      &WPG1Parser::handleLine },
165 		{ 0x06, "Polyline",                  &WPG1Parser::handlePolyline },
166 		{ 0x07, "Rectangle",                 &WPG1Parser::handleRectangle },
167 		{ 0x08, "Polygon",                   &WPG1Parser::handlePolygon },
168 		{ 0x09, "Ellipse",                   &WPG1Parser::handleEllipse },
169 		{ 0x0a, "Reserved",                  nullptr },
170 		{ 0x0b, "Bitmap (Type 1)",           &WPG1Parser::handleBitmapTypeOne },
171 		{ 0x0c, "Graphics Text (Type 1)",    nullptr },
172 		{ 0x0d, "Grephics Text Attributes",  nullptr },
173 		{ 0x0e, "Colormap",                  &WPG1Parser::handleColormap },
174 		{ 0x0f, "Start WPG",                 &WPG1Parser::handleStartWPG },
175 		{ 0x10, "End WPG",                   &WPG1Parser::handleEndWPG },
176 		{ 0x11, "Postscript Data (Type 1)",  &WPG1Parser::handlePostscriptTypeOne },
177 		{ 0x12, "Output Attributes",         nullptr },
178 		{ 0x13, "Curved Polyline",           &WPG1Parser::handleCurvedPolyline },
179 		{ 0x14, "Bitmap (Type 2)",           &WPG1Parser::handleBitmapTypeTwo },
180 		{ 0x15, "Start Figure",              nullptr },
181 		{ 0x16, "Start Chart",               nullptr },
182 		{ 0x17, "Planperfect Data",          nullptr },
183 		{ 0x18, "Graphics Text (Type 2)",    nullptr },
184 		{ 0x19, "Start WPG (Type 2)",        nullptr },
185 		{ 0x1a, "Graphics Text (Type 3)",    nullptr },
186 		{ 0x1b, "Postscript Data (Type 2)",  &WPG1Parser::handlePostscriptTypeTwo },
187 		{ 0x00, nullptr, nullptr } // end marker
188 	};
189 
190 	// initialization
191 	m_recordLength = 0;
192 	m_recordEnd = 0;
193 	m_success = true;
194 	m_exit = false;
195 	m_graphicsStarted = false;
196 
197 	// default style
198 	m_pen.foreColor = libwpg::WPGColor(0,0,0);
199 	m_pen.backColor = libwpg::WPGColor(0,0,0);
200 	m_pen.width = 0.001;
201 	m_pen.height = 0.001;
202 	m_pen.solid = true;
203 	m_pen.dashArray = libwpg::WPGDashArray();
204 	m_brush.foreColor = libwpg::WPGColor(0,0,0);
205 	m_brush.backColor = libwpg::WPGColor(0,0,0);
206 	resetPalette();
207 
208 	while(!m_input->atEOS())
209 	{
210 #ifdef DEBUG
211 		long recordPos = m_input->tell();
212 #endif
213 		int recordType = readU8();
214 		if (recordType == 0)
215 			break;
216 		m_recordLength = readVariableLengthInteger();
217 		m_recordEnd = m_input->tell() + m_recordLength - 1;
218 
219 		// search function to handler this record
220 		int index = -1;
221 		for(int i = 0; (index < 0) && handlers[i].name; i++)
222 			if(handlers[i].type == recordType)
223 				index = i;
224 
225 		WPG_DEBUG_MSG(("\n"));
226 		if(index < 0)
227 			WPG_DEBUG_MSG(("Unknown record type 0x%02x at %li  size %d\n",
228 				recordType, recordPos, m_recordLength));
229 		else
230 		{
231 			Method recordHandler = handlers[index].handler;
232 			if(!recordHandler)
233 				WPG_DEBUG_MSG(("Record '%s' (ignored) type 0x%02x at %li  size %d\n",
234 					handlers[index].name, recordType, recordPos, m_recordLength));
235 			else
236 			{
237 				WPG_DEBUG_MSG(("Record '%s' type 0x%02x at %li  size %d\n",
238 					handlers[index].name, recordType, recordPos, m_recordLength));
239 
240 				// invoke the handler for this record
241 				(this->*recordHandler)();
242 			}
243 		}
244 
245 		//if(m_input->tell() > m_recordEnd+1)
246 		{
247 			//WPG_DEBUG_MSG(("Record 0x%x consumes more bytes than necessary!\n", recordType));
248 			WPG_DEBUG_MSG(("Current stream position: %li\n", m_input->tell()));
249 		}
250 
251 		if(m_exit) break;
252 
253 		m_input->seek(m_recordEnd+1, WPX_SEEK_SET);
254 	}
255 
256 	if (!m_exit)
257 		handleEndWPG();
258 
259 	return m_success;
260 }
261 
handleStartWPG()262 void WPG1Parser::handleStartWPG()
263 {
264 	if (m_graphicsStarted)
265 	{
266 		handleEndWPG();
267 		return;
268 	}
269 	// unsigned char version = readU8();
270 	// unsigned char bitFlags = readU8();
271 	m_input->seek(2, WPX_SEEK_CUR);
272 	m_width = readU16();
273 	m_height = readU16();
274 
275 	double width = (double)m_width / 1200.0;
276 	double height = (double)m_height / 1200.0;
277 	m_painter->startGraphics(width, height);
278 	m_graphicsStarted = true;
279 
280 	WPG_DEBUG_MSG(("StartWPG\n"));
281 }
282 
handleEndWPG()283 void WPG1Parser::handleEndWPG()
284 {
285 	if (!m_graphicsStarted)
286 		return;
287 	m_painter->endGraphics();
288 	m_exit = true;
289 
290 	WPG_DEBUG_MSG(("EndWPG\n"));
291 }
292 
handleColormap()293 void WPG1Parser::handleColormap()
294 {
295 	if (!m_graphicsStarted)
296 		return;
297 	unsigned startIndex = readU16();
298 	unsigned numEntries = readU16();
299 	if (startIndex > 255 || numEntries > 256 || startIndex + numEntries > 256)
300 		return;
301 
302 	WPG_DEBUG_MSG(("Colormap\n"));
303 	for(unsigned int i = 0; i < numEntries; i++)
304 	{
305 		libwpg::WPGColor color;
306 		color.red = readU8();
307 		color.green = readU8();
308 		color.blue = readU8();
309 		m_colorPalette[startIndex+i] = color;
310 		WPG_DEBUG_MSG(("Index#%d: RGB %d %d %d\n", startIndex+i, color.red, color.green, color.blue));
311 	}
312 }
313 
handleFillAttributes()314 void WPG1Parser::handleFillAttributes()
315 {
316 	if (!m_graphicsStarted)
317 		return;
318 	unsigned char style = readU8();
319 	unsigned char color = readU8();
320 
321 	if(style == 0)
322 		m_brush.style = libwpg::WPGBrush::NoBrush;
323 	if(style == 1)
324 		m_brush.style = libwpg::WPGBrush::Solid;
325 
326 	m_brush.foreColor = m_colorPalette[color];
327 
328 	WPG_DEBUG_MSG(("Fill Attributes\n"));
329 	WPG_DEBUG_MSG(("         Fill style: %d\n", style));
330 	WPG_DEBUG_MSG(("   Fill color index: %d\n", color));
331 }
332 
handleLineAttributes()333 void WPG1Parser::handleLineAttributes()
334 {
335 	if (!m_graphicsStarted)
336 		return;
337 	unsigned char style = readU8();
338 	unsigned char color = readU8();
339 	unsigned int width = readU16();
340 
341 	m_pen.solid = style != 0;
342 	m_pen.foreColor = m_colorPalette[color];
343 	if (!width && m_pen.solid)
344 		m_pen.width = 0.001;
345 	else
346 		m_pen.width = (double)width / 1200.0;
347 
348 	WPG_DEBUG_MSG(("Line Attributes\n"));
349 	WPG_DEBUG_MSG(("         Line style: %d\n", style));
350 	WPG_DEBUG_MSG(("   Line color index: %d\n", color));
351 	WPG_DEBUG_MSG(("         Line width: %d\n", width));
352 }
353 
handleLine()354 void WPG1Parser::handleLine()
355 {
356 	if (!m_graphicsStarted)
357 		return;
358 	int sx = readS16();
359 	int sy = readS16();
360 	int ex = readS16();
361 	int ey = readS16();
362 
363 	libwpg::WPGPointArray points;
364 	points.add(libwpg::WPGPoint((double)sx/1200.0, (double)(m_height-sy)/1200.0));
365 	points.add(libwpg::WPGPoint((double)ex/1200.0, (double)(m_height-ey)/1200.0));
366 
367 	m_painter->setBrush(m_brush);
368 	m_painter->setPen(m_pen);
369 	m_painter->drawPolygon(points, true);
370 
371 	WPG_DEBUG_MSG(("Line\n"));
372 	WPG_DEBUG_MSG(("    Starting point: %d,%d\n", sx, sy));
373 	WPG_DEBUG_MSG(("         End point: %d,%d\n", ex, ey));
374 }
375 
handlePolyline()376 void WPG1Parser::handlePolyline()
377 {
378 	if (!m_graphicsStarted)
379 		return;
380 	unsigned int count = readU16();
381 
382 	libwpg::WPGPointArray points;
383 	for(unsigned int i = 0; i < count; i++ )
384 	{
385 		long x = readS16();
386 		long y = readS16();
387 		points.add(libwpg::WPGPoint((double)x/1200.0, (double)(m_height-y)/1200.0));
388 	}
389 
390 	m_painter->setBrush(libwpg::WPGBrush()); // not filled
391 	m_painter->setPen(m_pen);
392 	m_painter->drawPolygon(points, false);
393 
394 	WPG_DEBUG_MSG(("Polyline\n"));
395 }
396 
handleRectangle()397 void WPG1Parser::handleRectangle()
398 {
399 	if (!m_graphicsStarted)
400 		return;
401 	int x = readS16();
402 	int y = readS16();
403 	int w = readS16();
404 	int h = readS16();
405 
406 	libwpg::WPGRect rect;
407 	rect.x1 = (double)x/1200.0;
408 	// in WPG, we have the coordinate of lower left point, in SVG-ish coordinates we have to get upper left
409 	rect.y1 = (double)(m_height - h - y)/1200.0;
410 	rect.x2 = rect.x1 + (double)w/1200.0;
411 	rect.y2 = rect.y1 + (double)h/1200.0;
412 
413 	m_painter->setBrush(m_brush);
414 	m_painter->setPen(m_pen);
415 	m_painter->drawRectangle(rect, 0, 0);
416 
417 	WPG_DEBUG_MSG(("Line\n"));
418 	WPG_DEBUG_MSG(("    Corner point: %d,%d\n", x, y));
419 	WPG_DEBUG_MSG(("           Width: %d\n", w));
420 	WPG_DEBUG_MSG(("          Height: %d\n", h));
421 }
422 
handlePolygon()423 void WPG1Parser::handlePolygon()
424 {
425 	if (!m_graphicsStarted)
426 		return;
427 	unsigned int count = readU16();
428 
429 	libwpg::WPGPointArray points;
430 	for(unsigned int i = 0; i < count; i++ )
431 	{
432 		long x = readS16();
433 		long y = readS16();
434 		points.add(libwpg::WPGPoint((double)x/1200.0, (double)(m_height-y)/1200.0));
435 	}
436 
437 	m_painter->setBrush(m_brush);
438 	m_painter->setPen(m_pen);
439 	m_painter->drawPolygon(points, true);
440 
441 	WPG_DEBUG_MSG(("Polygon\n"));
442 }
443 
handleEllipse()444 void WPG1Parser::handleEllipse()
445 {
446 	if (!m_graphicsStarted)
447 		return;
448 	int cx = readS16();
449 	int cy = readS16();
450 	int rx = readS16();
451 	int ry = readS16();
452 	readS16();
453 	readS16();
454 	readS16();
455 	readS16();
456 /*
457 	int rotation = readS16();
458 	int beginAngle = readS16();
459 	int endAngle = readS16();
460 	unsigned flags = readU16();
461 */
462 	libwpg::WPGPoint center;
463 	center.x = (double)cx/1200.0;
464 	center.y = (double)(m_height-cy)/1200.0;
465 
466 	double radx = (double)rx/1200.0;
467 	double rady = (double)ry/1200.0;
468 
469 	m_painter->setBrush(m_brush);
470 	m_painter->setPen(m_pen);
471 	m_painter->drawEllipse(center, radx, rady);
472 
473 	WPG_DEBUG_MSG(("Ellipse\n"));
474 	WPG_DEBUG_MSG(("    Center point: %d,%d\n", cx, cy));
475 	WPG_DEBUG_MSG(("        Radius x: %d\n", rx));
476 	WPG_DEBUG_MSG(("        Radius y: %d\n", ry));
477 }
478 
handleCurvedPolyline()479 void WPG1Parser::handleCurvedPolyline()
480 {
481 	if (!m_graphicsStarted)
482 		return;
483 	readU32();
484 	unsigned int count = readU16();
485 	if (!count)
486 		return;
487 	libwpg::WPGPath path;
488 	path.closed = false;
489 	path.framed = true;
490 	path.filled = true;
491 	long xInitial = readS16();
492 	long yInitial = readS16();
493 	path.moveTo(libwpg::WPGPoint((double)xInitial/1200.0, (double)(m_height-yInitial)/1200.0));
494 	for (unsigned i = 1; i < (count-1)/3; i++)
495 	{
496 		long xControl1 = readS16();
497 		long yControl1 = readS16();
498 		long xControl2 = readS16();
499 		long yControl2 = readS16();
500 		long xCoordinate = readS16();
501 		long yCoordinate = readS16();
502 		path.curveTo(libwpg::WPGPoint((double)xControl1/1200.0, (double)(m_height-yControl1)/1200.0),
503 			libwpg::WPGPoint((double)xControl2/1200.0, (double)(m_height-yControl2)/1200.0),
504 			libwpg::WPGPoint((double)xCoordinate/1200.0, (double)(m_height-yCoordinate)/1200.0));
505 	}
506 
507 	m_painter->setBrush(path.closed ? m_brush : libwpg::WPGBrush());
508 	m_painter->setPen(m_pen);
509 	m_painter->drawPath(path);
510 
511 	WPG_DEBUG_MSG(("Curved Polyline\n"));
512 }
513 
decodeRLE(std::vector<unsigned char> & buffer,unsigned width,unsigned height,unsigned depth)514 void WPG1Parser::decodeRLE(std::vector<unsigned char>& buffer, unsigned width, unsigned height, unsigned depth)
515 {
516 	buffer.clear();
517 
518 	// This are the known depth values for WPG1, no point to try to decode others since they are likely to indicate corruption
519 	if (depth != 8 && depth != 4 && depth != 2 && depth != 1)
520 		return;
521 
522 	// round to the next byte
523 	unsigned scanline_width = (width * depth + 7)/8;
524 	unsigned tmpBufferSize = scanline_width * height;
525 	WPG_DEBUG_MSG(("Scanline width: %d\n", scanline_width));
526 	WPG_DEBUG_MSG(("Output size: %d\n", scanline_width * height));
527 
528 	WPG_DEBUG_MSG(("Decoding RLE data\n"));
529 
530 	buffer.reserve(tmpBufferSize);
531  	while (m_input->tell() < m_recordEnd && !m_input->atEOS() && buffer.size() < tmpBufferSize)
532 	{
533 		unsigned char opcode = readU8();
534 
535 		if(opcode & 0x80)
536 		{
537 			// run of byte
538 			int count = (int)(opcode & 0x7f);
539 			unsigned char pixel = (count > 0) ? readU8() : 0xff;
540 			if(count == 0)
541 				count = (int)readU8();
542 			for( ; count ; --count)
543 				buffer.push_back( pixel );
544 		}
545 		else
546 		{
547 			int count = (int)(opcode & 0x7f);
548 			if(count > 0)
549 			{
550 				// literal byte copy
551 				for( ; count ; --count)
552 					buffer.push_back( readU8() );
553 			}
554 			else
555 			{
556 				// copy entire scan line
557 				count = (int)readU8();
558 				if (buffer.size() < scanline_width )
559 				{
560 					WPG_DEBUG_MSG(("Cannot copy the scanline, not enough data %li\n", (long)buffer.size()));
561 					break;
562 				}
563 				unsigned raster_source = buffer.size() - scanline_width;
564 				for( ; count; --count)
565 					for(unsigned r = 0; r < scanline_width ; r++)
566 					{
567 						unsigned char pixel = buffer[raster_source + r];
568 						buffer.push_back( pixel );
569 					}
570 			}
571 		}
572 	}
573 	WPG_DEBUG_MSG(("Finish decoding RLE data\n"));
574 	WPG_DEBUG_MSG(("Buffer length: %li\n", (long)buffer.size()));
575 
576 	while (buffer.size() < tmpBufferSize)
577 		buffer.push_back(0);
578 }
579 
fillPixels(libwpg::WPGBitmap & bitmap,const unsigned char * buffer,unsigned width,unsigned height,unsigned depth)580 void WPG1Parser::fillPixels(libwpg::WPGBitmap& bitmap, const unsigned char* buffer, unsigned width, unsigned height, unsigned depth)
581 {
582 	// sanity
583 	if(!buffer)
584 		return;
585 
586 	if (depth != 8 && depth != 4 && depth != 2 && depth != 1)
587 		return;
588 
589 	// round to the next byte
590 	unsigned scanline_width = (width * depth + 7)/8;
591 
592 	// 1-bit image: black and white
593 	if(depth == 1)
594 	{
595 		libwpg::WPGColor black(0, 0, 0);
596 		libwpg::WPGColor white(255, 255, 255);
597 		for(unsigned y = 0; y < height; y++)
598 		{
599 			const unsigned char* buf = buffer + y * scanline_width;
600 			for(unsigned x = 0; x < width; x++)
601 				if(buf[x/8] & (0x80 >> (x & 7)))
602 					bitmap.setPixel(x, y, white);
603 				else
604 					bitmap.setPixel(x, y, black);
605 		}
606 	}
607 	// 2-bit image: 4-color bitmap (indexed)
608 	else if(depth == 2)
609 	{
610 		unsigned i = 0;
611 		for (unsigned y = 0; y < height; y++)
612 		for (unsigned x = 0; x < width; x++, i++)
613 		{
614 			if ((x==0) && (i % 4 != 0))
615 				i = (i/4 + 1) * 4;
616 			unsigned index = ((buffer[i/4] & (0x03 << 2*(3 - (i % 4)))) >> 2*(3 - (i % 4)));
617 			const libwpg::WPGColor& color = m_colorPalette[index];
618 			bitmap.setPixel(x, y, color);
619 		}
620 	}
621 	// 4 -bit image: 16-colour bitmap (indexed)
622 	else if(depth == 4)
623 	{
624 		unsigned i = 0;
625 		for (unsigned y = 0; y < height; y++)
626 		for (unsigned x = 0; x < width; x++, i++)
627 		{
628 			if ((x==0) && (i % 2 != 0))
629 				i = (i/2 + 1) * 2;
630 			unsigned index = ((buffer[i/2] & (0x0f << 4*(1 - (i % 2)))) >> 4*(1 - (i % 2)));
631 			const libwpg::WPGColor& color = m_colorPalette[index];
632 			bitmap.setPixel(x, y, color);
633 		}
634 	}
635 	// 8-bit image: 256-colour image (indexed)
636 	else if(depth == 8)
637 	{
638 		for(unsigned y = 0; y < height; y++)
639 		{
640 			const unsigned char* buf = buffer + y * scanline_width;
641 			for(unsigned x = 0; x < width; x++)
642 			{
643 				const libwpg::WPGColor& color = m_colorPalette[buf[x]];
644 				bitmap.setPixel(x, y, color);
645 			}
646 		}
647 
648 	}
649 
650 	// debugging only
651 /*	if(buffer && 0)
652 	{
653 		for(unsigned x = 0; x < width; x++)
654 		for(unsigned y = 0; y < height; y++)
655 		{
656 			libwpg::WPGColor color = bitmap.pixel(x,y);
657 			WPG_DEBUG_MSG((" pixel at %d, %d: %3d %3d %3d\n", x, y, color.red, color.green, color.blue));
658 		}
659 	}*/
660 }
661 
handleBitmapTypeOne()662 void WPG1Parser::handleBitmapTypeOne()
663 {
664 	if (!m_graphicsStarted)
665 		return;
666 	int width = readS16();
667 	int height = readS16();
668 	int depth = readS16();
669 	int hres = readS16();
670 	int vres = readS16();
671 
672 	WPG_DEBUG_MSG(("Bitmap\n"));
673 	WPG_DEBUG_MSG(("                Width: %d\n", width));
674 	WPG_DEBUG_MSG(("               Height: %d\n", height));
675 	WPG_DEBUG_MSG(("                Depth: %d\n", depth));
676 	WPG_DEBUG_MSG(("Horizontal resolution: %d\n", hres));
677 	WPG_DEBUG_MSG(("  Vertical resolution: %d\n", vres));
678 
679 	// if this happens, likely corruption, bail out.
680 	if (depth != 1 && depth != 2 && depth != 4 && depth != 8)
681 		return;
682 
683 	// Sanity checks
684 	if(hres <= 0)
685 		hres = 1200;
686 	if(vres <= 0)
687 		vres = 1200;
688 	if (width < 0)
689 		width = 0;
690 	if (height < 0)
691 		height = 0;
692 	if (depth < 0)
693 		depth = 0;
694 
695 	// Bitmap Type 1 does not specify position
696 	// Assume on the corner (0,0)
697 	libwpg::WPGBitmap bitmap(width, height);
698 	bitmap.rect.x1 = 0;
699 	bitmap.rect.y1 = 0;
700 	bitmap.rect.x2 = (double)width/(double)hres;
701 	bitmap.rect.y2 = (double)height/(double)vres;
702 
703 	std::vector<unsigned char> buffer;
704 	decodeRLE(buffer, width, height, depth);
705 	if (!buffer.empty() && buffer.size() == (size_t)((width*depth + 7)/8)*height)
706 	{
707 		fillPixels(bitmap, &buffer[0], width, height, depth);
708 		m_painter->drawBitmap(bitmap, hres, vres);
709 	}
710 }
711 
handleBitmapTypeTwo()712 void WPG1Parser::handleBitmapTypeTwo()
713 {
714 	if (!m_graphicsStarted)
715 		return;
716 	int rotation = readS16();
717 	int x1 = readS16();
718 	int y1 = readS16();
719 	int x2 = readS16();
720 	int y2 = readS16();
721 	int width = readS16();
722 	int height = readS16();
723 	int depth = readS16();
724 	int hres = readS16();
725 	int vres = readS16();
726 
727 	WPG_DEBUG_MSG(("Bitmap\n"));
728 	WPG_DEBUG_MSG(("       Rotation Angle: %d\n", rotation));
729 	WPG_DEBUG_MSG(("      Top left corner: %d,%d\n", x1, y1));
730 	WPG_DEBUG_MSG(("  Bottom right corner: %d,%d\n", x2, y2));
731 	WPG_DEBUG_MSG(("                Width: %d\n", width));
732 	WPG_DEBUG_MSG(("               Height: %d\n", height));
733 	WPG_DEBUG_MSG(("                Depth: %d\n", depth));
734 	WPG_DEBUG_MSG(("Horizontal resolution: %d\n", hres));
735 	WPG_DEBUG_MSG(("  Vertical resolution: %d\n", vres));
736 
737 	// if this happens, likely corruption, bail out.
738 	if (rotation < 0 || rotation > 359)
739 		return;
740 	if (depth != 1 && depth != 2 && depth != 4 && depth != 8)
741 		return;
742 
743 	// Sanity checks
744 	if(hres <= 0)
745 		hres = 1200;
746 	if(vres <= 0)
747 		vres = 1200;
748 	if (width < 0)
749 		width = 0;
750 	if (height < 0)
751 		height = 0;
752 	if (depth < 0)
753 		depth = 0;
754 
755 	y1 = m_height - y1;
756 	y2 = m_height - y2;
757 
758 	long xs1 = (x1 <= x2) ? x1 : x2;
759 	long xs2 = (x1 <= x2) ? x2 : x1;
760 	long ys1 = (y1 <= y2) ? y1 : y2;
761 	long ys2 = (y1 <= y2) ? y2 : y1;
762 	WPG_DEBUG_MSG(("%li %li   %li %li\n", xs1, ys1, xs2, ys2));
763 
764 	libwpg::WPGBitmap bitmap(width, height);
765 	bitmap.rect.x1 = (double)xs1/1200.0;
766 	bitmap.rect.y1 = (double)(ys1)/1200.0;
767 	bitmap.rect.x2 = (double)xs2/1200.0;
768 	bitmap.rect.y2 = (double)(ys2)/1200.0;
769 
770 	std::vector<unsigned char> buffer;
771 	decodeRLE(buffer, width, height, depth);
772 	if (buffer.size() && buffer.size() == (size_t)((width*depth + 7)/8)*height)
773 	{
774 		fillPixels(bitmap, &buffer[0], width, height, depth);
775 		m_painter->drawBitmap(bitmap, hres, vres);
776 	}
777 }
778 
handlePostscriptTypeOne()779 void WPG1Parser::handlePostscriptTypeOne()
780 {
781 	if (!m_graphicsStarted)
782 		return;
783 	long x1 = readS16();
784 	long y1 = readS16();
785 	long x2 = readS16();
786 	long y2 = readS16();
787 	libwpg::WPGBinaryData data;
788 	data.rect.x1 = (double)x1/72.0;
789 	data.rect.y1 = (double)m_height/1200.0 - (double)y1/72.0;
790 	data.rect.x2 = (double)x2/72.0;
791 	data.rect.y2 = (double)m_height/1200.0 - (double)y2/72.0;
792 
793 	data.clear();
794 	while (m_input->tell() <= m_recordEnd)
795 		data.append((char)readU8());
796 	data.mimeType = "application/x-postscript";
797 	if (data.size())
798 		m_painter->drawImageObject(data);
799 }
800 
handlePostscriptTypeTwo()801 void WPG1Parser::handlePostscriptTypeTwo()
802 {
803 	if (!m_graphicsStarted)
804 		return;
805 #ifdef DEBUG
806 	unsigned lengthOfData = readU32();
807 	int rotation = readS16();
808 #else
809 	readU32();
810 	readS16();
811 #endif
812 	int x1 = readS16();
813 	int y1 = readS16();
814 	int x2 = readS16();
815 	int y2 = readS16();
816 
817 	WPG_DEBUG_MSG(("Postscript (Type 2)\n"));
818 	WPG_DEBUG_MSG(("       Length of Data: %d\n", lengthOfData));
819 	WPG_DEBUG_MSG(("       Rotation Angle: %d\n", rotation));
820 	WPG_DEBUG_MSG(("   Bottom left corner: %d,%d\n", x1, y1));
821 	WPG_DEBUG_MSG(("     Top right corner: %d,%d\n", x2, y2));
822 
823 	y1 = m_height - y1;
824 	y2 = m_height - y2;
825 
826 	long xs1 = (x1 <= x2) ? x1 : x2;
827 	long xs2 = (x1 <= x2) ? x2 : x1;
828 	long ys1 = (y1 <= y2) ? y1 : y2;
829 	long ys2 = (y1 <= y2) ? y2 : y1;
830 	WPG_DEBUG_MSG(("%li %li   %li %li\n", xs1, ys1, xs2, ys2));
831 
832 	libwpg::WPGBinaryData data;
833 	data.rect.x1 = (double)xs1/1200.0;
834 	data.rect.y1 = (double)(ys1)/1200.0;
835 	data.rect.x2 = (double)xs2/1200.0;
836 	data.rect.y2 = (double)(ys2)/1200.0;
837 
838 	data.mimeType = "image/x-eps";
839 
840 	m_input->seek(48, WPX_SEEK_CUR);
841 
842 	data.clear();
843 	while (m_input->tell() <= m_recordEnd)
844 		data.append((char)readU8());
845 	if (data.size())
846 		m_painter->drawImageObject(data);
847 }
848 
resetPalette()849 void WPG1Parser::resetPalette()
850 {
851 	m_colorPalette.clear();
852 	for (int i=0; i<256; i++)
853 	{
854 		libwpg::WPGColor color;
855 		color.red = defaultWPG1PaletteRed[i];
856 		color.green = defaultWPG1PaletteGreen[i];
857 		color.blue = defaultWPG1PaletteBlue[i];
858 		m_colorPalette[i] = color;
859 	}
860 }
861 
862