]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/aux/antiword/imgexam.c
exec(2): fix prototypes
[plan9front.git] / sys / src / cmd / aux / antiword / imgexam.c
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 */