📄 tif_dirread.c
字号:
/* $Id: tif_dirread.c,v 1.82 2006/03/16 12:24:53 dron Exp $ *//* * Copyright (c) 1988-1997 Sam Leffler * Copyright (c) 1991-1997 Silicon Graphics, Inc. * * Permission to use, copy, modify, distribute, and sell this software and * its documentation for any purpose is hereby granted without fee, provided * that (i) the above copyright notices and this permission notice appear in * all copies of the software and related documentation, and (ii) the names of * Sam Leffler and Silicon Graphics may not be used in any advertising or * publicity relating to the software without the specific, prior written * permission of Sam Leffler and Silicon Graphics. * * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. * * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE * OF THIS SOFTWARE. *//* * TIFF Library. * * Directory Read Support Routines. */#include "tiffiop.h"#define IGNORE 0 /* tag placeholder used below */#ifdef HAVE_IEEEFP# define TIFFCvtIEEEFloatToNative(tif, n, fp)# define TIFFCvtIEEEDoubleToNative(tif, n, dp)#elseextern void TIFFCvtIEEEFloatToNative(TIFF*, uint32, float*);extern void TIFFCvtIEEEDoubleToNative(TIFF*, uint32, double*);#endifstatic int EstimateStripByteCounts(TIFF*, TIFFDirEntry*, uint16);static void MissingRequired(TIFF*, const char*);static int CheckDirCount(TIFF*, TIFFDirEntry*, uint32);static tsize_t TIFFFetchData(TIFF*, TIFFDirEntry*, char*);static tsize_t TIFFFetchString(TIFF*, TIFFDirEntry*, char*);static float TIFFFetchRational(TIFF*, TIFFDirEntry*);static int TIFFFetchNormalTag(TIFF*, TIFFDirEntry*);static int TIFFFetchPerSampleShorts(TIFF*, TIFFDirEntry*, uint16*);static int TIFFFetchPerSampleLongs(TIFF*, TIFFDirEntry*, uint32*);static int TIFFFetchPerSampleAnys(TIFF*, TIFFDirEntry*, double*);static int TIFFFetchShortArray(TIFF*, TIFFDirEntry*, uint16*);static int TIFFFetchStripThing(TIFF*, TIFFDirEntry*, long, uint32**);static int TIFFFetchRefBlackWhite(TIFF*, TIFFDirEntry*);static float TIFFFetchFloat(TIFF*, TIFFDirEntry*);static int TIFFFetchFloatArray(TIFF*, TIFFDirEntry*, float*);static int TIFFFetchDoubleArray(TIFF*, TIFFDirEntry*, double*);static int TIFFFetchAnyArray(TIFF*, TIFFDirEntry*, double*);static int TIFFFetchShortPair(TIFF*, TIFFDirEntry*);static void ChopUpSingleUncompressedStrip(TIFF*);/* * Read the next TIFF directory from a file * and convert it to the internal format. * We read directories sequentially. */intTIFFReadDirectory(TIFF* tif){ static const char module[] = "TIFFReadDirectory"; int n; TIFFDirectory* td; TIFFDirEntry *dp, *dir = NULL; uint16 iv; uint32 v; const TIFFFieldInfo* fip; size_t fix; uint16 dircount; toff_t nextdiroff; int diroutoforderwarning = 0; toff_t* new_dirlist; tif->tif_diroff = tif->tif_nextdiroff; if (tif->tif_diroff == 0) /* no more directories */ return (0); /* * XXX: Trick to prevent IFD looping. The one can create TIFF file * with looped directory pointers. We will maintain a list of already * seen directories and check every IFD offset against this list. */ for (n = 0; n < tif->tif_dirnumber; n++) { if (tif->tif_dirlist[n] == tif->tif_diroff) return (0); } tif->tif_dirnumber++; new_dirlist = (toff_t *)_TIFFrealloc(tif->tif_dirlist, tif->tif_dirnumber * sizeof(toff_t)); if (!new_dirlist) { TIFFErrorExt(tif->tif_clientdata, module, "%s: Failed to allocate space for IFD list", tif->tif_name); return (0); } tif->tif_dirlist = new_dirlist; tif->tif_dirlist[tif->tif_dirnumber - 1] = tif->tif_diroff; /* * Cleanup any previous compression state. */ (*tif->tif_cleanup)(tif); tif->tif_curdir++; nextdiroff = 0; if (!isMapped(tif)) { if (!SeekOK(tif, tif->tif_diroff)) { TIFFErrorExt(tif->tif_clientdata, module, "%s: Seek error accessing TIFF directory", tif->tif_name); return (0); } if (!ReadOK(tif, &dircount, sizeof (uint16))) { TIFFErrorExt(tif->tif_clientdata, module, "%s: Can not read TIFF directory count", tif->tif_name); return (0); } if (tif->tif_flags & TIFF_SWAB) TIFFSwabShort(&dircount); dir = (TIFFDirEntry *)_TIFFCheckMalloc(tif, dircount, sizeof (TIFFDirEntry), "to read TIFF directory"); if (dir == NULL) return (0); if (!ReadOK(tif, dir, dircount*sizeof (TIFFDirEntry))) { TIFFErrorExt(tif->tif_clientdata, module, "%.100s: Can not read TIFF directory", tif->tif_name); goto bad; } /* * Read offset to next directory for sequential scans. */ (void) ReadOK(tif, &nextdiroff, sizeof (uint32)); } else { toff_t off = tif->tif_diroff; if (off + sizeof (uint16) > tif->tif_size) { TIFFErrorExt(tif->tif_clientdata, module, "%s: Can not read TIFF directory count", tif->tif_name); return (0); } else _TIFFmemcpy(&dircount, tif->tif_base + off, sizeof (uint16)); off += sizeof (uint16); if (tif->tif_flags & TIFF_SWAB) TIFFSwabShort(&dircount); dir = (TIFFDirEntry *)_TIFFCheckMalloc(tif, dircount, sizeof (TIFFDirEntry), "to read TIFF directory"); if (dir == NULL) return (0); if (off + dircount*sizeof (TIFFDirEntry) > tif->tif_size) { TIFFErrorExt(tif->tif_clientdata, module, "%s: Can not read TIFF directory", tif->tif_name); goto bad; } else { _TIFFmemcpy(dir, tif->tif_base + off, dircount*sizeof (TIFFDirEntry)); } off += dircount* sizeof (TIFFDirEntry); if (off + sizeof (uint32) <= tif->tif_size) _TIFFmemcpy(&nextdiroff, tif->tif_base+off, sizeof (uint32)); } if (tif->tif_flags & TIFF_SWAB) TIFFSwabLong(&nextdiroff); tif->tif_nextdiroff = nextdiroff; tif->tif_flags &= ~TIFF_BEENWRITING; /* reset before new dir */ /* * Setup default value and then make a pass over * the fields to check type and tag information, * and to extract info required to size data * structures. A second pass is made afterwards * to read in everthing not taken in the first pass. */ td = &tif->tif_dir; /* free any old stuff and reinit */ TIFFFreeDirectory(tif); TIFFDefaultDirectory(tif); /* * Electronic Arts writes gray-scale TIFF files * without a PlanarConfiguration directory entry. * Thus we setup a default value here, even though * the TIFF spec says there is no default value. */ TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); /* * Sigh, we must make a separate pass through the * directory for the following reason: * * We must process the Compression tag in the first pass * in order to merge in codec-private tag definitions (otherwise * we may get complaints about unknown tags). However, the * Compression tag may be dependent on the SamplesPerPixel * tag value because older TIFF specs permited Compression * to be written as a SamplesPerPixel-count tag entry. * Thus if we don't first figure out the correct SamplesPerPixel * tag value then we may end up ignoring the Compression tag * value because it has an incorrect count value (if the * true value of SamplesPerPixel is not 1). * * It sure would have been nice if Aldus had really thought * this stuff through carefully. */ for (dp = dir, n = dircount; n > 0; n--, dp++) { if (tif->tif_flags & TIFF_SWAB) { TIFFSwabArrayOfShort(&dp->tdir_tag, 2); TIFFSwabArrayOfLong(&dp->tdir_count, 2); } if (dp->tdir_tag == TIFFTAG_SAMPLESPERPIXEL) { if (!TIFFFetchNormalTag(tif, dp)) goto bad; dp->tdir_tag = IGNORE; } } /* * First real pass over the directory. */ fix = 0; for (dp = dir, n = dircount; n > 0; n--, dp++) { if (fix >= tif->tif_nfields || dp->tdir_tag == IGNORE) continue; /* * Silicon Beach (at least) writes unordered * directory tags (violating the spec). Handle * it here, but be obnoxious (maybe they'll fix it?). */ if (dp->tdir_tag < tif->tif_fieldinfo[fix]->field_tag) { if (!diroutoforderwarning) { TIFFWarningExt(tif->tif_clientdata, module, "%s: invalid TIFF directory; tags are not sorted in ascending order", tif->tif_name); diroutoforderwarning = 1; } fix = 0; /* O(n^2) */ } while (fix < tif->tif_nfields && tif->tif_fieldinfo[fix]->field_tag < dp->tdir_tag) fix++; if (fix >= tif->tif_nfields || tif->tif_fieldinfo[fix]->field_tag != dp->tdir_tag) { TIFFWarningExt(tif->tif_clientdata, module, "%s: unknown field with tag %d (0x%x) encountered", tif->tif_name, dp->tdir_tag, dp->tdir_tag, dp->tdir_type); TIFFMergeFieldInfo(tif, _TIFFCreateAnonFieldInfo(tif, dp->tdir_tag, (TIFFDataType) dp->tdir_type), 1 ); fix = 0; while (fix < tif->tif_nfields && tif->tif_fieldinfo[fix]->field_tag < dp->tdir_tag) fix++; } /* * Null out old tags that we ignore. */ if (tif->tif_fieldinfo[fix]->field_bit == FIELD_IGNORE) { ignore: dp->tdir_tag = IGNORE; continue; } /* * Check data type. */ fip = tif->tif_fieldinfo[fix]; while (dp->tdir_type != (unsigned short) fip->field_type && fix < tif->tif_nfields) { if (fip->field_type == TIFF_ANY) /* wildcard */ break; fip = tif->tif_fieldinfo[++fix]; if (fix >= tif->tif_nfields || fip->field_tag != dp->tdir_tag) { TIFFWarningExt(tif->tif_clientdata, module, "%s: wrong data type %d for \"%s\"; tag ignored", tif->tif_name, dp->tdir_type, tif->tif_fieldinfo[fix-1]->field_name); goto ignore; } } /* * Check count if known in advance. */ if (fip->field_readcount != TIFF_VARIABLE && fip->field_readcount != TIFF_VARIABLE2) { uint32 expected = (fip->field_readcount == TIFF_SPP) ? (uint32) td->td_samplesperpixel : (uint32) fip->field_readcount; if (!CheckDirCount(tif, dp, expected)) goto ignore; } switch (dp->tdir_tag) { case TIFFTAG_COMPRESSION: /* * The 5.0 spec says the Compression tag has * one value, while earlier specs say it has * one value per sample. Because of this, we * accept the tag if one value is supplied. */ if (dp->tdir_count == 1) { v = TIFFExtractData(tif, dp->tdir_type, dp->tdir_offset); if (!TIFFSetField(tif, dp->tdir_tag, (uint16)v)) goto bad; break; /* XXX: workaround for broken TIFFs */ } else if (dp->tdir_type == TIFF_LONG) { if (!TIFFFetchPerSampleLongs(tif, dp, &v) || !TIFFSetField(tif, dp->tdir_tag, (uint16)v)) goto bad; } else { if (!TIFFFetchPerSampleShorts(tif, dp, &iv) || !TIFFSetField(tif, dp->tdir_tag, iv)) goto bad; } dp->tdir_tag = IGNORE; break; case TIFFTAG_STRIPOFFSETS: case TIFFTAG_STRIPBYTECOUNTS: case TIFFTAG_TILEOFFSETS: case TIFFTAG_TILEBYTECOUNTS: TIFFSetFieldBit(tif, fip->field_bit); break; case TIFFTAG_IMAGEWIDTH: case TIFFTAG_IMAGELENGTH: case TIFFTAG_IMAGEDEPTH: case TIFFTAG_TILELENGTH: case TIFFTAG_TILEWIDTH: case TIFFTAG_TILEDEPTH: case TIFFTAG_PLANARCONFIG: case TIFFTAG_ROWSPERSTRIP: case TIFFTAG_EXTRASAMPLES: if (!TIFFFetchNormalTag(tif, dp)) goto bad; dp->tdir_tag = IGNORE; break; } } /* * Allocate directory structure and setup defaults. */ if (!TIFFFieldSet(tif, FIELD_IMAGEDIMENSIONS)) { MissingRequired(tif, "ImageLength"); goto bad; } /* * Setup appropriate structures (by strip or by tile) */ if (!TIFFFieldSet(tif, FIELD_TILEDIMENSIONS)) { td->td_nstrips = TIFFNumberOfStrips(tif); td->td_tilewidth = td->td_imagewidth; td->td_tilelength = td->td_rowsperstrip; td->td_tiledepth = td->td_imagedepth; tif->tif_flags &= ~TIFF_ISTILED; } else { td->td_nstrips = TIFFNumberOfTiles(tif); tif->tif_flags |= TIFF_ISTILED; } if (!td->td_nstrips) { TIFFErrorExt(tif->tif_clientdata, module, "%s: cannot handle zero number of %s", tif->tif_name, isTiled(tif) ? "tiles" : "strips"); goto bad; } td->td_stripsperimage = td->td_nstrips; if (td->td_planarconfig == PLANARCONFIG_SEPARATE) td->td_stripsperimage /= td->td_samplesperpixel; if (!TIFFFieldSet(tif, FIELD_STRIPOFFSETS)) { MissingRequired(tif, isTiled(tif) ? "TileOffsets" : "StripOffsets"); goto bad; } /* * Second pass: extract other information. */ for (dp = dir, n = dircount; n > 0; n--, dp++) { if (dp->tdir_tag == IGNORE) continue; switch (dp->tdir_tag) { case TIFFTAG_MINSAMPLEVALUE: case TIFFTAG_MAXSAMPLEVALUE: case TIFFTAG_BITSPERSAMPLE: case TIFFTAG_DATATYPE: case TIFFTAG_SAMPLEFORMAT: /* * The 5.0 spec says the Compression tag has * one value, while earlier specs say it has * one value per sample. Because of this, we * accept the tag if one value is supplied. * * The MinSampleValue, MaxSampleValue, BitsPerSample * DataType and SampleFormat tags are supposed to be * written as one value/sample, but some vendors * incorrectly write one value only -- so we accept * that as well (yech). Other vendors write correct * value for NumberOfSamples, but incorrect one for * BitsPerSample and friends, and we will read this * too. */ if (dp->tdir_count == 1) { v = TIFFExtractData(tif, dp->tdir_type, dp->tdir_offset); if (!TIFFSetField(tif, dp->tdir_tag, (uint16)v)) goto bad; /* XXX: workaround for broken TIFFs */ } else if (dp->tdir_tag == TIFFTAG_BITSPERSAMPLE && dp->tdir_type == TIFF_LONG) { if (!TIFFFetchPerSampleLongs(tif, dp, &v) || !TIFFSetField(tif, dp->tdir_tag, (uint16)v)) goto bad; } else { if (!TIFFFetchPerSampleShorts(tif, dp, &iv) || !TIFFSetField(tif, dp->tdir_tag, iv)) goto bad; } break; case TIFFTAG_SMINSAMPLEVALUE: case TIFFTAG_SMAXSAMPLEVALUE: { double dv = 0.0; if (!TIFFFetchPerSampleAnys(tif, dp, &dv) || !TIFFSetField(tif, dp->tdir_tag, dv))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -