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