xref: /plan9/sys/src/cmd/aux/antiword/imgexam.c (revision 25b329d522281a8cdd35da0dcc08c3fc621059a9)
1 /*
2  * imgexam.c
3  * Copyright (C) 2000-2004 A.J. van Os; Released under GNU GPL
4  *
5  * Description:
6  * Functions to examine image headers
7  *
8  *================================================================
9  * Part of this software is based on:
10  * jpeg2ps - convert JPEG compressed images to PostScript Level 2
11  * Copyright (C) 1994-99 Thomas Merz (tm@muc.de)
12  *================================================================
13  * The credit should go to him, but all the bugs are mine.
14  */
15 
16 #include <stdio.h>
17 #include <string.h>
18 #include <ctype.h>
19 #include "antiword.h"
20 
21 /* BMP compression types */
22 #define BI_RGB		0
23 #define BI_RLE8		1
24 #define BI_RLE4		2
25 
26 /* PNG colortype bits */
27 #define PNG_CB_PALETTE		0x01
28 #define PNG_CB_COLOR		0x02
29 #define PNG_CB_ALPHA		0x04
30 
31 /* Instance signature */
32 #define MSOBI_WMF	0x0216
33 #define MSOBI_EMF	0x03d4
34 #define MSOBI_PICT	0x0542
35 #define MSOBI_PNG	0x06e0
36 #define MSOBI_JPEG	0x046a
37 #define MSOBI_DIB	0x07a8
38 
39 /* The following enum is stolen from the IJG JPEG library */
40 typedef enum {		/* JPEG marker codes			*/
41 	M_SOF0	= 0xc0,	/* baseline DCT				*/
42 	M_SOF1	= 0xc1,	/* extended sequential DCT		*/
43 	M_SOF2	= 0xc2,	/* progressive DCT			*/
44 	M_SOF3	= 0xc3,	/* lossless (sequential)		*/
45 
46 	M_SOF5	= 0xc5,	/* differential sequential DCT		*/
47 	M_SOF6	= 0xc6,	/* differential progressive DCT		*/
48 	M_SOF7	= 0xc7,	/* differential lossless		*/
49 
50 	M_JPG	= 0xc8,	/* JPEG extensions			*/
51 	M_SOF9	= 0xc9,	/* extended sequential DCT		*/
52 	M_SOF10	= 0xca,	/* progressive DCT			*/
53 	M_SOF11	= 0xcb,	/* lossless (sequential)		*/
54 
55 	M_SOF13	= 0xcd,	/* differential sequential DCT		*/
56 	M_SOF14	= 0xce,	/* differential progressive DCT		*/
57 	M_SOF15	= 0xcf,	/* differential lossless		*/
58 
59 	M_DHT	= 0xc4,	/* define Huffman tables		*/
60 
61 	M_DAC	= 0xcc,	/* define arithmetic conditioning table	*/
62 
63 	M_RST0	= 0xd0,	/* restart				*/
64 	M_RST1	= 0xd1,	/* restart				*/
65 	M_RST2	= 0xd2,	/* restart				*/
66 	M_RST3	= 0xd3,	/* restart				*/
67 	M_RST4	= 0xd4,	/* restart				*/
68 	M_RST5	= 0xd5,	/* restart				*/
69 	M_RST6	= 0xd6,	/* restart				*/
70 	M_RST7	= 0xd7,	/* restart				*/
71 
72 	M_SOI	= 0xd8,	/* start of image			*/
73 	M_EOI	= 0xd9,	/* end of image				*/
74 	M_SOS	= 0xda,	/* start of scan			*/
75 	M_DQT	= 0xdb,	/* define quantization tables		*/
76 	M_DNL	= 0xdc,	/* define number of lines		*/
77 	M_DRI	= 0xdd,	/* define restart interval		*/
78 	M_DHP	= 0xde,	/* define hierarchical progression	*/
79 	M_EXP	= 0xdf,	/* expand reference image(s)		*/
80 
81 	M_APP0	= 0xe0,	/* application marker, used for JFIF	*/
82 	M_APP1	= 0xe1,	/* application marker			*/
83 	M_APP2	= 0xe2,	/* application marker			*/
84 	M_APP3	= 0xe3,	/* application marker			*/
85 	M_APP4	= 0xe4,	/* application marker			*/
86 	M_APP5	= 0xe5,	/* application marker			*/
87 	M_APP6	= 0xe6,	/* application marker			*/
88 	M_APP7	= 0xe7,	/* application marker			*/
89 	M_APP8	= 0xe8,	/* application marker			*/
90 	M_APP9	= 0xe9,	/* application marker			*/
91 	M_APP10	= 0xea,	/* application marker			*/
92 	M_APP11	= 0xeb,	/* application marker			*/
93 	M_APP12	= 0xec,	/* application marker			*/
94 	M_APP13	= 0xed,	/* application marker			*/
95 	M_APP14	= 0xee,	/* application marker, used by Adobe	*/
96 	M_APP15	= 0xef,	/* application marker			*/
97 
98 	M_JPG0	= 0xf0,	/* reserved for JPEG extensions		*/
99 	M_JPG13	= 0xfd,	/* reserved for JPEG extensions		*/
100 	M_COM	= 0xfe,	/* comment				*/
101 
102 	M_TEM	= 0x01	/* temporary use			*/
103 } JPEG_MARKER;
104 
105 
106 /*
107  * bFillPaletteDIB - fill the palette part of the imagesdata
108  *
109  * returns TRUE if the images must be a color image, otherwise FALSE;
110  */
111 static BOOL
bFillPaletteDIB(FILE * pFile,imagedata_type * pImg,BOOL bNewFormat)112 bFillPaletteDIB(FILE *pFile, imagedata_type *pImg, BOOL bNewFormat)
113 {
114 	int	iIndex;
115 	BOOL	bIsColorPalette;
116 
117 	fail(pFile == NULL);
118 	fail(pImg == NULL);
119 
120 	if (pImg->uiBitsPerComponent > 8) {
121 		/* No palette, image uses more than 256 colors */
122 		return TRUE;
123 	}
124 
125 	if (pImg->iColorsUsed <= 0) {
126 		/* Not specified, so compute the number of colors used */
127 		pImg->iColorsUsed = 1 << pImg->uiBitsPerComponent;
128 	}
129 
130 	fail(pImg->iColorsUsed > 256);
131 	if (pImg->iColorsUsed > 256) {
132 		pImg->iColorsUsed = 256;
133 	}
134 
135 	bIsColorPalette = FALSE;
136 	for (iIndex = 0; iIndex < pImg->iColorsUsed; iIndex++) {
137 		/* From BGR order to RGB order */
138 		pImg->aucPalette[iIndex][2] = (UCHAR)iNextByte(pFile);
139 		pImg->aucPalette[iIndex][1] = (UCHAR)iNextByte(pFile);
140 		pImg->aucPalette[iIndex][0] = (UCHAR)iNextByte(pFile);
141 		if (bNewFormat) {
142 			(void)iNextByte(pFile);
143 		}
144 		NO_DBG_PRINT_BLOCK(pImg->aucPalette[iIndex], 3);
145 		if (pImg->aucPalette[iIndex][0] !=
146 		     pImg->aucPalette[iIndex][1] ||
147 		    pImg->aucPalette[iIndex][1] !=
148 		     pImg->aucPalette[iIndex][2]) {
149 			bIsColorPalette = TRUE;
150 		}
151 	}
152 
153 	return bIsColorPalette;
154 } /* end of bFillPaletteDIB */
155 
156 /*
157  * bExamineDIB - Examine a DIB header
158  *
159  * return TRUE if successful, otherwise FALSE
160  */
161 static BOOL
bExamineDIB(FILE * pFile,imagedata_type * pImg)162 bExamineDIB(FILE *pFile, imagedata_type *pImg)
163 {
164 	size_t	tHeaderSize;
165 	int	iPlanes, iCompression;
166 
167 	tHeaderSize = (size_t)ulNextLong(pFile);
168 	switch (tHeaderSize) {
169 	case 12:
170 		pImg->iWidth = (int)usNextWord(pFile);
171 		pImg->iHeight = (int)usNextWord(pFile);
172 		iPlanes = (int)usNextWord(pFile);
173 		pImg->uiBitsPerComponent = (UINT)usNextWord(pFile);
174 		iCompression = BI_RGB;
175 		pImg->iColorsUsed = 0;
176 		break;
177 	case 40:
178 	case 64:
179 		pImg->iWidth = (int)ulNextLong(pFile);
180 		pImg->iHeight = (int)ulNextLong(pFile);
181 		iPlanes = (int)usNextWord(pFile);
182 		pImg->uiBitsPerComponent = (UINT)usNextWord(pFile);
183 		iCompression = (int)ulNextLong(pFile);
184 		(void)tSkipBytes(pFile, 12);
185 		pImg->iColorsUsed = (int)ulNextLong(pFile);
186 		(void)tSkipBytes(pFile, tHeaderSize - 36);
187 		break;
188 	default:
189 		DBG_DEC(tHeaderSize);
190 		return FALSE;
191 	}
192 	DBG_DEC(pImg->iWidth);
193 	DBG_DEC(pImg->iHeight);
194 	DBG_DEC(pImg->uiBitsPerComponent);
195 	DBG_DEC(iCompression);
196 	DBG_DEC(pImg->iColorsUsed);
197 
198 	/* Do some sanity checks with the parameters */
199 	if (iPlanes != 1) {
200 		DBG_DEC(iPlanes);
201 		return FALSE;
202 	}
203 	if (pImg->iWidth <= 0 || pImg->iHeight <= 0) {
204 		DBG_DEC(pImg->iWidth);
205 		DBG_DEC(pImg->iHeight);
206 		return FALSE;
207 	}
208 	if (pImg->uiBitsPerComponent != 1 && pImg->uiBitsPerComponent != 4 &&
209 	    pImg->uiBitsPerComponent != 8 && pImg->uiBitsPerComponent != 24) {
210 		DBG_DEC(pImg->uiBitsPerComponent);
211 		return FALSE;
212 	}
213 	if (iCompression != BI_RGB &&
214 	    (pImg->uiBitsPerComponent == 1 || pImg->uiBitsPerComponent == 24)) {
215 		return FALSE;
216 	}
217 	if (iCompression == BI_RLE8 && pImg->uiBitsPerComponent == 4) {
218 		return FALSE;
219 	}
220 	if (iCompression == BI_RLE4 && pImg->uiBitsPerComponent == 8) {
221 		return FALSE;
222 	}
223 
224 	switch (iCompression) {
225 	case BI_RGB:
226 		pImg->eCompression = compression_none;
227 		break;
228 	case BI_RLE4:
229 		pImg->eCompression = compression_rle4;
230 		break;
231 	case BI_RLE8:
232 		pImg->eCompression = compression_rle8;
233 		break;
234 	default:
235 		DBG_DEC(iCompression);
236 		return FALSE;
237 	}
238 
239 	pImg->bColorImage = bFillPaletteDIB(pFile, pImg, tHeaderSize > 12);
240 
241 	if (pImg->uiBitsPerComponent <= 8) {
242 		pImg->iComponents = 1;
243 	} else {
244 		pImg->iComponents = (int)(pImg->uiBitsPerComponent / 8);
245 	}
246 
247 	return TRUE;
248 } /* end of bExamineDIB */
249 
250 /*
251  * iNextMarker - read the next JPEG marker
252  */
253 static int
iNextMarker(FILE * pFile)254 iNextMarker(FILE *pFile)
255 {
256 	int	iMarker;
257 
258 	do {
259 		do {
260 			iMarker = iNextByte(pFile);
261 		} while (iMarker != 0xff && iMarker != EOF);
262 		if (iMarker == EOF) {
263 			return EOF;
264 		}
265 		do {
266 			iMarker = iNextByte(pFile);
267 		} while (iMarker == 0xff);
268 	} while (iMarker == 0x00);			/* repeat if ff/00 */
269 
270 	return iMarker;
271 } /* end of iNextMarker */
272 
273 /*
274  * bExamineJPEG - Examine a JPEG header
275  *
276  * return TRUE if successful, otherwise FALSE
277  */
278 static BOOL
bExamineJPEG(FILE * pFile,imagedata_type * pImg)279 bExamineJPEG(FILE *pFile, imagedata_type *pImg)
280 {
281 	size_t	tLength;
282 	int	iMarker, iIndex;
283 	char	appstring[10];
284 	BOOL	bSOFDone;
285 
286 	tLength = 0;
287 	bSOFDone = FALSE;
288 
289 	/* process JPEG markers */
290 	while (!bSOFDone && (iMarker = iNextMarker(pFile)) != (int)M_EOI) {
291 		switch (iMarker) {
292 		case EOF:
293 			DBG_MSG("Error: unexpected end of JPEG file");
294 			return FALSE;
295 	/* The following are not officially supported in PostScript level 2 */
296 		case M_SOF2:
297 		case M_SOF3:
298 		case M_SOF5:
299 		case M_SOF6:
300 		case M_SOF7:
301 		case M_SOF9:
302 		case M_SOF10:
303 		case M_SOF11:
304 		case M_SOF13:
305 		case M_SOF14:
306 		case M_SOF15:
307 			DBG_HEX(iMarker);
308 			return FALSE;
309 		case M_SOF0:
310 		case M_SOF1:
311 			tLength = (size_t)usNextWordBE(pFile);
312 			pImg->uiBitsPerComponent = (UINT)iNextByte(pFile);
313 			pImg->iHeight = (int)usNextWordBE(pFile);
314 			pImg->iWidth = (int)usNextWordBE(pFile);
315 			pImg->iComponents = iNextByte(pFile);
316 			bSOFDone = TRUE;
317 			break;
318 		case M_APP14:
319 		/*
320 		 * Check for Adobe application marker. It is known (per Adobe's
321 		 * TN5116) to contain the string "Adobe" at the start of the
322 		 * APP14 marker.
323 		 */
324 			tLength = (size_t)usNextWordBE(pFile);
325 			if (tLength < 12) {
326 				(void)tSkipBytes(pFile, tLength - 2);
327 			} else {
328 				for (iIndex = 0; iIndex < 5; iIndex++) {
329 					appstring[iIndex] =
330 							(char)iNextByte(pFile);
331 				}
332 				appstring[5] = '\0';
333 				if (STREQ(appstring, "Adobe")) {
334 					pImg->bAdobe = TRUE;
335 				}
336 				(void)tSkipBytes(pFile, tLength - 7);
337 			}
338 			break;
339 		case M_SOI:		/* ignore markers without parameters */
340 		case M_EOI:
341 		case M_TEM:
342 		case M_RST0:
343 		case M_RST1:
344 		case M_RST2:
345 		case M_RST3:
346 		case M_RST4:
347 		case M_RST5:
348 		case M_RST6:
349 		case M_RST7:
350 			break;
351 		default:		/* skip variable length markers */
352 			tLength = (size_t)usNextWordBE(pFile);
353 			(void)tSkipBytes(pFile, tLength - 2);
354 			break;
355 		}
356 	}
357 
358 	DBG_DEC(pImg->iWidth);
359 	DBG_DEC(pImg->iHeight);
360 	DBG_DEC(pImg->uiBitsPerComponent);
361 	DBG_DEC(pImg->iComponents);
362 
363 	/* Do some sanity checks with the parameters */
364 	if (pImg->iHeight <= 0 ||
365 	    pImg->iWidth <= 0 ||
366 	    pImg->iComponents <= 0) {
367 		DBG_DEC(pImg->iHeight);
368 		DBG_DEC(pImg->iWidth);
369 		DBG_DEC(pImg->iComponents);
370 		return FALSE;
371 	}
372 
373 	/* Some broken JPEG files have this but they print anyway... */
374 	if (pImg->iComponents * 3 + 8 != (int)tLength) {
375 		DBG_MSG("Warning: SOF marker has incorrect length - ignored");
376 	}
377 
378 	if (pImg->uiBitsPerComponent != 8) {
379 		DBG_DEC(pImg->uiBitsPerComponent);
380 		DBG_MSG("Not supported in PostScript level 2");
381 		return FALSE;
382 	}
383 
384 	if (pImg->iComponents != 1 &&
385 	    pImg->iComponents != 3 &&
386 	    pImg->iComponents != 4) {
387 		DBG_DEC(pImg->iComponents);
388 		return FALSE;
389 	}
390 
391 	pImg->bColorImage = pImg->iComponents >= 3;
392 	pImg->iColorsUsed = 0;
393 	pImg->eCompression = compression_jpeg;
394 
395 	return TRUE;
396 } /* end of bExamineJPEG */
397 
398 /*
399  * bFillPalettePNG - fill the palette part of the imagesdata
400  *
401  * returns TRUE if sucessful, otherwise FALSE;
402  */
403 static BOOL
bFillPalettePNG(FILE * pFile,imagedata_type * pImg,size_t tLength)404 bFillPalettePNG(FILE *pFile, imagedata_type *pImg, size_t tLength)
405 {
406 	int	iIndex, iEntries;
407 
408 	fail(pFile == NULL);
409 	fail(pImg == NULL);
410 
411 	if (pImg->uiBitsPerComponent > 8) {
412 		/* No palette, image uses more than 256 colors */
413 		return TRUE;
414 	}
415 
416 	if (!pImg->bColorImage) {
417 		/* Only color images can have a palette */
418 		return FALSE;
419 	}
420 
421 	if (tLength % 3 != 0) {
422 		/* Each palette entry takes three bytes */
423 		DBG_DEC(tLength);
424 		return FALSE;
425 	}
426 
427 	iEntries = (int)(tLength / 3);
428 	DBG_DEC(iEntries);
429 	pImg->iColorsUsed = 1 << pImg->uiBitsPerComponent;
430 	DBG_DEC(pImg->iColorsUsed);
431 
432 	if (iEntries > 256) {
433 		DBG_DEC(iEntries);
434 		return FALSE;
435 	}
436 
437 	for (iIndex = 0; iIndex < iEntries; iIndex++) {
438 		pImg->aucPalette[iIndex][0] = (UCHAR)iNextByte(pFile);
439 		pImg->aucPalette[iIndex][1] = (UCHAR)iNextByte(pFile);
440 		pImg->aucPalette[iIndex][2] = (UCHAR)iNextByte(pFile);
441 		NO_DBG_PRINT_BLOCK(pImg->aucPalette[iIndex], 3);
442 	}
443 	for (;iIndex < pImg->iColorsUsed; iIndex++) {
444 		pImg->aucPalette[iIndex][0] = 0;
445 		pImg->aucPalette[iIndex][1] = 0;
446 		pImg->aucPalette[iIndex][2] = 0;
447 	}
448 
449 	return TRUE;
450 } /* end of bFillPalettePNG */
451 
452 /*
453  * bExaminePNG - Examine a PNG header
454  *
455  * return TRUE if successful, otherwise FALSE
456  */
457 static BOOL
bExaminePNG(FILE * pFile,imagedata_type * pImg)458 bExaminePNG(FILE *pFile, imagedata_type *pImg)
459 {
460 	size_t		tLength;
461 	ULONG		ulLong1, ulLong2, ulName;
462 	int		iIndex, iTmp;
463 	int		iCompressionMethod, iFilterMethod, iInterlaceMethod;
464 	int		iColor, iIncrement;
465 	BOOL		bHasPalette, bHasAlpha;
466 	UCHAR	aucBuf[4];
467 
468 	/* Check signature */
469 	ulLong1 = ulNextLongBE(pFile);
470 	ulLong2 = ulNextLongBE(pFile);
471 	if (ulLong1 != 0x89504e47UL || ulLong2 != 0x0d0a1a0aUL) {
472 		DBG_HEX(ulLong1);
473 		DBG_HEX(ulLong2);
474 		return FALSE;
475 	}
476 
477 	ulName = 0x00;
478 	bHasPalette = FALSE;
479 
480 	/* Examine chunks */
481 	while (ulName != PNG_CN_IEND) {
482 		tLength = (size_t)ulNextLongBE(pFile);
483 		ulName = 0x00;
484 		for (iIndex = 0; iIndex < (int)elementsof(aucBuf); iIndex++) {
485 			aucBuf[iIndex] = (UCHAR)iNextByte(pFile);
486 			if (!isalpha(aucBuf[iIndex])) {
487 				DBG_HEX(aucBuf[iIndex]);
488 				return FALSE;
489 			}
490 			ulName <<= 8;
491 			ulName |= aucBuf[iIndex];
492 		}
493 
494 		switch (ulName) {
495 		case PNG_CN_IHDR:
496 			/* Header chunck */
497 			if (tLength < 13) {
498 				DBG_DEC(tLength);
499 				return FALSE;
500 			}
501 			pImg->iWidth = (int)ulNextLongBE(pFile);
502 			pImg->iHeight = (int)ulNextLongBE(pFile);
503 			pImg->uiBitsPerComponent = (UINT)iNextByte(pFile);
504 			iTmp = iNextByte(pFile);
505 			NO_DBG_HEX(iTmp);
506 			pImg->bColorImage = (iTmp & PNG_CB_COLOR) != 0;
507 			bHasPalette = (iTmp & PNG_CB_PALETTE) != 0;
508 			bHasAlpha = (iTmp & PNG_CB_ALPHA) != 0;
509 			if (bHasPalette && pImg->uiBitsPerComponent > 8) {
510 				/* This should not happen */
511 				return FALSE;
512 			}
513 			pImg->iComponents =
514 				(bHasPalette || !pImg->bColorImage) ? 1 : 3;
515 			if (bHasAlpha) {
516 				pImg->iComponents++;
517 			}
518 			iCompressionMethod = iNextByte(pFile);
519 			if (iCompressionMethod != 0) {
520 				DBG_DEC(iCompressionMethod);
521 				return FALSE;
522 			}
523 			iFilterMethod = iNextByte(pFile);
524 			if (iFilterMethod != 0) {
525 				DBG_DEC(iFilterMethod);
526 				return FALSE;
527 			}
528 			iInterlaceMethod = iNextByte(pFile);
529 			if (iInterlaceMethod != 0) {
530 				DBG_DEC(iInterlaceMethod);
531 				return FALSE;
532 			}
533 			pImg->iColorsUsed = 0;
534 			(void)tSkipBytes(pFile, tLength - 13 + 4);
535 			break;
536 		case PNG_CN_PLTE:
537 			if (!bHasPalette) {
538 				return FALSE;
539 			}
540 			if (!bFillPalettePNG(pFile, pImg, tLength)) {
541 				return FALSE;
542 			}
543 			(void)tSkipBytes(pFile, 4);
544 			break;
545 		default:
546 			(void)tSkipBytes(pFile, tLength + 4);
547 			break;
548 		}
549 	}
550 
551 	DBG_DEC(pImg->iWidth);
552 	DBG_DEC(pImg->iHeight);
553 	DBG_DEC(pImg->uiBitsPerComponent);
554 	DBG_DEC(pImg->iColorsUsed);
555 	DBG_DEC(pImg->iComponents);
556 
557 	/* Do some sanity checks with the parameters */
558 	if (pImg->iWidth <= 0 || pImg->iHeight <= 0) {
559 		return FALSE;
560 	}
561 
562 	if (pImg->uiBitsPerComponent != 1 && pImg->uiBitsPerComponent != 2 &&
563 	    pImg->uiBitsPerComponent != 4 && pImg->uiBitsPerComponent != 8 &&
564 	    pImg->uiBitsPerComponent != 16) {
565 		DBG_DEC(pImg->uiBitsPerComponent);
566 		return  FALSE;
567 	}
568 
569 	if (pImg->iComponents != 1 && pImg->iComponents != 3) {
570 		/* Not supported */
571 		DBG_DEC(pImg->iComponents);
572 		return FALSE;
573 	}
574 
575 	if (pImg->uiBitsPerComponent > 8) {
576 		/* Not supported */
577 		DBG_DEC(pImg->uiBitsPerComponent);
578 		return FALSE;
579 	}
580 
581 	if (pImg->iColorsUsed == 0 &&
582 	    pImg->iComponents == 1 &&
583 	    pImg->uiBitsPerComponent <= 4) {
584 		/*
585 		 * No palette is supplied, but PostScript needs one in these
586 		 * cases, so we add a default palette here
587 		 */
588 		pImg->iColorsUsed = 1 << pImg->uiBitsPerComponent;
589 		iIncrement = 0xff / (pImg->iColorsUsed - 1);
590 		for (iIndex = 0, iColor = 0x00;
591 		     iIndex < pImg->iColorsUsed;
592 		     iIndex++, iColor += iIncrement) {
593 			pImg->aucPalette[iIndex][0] = (UCHAR)iColor;
594 			pImg->aucPalette[iIndex][1] = (UCHAR)iColor;
595 			pImg->aucPalette[iIndex][2] = (UCHAR)iColor;
596 		}
597 		/* Just to be sure */
598 		pImg->bColorImage = FALSE;
599 	}
600 
601 	pImg->eCompression = compression_zlib;
602 
603 	return TRUE;
604 } /* end of bExaminePNG */
605 
606 /*
607  * bExamineWMF - Examine a WMF header
608  *
609  * return TRUE if successful, otherwise FALSE
610  */
611 static BOOL
bExamineWMF(FILE * pFile,imagedata_type * pImg)612 bExamineWMF(FILE *pFile, imagedata_type *pImg)
613 {
614 	ULONG	ulFileSize, ulMaxRecord, ulMagic;
615 	USHORT	usType, usHeaderSize, usVersion, usNoObjects;
616 
617 	usType = usNextWord(pFile);
618 	usHeaderSize = usNextWord(pFile);
619 	ulMagic = ((ULONG)usHeaderSize << 16) | (ULONG)usType;
620 	usVersion = usNextWord(pFile);
621 	ulFileSize = ulNextLong(pFile);
622 	usNoObjects = usNextWord(pFile);
623 	ulMaxRecord = ulNextLong(pFile);
624 
625 	DBG_HEX(ulMagic);
626 	DBG_DEC(usType);
627 	DBG_DEC(usHeaderSize);
628 	DBG_HEX(usVersion);
629 	DBG_DEC(ulFileSize);
630 	DBG_DEC(usNoObjects);
631 	DBG_DEC(ulMaxRecord);
632 
633 	return FALSE;
634 } /* end of bExamineWMF */
635 
636 #if !defined(__riscos)
637 /*
638  * vImage2Papersize - make sure the image fits on the paper
639  *
640  * This function should not be needed if Word would do a proper job
641  */
642 static void
vImage2Papersize(imagedata_type * pImg)643 vImage2Papersize(imagedata_type *pImg)
644 {
645 	static int	iNetPageHeight = -1;
646 	static int	iNetPageWidth = -1;
647 	options_type	tOptions;
648         double  dVerFactor, dHorFactor, dFactor;
649 
650 	DBG_MSG("vImage2Papersize");
651 
652 	fail(pImg == NULL);
653 
654 	if (iNetPageHeight < 0 || iNetPageWidth < 0) {
655 		/* Get the page dimensions from the options */
656 		vGetOptions(&tOptions);
657 		/* Add 999 to err on the save side */
658 		iNetPageHeight = tOptions.iPageHeight -
659 				(lDrawUnits2MilliPoints(
660 					PS_TOP_MARGIN + PS_BOTTOM_MARGIN) +
661 					999) / 1000;
662 		iNetPageWidth = tOptions.iPageWidth -
663 				(lDrawUnits2MilliPoints(
664 					PS_LEFT_MARGIN + PS_RIGHT_MARGIN) +
665 					999) / 1000;
666 		DBG_DEC(iNetPageHeight);
667 		DBG_DEC(iNetPageWidth);
668 	}
669 
670 	if (pImg->iVerSizeScaled < iNetPageHeight &&
671 	    pImg->iHorSizeScaled < iNetPageWidth) {
672 		/* The image fits on the paper */
673 		return;
674 	}
675 
676 	dVerFactor = (double)iNetPageHeight / (double)pImg->iVerSizeScaled;
677 	dHorFactor = (double)iNetPageWidth / (double)pImg->iHorSizeScaled;
678         dFactor = min(dVerFactor, dHorFactor);
679         DBG_FLT(dFactor);
680         /* Round down, just to be on the save side */
681         pImg->iVerSizeScaled = (int)(pImg->iVerSizeScaled * dFactor);
682         pImg->iHorSizeScaled = (int)(pImg->iHorSizeScaled * dFactor);
683 } /* end of vImage2Papersize */
684 #endif /* !__riscos */
685 
686 /*
687  * tFind6Image - skip until the image is found
688  *
689  * Find the image in Word 6/7 files
690  *
691  * returns the new position when a image is found, otherwise -1
692  */
693 static size_t
tFind6Image(FILE * pFile,size_t tPosition,size_t tLength,imagetype_enum * peImageType)694 tFind6Image(FILE *pFile, size_t tPosition, size_t tLength,
695 	imagetype_enum *peImageType)
696 {
697 	ULONG	ulMarker;
698 	size_t	tRecordLength, tToSkip;
699 	USHORT	usMarker;
700 
701 	fail(pFile == NULL);
702 	fail(peImageType == NULL);
703 
704 	*peImageType = imagetype_is_unknown;
705 	if (tPosition + 18 >= tLength) {
706 		return (size_t)-1;
707 	}
708 
709 	ulMarker = ulNextLong(pFile);
710 	if (ulMarker != 0x00090001) {
711 		DBG_HEX(ulMarker);
712 		return (size_t)-1;
713 	}
714 	usMarker = usNextWord(pFile);
715 	if (usMarker != 0x0300) {
716 		DBG_HEX(usMarker);
717 		return (size_t)-1;
718 	}
719 	(void)tSkipBytes(pFile, 10);
720 	usMarker = usNextWord(pFile);
721 	if (usMarker != 0x0000) {
722 		DBG_HEX(usMarker);
723 		return (size_t)-1;
724 	}
725 	tPosition += 18;
726 
727 	while (tPosition + 6 <= tLength) {
728 		tRecordLength = (size_t)ulNextLong(pFile);
729 		usMarker = usNextWord(pFile);
730 		tPosition += 6;
731 		NO_DBG_DEC(tRecordLength);
732 		NO_DBG_HEX(usMarker);
733 		switch (usMarker) {
734 		case 0x0000:
735 			DBG_HEX(ulGetDataOffset(pFile));
736 			return (size_t)-1;
737 		case 0x0b41:
738 			DBG_MSG("DIB");
739 			*peImageType = imagetype_is_dib;
740 			tPosition += tSkipBytes(pFile, 20);
741 			return tPosition;
742 		case 0x0f43:
743 			DBG_MSG("DIB");
744 			*peImageType = imagetype_is_dib;
745 			tPosition += tSkipBytes(pFile, 22);
746 			return tPosition;
747 		default:
748 			if (tRecordLength < 3) {
749 				break;
750 			}
751 			if (tRecordLength > SIZE_T_MAX / 2) {
752 				/*
753 				 * No need to compute the number of bytes
754 				 * to skip
755 				 */
756 				DBG_DEC(tRecordLength);
757 				DBG_HEX(tRecordLength);
758 				DBG_FIXME();
759 				return (size_t)-1;
760 			}
761 			tToSkip = tRecordLength * 2 - 6;
762 			if (tToSkip > tLength - tPosition) {
763 				/* You can't skip this number of bytes */
764 				DBG_DEC(tToSkip);
765 				DBG_DEC(tLength - tPosition);
766 				return (size_t)-1;
767 			}
768 			tPosition += tSkipBytes(pFile, tToSkip);
769 			break;
770 		}
771 	}
772 
773 	return (size_t)-1;
774 } /* end of tFind6Image */
775 
776 /*
777  * tFind8Image - skip until the image is found
778  *
779  * Find the image in Word 8/9/10 files
780  *
781  * returns the new position when a image is found, otherwise -1
782  */
783 static size_t
tFind8Image(FILE * pFile,size_t tPosition,size_t tLength,imagetype_enum * peImageType)784 tFind8Image(FILE *pFile, size_t tPosition, size_t tLength,
785 	imagetype_enum *peImageType)
786 {
787 	size_t	tRecordLength, tNameLen;
788 	USHORT	usRecordVersion, usRecordType, usRecordInstance;
789 	USHORT	usTmp;
790 
791 	fail(pFile == NULL);
792 	fail(peImageType == NULL);
793 
794 	*peImageType = imagetype_is_unknown;
795 	while (tPosition + 8 <= tLength) {
796 		usTmp = usNextWord(pFile);
797 		usRecordVersion = usTmp & 0x000f;
798 		usRecordInstance = usTmp >> 4;
799 		usRecordType = usNextWord(pFile);
800 		tRecordLength = (size_t)ulNextLong(pFile);
801 		tPosition += 8;
802 		NO_DBG_HEX(usRecordVersion);
803 		NO_DBG_HEX(usRecordInstance);
804 		NO_DBG_HEX(usRecordType);
805 		NO_DBG_DEC(tRecordLength);
806 		switch (usRecordType) {
807 		case 0xf000: case 0xf001: case 0xf002: case 0xf003:
808 		case 0xf004: case 0xf005:
809 			break;
810 		case 0xf007:
811 			tPosition += tSkipBytes(pFile, 33);
812 			tNameLen = (size_t)iNextByte(pFile);
813 			tPosition++;
814 			DBG_DEC_C(tNameLen != 0, tNameLen);
815 			tPosition += tSkipBytes(pFile, 2 + tNameLen * 2);
816 			break;
817 		case 0xf008:
818 			tPosition += tSkipBytes(pFile, 8);
819 			break;
820 		case 0xf009:
821 			tPosition += tSkipBytes(pFile, 16);
822 			break;
823 		case 0xf006: case 0xf00a: case 0xf00b: case 0xf00d:
824 		case 0xf00e: case 0xf00f: case 0xf010: case 0xf011:
825 		case 0xf122:
826 			tPosition += tSkipBytes(pFile, tRecordLength);
827 			break;
828 		case 0xf01a:
829 			DBG_MSG("EMF");
830 			*peImageType = imagetype_is_emf;
831 			tPosition += tSkipBytes(pFile, 50);
832 			if ((usRecordInstance ^ MSOBI_EMF) == 1) {
833 				tPosition += tSkipBytes(pFile, 16);
834 			}
835 			return tPosition;
836 		case 0xf01b:
837 			DBG_MSG("WMF");
838 			*peImageType = imagetype_is_wmf;
839 			tPosition += tSkipBytes(pFile, 50);
840 			if ((usRecordInstance ^ MSOBI_WMF) == 1) {
841 				tPosition += tSkipBytes(pFile, 16);
842 			}
843 			return tPosition;
844 		case 0xf01c:
845 			DBG_MSG("PICT");
846 			*peImageType = imagetype_is_pict;
847 			tPosition += tSkipBytes(pFile, 50);
848 			if ((usRecordInstance ^ MSOBI_PICT) == 1) {
849 				tPosition += tSkipBytes(pFile, 16);
850 			}
851 			return tPosition;
852 		case 0xf01d:
853 			DBG_MSG("JPEG");
854 			*peImageType = imagetype_is_jpeg;
855 			tPosition += tSkipBytes(pFile, 17);
856 			if ((usRecordInstance ^ MSOBI_JPEG) == 1) {
857 				tPosition += tSkipBytes(pFile, 16);
858 			}
859 			return tPosition;
860 		case 0xf01e:
861 			DBG_MSG("PNG");
862 			*peImageType = imagetype_is_png;
863 			tPosition += tSkipBytes(pFile, 17);
864 			if ((usRecordInstance ^ MSOBI_PNG) == 1) {
865 				tPosition += tSkipBytes(pFile, 16);
866 			}
867 			return tPosition;
868 		case 0xf01f:
869 			DBG_MSG("DIB");
870 			/* DIB is a BMP minus its 14 byte header */
871 			*peImageType = imagetype_is_dib;
872 			tPosition += tSkipBytes(pFile, 17);
873 			if ((usRecordInstance ^ MSOBI_DIB) == 1) {
874 				tPosition += tSkipBytes(pFile, 16);
875 			}
876 			return tPosition;
877 		case 0xf00c:
878 		default:
879 			DBG_HEX(usRecordType);
880 			DBG_DEC_C(tRecordLength % 4 != 0, tRecordLength);
881 			DBG_FIXME();
882 			return (size_t)-1;
883 		}
884 	}
885 
886 	return (size_t)-1;
887 } /* end of tFind8Image */
888 
889 /*
890  * eExamineImage - Examine the image
891  *
892  * Returns an indication of the amount of information found
893  */
894 image_info_enum
eExamineImage(FILE * pFile,ULONG ulFileOffsetImage,imagedata_type * pImg)895 eExamineImage(FILE *pFile, ULONG ulFileOffsetImage, imagedata_type *pImg)
896 {
897 	long	lTmp;
898 	size_t	tWordHeaderLen, tLength, tPos;
899 	int	iType, iHorSize, iVerSize;
900 	USHORT	usHorScalingFactor, usVerScalingFactor;
901 
902 	if (ulFileOffsetImage == FC_INVALID) {
903 		return image_no_information;
904 	}
905 	DBG_HEX(ulFileOffsetImage);
906 
907 	if (!bSetDataOffset(pFile, ulFileOffsetImage)) {
908 		return image_no_information;
909 	}
910 
911 	tLength = (size_t)ulNextLong(pFile);
912 	DBG_DEC(tLength);
913 	if (tLength < 46) {
914 		/* Smaller than the smallest known header */
915 		DBG_FIXME();
916 		return image_no_information;
917 	}
918 	tWordHeaderLen = (size_t)usNextWord(pFile);
919 	DBG_DEC(tWordHeaderLen);
920 	fail(tWordHeaderLen != 46 &&
921 		tWordHeaderLen != 58 &&
922 		tWordHeaderLen != 68);
923 
924 	if (tLength < tWordHeaderLen) {
925 		/* Smaller than the current header */
926 		return image_no_information;
927 	}
928 	iType = (int)usNextWord(pFile);
929 	DBG_DEC(iType);
930 	(void)tSkipBytes(pFile, 28 - 8);
931 
932 	lTmp = lTwips2MilliPoints(usNextWord(pFile));
933 	iHorSize = (int)(lTmp / 1000);
934 	if (lTmp % 1000 != 0) {
935 		iHorSize++;
936 	}
937 	DBG_DEC(iHorSize);
938 	lTmp = lTwips2MilliPoints(usNextWord(pFile));
939 	iVerSize = (int)(lTmp / 1000);
940 	if (lTmp % 1000 != 0) {
941 		iVerSize++;
942 	}
943 	DBG_DEC(iVerSize);
944 
945 	usHorScalingFactor = usNextWord(pFile);
946 	DBG_DEC(usHorScalingFactor);
947 	usVerScalingFactor = usNextWord(pFile);
948 	DBG_DEC(usVerScalingFactor);
949 
950 	/* Sanity checks */
951 	lTmp = (long)iHorSize * (long)usHorScalingFactor;
952 	if (lTmp < 2835) {
953 		/* This image would be less than 1 millimeter wide */
954 		DBG_DEC(lTmp);
955 		return image_no_information;
956 	}
957 	lTmp = (long)iVerSize * (long)usVerScalingFactor;
958 	if (lTmp < 2835) {
959 		/* This image would be less than 1 millimeter high */
960 		DBG_DEC(lTmp);
961 		return image_no_information;
962 	}
963 
964 	/* Skip the rest of the header */
965 	(void)tSkipBytes(pFile, tWordHeaderLen - 36);
966 	tPos = tWordHeaderLen;
967 
968 	(void)memset(pImg, 0, sizeof(*pImg));
969 
970 	switch (iType) {
971 	case   7:
972 	case   8:
973 		tPos = tFind6Image(pFile, tPos, tLength, &pImg->eImageType);
974 		if (tPos == (size_t)-1) {
975 			/* No image found */
976 			return image_no_information;
977 		}
978 		DBG_HEX(tPos);
979 		break;
980 	case  94:	/* Word 6/7, no image just a pathname */
981 		pImg->eImageType = imagetype_is_external;
982 		DBG_HEX(ulFileOffsetImage + tPos);
983 		break;
984 	case 100:
985 		tPos = tFind8Image(pFile, tPos, tLength, &pImg->eImageType);
986 		if (tPos == (size_t)-1) {
987 			/* No image found */
988 			return image_no_information;
989 		}
990 		DBG_HEX(tPos);
991 		break;
992 	case 102:	/* Word 8/9/10, no image just a pathname or URL */
993 		pImg->eImageType = imagetype_is_external;
994 		DBG_HEX(ulFileOffsetImage + tPos);
995 		break;
996 	default:
997 		DBG_DEC(iType);
998 		DBG_HEX(ulFileOffsetImage + tPos);
999 		DBG_FIXME();
1000 		return image_no_information;
1001 	}
1002 
1003 	/* Minimal information is now available */
1004 	pImg->tLength = tLength;
1005 	pImg->tPosition = tPos;
1006 	pImg->iHorSizeScaled =
1007 		(int)(((long)iHorSize * (long)usHorScalingFactor + 500) / 1000);
1008 	pImg->iVerSizeScaled =
1009 		(int)(((long)iVerSize * (long)usVerScalingFactor + 500) / 1000);
1010 #if !defined(__riscos)
1011 	vImage2Papersize(pImg);
1012 #endif /* !__riscos */
1013 
1014 	/* Image type specific examinations */
1015 	switch (pImg->eImageType) {
1016 	case imagetype_is_dib:
1017 		if (bExamineDIB(pFile, pImg)) {
1018 			return image_full_information;
1019 		}
1020 		return image_minimal_information;
1021 	case imagetype_is_jpeg:
1022 		if (bExamineJPEG(pFile, pImg)) {
1023 			return image_full_information;
1024 		}
1025 		return image_minimal_information;
1026 	case imagetype_is_png:
1027 		if (bExaminePNG(pFile, pImg)) {
1028 			return image_full_information;
1029 		}
1030 		return image_minimal_information;
1031 	case imagetype_is_wmf:
1032 		if (bExamineWMF(pFile, pImg)) {
1033 			return image_full_information;
1034 		}
1035 		return image_minimal_information;
1036 	case imagetype_is_emf:
1037 	case imagetype_is_pict:
1038 	case imagetype_is_external:
1039 		return image_minimal_information;
1040 	case imagetype_is_unknown:
1041 	default:
1042 		return image_no_information;
1043 	}
1044 } /* end of eExamineImage */
1045