Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/feature_unix/sys/src/cmd/aux/antiword/imgexam.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
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
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
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
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
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
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
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
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
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
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
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 */