diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/aux/antiword/imgexam.c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/aux/antiword/imgexam.c')
-rwxr-xr-x | sys/src/cmd/aux/antiword/imgexam.c | 1044 |
1 files changed, 1044 insertions, 0 deletions
diff --git a/sys/src/cmd/aux/antiword/imgexam.c b/sys/src/cmd/aux/antiword/imgexam.c new file mode 100755 index 000000000..2b8384af8 --- /dev/null +++ b/sys/src/cmd/aux/antiword/imgexam.c @@ -0,0 +1,1044 @@ +/* + * imgexam.c + * Copyright (C) 2000-2004 A.J. van Os; Released under GNU GPL + * + * Description: + * Functions to examine image headers + * + *================================================================ + * Part of this software is based on: + * jpeg2ps - convert JPEG compressed images to PostScript Level 2 + * Copyright (C) 1994-99 Thomas Merz (tm@muc.de) + *================================================================ + * The credit should go to him, but all the bugs are mine. + */ + +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include "antiword.h" + +/* BMP compression types */ +#define BI_RGB 0 +#define BI_RLE8 1 +#define BI_RLE4 2 + +/* PNG colortype bits */ +#define PNG_CB_PALETTE 0x01 +#define PNG_CB_COLOR 0x02 +#define PNG_CB_ALPHA 0x04 + +/* Instance signature */ +#define MSOBI_WMF 0x0216 +#define MSOBI_EMF 0x03d4 +#define MSOBI_PICT 0x0542 +#define MSOBI_PNG 0x06e0 +#define MSOBI_JPEG 0x046a +#define MSOBI_DIB 0x07a8 + +/* The following enum is stolen from the IJG JPEG library */ +typedef enum { /* JPEG marker codes */ + M_SOF0 = 0xc0, /* baseline DCT */ + M_SOF1 = 0xc1, /* extended sequential DCT */ + M_SOF2 = 0xc2, /* progressive DCT */ + M_SOF3 = 0xc3, /* lossless (sequential) */ + + M_SOF5 = 0xc5, /* differential sequential DCT */ + M_SOF6 = 0xc6, /* differential progressive DCT */ + M_SOF7 = 0xc7, /* differential lossless */ + + M_JPG = 0xc8, /* JPEG extensions */ + M_SOF9 = 0xc9, /* extended sequential DCT */ + M_SOF10 = 0xca, /* progressive DCT */ + M_SOF11 = 0xcb, /* lossless (sequential) */ + + M_SOF13 = 0xcd, /* differential sequential DCT */ + M_SOF14 = 0xce, /* differential progressive DCT */ + M_SOF15 = 0xcf, /* differential lossless */ + + M_DHT = 0xc4, /* define Huffman tables */ + + M_DAC = 0xcc, /* define arithmetic conditioning table */ + + M_RST0 = 0xd0, /* restart */ + M_RST1 = 0xd1, /* restart */ + M_RST2 = 0xd2, /* restart */ + M_RST3 = 0xd3, /* restart */ + M_RST4 = 0xd4, /* restart */ + M_RST5 = 0xd5, /* restart */ + M_RST6 = 0xd6, /* restart */ + M_RST7 = 0xd7, /* restart */ + + M_SOI = 0xd8, /* start of image */ + M_EOI = 0xd9, /* end of image */ + M_SOS = 0xda, /* start of scan */ + M_DQT = 0xdb, /* define quantization tables */ + M_DNL = 0xdc, /* define number of lines */ + M_DRI = 0xdd, /* define restart interval */ + M_DHP = 0xde, /* define hierarchical progression */ + M_EXP = 0xdf, /* expand reference image(s) */ + + M_APP0 = 0xe0, /* application marker, used for JFIF */ + M_APP1 = 0xe1, /* application marker */ + M_APP2 = 0xe2, /* application marker */ + M_APP3 = 0xe3, /* application marker */ + M_APP4 = 0xe4, /* application marker */ + M_APP5 = 0xe5, /* application marker */ + M_APP6 = 0xe6, /* application marker */ + M_APP7 = 0xe7, /* application marker */ + M_APP8 = 0xe8, /* application marker */ + M_APP9 = 0xe9, /* application marker */ + M_APP10 = 0xea, /* application marker */ + M_APP11 = 0xeb, /* application marker */ + M_APP12 = 0xec, /* application marker */ + M_APP13 = 0xed, /* application marker */ + M_APP14 = 0xee, /* application marker, used by Adobe */ + M_APP15 = 0xef, /* application marker */ + + M_JPG0 = 0xf0, /* reserved for JPEG extensions */ + M_JPG13 = 0xfd, /* reserved for JPEG extensions */ + M_COM = 0xfe, /* comment */ + + M_TEM = 0x01 /* temporary use */ +} JPEG_MARKER; + + +/* + * bFillPaletteDIB - fill the palette part of the imagesdata + * + * returns TRUE if the images must be a color image, otherwise FALSE; + */ +static BOOL +bFillPaletteDIB(FILE *pFile, imagedata_type *pImg, BOOL bNewFormat) +{ + int iIndex; + BOOL bIsColorPalette; + + fail(pFile == NULL); + fail(pImg == NULL); + + if (pImg->uiBitsPerComponent > 8) { + /* No palette, image uses more than 256 colors */ + return TRUE; + } + + if (pImg->iColorsUsed <= 0) { + /* Not specified, so compute the number of colors used */ + pImg->iColorsUsed = 1 << pImg->uiBitsPerComponent; + } + + fail(pImg->iColorsUsed > 256); + if (pImg->iColorsUsed > 256) { + pImg->iColorsUsed = 256; + } + + bIsColorPalette = FALSE; + for (iIndex = 0; iIndex < pImg->iColorsUsed; iIndex++) { + /* From BGR order to RGB order */ + pImg->aucPalette[iIndex][2] = (UCHAR)iNextByte(pFile); + pImg->aucPalette[iIndex][1] = (UCHAR)iNextByte(pFile); + pImg->aucPalette[iIndex][0] = (UCHAR)iNextByte(pFile); + if (bNewFormat) { + (void)iNextByte(pFile); + } + NO_DBG_PRINT_BLOCK(pImg->aucPalette[iIndex], 3); + if (pImg->aucPalette[iIndex][0] != + pImg->aucPalette[iIndex][1] || + pImg->aucPalette[iIndex][1] != + pImg->aucPalette[iIndex][2]) { + bIsColorPalette = TRUE; + } + } + + return bIsColorPalette; +} /* end of bFillPaletteDIB */ + +/* + * bExamineDIB - Examine a DIB header + * + * return TRUE if successful, otherwise FALSE + */ +static BOOL +bExamineDIB(FILE *pFile, imagedata_type *pImg) +{ + size_t tHeaderSize; + int iPlanes, iCompression; + + tHeaderSize = (size_t)ulNextLong(pFile); + switch (tHeaderSize) { + case 12: + pImg->iWidth = (int)usNextWord(pFile); + pImg->iHeight = (int)usNextWord(pFile); + iPlanes = (int)usNextWord(pFile); + pImg->uiBitsPerComponent = (UINT)usNextWord(pFile); + iCompression = BI_RGB; + pImg->iColorsUsed = 0; + break; + case 40: + case 64: + pImg->iWidth = (int)ulNextLong(pFile); + pImg->iHeight = (int)ulNextLong(pFile); + iPlanes = (int)usNextWord(pFile); + pImg->uiBitsPerComponent = (UINT)usNextWord(pFile); + iCompression = (int)ulNextLong(pFile); + (void)tSkipBytes(pFile, 12); + pImg->iColorsUsed = (int)ulNextLong(pFile); + (void)tSkipBytes(pFile, tHeaderSize - 36); + break; + default: + DBG_DEC(tHeaderSize); + return FALSE; + } + DBG_DEC(pImg->iWidth); + DBG_DEC(pImg->iHeight); + DBG_DEC(pImg->uiBitsPerComponent); + DBG_DEC(iCompression); + DBG_DEC(pImg->iColorsUsed); + + /* Do some sanity checks with the parameters */ + if (iPlanes != 1) { + DBG_DEC(iPlanes); + return FALSE; + } + if (pImg->iWidth <= 0 || pImg->iHeight <= 0) { + DBG_DEC(pImg->iWidth); + DBG_DEC(pImg->iHeight); + return FALSE; + } + if (pImg->uiBitsPerComponent != 1 && pImg->uiBitsPerComponent != 4 && + pImg->uiBitsPerComponent != 8 && pImg->uiBitsPerComponent != 24) { + DBG_DEC(pImg->uiBitsPerComponent); + return FALSE; + } + if (iCompression != BI_RGB && + (pImg->uiBitsPerComponent == 1 || pImg->uiBitsPerComponent == 24)) { + return FALSE; + } + if (iCompression == BI_RLE8 && pImg->uiBitsPerComponent == 4) { + return FALSE; + } + if (iCompression == BI_RLE4 && pImg->uiBitsPerComponent == 8) { + return FALSE; + } + + switch (iCompression) { + case BI_RGB: + pImg->eCompression = compression_none; + break; + case BI_RLE4: + pImg->eCompression = compression_rle4; + break; + case BI_RLE8: + pImg->eCompression = compression_rle8; + break; + default: + DBG_DEC(iCompression); + return FALSE; + } + + pImg->bColorImage = bFillPaletteDIB(pFile, pImg, tHeaderSize > 12); + + if (pImg->uiBitsPerComponent <= 8) { + pImg->iComponents = 1; + } else { + pImg->iComponents = (int)(pImg->uiBitsPerComponent / 8); + } + + return TRUE; +} /* end of bExamineDIB */ + +/* + * iNextMarker - read the next JPEG marker + */ +static int +iNextMarker(FILE *pFile) +{ + int iMarker; + + do { + do { + iMarker = iNextByte(pFile); + } while (iMarker != 0xff && iMarker != EOF); + if (iMarker == EOF) { + return EOF; + } + do { + iMarker = iNextByte(pFile); + } while (iMarker == 0xff); + } while (iMarker == 0x00); /* repeat if ff/00 */ + + return iMarker; +} /* end of iNextMarker */ + +/* + * bExamineJPEG - Examine a JPEG header + * + * return TRUE if successful, otherwise FALSE + */ +static BOOL +bExamineJPEG(FILE *pFile, imagedata_type *pImg) +{ + size_t tLength; + int iMarker, iIndex; + char appstring[10]; + BOOL bSOFDone; + + tLength = 0; + bSOFDone = FALSE; + + /* process JPEG markers */ + while (!bSOFDone && (iMarker = iNextMarker(pFile)) != (int)M_EOI) { + switch (iMarker) { + case EOF: + DBG_MSG("Error: unexpected end of JPEG file"); + return FALSE; + /* The following are not officially supported in PostScript level 2 */ + case M_SOF2: + case M_SOF3: + case M_SOF5: + case M_SOF6: + case M_SOF7: + case M_SOF9: + case M_SOF10: + case M_SOF11: + case M_SOF13: + case M_SOF14: + case M_SOF15: + DBG_HEX(iMarker); + return FALSE; + case M_SOF0: + case M_SOF1: + tLength = (size_t)usNextWordBE(pFile); + pImg->uiBitsPerComponent = (UINT)iNextByte(pFile); + pImg->iHeight = (int)usNextWordBE(pFile); + pImg->iWidth = (int)usNextWordBE(pFile); + pImg->iComponents = iNextByte(pFile); + bSOFDone = TRUE; + break; + case M_APP14: + /* + * Check for Adobe application marker. It is known (per Adobe's + * TN5116) to contain the string "Adobe" at the start of the + * APP14 marker. + */ + tLength = (size_t)usNextWordBE(pFile); + if (tLength < 12) { + (void)tSkipBytes(pFile, tLength - 2); + } else { + for (iIndex = 0; iIndex < 5; iIndex++) { + appstring[iIndex] = + (char)iNextByte(pFile); + } + appstring[5] = '\0'; + if (STREQ(appstring, "Adobe")) { + pImg->bAdobe = TRUE; + } + (void)tSkipBytes(pFile, tLength - 7); + } + break; + case M_SOI: /* ignore markers without parameters */ + case M_EOI: + case M_TEM: + case M_RST0: + case M_RST1: + case M_RST2: + case M_RST3: + case M_RST4: + case M_RST5: + case M_RST6: + case M_RST7: + break; + default: /* skip variable length markers */ + tLength = (size_t)usNextWordBE(pFile); + (void)tSkipBytes(pFile, tLength - 2); + break; + } + } + + DBG_DEC(pImg->iWidth); + DBG_DEC(pImg->iHeight); + DBG_DEC(pImg->uiBitsPerComponent); + DBG_DEC(pImg->iComponents); + + /* Do some sanity checks with the parameters */ + if (pImg->iHeight <= 0 || + pImg->iWidth <= 0 || + pImg->iComponents <= 0) { + DBG_DEC(pImg->iHeight); + DBG_DEC(pImg->iWidth); + DBG_DEC(pImg->iComponents); + return FALSE; + } + + /* Some broken JPEG files have this but they print anyway... */ + if (pImg->iComponents * 3 + 8 != (int)tLength) { + DBG_MSG("Warning: SOF marker has incorrect length - ignored"); + } + + if (pImg->uiBitsPerComponent != 8) { + DBG_DEC(pImg->uiBitsPerComponent); + DBG_MSG("Not supported in PostScript level 2"); + return FALSE; + } + + if (pImg->iComponents != 1 && + pImg->iComponents != 3 && + pImg->iComponents != 4) { + DBG_DEC(pImg->iComponents); + return FALSE; + } + + pImg->bColorImage = pImg->iComponents >= 3; + pImg->iColorsUsed = 0; + pImg->eCompression = compression_jpeg; + + return TRUE; +} /* end of bExamineJPEG */ + +/* + * bFillPalettePNG - fill the palette part of the imagesdata + * + * returns TRUE if sucessful, otherwise FALSE; + */ +static BOOL +bFillPalettePNG(FILE *pFile, imagedata_type *pImg, size_t tLength) +{ + int iIndex, iEntries; + + fail(pFile == NULL); + fail(pImg == NULL); + + if (pImg->uiBitsPerComponent > 8) { + /* No palette, image uses more than 256 colors */ + return TRUE; + } + + if (!pImg->bColorImage) { + /* Only color images can have a palette */ + return FALSE; + } + + if (tLength % 3 != 0) { + /* Each palette entry takes three bytes */ + DBG_DEC(tLength); + return FALSE; + } + + iEntries = (int)(tLength / 3); + DBG_DEC(iEntries); + pImg->iColorsUsed = 1 << pImg->uiBitsPerComponent; + DBG_DEC(pImg->iColorsUsed); + + if (iEntries > 256) { + DBG_DEC(iEntries); + return FALSE; + } + + for (iIndex = 0; iIndex < iEntries; iIndex++) { + pImg->aucPalette[iIndex][0] = (UCHAR)iNextByte(pFile); + pImg->aucPalette[iIndex][1] = (UCHAR)iNextByte(pFile); + pImg->aucPalette[iIndex][2] = (UCHAR)iNextByte(pFile); + NO_DBG_PRINT_BLOCK(pImg->aucPalette[iIndex], 3); + } + for (;iIndex < pImg->iColorsUsed; iIndex++) { + pImg->aucPalette[iIndex][0] = 0; + pImg->aucPalette[iIndex][1] = 0; + pImg->aucPalette[iIndex][2] = 0; + } + + return TRUE; +} /* end of bFillPalettePNG */ + +/* + * bExaminePNG - Examine a PNG header + * + * return TRUE if successful, otherwise FALSE + */ +static BOOL +bExaminePNG(FILE *pFile, imagedata_type *pImg) +{ + size_t tLength; + ULONG ulLong1, ulLong2, ulName; + int iIndex, iTmp; + int iCompressionMethod, iFilterMethod, iInterlaceMethod; + int iColor, iIncrement; + BOOL bHasPalette, bHasAlpha; + UCHAR aucBuf[4]; + + /* Check signature */ + ulLong1 = ulNextLongBE(pFile); + ulLong2 = ulNextLongBE(pFile); + if (ulLong1 != 0x89504e47UL || ulLong2 != 0x0d0a1a0aUL) { + DBG_HEX(ulLong1); + DBG_HEX(ulLong2); + return FALSE; + } + + ulName = 0x00; + bHasPalette = FALSE; + + /* Examine chunks */ + while (ulName != PNG_CN_IEND) { + tLength = (size_t)ulNextLongBE(pFile); + ulName = 0x00; + for (iIndex = 0; iIndex < (int)elementsof(aucBuf); iIndex++) { + aucBuf[iIndex] = (UCHAR)iNextByte(pFile); + if (!isalpha(aucBuf[iIndex])) { + DBG_HEX(aucBuf[iIndex]); + return FALSE; + } + ulName <<= 8; + ulName |= aucBuf[iIndex]; + } + + switch (ulName) { + case PNG_CN_IHDR: + /* Header chunck */ + if (tLength < 13) { + DBG_DEC(tLength); + return FALSE; + } + pImg->iWidth = (int)ulNextLongBE(pFile); + pImg->iHeight = (int)ulNextLongBE(pFile); + pImg->uiBitsPerComponent = (UINT)iNextByte(pFile); + iTmp = iNextByte(pFile); + NO_DBG_HEX(iTmp); + pImg->bColorImage = (iTmp & PNG_CB_COLOR) != 0; + bHasPalette = (iTmp & PNG_CB_PALETTE) != 0; + bHasAlpha = (iTmp & PNG_CB_ALPHA) != 0; + if (bHasPalette && pImg->uiBitsPerComponent > 8) { + /* This should not happen */ + return FALSE; + } + pImg->iComponents = + (bHasPalette || !pImg->bColorImage) ? 1 : 3; + if (bHasAlpha) { + pImg->iComponents++; + } + iCompressionMethod = iNextByte(pFile); + if (iCompressionMethod != 0) { + DBG_DEC(iCompressionMethod); + return FALSE; + } + iFilterMethod = iNextByte(pFile); + if (iFilterMethod != 0) { + DBG_DEC(iFilterMethod); + return FALSE; + } + iInterlaceMethod = iNextByte(pFile); + if (iInterlaceMethod != 0) { + DBG_DEC(iInterlaceMethod); + return FALSE; + } + pImg->iColorsUsed = 0; + (void)tSkipBytes(pFile, tLength - 13 + 4); + break; + case PNG_CN_PLTE: + if (!bHasPalette) { + return FALSE; + } + if (!bFillPalettePNG(pFile, pImg, tLength)) { + return FALSE; + } + (void)tSkipBytes(pFile, 4); + break; + default: + (void)tSkipBytes(pFile, tLength + 4); + break; + } + } + + DBG_DEC(pImg->iWidth); + DBG_DEC(pImg->iHeight); + DBG_DEC(pImg->uiBitsPerComponent); + DBG_DEC(pImg->iColorsUsed); + DBG_DEC(pImg->iComponents); + + /* Do some sanity checks with the parameters */ + if (pImg->iWidth <= 0 || pImg->iHeight <= 0) { + return FALSE; + } + + if (pImg->uiBitsPerComponent != 1 && pImg->uiBitsPerComponent != 2 && + pImg->uiBitsPerComponent != 4 && pImg->uiBitsPerComponent != 8 && + pImg->uiBitsPerComponent != 16) { + DBG_DEC(pImg->uiBitsPerComponent); + return FALSE; + } + + if (pImg->iComponents != 1 && pImg->iComponents != 3) { + /* Not supported */ + DBG_DEC(pImg->iComponents); + return FALSE; + } + + if (pImg->uiBitsPerComponent > 8) { + /* Not supported */ + DBG_DEC(pImg->uiBitsPerComponent); + return FALSE; + } + + if (pImg->iColorsUsed == 0 && + pImg->iComponents == 1 && + pImg->uiBitsPerComponent <= 4) { + /* + * No palette is supplied, but PostScript needs one in these + * cases, so we add a default palette here + */ + pImg->iColorsUsed = 1 << pImg->uiBitsPerComponent; + iIncrement = 0xff / (pImg->iColorsUsed - 1); + for (iIndex = 0, iColor = 0x00; + iIndex < pImg->iColorsUsed; + iIndex++, iColor += iIncrement) { + pImg->aucPalette[iIndex][0] = (UCHAR)iColor; + pImg->aucPalette[iIndex][1] = (UCHAR)iColor; + pImg->aucPalette[iIndex][2] = (UCHAR)iColor; + } + /* Just to be sure */ + pImg->bColorImage = FALSE; + } + + pImg->eCompression = compression_zlib; + + return TRUE; +} /* end of bExaminePNG */ + +/* + * bExamineWMF - Examine a WMF header + * + * return TRUE if successful, otherwise FALSE + */ +static BOOL +bExamineWMF(FILE *pFile, imagedata_type *pImg) +{ + ULONG ulFileSize, ulMaxRecord, ulMagic; + USHORT usType, usHeaderSize, usVersion, usNoObjects; + + usType = usNextWord(pFile); + usHeaderSize = usNextWord(pFile); + ulMagic = ((ULONG)usHeaderSize << 16) | (ULONG)usType; + usVersion = usNextWord(pFile); + ulFileSize = ulNextLong(pFile); + usNoObjects = usNextWord(pFile); + ulMaxRecord = ulNextLong(pFile); + + DBG_HEX(ulMagic); + DBG_DEC(usType); + DBG_DEC(usHeaderSize); + DBG_HEX(usVersion); + DBG_DEC(ulFileSize); + DBG_DEC(usNoObjects); + DBG_DEC(ulMaxRecord); + + return FALSE; +} /* end of bExamineWMF */ + +#if !defined(__riscos) +/* + * vImage2Papersize - make sure the image fits on the paper + * + * This function should not be needed if Word would do a proper job + */ +static void +vImage2Papersize(imagedata_type *pImg) +{ + static int iNetPageHeight = -1; + static int iNetPageWidth = -1; + options_type tOptions; + double dVerFactor, dHorFactor, dFactor; + + DBG_MSG("vImage2Papersize"); + + fail(pImg == NULL); + + if (iNetPageHeight < 0 || iNetPageWidth < 0) { + /* Get the page dimensions from the options */ + vGetOptions(&tOptions); + /* Add 999 to err on the save side */ + iNetPageHeight = tOptions.iPageHeight - + (lDrawUnits2MilliPoints( + PS_TOP_MARGIN + PS_BOTTOM_MARGIN) + + 999) / 1000; + iNetPageWidth = tOptions.iPageWidth - + (lDrawUnits2MilliPoints( + PS_LEFT_MARGIN + PS_RIGHT_MARGIN) + + 999) / 1000; + DBG_DEC(iNetPageHeight); + DBG_DEC(iNetPageWidth); + } + + if (pImg->iVerSizeScaled < iNetPageHeight && + pImg->iHorSizeScaled < iNetPageWidth) { + /* The image fits on the paper */ + return; + } + + dVerFactor = (double)iNetPageHeight / (double)pImg->iVerSizeScaled; + dHorFactor = (double)iNetPageWidth / (double)pImg->iHorSizeScaled; + dFactor = min(dVerFactor, dHorFactor); + DBG_FLT(dFactor); + /* Round down, just to be on the save side */ + pImg->iVerSizeScaled = (int)(pImg->iVerSizeScaled * dFactor); + pImg->iHorSizeScaled = (int)(pImg->iHorSizeScaled * dFactor); +} /* end of vImage2Papersize */ +#endif /* !__riscos */ + +/* + * tFind6Image - skip until the image is found + * + * Find the image in Word 6/7 files + * + * returns the new position when a image is found, otherwise -1 + */ +static size_t +tFind6Image(FILE *pFile, size_t tPosition, size_t tLength, + imagetype_enum *peImageType) +{ + ULONG ulMarker; + size_t tRecordLength, tToSkip; + USHORT usMarker; + + fail(pFile == NULL); + fail(peImageType == NULL); + + *peImageType = imagetype_is_unknown; + if (tPosition + 18 >= tLength) { + return (size_t)-1; + } + + ulMarker = ulNextLong(pFile); + if (ulMarker != 0x00090001) { + DBG_HEX(ulMarker); + return (size_t)-1; + } + usMarker = usNextWord(pFile); + if (usMarker != 0x0300) { + DBG_HEX(usMarker); + return (size_t)-1; + } + (void)tSkipBytes(pFile, 10); + usMarker = usNextWord(pFile); + if (usMarker != 0x0000) { + DBG_HEX(usMarker); + return (size_t)-1; + } + tPosition += 18; + + while (tPosition + 6 <= tLength) { + tRecordLength = (size_t)ulNextLong(pFile); + usMarker = usNextWord(pFile); + tPosition += 6; + NO_DBG_DEC(tRecordLength); + NO_DBG_HEX(usMarker); + switch (usMarker) { + case 0x0000: + DBG_HEX(ulGetDataOffset(pFile)); + return (size_t)-1; + case 0x0b41: + DBG_MSG("DIB"); + *peImageType = imagetype_is_dib; + tPosition += tSkipBytes(pFile, 20); + return tPosition; + case 0x0f43: + DBG_MSG("DIB"); + *peImageType = imagetype_is_dib; + tPosition += tSkipBytes(pFile, 22); + return tPosition; + default: + if (tRecordLength < 3) { + break; + } + if (tRecordLength > SIZE_T_MAX / 2) { + /* + * No need to compute the number of bytes + * to skip + */ + DBG_DEC(tRecordLength); + DBG_HEX(tRecordLength); + DBG_FIXME(); + return (size_t)-1; + } + tToSkip = tRecordLength * 2 - 6; + if (tToSkip > tLength - tPosition) { + /* You can't skip this number of bytes */ + DBG_DEC(tToSkip); + DBG_DEC(tLength - tPosition); + return (size_t)-1; + } + tPosition += tSkipBytes(pFile, tToSkip); + break; + } + } + + return (size_t)-1; +} /* end of tFind6Image */ + +/* + * tFind8Image - skip until the image is found + * + * Find the image in Word 8/9/10 files + * + * returns the new position when a image is found, otherwise -1 + */ +static size_t +tFind8Image(FILE *pFile, size_t tPosition, size_t tLength, + imagetype_enum *peImageType) +{ + size_t tRecordLength, tNameLen; + USHORT usRecordVersion, usRecordType, usRecordInstance; + USHORT usTmp; + + fail(pFile == NULL); + fail(peImageType == NULL); + + *peImageType = imagetype_is_unknown; + while (tPosition + 8 <= tLength) { + usTmp = usNextWord(pFile); + usRecordVersion = usTmp & 0x000f; + usRecordInstance = usTmp >> 4; + usRecordType = usNextWord(pFile); + tRecordLength = (size_t)ulNextLong(pFile); + tPosition += 8; + NO_DBG_HEX(usRecordVersion); + NO_DBG_HEX(usRecordInstance); + NO_DBG_HEX(usRecordType); + NO_DBG_DEC(tRecordLength); + switch (usRecordType) { + case 0xf000: case 0xf001: case 0xf002: case 0xf003: + case 0xf004: case 0xf005: + break; + case 0xf007: + tPosition += tSkipBytes(pFile, 33); + tNameLen = (size_t)iNextByte(pFile); + tPosition++; + DBG_DEC_C(tNameLen != 0, tNameLen); + tPosition += tSkipBytes(pFile, 2 + tNameLen * 2); + break; + case 0xf008: + tPosition += tSkipBytes(pFile, 8); + break; + case 0xf009: + tPosition += tSkipBytes(pFile, 16); + break; + case 0xf006: case 0xf00a: case 0xf00b: case 0xf00d: + case 0xf00e: case 0xf00f: case 0xf010: case 0xf011: + case 0xf122: + tPosition += tSkipBytes(pFile, tRecordLength); + break; + case 0xf01a: + DBG_MSG("EMF"); + *peImageType = imagetype_is_emf; + tPosition += tSkipBytes(pFile, 50); + if ((usRecordInstance ^ MSOBI_EMF) == 1) { + tPosition += tSkipBytes(pFile, 16); + } + return tPosition; + case 0xf01b: + DBG_MSG("WMF"); + *peImageType = imagetype_is_wmf; + tPosition += tSkipBytes(pFile, 50); + if ((usRecordInstance ^ MSOBI_WMF) == 1) { + tPosition += tSkipBytes(pFile, 16); + } + return tPosition; + case 0xf01c: + DBG_MSG("PICT"); + *peImageType = imagetype_is_pict; + tPosition += tSkipBytes(pFile, 50); + if ((usRecordInstance ^ MSOBI_PICT) == 1) { + tPosition += tSkipBytes(pFile, 16); + } + return tPosition; + case 0xf01d: + DBG_MSG("JPEG"); + *peImageType = imagetype_is_jpeg; + tPosition += tSkipBytes(pFile, 17); + if ((usRecordInstance ^ MSOBI_JPEG) == 1) { + tPosition += tSkipBytes(pFile, 16); + } + return tPosition; + case 0xf01e: + DBG_MSG("PNG"); + *peImageType = imagetype_is_png; + tPosition += tSkipBytes(pFile, 17); + if ((usRecordInstance ^ MSOBI_PNG) == 1) { + tPosition += tSkipBytes(pFile, 16); + } + return tPosition; + case 0xf01f: + DBG_MSG("DIB"); + /* DIB is a BMP minus its 14 byte header */ + *peImageType = imagetype_is_dib; + tPosition += tSkipBytes(pFile, 17); + if ((usRecordInstance ^ MSOBI_DIB) == 1) { + tPosition += tSkipBytes(pFile, 16); + } + return tPosition; + case 0xf00c: + default: + DBG_HEX(usRecordType); + DBG_DEC_C(tRecordLength % 4 != 0, tRecordLength); + DBG_FIXME(); + return (size_t)-1; + } + } + + return (size_t)-1; +} /* end of tFind8Image */ + +/* + * eExamineImage - Examine the image + * + * Returns an indication of the amount of information found + */ +image_info_enum +eExamineImage(FILE *pFile, ULONG ulFileOffsetImage, imagedata_type *pImg) +{ + long lTmp; + size_t tWordHeaderLen, tLength, tPos; + int iType, iHorSize, iVerSize; + USHORT usHorScalingFactor, usVerScalingFactor; + + if (ulFileOffsetImage == FC_INVALID) { + return image_no_information; + } + DBG_HEX(ulFileOffsetImage); + + if (!bSetDataOffset(pFile, ulFileOffsetImage)) { + return image_no_information; + } + + tLength = (size_t)ulNextLong(pFile); + DBG_DEC(tLength); + if (tLength < 46) { + /* Smaller than the smallest known header */ + DBG_FIXME(); + return image_no_information; + } + tWordHeaderLen = (size_t)usNextWord(pFile); + DBG_DEC(tWordHeaderLen); + fail(tWordHeaderLen != 46 && + tWordHeaderLen != 58 && + tWordHeaderLen != 68); + + if (tLength < tWordHeaderLen) { + /* Smaller than the current header */ + return image_no_information; + } + iType = (int)usNextWord(pFile); + DBG_DEC(iType); + (void)tSkipBytes(pFile, 28 - 8); + + lTmp = lTwips2MilliPoints(usNextWord(pFile)); + iHorSize = (int)(lTmp / 1000); + if (lTmp % 1000 != 0) { + iHorSize++; + } + DBG_DEC(iHorSize); + lTmp = lTwips2MilliPoints(usNextWord(pFile)); + iVerSize = (int)(lTmp / 1000); + if (lTmp % 1000 != 0) { + iVerSize++; + } + DBG_DEC(iVerSize); + + usHorScalingFactor = usNextWord(pFile); + DBG_DEC(usHorScalingFactor); + usVerScalingFactor = usNextWord(pFile); + DBG_DEC(usVerScalingFactor); + + /* Sanity checks */ + lTmp = (long)iHorSize * (long)usHorScalingFactor; + if (lTmp < 2835) { + /* This image would be less than 1 millimeter wide */ + DBG_DEC(lTmp); + return image_no_information; + } + lTmp = (long)iVerSize * (long)usVerScalingFactor; + if (lTmp < 2835) { + /* This image would be less than 1 millimeter high */ + DBG_DEC(lTmp); + return image_no_information; + } + + /* Skip the rest of the header */ + (void)tSkipBytes(pFile, tWordHeaderLen - 36); + tPos = tWordHeaderLen; + + (void)memset(pImg, 0, sizeof(*pImg)); + + switch (iType) { + case 7: + case 8: + tPos = tFind6Image(pFile, tPos, tLength, &pImg->eImageType); + if (tPos == (size_t)-1) { + /* No image found */ + return image_no_information; + } + DBG_HEX(tPos); + break; + case 94: /* Word 6/7, no image just a pathname */ + pImg->eImageType = imagetype_is_external; + DBG_HEX(ulFileOffsetImage + tPos); + break; + case 100: + tPos = tFind8Image(pFile, tPos, tLength, &pImg->eImageType); + if (tPos == (size_t)-1) { + /* No image found */ + return image_no_information; + } + DBG_HEX(tPos); + break; + case 102: /* Word 8/9/10, no image just a pathname or URL */ + pImg->eImageType = imagetype_is_external; + DBG_HEX(ulFileOffsetImage + tPos); + break; + default: + DBG_DEC(iType); + DBG_HEX(ulFileOffsetImage + tPos); + DBG_FIXME(); + return image_no_information; + } + + /* Minimal information is now available */ + pImg->tLength = tLength; + pImg->tPosition = tPos; + pImg->iHorSizeScaled = + (int)(((long)iHorSize * (long)usHorScalingFactor + 500) / 1000); + pImg->iVerSizeScaled = + (int)(((long)iVerSize * (long)usVerScalingFactor + 500) / 1000); +#if !defined(__riscos) + vImage2Papersize(pImg); +#endif /* !__riscos */ + + /* Image type specific examinations */ + switch (pImg->eImageType) { + case imagetype_is_dib: + if (bExamineDIB(pFile, pImg)) { + return image_full_information; + } + return image_minimal_information; + case imagetype_is_jpeg: + if (bExamineJPEG(pFile, pImg)) { + return image_full_information; + } + return image_minimal_information; + case imagetype_is_png: + if (bExaminePNG(pFile, pImg)) { + return image_full_information; + } + return image_minimal_information; + case imagetype_is_wmf: + if (bExamineWMF(pFile, pImg)) { + return image_full_information; + } + return image_minimal_information; + case imagetype_is_emf: + case imagetype_is_pict: + case imagetype_is_external: + return image_minimal_information; + case imagetype_is_unknown: + default: + return image_no_information; + } +} /* end of eExamineImage */ |