1 /*
2     Ming, an SWF output library
3     Copyright (C) 2002  Opaque Industries - http://www.opaque.net/
4 
5     This library is free software; you can redistribute it and/or
6     modify it under the terms of the GNU Lesser General Public
7     License as published by the Free Software Foundation; either
8     version 2.1 of the License, or (at your option) any later version.
9 
10     This library is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13     Lesser General Public License for more details.
14 
15     You should have received a copy of the GNU Lesser General Public
16     License along with this library; if not, write to the Free Software
17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 */
19 
20 /* $Id$ */
21 
22 #include <stdlib.h>
23 
24 #include "jpeg.h"
25 #include "character.h"
26 #include "input.h"
27 #include "error.h"
28 #include "method.h"
29 #include "libming.h"
30 
31 
32 struct SWFJpegBitmap_s
33 {
34 	struct SWFCharacter_s character;
35 
36 	SWFInput input;
37 	int length;
38 
39 #if TRACK_ALLOCS
40 	/* memory node for garbage collection */
41 	mem_node *gcnode;
42 #endif
43 };
44 
45 struct SWFJpegWithAlpha_s
46 {
47 	struct SWFCharacter_s character;
48 
49 	SWFInput input;	 /* leave these here so that we */
50 	int length;			 /* can cast this to swfJpegBitmap */
51 
52 #if TRACK_ALLOCS
53 	/* memory node for garbage collection */
54 	mem_node *gcnode;
55 #endif
56 	/* ---insert additions here (for casting to swfJpegBitmap) --- */
57 	SWFInput alpha;
58 	int jpegLength;
59 };
60 
61 /* JPEG stream markers: */
62 #define JPEG_MARKER 0xFF
63 
64 /* Start of Image, End of Image */
65 #define JPEG_SOI	0xD8
66 #define JPEG_EOI	0xD9
67 
68 #define JPEG_JFIF 0xE0
69 
70 /* encoding markers, quantization tables and Huffman tables */
71 #define JPEG_QUANT 0xDB
72 #define JPEG_HUFF	 0xC4
73 
74 /* image markers, start of frame and start of scan */
75 #define JPEG_SOF0 0xC0
76 #define JPEG_SOF1 0xC1
77 #define JPEG_SOF2 0xC2
78 #define JPEG_SOS	0xDA
79 
80 #define JPEG_ED		0xED /* app13 */
81 #define JPEG_EE		0xEE /* app14 */
82 #define JPEG_DD		0xDD /* ??? */
83 
84 
85 static int
completeSWFJpegBitmap(SWFBlock block)86 completeSWFJpegBitmap(SWFBlock block)
87 {
88 	return ((SWFJpegBitmap)block)->length;
89 }
90 
91 
92 
93 /* clumsy utility function.. */
94 void
dumpJpegBlock(byte type,SWFInput input,SWFByteOutputMethod method,void * data)95 dumpJpegBlock(byte type,
96 							SWFInput input, SWFByteOutputMethod method, void *data)
97 {
98 	int i, l0, l1, length;
99 
100 	method(JPEG_MARKER, data);
101 	method(type, data);
102 
103 	method((unsigned char)(l0 = SWFInput_getChar(input)), data);
104 	method((unsigned char)(l1 = SWFInput_getChar(input)), data);
105 
106 	length = (l0<<8) + l1 - 2;
107 
108 	for ( i=0; i<length; ++i )
109 		method((unsigned char)SWFInput_getChar(input), data);
110 }
111 
112 
113 int
skipJpegBlock(SWFInput input)114 skipJpegBlock(SWFInput input)
115 {
116 	int length = (SWFInput_getChar(input)<<8) + SWFInput_getChar(input);
117 
118 	SWFInput_seek(input, length-2, SEEK_CUR);
119 
120 	return length;
121 }
122 
123 
124 void
methodWriteJpegFile(SWFInput input,SWFByteOutputMethod method,void * data)125 methodWriteJpegFile(SWFInput input, SWFByteOutputMethod method, void *data)
126 {
127 	int c;
128 
129 	SWFInput_rewind(input);
130 
131 	if ( (c = SWFInput_getChar(input)) != JPEG_MARKER )
132 		SWF_error("Initial Jpeg marker not found!");
133 
134 	if ( (c = SWFInput_getChar(input)) != JPEG_SOI )
135 		SWF_error("Jpeg SOI not found!");
136 
137 	/*
138 	method(JPEG_MARKER, data);
139 	method(JPEG_SOI, data);
140 	method(JPEG_MARKER, data);
141 	method(JPEG_EOI, data);
142 	*/
143 
144 	method(JPEG_MARKER, data);
145 	method(JPEG_SOI, data);
146 
147 	for ( ;; )
148 	{
149 		if ( SWFInput_getChar(input) != JPEG_MARKER )
150 			SWF_error("Jpeg marker not found where expected!");
151 
152 		switch ( c = SWFInput_getChar(input) )
153 		{
154 			case JPEG_EOI:
155 				SWF_error("Unexpected end of Jpeg file (EOI found)!");
156 
157 	/*	case JPEG_JFIF: */
158 			case JPEG_QUANT:
159 			case JPEG_HUFF:
160 			case JPEG_DD:
161 				/* if(!finishedEncoding) */
162 				dumpJpegBlock((unsigned char)c, input, method, data);
163 				/* else
164 					 SWF_error("Encoding tables found in Jpeg image section!"); */
165 				break;
166 
167 			case JPEG_SOF0:
168 			case JPEG_SOF1:
169 			case JPEG_SOF2:
170 				/*
171 				if(!finishedEncoding)
172 				{
173 					finishedEncoding = TRUE;
174 					method(JPEG_MARKER, data);
175 					method(JPEG_EOI, data);
176 					method(JPEG_MARKER, data);
177 					method(JPEG_SOI, data);
178 					method(JPEG_MARKER, data);
179 					method(c, data);
180 				}
181 				*/
182 				dumpJpegBlock((unsigned char)c, input, method, data);
183 				break;
184 
185 			case JPEG_SOS:
186 				/*
187 					if(!finishedEncoding)
188 					SWF_error("Found SOS before SOF in Jpeg file!");
189 				*/
190 				break;
191 
192 			default:
193 				/* dumpJpegBlock(c, input, method, data); */
194 				skipJpegBlock(input);
195 		}
196 
197 		if ( c == JPEG_SOS )
198 			break;
199 
200 		if ( SWFInput_eof(input) )
201 			SWF_error("Unexpected end of Jpeg file (EOF found)!");
202 	}
203 
204 	if ( c != JPEG_SOS )
205 		SWF_error("SOS block not found in Jpeg file!");
206 
207 	/* rest is SOS, dump to end of file */
208 	method(JPEG_MARKER, data);
209 	method((unsigned char)c, data);
210 
211 	while ( (c = SWFInput_getChar(input)) != EOF )
212 		method((unsigned char)c, data);
213 }
214 
215 
216 void
writeSWFJpegBitmapToMethod(SWFBlock block,SWFByteOutputMethod method,void * data)217 writeSWFJpegBitmapToMethod(SWFBlock block, SWFByteOutputMethod method, void *data)
218 {
219 	SWFJpegBitmap jpeg = (SWFJpegBitmap)block;
220 
221 	methodWriteUInt16(CHARACTERID(jpeg), method, data);
222 	methodWriteJpegFile(jpeg->input, method, data);
223 }
224 
225 
226 void
writeSWFJpegWithAlphaToMethod(SWFBlock block,SWFByteOutputMethod method,void * data)227 writeSWFJpegWithAlphaToMethod(SWFBlock block, SWFByteOutputMethod method, void *data)
228 {
229 	SWFJpegWithAlpha jpeg = (SWFJpegWithAlpha)block;
230 	int c;
231 
232 	methodWriteUInt16(CHARACTERID(jpeg), method, data);
233 	methodWriteUInt32(jpeg->jpegLength, method, data);
234 	methodWriteJpegFile(jpeg->input, method, data);
235 
236 	/* now write alpha file.. */
237 
238 	SWFInput_rewind(jpeg->alpha);
239 
240 	while ( (c = SWFInput_getChar(jpeg->alpha)) != EOF )
241 		method((unsigned char)c, data);
242 }
243 
244 
245 void
destroySWFJpegBitmap(SWFJpegBitmap jpegBitmap)246 destroySWFJpegBitmap(SWFJpegBitmap jpegBitmap)
247 {
248 	free(CHARACTER(jpegBitmap)->bounds);
249 #if TRACK_ALLOCS
250 	ming_gc_remove_node(jpegBitmap->gcnode);
251 #endif
252 	free(jpegBitmap);
253 }
254 
255 
256 struct jpegInfo
257 {
258 	int width;
259 	int height;
260 	int length;
261 };
262 
263 static struct jpegInfo*
scanJpegFile(SWFInput input)264 scanJpegFile(SWFInput input)
265 {
266 	int length = 0, l, c;
267 	long pos, end;
268 
269 	struct jpegInfo* info = (struct jpegInfo*)malloc(sizeof(struct jpegInfo));
270 
271 	/* If malloc failed, return NULL to signify this */
272 	if (NULL == info)
273 		return NULL;
274 
275 	/* scan file, get height and width, make sure it looks valid,
276 		 also figure length of block.. */
277 
278 	if ( SWFInput_getChar(input) != JPEG_MARKER )
279 		SWF_error("Initial Jpeg marker not found!");
280 
281 	if ( SWFInput_getChar(input) != JPEG_SOI )
282 		SWF_error("Jpeg SOI not found!");
283 
284 	for ( ;; )
285 	{
286 		if ( SWFInput_getChar(input) != JPEG_MARKER )
287 			SWF_error("Jpeg marker not found where expected!");
288 
289 		switch ( c = SWFInput_getChar(input) )
290 		{
291 			case JPEG_EOI:
292 				SWF_error("Unexpected end of Jpeg file (EOI found)!");
293 
294 	/*	case JPEG_JFIF: */
295 			case JPEG_QUANT:
296 			case JPEG_HUFF:
297 			case JPEG_DD:
298 				/*
299 				if(finishedEncoding)
300 					SWF_error("Encoding tables found in Jpeg image section!");
301 				*/
302 				length += skipJpegBlock(input) + 2;
303 				break;
304 
305 			case JPEG_SOF2:
306 				SWF_error("Only baseline (frame 0) jpegs are supported!");
307 
308 			case JPEG_SOF0:
309 			case JPEG_SOF1:
310 				/*
311 				if ( finishedEncoding )
312 					SWF_error("Found second SOF in Jpeg file!");
313 				else
314 				{
315 					finishedEncoding = TRUE;
316 					length += 4; // end image, start image
317 				}
318 				*/
319 
320 				l = SWFInput_getUInt16_BE(input);
321 				SWFInput_getChar(input); /* precision */
322 				info->height = SWFInput_getUInt16_BE(input);
323 				info->width = SWFInput_getUInt16_BE(input);
324 
325 				length += l + 2;
326 				l -= 7;
327 
328 				SWFInput_seek(input, l, SEEK_CUR);
329 
330 				break;
331 
332 			case JPEG_SOS:
333 				/*
334 					if(!finishedEncoding)
335 					SWF_error("Found SOS before SOF in Jpeg file!");
336 				*/
337 				break;
338 
339 			default:
340 				/* length += */
341 				skipJpegBlock(input); /* + 2 */
342 		}
343 
344 		if ( c == JPEG_SOS )
345 			break;
346 
347 		if ( SWFInput_eof(input) )
348 			SWF_error("Unexpected end of Jpeg file (EOF found)!");
349 	}
350 
351 	if ( c != JPEG_SOS )
352 		SWF_error("SOS block not found in Jpeg file!");
353 
354 	/* rest is SOS, dump to end of file */
355 
356 	length += 2; /* SOS tag */
357 
358 	/* figure out how long the rest of the file is */
359 	pos = SWFInput_tell(input);
360 	SWFInput_seek(input, 0, SEEK_END);
361 	end = SWFInput_tell(input);
362 
363 	length += end - pos;
364 
365 	info->length = length;
366 
367 	return info;
368 }
369 
370 
371 SWFJpegBitmap
newSWFJpegBitmap_fromInput(SWFInput input)372 newSWFJpegBitmap_fromInput(SWFInput input)
373 {
374 	SWFJpegBitmap jpeg;
375 	struct jpegInfo *info;
376 	SWFRect temp_rect;
377 
378 	jpeg = (SWFJpegBitmap) malloc(sizeof(struct SWFJpegBitmap_s));
379 
380 	/* If malloc failed, return NULL to signify this */
381 	if (NULL == jpeg)
382 		return NULL;
383 
384 	SWFCharacterInit((SWFCharacter)jpeg);
385 
386 	CHARACTERID(jpeg) = ++SWF_gNumCharacters;
387 
388 	BLOCK(jpeg)->writeBlock = writeSWFJpegBitmapToMethod;
389 	BLOCK(jpeg)->complete = completeSWFJpegBitmap;
390 	BLOCK(jpeg)->dtor = (destroySWFBlockMethod) destroySWFJpegBitmap;
391 	BLOCK(jpeg)->type = SWF_DEFINEBITSJPEG2;
392 
393 	jpeg->input = input;
394 
395 	info = scanJpegFile(input);
396 
397 	/* If scanJpegFile() failed, return NULL to signify this */
398 	if (NULL == info)
399 	{
400 		free (jpeg);
401 		return NULL;
402 	}
403 
404 	temp_rect = newSWFRect(0, info->width, 0, info->height);
405 
406 	/* If newSWFRect() failed, return NULL to signify this */
407 	if (NULL == temp_rect)
408 	{
409 		free(info);
410 		free(jpeg);
411 		return NULL;
412 	}
413 
414 	CHARACTER(jpeg)->bounds = temp_rect;
415 	jpeg->length = info->length + 4;
416 
417 	free(info);
418 
419 #if TRACK_ALLOCS
420 	jpeg->gcnode = ming_gc_add_node(jpeg, (dtorfunctype) destroySWFBitmap);
421 #endif
422 
423 	return jpeg;
424 }
425 
426 
427 static void
destroySWFJpegBitmap_andInputs(SWFJpegBitmap jpegBitmap)428 destroySWFJpegBitmap_andInputs(SWFJpegBitmap jpegBitmap)
429 {
430 	destroySWFInput(jpegBitmap->input);
431 	destroySWFJpegBitmap(jpegBitmap);
432 }
433 
434 
435 SWFJpegBitmap
newSWFJpegBitmap(FILE * f)436 newSWFJpegBitmap(FILE *f)
437 {
438 	SWFJpegBitmap jpeg = newSWFJpegBitmap_fromInput(newSWFInput_file(f));
439 
440 	/* If newSWFJpegBitmap_fromInput() failed, return NULL to signify this */
441 	if (NULL == jpeg)
442 		return NULL;
443 
444 	BLOCK(jpeg)->dtor = (destroySWFBlockMethod) destroySWFJpegBitmap_andInputs;
445 	return jpeg;
446 }
447 
448 
449 /* f is a jpeg file, alpha is zlib-compressed data */
450 
451 SWFJpegWithAlpha
newSWFJpegWithAlpha_fromInput(SWFInput input,SWFInput alpha)452 newSWFJpegWithAlpha_fromInput(SWFInput input, SWFInput alpha)
453 {
454 	SWFRect temp_rect;
455 	SWFJpegWithAlpha jpeg;
456 	struct jpegInfo *info;
457 	int alen;
458 
459 	jpeg = (SWFJpegWithAlpha) malloc(sizeof(struct SWFJpegWithAlpha_s));
460 
461 	/* If malloc failed, return NULL to signify this */
462 	if (NULL == jpeg)
463 		return NULL;
464 
465 	SWFCharacterInit((SWFCharacter)jpeg);
466 
467 	CHARACTERID(jpeg) = ++SWF_gNumCharacters;
468 
469 	BLOCK(jpeg)->writeBlock = writeSWFJpegWithAlphaToMethod;
470 	BLOCK(jpeg)->complete = completeSWFJpegBitmap; // can use same complete
471 	BLOCK(jpeg)->dtor = (destroySWFBlockMethod) destroySWFJpegBitmap;			 // ditto here
472 	BLOCK(jpeg)->type = SWF_DEFINEBITSJPEG3;
473 
474 	jpeg->input = input;
475 	jpeg->alpha = alpha;
476 
477 	info = scanJpegFile(input);
478 
479 	/* If scanJpegFile() failed, return NULL to signify this */
480 	if (NULL == info)
481 	{
482 		free (jpeg);
483 		return NULL;
484 	}
485 
486 	temp_rect = newSWFRect(0, info->width, 0, info->height);
487 
488 	/* If newSWFRect() failed, return NULL to signify this */
489 	if (NULL == temp_rect)
490 	{
491 		free(info);
492 		free(jpeg);
493 		return NULL;
494 	}
495 
496 	CHARACTER(jpeg)->bounds = temp_rect;
497 	jpeg->jpegLength = info->length + 2; /* ?? */
498 
499 	free(info);
500 
501 	if ( (alen = SWFInput_length(alpha)) == -1 )
502 		SWF_error("couldn't get alpha file length!");
503 
504 	jpeg->length = jpeg->jpegLength + alen + 6;
505 #if TRACK_ALLOCS
506 	jpeg->gcnode = ming_gc_add_node(jpeg, (dtorfunctype) destroySWFBitmap);
507 #endif
508 
509 	return jpeg;
510 }
511 
512 
513 void
destroySWFJpegAlpha_andInputs(SWFJpegWithAlpha jpegWithAlpha)514 destroySWFJpegAlpha_andInputs(SWFJpegWithAlpha jpegWithAlpha)
515 {
516 	destroySWFInput(jpegWithAlpha->input);
517 	destroySWFInput(jpegWithAlpha->alpha);
518 	destroySWFJpegBitmap((SWFJpegBitmap) jpegWithAlpha);
519 }
520 
521 
522 SWFJpegWithAlpha
newSWFJpegWithAlpha(FILE * f,FILE * alpha)523 newSWFJpegWithAlpha(FILE *f, FILE *alpha)
524 {
525 	SWFJpegWithAlpha jpeg =
526 		newSWFJpegWithAlpha_fromInput(newSWFInput_file(f), newSWFInput_file(alpha));
527 
528 	/* If newSWFJpegBitmap_fromInput() failed, return NULL to signify this */
529 	if (NULL == jpeg)
530 		return NULL;
531 
532 	BLOCK(jpeg)->dtor = (destroySWFBlockMethod) destroySWFJpegAlpha_andInputs;
533 	return jpeg;
534 }
535 
536 
537 /*
538  * Local variables:
539  * tab-width: 2
540  * c-basic-offset: 2
541  * End:
542  */
543