examples/PIPS/antiword/src/imgexam.c

00001 /*
00002  * imgexam.c
00003  * Copyright (C) 2000-2004 A.J. van Os; Released under GNU GPL
00004  *
00005  * Description:
00006  * Functions to examine image headers
00007  *
00008  *================================================================
00009  * Part of this software is based on:
00010  * jpeg2ps - convert JPEG compressed images to PostScript Level 2
00011  * Copyright (C) 1994-99 Thomas Merz ([email protected])
00012  *================================================================
00013  * The credit should go to him, but all the bugs are mine.
00014  */
00015 
00016 #include <stdio.h>
00017 #include <string.h>
00018 #include <ctype.h>
00019 #include "antiword.h"
00020 
00021 /* BMP compression types */
00022 #define BI_RGB          0
00023 #define BI_RLE8         1
00024 #define BI_RLE4         2
00025 
00026 /* PNG colortype bits */
00027 #define PNG_CB_PALETTE          0x01
00028 #define PNG_CB_COLOR            0x02
00029 #define PNG_CB_ALPHA            0x04
00030 
00031 /* Instance signature */
00032 #define MSOBI_WMF       0x0216
00033 #define MSOBI_EMF       0x03d4
00034 #define MSOBI_PICT      0x0542
00035 #define MSOBI_PNG       0x06e0
00036 #define MSOBI_JPEG      0x046a
00037 #define MSOBI_DIB       0x07a8
00038 
00039 /* The following enum is stolen from the IJG JPEG library */
00040 typedef enum {          /* JPEG marker codes                    */
00041         M_SOF0  = 0xc0, /* baseline DCT                         */
00042         M_SOF1  = 0xc1, /* extended sequential DCT              */
00043         M_SOF2  = 0xc2, /* progressive DCT                      */
00044         M_SOF3  = 0xc3, /* lossless (sequential)                */
00045 
00046         M_SOF5  = 0xc5, /* differential sequential DCT          */
00047         M_SOF6  = 0xc6, /* differential progressive DCT         */
00048         M_SOF7  = 0xc7, /* differential lossless                */
00049 
00050         M_JPG   = 0xc8, /* JPEG extensions                      */
00051         M_SOF9  = 0xc9, /* extended sequential DCT              */
00052         M_SOF10 = 0xca, /* progressive DCT                      */
00053         M_SOF11 = 0xcb, /* lossless (sequential)                */
00054 
00055         M_SOF13 = 0xcd, /* differential sequential DCT          */
00056         M_SOF14 = 0xce, /* differential progressive DCT         */
00057         M_SOF15 = 0xcf, /* differential lossless                */
00058 
00059         M_DHT   = 0xc4, /* define Huffman tables                */
00060 
00061         M_DAC   = 0xcc, /* define arithmetic conditioning table */
00062 
00063         M_RST0  = 0xd0, /* restart                              */
00064         M_RST1  = 0xd1, /* restart                              */
00065         M_RST2  = 0xd2, /* restart                              */
00066         M_RST3  = 0xd3, /* restart                              */
00067         M_RST4  = 0xd4, /* restart                              */
00068         M_RST5  = 0xd5, /* restart                              */
00069         M_RST6  = 0xd6, /* restart                              */
00070         M_RST7  = 0xd7, /* restart                              */
00071 
00072         M_SOI   = 0xd8, /* start of image                       */
00073         M_EOI   = 0xd9, /* end of image                         */
00074         M_SOS   = 0xda, /* start of scan                        */
00075         M_DQT   = 0xdb, /* define quantization tables           */
00076         M_DNL   = 0xdc, /* define number of lines               */
00077         M_DRI   = 0xdd, /* define restart interval              */
00078         M_DHP   = 0xde, /* define hierarchical progression      */
00079         M_EXP   = 0xdf, /* expand reference image(s)            */
00080 
00081         M_APP0  = 0xe0, /* application marker, used for JFIF    */
00082         M_APP1  = 0xe1, /* application marker                   */
00083         M_APP2  = 0xe2, /* application marker                   */
00084         M_APP3  = 0xe3, /* application marker                   */
00085         M_APP4  = 0xe4, /* application marker                   */
00086         M_APP5  = 0xe5, /* application marker                   */
00087         M_APP6  = 0xe6, /* application marker                   */
00088         M_APP7  = 0xe7, /* application marker                   */
00089         M_APP8  = 0xe8, /* application marker                   */
00090         M_APP9  = 0xe9, /* application marker                   */
00091         M_APP10 = 0xea, /* application marker                   */
00092         M_APP11 = 0xeb, /* application marker                   */
00093         M_APP12 = 0xec, /* application marker                   */
00094         M_APP13 = 0xed, /* application marker                   */
00095         M_APP14 = 0xee, /* application marker, used by Adobe    */
00096         M_APP15 = 0xef, /* application marker                   */
00097 
00098         M_JPG0  = 0xf0, /* reserved for JPEG extensions         */
00099         M_JPG13 = 0xfd, /* reserved for JPEG extensions         */
00100         M_COM   = 0xfe, /* comment                              */
00101 
00102         M_TEM   = 0x01  /* temporary use                        */
00103 } JPEG_MARKER;
00104 
00105 
00106 /*
00107  * bFillPaletteDIB - fill the palette part of the imagesdata
00108  *
00109  * returns TRUE if the images must be a color image, otherwise FALSE;
00110  */
00111 static BOOL
00112 bFillPaletteDIB(FILE *pFile, imagedata_type *pImg, BOOL bNewFormat)
00113 {
00114         int     iIndex;
00115         BOOL    bIsColorPalette;
00116 
00117         fail(pFile == NULL);
00118         fail(pImg == NULL);
00119 
00120         if (pImg->uiBitsPerComponent > 8) {
00121                 /* No palette, image uses more than 256 colors */
00122                 return TRUE;
00123         }
00124 
00125         if (pImg->iColorsUsed <= 0) {
00126                 /* Not specified, so compute the number of colors used */
00127                 pImg->iColorsUsed = 1 << pImg->uiBitsPerComponent;
00128         }
00129 
00130         fail(pImg->iColorsUsed > 256);
00131         if (pImg->iColorsUsed > 256) {
00132                 pImg->iColorsUsed = 256;
00133         }
00134 
00135         bIsColorPalette = FALSE;
00136         for (iIndex = 0; iIndex < pImg->iColorsUsed; iIndex++) {
00137                 /* From BGR order to RGB order */
00138                 pImg->aucPalette[iIndex][2] = (UCHAR)iNextByte(pFile);
00139                 pImg->aucPalette[iIndex][1] = (UCHAR)iNextByte(pFile);
00140                 pImg->aucPalette[iIndex][0] = (UCHAR)iNextByte(pFile);
00141                 if (bNewFormat) {
00142                         (void)iNextByte(pFile);
00143                 }
00144                 NO_DBG_PRINT_BLOCK(pImg->aucPalette[iIndex], 3);
00145                 if (pImg->aucPalette[iIndex][0] !=
00146                      pImg->aucPalette[iIndex][1] ||
00147                     pImg->aucPalette[iIndex][1] !=
00148                      pImg->aucPalette[iIndex][2]) {
00149                         bIsColorPalette = TRUE;
00150                 }
00151         }
00152 
00153         return bIsColorPalette;
00154 } /* end of bFillPaletteDIB */
00155 
00156 /*
00157  * bExamineDIB - Examine a DIB header
00158  *
00159  * return TRUE if successful, otherwise FALSE
00160  */
00161 static BOOL
00162 bExamineDIB(FILE *pFile, imagedata_type *pImg)
00163 {
00164         size_t  tHeaderSize;
00165         int     iPlanes, iCompression;
00166 
00167         tHeaderSize = (size_t)ulNextLong(pFile);
00168         switch (tHeaderSize) {
00169         case 12:
00170                 pImg->iWidth = (int)usNextWord(pFile);
00171                 pImg->iHeight = (int)usNextWord(pFile);
00172                 iPlanes = (int)usNextWord(pFile);
00173                 pImg->uiBitsPerComponent = (UINT)usNextWord(pFile);
00174                 iCompression = BI_RGB;
00175                 pImg->iColorsUsed = 0;
00176                 break;
00177         case 40:
00178         case 64:
00179                 pImg->iWidth = (int)ulNextLong(pFile);
00180                 pImg->iHeight = (int)ulNextLong(pFile);
00181                 iPlanes = (int)usNextWord(pFile);
00182                 pImg->uiBitsPerComponent = (UINT)usNextWord(pFile);
00183                 iCompression = (int)ulNextLong(pFile);
00184                 (void)tSkipBytes(pFile, 12);
00185                 pImg->iColorsUsed = (int)ulNextLong(pFile);
00186                 (void)tSkipBytes(pFile, tHeaderSize - 36);
00187                 break;
00188         default:
00189                 DBG_DEC(tHeaderSize);
00190                 return FALSE;
00191         }
00192         DBG_DEC(pImg->iWidth);
00193         DBG_DEC(pImg->iHeight);
00194         DBG_DEC(pImg->uiBitsPerComponent);
00195         DBG_DEC(iCompression);
00196         DBG_DEC(pImg->iColorsUsed);
00197 
00198         /* Do some sanity checks with the parameters */
00199         if (iPlanes != 1) {
00200                 DBG_DEC(iPlanes);
00201                 return FALSE;
00202         }
00203         if (pImg->iWidth <= 0 || pImg->iHeight <= 0) {
00204                 DBG_DEC(pImg->iWidth);
00205                 DBG_DEC(pImg->iHeight);
00206                 return FALSE;
00207         }
00208         if (pImg->uiBitsPerComponent != 1 && pImg->uiBitsPerComponent != 4 &&
00209             pImg->uiBitsPerComponent != 8 && pImg->uiBitsPerComponent != 24) {
00210                 DBG_DEC(pImg->uiBitsPerComponent);
00211                 return FALSE;
00212         }
00213         if (iCompression != BI_RGB &&
00214             (pImg->uiBitsPerComponent == 1 || pImg->uiBitsPerComponent == 24)) {
00215                 return FALSE;
00216         }
00217         if (iCompression == BI_RLE8 && pImg->uiBitsPerComponent == 4) {
00218                 return FALSE;
00219         }
00220         if (iCompression == BI_RLE4 && pImg->uiBitsPerComponent == 8) {
00221                 return FALSE;
00222         }
00223 
00224         switch (iCompression) {
00225         case BI_RGB:
00226                 pImg->eCompression = compression_none;
00227                 break;
00228         case BI_RLE4:
00229                 pImg->eCompression = compression_rle4;
00230                 break;
00231         case BI_RLE8:
00232                 pImg->eCompression = compression_rle8;
00233                 break;
00234         default:
00235                 DBG_DEC(iCompression);
00236                 return FALSE;
00237         }
00238 
00239         pImg->bColorImage = bFillPaletteDIB(pFile, pImg, tHeaderSize > 12);
00240 
00241         if (pImg->uiBitsPerComponent <= 8) {
00242                 pImg->iComponents = 1;
00243         } else {
00244                 pImg->iComponents = (int)(pImg->uiBitsPerComponent / 8);
00245         }
00246 
00247         return TRUE;
00248 } /* end of bExamineDIB */
00249 
00250 /*
00251  * iNextMarker - read the next JPEG marker
00252  */
00253 static int
00254 iNextMarker(FILE *pFile)
00255 {
00256         int     iMarker;
00257 
00258         do {
00259                 do {
00260                         iMarker = iNextByte(pFile);
00261                 } while (iMarker != 0xff && iMarker != EOF);
00262                 if (iMarker == EOF) {
00263                         return EOF;
00264                 }
00265                 do {
00266                         iMarker = iNextByte(pFile);
00267                 } while (iMarker == 0xff);
00268         } while (iMarker == 0x00);                      /* repeat if ff/00 */
00269 
00270         return iMarker;
00271 } /* end of iNextMarker */
00272 
00273 /*
00274  * bExamineJPEG - Examine a JPEG header
00275  *
00276  * return TRUE if successful, otherwise FALSE
00277  */
00278 static BOOL
00279 bExamineJPEG(FILE *pFile, imagedata_type *pImg)
00280 {
00281         size_t  tLength;
00282         int     iMarker, iIndex;
00283         char    appstring[10];
00284         BOOL    bSOFDone;
00285 
00286         tLength = 0;
00287         bSOFDone = FALSE;
00288 
00289         /* process JPEG markers */
00290         while (!bSOFDone && (iMarker = iNextMarker(pFile)) != (int)M_EOI) {
00291                 switch (iMarker) {
00292                 case EOF:
00293                         DBG_MSG("Error: unexpected end of JPEG file");
00294                         return FALSE;
00295         /* The following are not officially supported in PostScript level 2 */
00296                 case M_SOF2:
00297                 case M_SOF3:
00298                 case M_SOF5:
00299                 case M_SOF6:
00300                 case M_SOF7:
00301                 case M_SOF9:
00302                 case M_SOF10:
00303                 case M_SOF11:
00304                 case M_SOF13:
00305                 case M_SOF14:
00306                 case M_SOF15:
00307                         DBG_HEX(iMarker);
00308                         return FALSE;
00309                 case M_SOF0:
00310                 case M_SOF1:
00311                         tLength = (size_t)usNextWordBE(pFile);
00312                         pImg->uiBitsPerComponent = (UINT)iNextByte(pFile);
00313                         pImg->iHeight = (int)usNextWordBE(pFile);
00314                         pImg->iWidth = (int)usNextWordBE(pFile);
00315                         pImg->iComponents = iNextByte(pFile);
00316                         bSOFDone = TRUE;
00317                         break;
00318                 case M_APP14:
00319                 /*
00320                  * Check for Adobe application marker. It is known (per Adobe's
00321                  * TN5116) to contain the string "Adobe" at the start of the
00322                  * APP14 marker.
00323                  */
00324                         tLength = (size_t)usNextWordBE(pFile);
00325                         if (tLength < 12) {
00326                                 (void)tSkipBytes(pFile, tLength - 2);
00327                         } else {
00328                                 for (iIndex = 0; iIndex < 5; iIndex++) {
00329                                         appstring[iIndex] =
00330                                                         (char)iNextByte(pFile);
00331                                 }
00332                                 appstring[5] = '\0';
00333                                 if (STREQ(appstring, "Adobe")) {
00334                                         pImg->bAdobe = TRUE;
00335                                 }
00336                                 (void)tSkipBytes(pFile, tLength - 7);
00337                         }
00338                         break;
00339                 case M_SOI:             /* ignore markers without parameters */
00340                 case M_EOI:
00341                 case M_TEM:
00342                 case M_RST0:
00343                 case M_RST1:
00344                 case M_RST2:
00345                 case M_RST3:
00346                 case M_RST4:
00347                 case M_RST5:
00348                 case M_RST6:
00349                 case M_RST7:
00350                         break;
00351                 default:                /* skip variable length markers */
00352                         tLength = (size_t)usNextWordBE(pFile);
00353                         (void)tSkipBytes(pFile, tLength - 2);
00354                         break;
00355                 }
00356         }
00357 
00358         DBG_DEC(pImg->iWidth);
00359         DBG_DEC(pImg->iHeight);
00360         DBG_DEC(pImg->uiBitsPerComponent);
00361         DBG_DEC(pImg->iComponents);
00362 
00363         /* Do some sanity checks with the parameters */
00364         if (pImg->iHeight <= 0 ||
00365             pImg->iWidth <= 0 ||
00366             pImg->iComponents <= 0) {
00367                 DBG_DEC(pImg->iHeight);
00368                 DBG_DEC(pImg->iWidth);
00369                 DBG_DEC(pImg->iComponents);
00370                 return FALSE;
00371         }
00372 
00373         /* Some broken JPEG files have this but they print anyway... */
00374         if (pImg->iComponents * 3 + 8 != (int)tLength) {
00375                 DBG_MSG("Warning: SOF marker has incorrect length - ignored");
00376         }
00377 
00378         if (pImg->uiBitsPerComponent != 8) {
00379                 DBG_DEC(pImg->uiBitsPerComponent);
00380                 DBG_MSG("Not supported in PostScript level 2");
00381                 return FALSE;
00382         }
00383 
00384         if (pImg->iComponents != 1 &&
00385             pImg->iComponents != 3 &&
00386             pImg->iComponents != 4) {
00387                 DBG_DEC(pImg->iComponents);
00388                 return FALSE;
00389         }
00390 
00391         pImg->bColorImage = pImg->iComponents >= 3;
00392         pImg->iColorsUsed = 0;
00393         pImg->eCompression = compression_jpeg;
00394 
00395         return TRUE;
00396 } /* end of bExamineJPEG */
00397 
00398 /*
00399  * bFillPalettePNG - fill the palette part of the imagesdata
00400  *
00401  * returns TRUE if sucessful, otherwise FALSE;
00402  */
00403 static BOOL
00404 bFillPalettePNG(FILE *pFile, imagedata_type *pImg, size_t tLength)
00405 {
00406         int     iIndex, iEntries;
00407 
00408         fail(pFile == NULL);
00409         fail(pImg == NULL);
00410 
00411         if (pImg->uiBitsPerComponent > 8) {
00412                 /* No palette, image uses more than 256 colors */
00413                 return TRUE;
00414         }
00415 
00416         if (!pImg->bColorImage) {
00417                 /* Only color images can have a palette */
00418                 return FALSE;
00419         }
00420 
00421         if (tLength % 3 != 0) {
00422                 /* Each palette entry takes three bytes */
00423                 DBG_DEC(tLength);
00424                 return FALSE;
00425         }
00426 
00427         iEntries = (int)(tLength / 3);
00428         DBG_DEC(iEntries);
00429         pImg->iColorsUsed = 1 << pImg->uiBitsPerComponent;
00430         DBG_DEC(pImg->iColorsUsed);
00431 
00432         if (iEntries > 256) {
00433                 DBG_DEC(iEntries);
00434                 return FALSE;
00435         }
00436 
00437         for (iIndex = 0; iIndex < iEntries; iIndex++) {
00438                 pImg->aucPalette[iIndex][0] = (UCHAR)iNextByte(pFile);
00439                 pImg->aucPalette[iIndex][1] = (UCHAR)iNextByte(pFile);
00440                 pImg->aucPalette[iIndex][2] = (UCHAR)iNextByte(pFile);
00441                 NO_DBG_PRINT_BLOCK(pImg->aucPalette[iIndex], 3);
00442         }
00443         for (;iIndex < pImg->iColorsUsed; iIndex++) {
00444                 pImg->aucPalette[iIndex][0] = 0;
00445                 pImg->aucPalette[iIndex][1] = 0;
00446                 pImg->aucPalette[iIndex][2] = 0;
00447         }
00448 
00449         return TRUE;
00450 } /* end of bFillPalettePNG */
00451 
00452 /*
00453  * bExaminePNG - Examine a PNG header
00454  *
00455  * return TRUE if successful, otherwise FALSE
00456  */
00457 static BOOL
00458 bExaminePNG(FILE *pFile, imagedata_type *pImg)
00459 {
00460         size_t          tLength;
00461         ULONG           ulLong1, ulLong2, ulName;
00462         int             iIndex, iTmp;
00463         int             iCompressionMethod, iFilterMethod, iInterlaceMethod;
00464         int             iColor, iIncrement;
00465         BOOL            bHasPalette, bHasAlpha;
00466         UCHAR   aucBuf[4];
00467 
00468         /* Check signature */
00469         ulLong1 = ulNextLongBE(pFile);
00470         ulLong2 = ulNextLongBE(pFile);
00471         if (ulLong1 != 0x89504e47UL || ulLong2 != 0x0d0a1a0aUL) {
00472                 DBG_HEX(ulLong1);
00473                 DBG_HEX(ulLong2);
00474                 return FALSE;
00475         }
00476 
00477         ulName = 0x00;
00478         bHasPalette = FALSE;
00479 
00480         /* Examine chunks */
00481         while (ulName != PNG_CN_IEND) {
00482                 tLength = (size_t)ulNextLongBE(pFile);
00483                 ulName = 0x00;
00484                 for (iIndex = 0; iIndex < (int)elementsof(aucBuf); iIndex++) {
00485                         aucBuf[iIndex] = (UCHAR)iNextByte(pFile);
00486                         if (!isalpha(aucBuf[iIndex])) {
00487                                 DBG_HEX(aucBuf[iIndex]);
00488                                 return FALSE;
00489                         }
00490                         ulName <<= 8;
00491                         ulName |= aucBuf[iIndex];
00492                 }
00493 
00494                 switch (ulName) {
00495                 case PNG_CN_IHDR:
00496                         /* Header chunck */
00497                         if (tLength < 13) {
00498                                 DBG_DEC(tLength);
00499                                 return FALSE;
00500                         }
00501                         pImg->iWidth = (int)ulNextLongBE(pFile);
00502                         pImg->iHeight = (int)ulNextLongBE(pFile);
00503                         pImg->uiBitsPerComponent = (UINT)iNextByte(pFile);
00504                         iTmp = iNextByte(pFile);
00505                         NO_DBG_HEX(iTmp);
00506                         pImg->bColorImage = (iTmp & PNG_CB_COLOR) != 0;
00507                         bHasPalette = (iTmp & PNG_CB_PALETTE) != 0;
00508                         bHasAlpha = (iTmp & PNG_CB_ALPHA) != 0;
00509                         if (bHasPalette && pImg->uiBitsPerComponent > 8) {
00510                                 /* This should not happen */
00511                                 return FALSE;
00512                         }
00513                         pImg->iComponents =
00514                                 (bHasPalette || !pImg->bColorImage) ? 1 : 3;
00515                         if (bHasAlpha) {
00516                                 pImg->iComponents++;
00517                         }
00518                         iCompressionMethod = iNextByte(pFile);
00519                         if (iCompressionMethod != 0) {
00520                                 DBG_DEC(iCompressionMethod);
00521                                 return FALSE;
00522                         }
00523                         iFilterMethod = iNextByte(pFile);
00524                         if (iFilterMethod != 0) {
00525                                 DBG_DEC(iFilterMethod);
00526                                 return FALSE;
00527                         }
00528                         iInterlaceMethod = iNextByte(pFile);
00529                         if (iInterlaceMethod != 0) {
00530                                 DBG_DEC(iInterlaceMethod);
00531                                 return FALSE;
00532                         }
00533                         pImg->iColorsUsed = 0;
00534                         (void)tSkipBytes(pFile, tLength - 13 + 4);
00535                         break;
00536                 case PNG_CN_PLTE:
00537                         if (!bHasPalette) {
00538                                 return FALSE;
00539                         }
00540                         if (!bFillPalettePNG(pFile, pImg, tLength)) {
00541                                 return FALSE;
00542                         }
00543                         (void)tSkipBytes(pFile, 4);
00544                         break;
00545                 default:
00546                         (void)tSkipBytes(pFile, tLength + 4);
00547                         break;
00548                 }
00549         }
00550 
00551         DBG_DEC(pImg->iWidth);
00552         DBG_DEC(pImg->iHeight);
00553         DBG_DEC(pImg->uiBitsPerComponent);
00554         DBG_DEC(pImg->iColorsUsed);
00555         DBG_DEC(pImg->iComponents);
00556 
00557         /* Do some sanity checks with the parameters */
00558         if (pImg->iWidth <= 0 || pImg->iHeight <= 0) {
00559                 return FALSE;
00560         }
00561 
00562         if (pImg->uiBitsPerComponent != 1 && pImg->uiBitsPerComponent != 2 &&
00563             pImg->uiBitsPerComponent != 4 && pImg->uiBitsPerComponent != 8 &&
00564             pImg->uiBitsPerComponent != 16) {
00565                 DBG_DEC(pImg->uiBitsPerComponent);
00566                 return  FALSE;
00567         }
00568 
00569         if (pImg->iComponents != 1 && pImg->iComponents != 3) {
00570                 /* Not supported */
00571                 DBG_DEC(pImg->iComponents);
00572                 return FALSE;
00573         }
00574 
00575         if (pImg->uiBitsPerComponent > 8) {
00576                 /* Not supported */
00577                 DBG_DEC(pImg->uiBitsPerComponent);
00578                 return FALSE;
00579         }
00580 
00581         if (pImg->iColorsUsed == 0 &&
00582             pImg->iComponents == 1 &&
00583             pImg->uiBitsPerComponent <= 4) {
00584                 /*
00585                  * No palette is supplied, but PostScript needs one in these
00586                  * cases, so we add a default palette here
00587                  */
00588                 pImg->iColorsUsed = 1 << pImg->uiBitsPerComponent;
00589                 iIncrement = 0xff / (pImg->iColorsUsed - 1);
00590                 for (iIndex = 0, iColor = 0x00;
00591                      iIndex < pImg->iColorsUsed;
00592                      iIndex++, iColor += iIncrement) {
00593                         pImg->aucPalette[iIndex][0] = (UCHAR)iColor;
00594                         pImg->aucPalette[iIndex][1] = (UCHAR)iColor;
00595                         pImg->aucPalette[iIndex][2] = (UCHAR)iColor;
00596                 }
00597                 /* Just to be sure */
00598                 pImg->bColorImage = FALSE;
00599         }
00600 
00601         pImg->eCompression = compression_zlib;
00602 
00603         return TRUE;
00604 } /* end of bExaminePNG */
00605 
00606 /*
00607  * bExamineWMF - Examine a WMF header
00608  *
00609  * return TRUE if successful, otherwise FALSE
00610  */
00611 static BOOL
00612 bExamineWMF(FILE *pFile, imagedata_type *pImg)
00613 {
00614         ULONG   ulFileSize, ulMaxRecord, ulMagic;
00615         USHORT  usType, usHeaderSize, usVersion, usNoObjects;
00616 
00617         usType = usNextWord(pFile);
00618         usHeaderSize = usNextWord(pFile);
00619         ulMagic = ((ULONG)usHeaderSize << 16) | (ULONG)usType;
00620         usVersion = usNextWord(pFile);
00621         ulFileSize = ulNextLong(pFile);
00622         usNoObjects = usNextWord(pFile);
00623         ulMaxRecord = ulNextLong(pFile);
00624 
00625         DBG_HEX(ulMagic);
00626         DBG_DEC(usType);
00627         DBG_DEC(usHeaderSize);
00628         DBG_HEX(usVersion);
00629         DBG_DEC(ulFileSize);
00630         DBG_DEC(usNoObjects);
00631         DBG_DEC(ulMaxRecord);
00632 
00633         return FALSE;
00634 } /* end of bExamineWMF */
00635 
00636 #if !defined(__riscos)
00637 /*
00638  * vImage2Papersize - make sure the image fits on the paper
00639  *
00640  * This function should not be needed if Word would do a proper job
00641  */
00642 static void
00643 vImage2Papersize(imagedata_type *pImg)
00644 {
00645         static int      iNetPageHeight = -1;
00646         static int      iNetPageWidth = -1;
00647         options_type    tOptions;
00648         double  dVerFactor, dHorFactor, dFactor;
00649 
00650         DBG_MSG("vImage2Papersize");
00651 
00652         fail(pImg == NULL);
00653 
00654         if (iNetPageHeight < 0 || iNetPageWidth < 0) {
00655                 /* Get the page dimensions from the options */
00656                 vGetOptions(&tOptions);
00657                 /* Add 999 to err on the save side */
00658                 iNetPageHeight = tOptions.iPageHeight -
00659                                 (lDrawUnits2MilliPoints(
00660                                         PS_TOP_MARGIN + PS_BOTTOM_MARGIN) +
00661                                         999) / 1000;
00662                 iNetPageWidth = tOptions.iPageWidth -
00663                                 (lDrawUnits2MilliPoints(
00664                                         PS_LEFT_MARGIN + PS_RIGHT_MARGIN) +
00665                                         999) / 1000;
00666                 DBG_DEC(iNetPageHeight);
00667                 DBG_DEC(iNetPageWidth);
00668         }
00669 
00670         if (pImg->iVerSizeScaled < iNetPageHeight &&
00671             pImg->iHorSizeScaled < iNetPageWidth) {
00672                 /* The image fits on the paper */
00673                 return;
00674         }
00675 
00676         dVerFactor = (double)iNetPageHeight / (double)pImg->iVerSizeScaled;
00677         dHorFactor = (double)iNetPageWidth / (double)pImg->iHorSizeScaled;
00678         dFactor = min(dVerFactor, dHorFactor);
00679         DBG_FLT(dFactor);
00680         /* Round down, just to be on the save side */
00681         pImg->iVerSizeScaled = (int)(pImg->iVerSizeScaled * dFactor);
00682         pImg->iHorSizeScaled = (int)(pImg->iHorSizeScaled * dFactor);
00683 } /* end of vImage2Papersize */
00684 #endif /* !__riscos */
00685 
00686 /*
00687  * tFind6Image - skip until the image is found
00688  *
00689  * Find the image in Word 6/7 files
00690  *
00691  * returns the new position when a image is found, otherwise -1
00692  */
00693 static size_t
00694 tFind6Image(FILE *pFile, size_t tPosition, size_t tLength,
00695         imagetype_enum *peImageType)
00696 {
00697         ULONG   ulMarker;
00698         size_t  tRecordLength, tToSkip;
00699         USHORT  usMarker;
00700 
00701         fail(pFile == NULL);
00702         fail(peImageType == NULL);
00703 
00704         *peImageType = imagetype_is_unknown;
00705         if (tPosition + 18 >= tLength) {
00706                 return (size_t)-1;
00707         }
00708 
00709         ulMarker = ulNextLong(pFile);
00710         if (ulMarker != 0x00090001) {
00711                 DBG_HEX(ulMarker);
00712                 return (size_t)-1;
00713         }
00714         usMarker = usNextWord(pFile);
00715         if (usMarker != 0x0300) {
00716                 DBG_HEX(usMarker);
00717                 return (size_t)-1;
00718         }
00719         (void)tSkipBytes(pFile, 10);
00720         usMarker = usNextWord(pFile);
00721         if (usMarker != 0x0000) {
00722                 DBG_HEX(usMarker);
00723                 return (size_t)-1;
00724         }
00725         tPosition += 18;
00726 
00727         while (tPosition + 6 <= tLength) {
00728                 tRecordLength = (size_t)ulNextLong(pFile);
00729                 usMarker = usNextWord(pFile);
00730                 tPosition += 6;
00731                 NO_DBG_DEC(tRecordLength);
00732                 NO_DBG_HEX(usMarker);
00733                 switch (usMarker) {
00734                 case 0x0000:
00735                         DBG_HEX(ulGetDataOffset(pFile));
00736                         return (size_t)-1;
00737                 case 0x0b41:
00738                         DBG_MSG("DIB");
00739                         *peImageType = imagetype_is_dib;
00740                         tPosition += tSkipBytes(pFile, 20);
00741                         return tPosition;
00742                 case 0x0f43:
00743                         DBG_MSG("DIB");
00744                         *peImageType = imagetype_is_dib;
00745                         tPosition += tSkipBytes(pFile, 22);
00746                         return tPosition;
00747                 default:
00748                         if (tRecordLength < 3) {
00749                                 break;
00750                         }
00751                         if (tRecordLength > SIZE_T_MAX / 2) {
00752                                 /*
00753                                  * No need to compute the number of bytes
00754                                  * to skip
00755                                  */
00756                                 DBG_DEC(tRecordLength);
00757                                 DBG_HEX(tRecordLength);
00758                                 DBG_FIXME();
00759                                 return (size_t)-1;
00760                         }
00761                         tToSkip = tRecordLength * 2 - 6;
00762                         if (tToSkip > tLength - tPosition) {
00763                                 /* You can't skip this number of bytes */
00764                                 DBG_DEC(tToSkip);
00765                                 DBG_DEC(tLength - tPosition);
00766                                 return (size_t)-1;
00767                         }
00768                         tPosition += tSkipBytes(pFile, tToSkip);
00769                         break;
00770                 }
00771         }
00772 
00773         return (size_t)-1;
00774 } /* end of tFind6Image */
00775 
00776 /*
00777  * tFind8Image - skip until the image is found
00778  *
00779  * Find the image in Word 8/9/10 files
00780  *
00781  * returns the new position when a image is found, otherwise -1
00782  */
00783 static size_t
00784 tFind8Image(FILE *pFile, size_t tPosition, size_t tLength,
00785         imagetype_enum *peImageType)
00786 {
00787         size_t  tRecordLength, tNameLen;
00788         USHORT  usRecordVersion, usRecordType, usRecordInstance;
00789         USHORT  usTmp;
00790 
00791         fail(pFile == NULL);
00792         fail(peImageType == NULL);
00793 
00794         *peImageType = imagetype_is_unknown;
00795         while (tPosition + 8 <= tLength) {
00796                 usTmp = usNextWord(pFile);
00797                 usRecordVersion = usTmp & 0x000f;
00798                 usRecordInstance = usTmp >> 4;
00799                 usRecordType = usNextWord(pFile);
00800                 tRecordLength = (size_t)ulNextLong(pFile);
00801                 tPosition += 8;
00802                 NO_DBG_HEX(usRecordVersion);
00803                 NO_DBG_HEX(usRecordInstance);
00804                 NO_DBG_HEX(usRecordType);
00805                 NO_DBG_DEC(tRecordLength);
00806                 switch (usRecordType) {
00807                 case 0xf000: case 0xf001: case 0xf002: case 0xf003:
00808                 case 0xf004: case 0xf005:
00809                         break;
00810                 case 0xf007:
00811                         tPosition += tSkipBytes(pFile, 33);
00812                         tNameLen = (size_t)iNextByte(pFile);
00813                         tPosition++;
00814                         DBG_DEC_C(tNameLen != 0, tNameLen);
00815                         tPosition += tSkipBytes(pFile, 2 + tNameLen * 2);
00816                         break;
00817                 case 0xf008:
00818                         tPosition += tSkipBytes(pFile, 8);
00819                         break;
00820                 case 0xf009:
00821                         tPosition += tSkipBytes(pFile, 16);
00822                         break;
00823                 case 0xf006: case 0xf00a: case 0xf00b: case 0xf00d:
00824                 case 0xf00e: case 0xf00f: case 0xf010: case 0xf011:
00825                 case 0xf122:
00826                         tPosition += tSkipBytes(pFile, tRecordLength);
00827                         break;
00828                 case 0xf01a:
00829                         DBG_MSG("EMF");
00830                         *peImageType = imagetype_is_emf;
00831                         tPosition += tSkipBytes(pFile, 50);
00832                         if ((usRecordInstance ^ MSOBI_EMF) == 1) {
00833                                 tPosition += tSkipBytes(pFile, 16);
00834                         }
00835                         return tPosition;
00836                 case 0xf01b:
00837                         DBG_MSG("WMF");
00838                         *peImageType = imagetype_is_wmf;
00839                         tPosition += tSkipBytes(pFile, 50);
00840                         if ((usRecordInstance ^ MSOBI_WMF) == 1) {
00841                                 tPosition += tSkipBytes(pFile, 16);
00842                         }
00843                         return tPosition;
00844                 case 0xf01c:
00845                         DBG_MSG("PICT");
00846                         *peImageType = imagetype_is_pict;
00847                         tPosition += tSkipBytes(pFile, 50);
00848                         if ((usRecordInstance ^ MSOBI_PICT) == 1) {
00849                                 tPosition += tSkipBytes(pFile, 16);
00850                         }
00851                         return tPosition;
00852                 case 0xf01d:
00853                         DBG_MSG("JPEG");
00854                         *peImageType = imagetype_is_jpeg;
00855                         tPosition += tSkipBytes(pFile, 17);
00856                         if ((usRecordInstance ^ MSOBI_JPEG) == 1) {
00857                                 tPosition += tSkipBytes(pFile, 16);
00858                         }
00859                         return tPosition;
00860                 case 0xf01e:
00861                         DBG_MSG("PNG");
00862                         *peImageType = imagetype_is_png;
00863                         tPosition += tSkipBytes(pFile, 17);
00864                         if ((usRecordInstance ^ MSOBI_PNG) == 1) {
00865                                 tPosition += tSkipBytes(pFile, 16);
00866                         }
00867                         return tPosition;
00868                 case 0xf01f:
00869                         DBG_MSG("DIB");
00870                         /* DIB is a BMP minus its 14 byte header */
00871                         *peImageType = imagetype_is_dib;
00872                         tPosition += tSkipBytes(pFile, 17);
00873                         if ((usRecordInstance ^ MSOBI_DIB) == 1) {
00874                                 tPosition += tSkipBytes(pFile, 16);
00875                         }
00876                         return tPosition;
00877                 case 0xf00c:
00878                 default:
00879                         DBG_HEX(usRecordType);
00880                         DBG_DEC_C(tRecordLength % 4 != 0, tRecordLength);
00881                         DBG_FIXME();
00882                         return (size_t)-1;
00883                 }
00884         }
00885 
00886         return (size_t)-1;
00887 } /* end of tFind8Image */
00888 
00889 /*
00890  * eExamineImage - Examine the image
00891  *
00892  * Returns an indication of the amount of information found
00893  */
00894 image_info_enum
00895 eExamineImage(FILE *pFile, ULONG ulFileOffsetImage, imagedata_type *pImg)
00896 {
00897         long    lTmp;
00898         size_t  tWordHeaderLen, tLength, tPos;
00899         int     iType, iHorSize, iVerSize;
00900         USHORT  usHorScalingFactor, usVerScalingFactor;
00901 
00902         if (ulFileOffsetImage == FC_INVALID) {
00903                 return image_no_information;
00904         }
00905         DBG_HEX(ulFileOffsetImage);
00906 
00907         if (!bSetDataOffset(pFile, ulFileOffsetImage)) {
00908                 return image_no_information;
00909         }
00910 
00911         tLength = (size_t)ulNextLong(pFile);
00912         DBG_DEC(tLength);
00913         if (tLength < 46) {
00914                 /* Smaller than the smallest known header */
00915                 DBG_FIXME();
00916                 return image_no_information;
00917         }
00918         tWordHeaderLen = (size_t)usNextWord(pFile);
00919         DBG_DEC(tWordHeaderLen);
00920         fail(tWordHeaderLen != 46 &&
00921                 tWordHeaderLen != 58 &&
00922                 tWordHeaderLen != 68);
00923 
00924         if (tLength < tWordHeaderLen) {
00925                 /* Smaller than the current header */
00926                 return image_no_information;
00927         }
00928         iType = (int)usNextWord(pFile);
00929         DBG_DEC(iType);
00930         (void)tSkipBytes(pFile, 28 - 8);
00931 
00932         lTmp = lTwips2MilliPoints(usNextWord(pFile));
00933         iHorSize = (int)(lTmp / 1000);
00934         if (lTmp % 1000 != 0) {
00935                 iHorSize++;
00936         }
00937         DBG_DEC(iHorSize);
00938         lTmp = lTwips2MilliPoints(usNextWord(pFile));
00939         iVerSize = (int)(lTmp / 1000);
00940         if (lTmp % 1000 != 0) {
00941                 iVerSize++;
00942         }
00943         DBG_DEC(iVerSize);
00944 
00945         usHorScalingFactor = usNextWord(pFile);
00946         DBG_DEC(usHorScalingFactor);
00947         usVerScalingFactor = usNextWord(pFile);
00948         DBG_DEC(usVerScalingFactor);
00949 
00950         /* Sanity checks */
00951         lTmp = (long)iHorSize * (long)usHorScalingFactor;
00952         if (lTmp < 2835) {
00953                 /* This image would be less than 1 millimeter wide */
00954                 DBG_DEC(lTmp);
00955                 return image_no_information;
00956         }
00957         lTmp = (long)iVerSize * (long)usVerScalingFactor;
00958         if (lTmp < 2835) {
00959                 /* This image would be less than 1 millimeter high */
00960                 DBG_DEC(lTmp);
00961                 return image_no_information;
00962         }
00963 
00964         /* Skip the rest of the header */
00965         (void)tSkipBytes(pFile, tWordHeaderLen - 36);
00966         tPos = tWordHeaderLen;
00967 
00968         (void)memset(pImg, 0, sizeof(*pImg));
00969 
00970         switch (iType) {
00971         case   7:
00972         case   8:
00973                 tPos = tFind6Image(pFile, tPos, tLength, &pImg->eImageType);
00974                 if (tPos == (size_t)-1) {
00975                         /* No image found */
00976                         return image_no_information;
00977                 }
00978                 DBG_HEX(tPos);
00979                 break;
00980         case  94:       /* Word 6/7, no image just a pathname */
00981                 pImg->eImageType = imagetype_is_external;
00982                 DBG_HEX(ulFileOffsetImage + tPos);
00983                 break;
00984         case 100:
00985                 tPos = tFind8Image(pFile, tPos, tLength, &pImg->eImageType);
00986                 if (tPos == (size_t)-1) {
00987                         /* No image found */
00988                         return image_no_information;
00989                 }
00990                 DBG_HEX(tPos);
00991                 break;
00992         case 102:       /* Word 8/9/10, no image just a pathname or URL */
00993                 pImg->eImageType = imagetype_is_external;
00994                 DBG_HEX(ulFileOffsetImage + tPos);
00995                 break;
00996         default:
00997                 DBG_DEC(iType);
00998                 DBG_HEX(ulFileOffsetImage + tPos);
00999                 DBG_FIXME();
01000                 return image_no_information;
01001         }
01002 
01003         /* Minimal information is now available */
01004         pImg->tLength = tLength;
01005         pImg->tPosition = tPos;
01006         pImg->iHorSizeScaled =
01007                 (int)(((long)iHorSize * (long)usHorScalingFactor + 500) / 1000);
01008         pImg->iVerSizeScaled =
01009                 (int)(((long)iVerSize * (long)usVerScalingFactor + 500) / 1000);
01010 #if !defined(__riscos)
01011         vImage2Papersize(pImg);
01012 #endif /* !__riscos */
01013 
01014         /* Image type specific examinations */
01015         switch (pImg->eImageType) {
01016         case imagetype_is_dib:
01017                 if (bExamineDIB(pFile, pImg)) {
01018                         return image_full_information;
01019                 }
01020                 return image_minimal_information;
01021         case imagetype_is_jpeg:
01022                 if (bExamineJPEG(pFile, pImg)) {
01023                         return image_full_information;
01024                 }
01025                 return image_minimal_information;
01026         case imagetype_is_png:
01027                 if (bExaminePNG(pFile, pImg)) {
01028                         return image_full_information;
01029                 }
01030                 return image_minimal_information;
01031         case imagetype_is_wmf:
01032                 if (bExamineWMF(pFile, pImg)) {
01033                         return image_full_information;
01034                 }
01035                 return image_minimal_information;
01036         case imagetype_is_emf:
01037         case imagetype_is_pict:
01038         case imagetype_is_external:
01039                 return image_minimal_information;
01040         case imagetype_is_unknown:
01041         default:
01042                 return image_no_information;
01043         }
01044 } /* end of eExamineImage */

Generated by  doxygen 1.6.2