void TIFFCleanup(TIFF *tif) { if (tif->tif_mode != O_RDONLY) /* * Flush buffered data and directory (if dirty). */ TIFFFlush(tif); (*tif->tif_cleanup)(tif); TIFFFreeDirectory(tif); if (tif->tif_dirlist) _TIFFfree(tif->tif_dirlist); /* Clean up client info links */ while (tif->tif_clientinfo) { TIFFClientInfoLink *link = tif->tif_clientinfo; tif->tif_clientinfo = link->next; _TIFFfree(link->name); _TIFFfree(link); } if (tif->tif_rawdata && (tif->tif_flags & TIFF_MYBUFFER)) _TIFFfree(tif->tif_rawdata); if (isMapped(tif)) TIFFUnmapFileContents(tif, tif->tif_base, tif->tif_size); /* Clean up custom fields */ if (tif->tif_nfields > 0) { size_t i; for (i = 0; i < tif->tif_nfields; i++) { TIFFFieldInfo *fld = tif->tif_fieldinfo[i]; if (fld->field_bit == FIELD_CUSTOM && strncmp("Tag ", fld->field_name, 4) == 0) { _TIFFfree(fld->field_name); _TIFFfree(fld); } } _TIFFfree(tif->tif_fieldinfo); } _TIFFfree(tif); }
void TIFFClose(TIFF* tif) { if (tif->tif_mode != O_RDONLY) /* * Flush buffered data and directory (if dirty). */ TIFFFlush(tif); (*tif->tif_cleanup)(tif); TIFFFreeDirectory(tif); if (tif->tif_rawdata && (tif->tif_flags&TIFF_MYBUFFER)) _TIFFfree(tif->tif_rawdata); if (isMapped(tif)) TIFFUnmapFileContents(tif, tif->tif_base, tif->tif_size); (void) TIFFCloseFile(tif); if (tif->tif_fieldinfo) _TIFFfree(tif->tif_fieldinfo); _TIFFfree(tif); }
/* * Write the contents of the current directory * to the specified file. This routine doesn't * handle overwriting a directory with auxiliary * storage that's been changed. */ static int _TIFFWriteDirectory(TIFF* tif, int done) { uint16 dircount; toff_t diroff; ttag_t tag; uint32 nfields; tsize_t dirsize; char* data; TIFFDirEntry* dir; TIFFDirectory* td; u_long b, fields[FIELD_SETLONGS]; int fi, nfi; if (tif->tif_mode == O_RDONLY) return (1); /* * Clear write state so that subsequent images with * different characteristics get the right buffers * setup for them. */ if (done) { if (tif->tif_flags & TIFF_POSTENCODE) { tif->tif_flags &= ~TIFF_POSTENCODE; if (!(*tif->tif_postencode)(tif)) { TIFFError(tif->tif_name, "Error post-encoding before directory write"); return (0); } } (*tif->tif_close)(tif); /* shutdown encoder */ /* * Flush any data that might have been written * by the compression close+cleanup routines. */ if (tif->tif_rawcc > 0 && !TIFFFlushData1(tif)) { TIFFError(tif->tif_name, "Error flushing data before directory write"); return (0); } if ((tif->tif_flags & TIFF_MYBUFFER) && tif->tif_rawdata) { _TIFFfree(tif->tif_rawdata); tif->tif_rawdata = NULL; tif->tif_rawcc = 0; tif->tif_rawdatasize = 0; } tif->tif_flags &= ~(TIFF_BEENWRITING|TIFF_BUFFERSETUP); } td = &tif->tif_dir; /* * Size the directory so that we can calculate * offsets for the data items that aren't kept * in-place in each field. */ nfields = 0; for (b = 0; b <= FIELD_LAST; b++) if (TIFFFieldSet(tif, b) && b != FIELD_CUSTOM) nfields += (b < FIELD_SUBFILETYPE ? 2 : 1); nfields += td->td_customValueCount; dirsize = nfields * sizeof (TIFFDirEntry); data = (char*) _TIFFmalloc(dirsize); if (data == NULL) { TIFFError(tif->tif_name, "Cannot write directory, out of space"); return (0); } /* * Directory hasn't been placed yet, put * it at the end of the file and link it * into the existing directory structure. */ if (tif->tif_diroff == 0 && !TIFFLinkDirectory(tif)) goto bad; tif->tif_dataoff = (toff_t)( tif->tif_diroff + sizeof (uint16) + dirsize + sizeof (toff_t)); if (tif->tif_dataoff & 1) tif->tif_dataoff++; (void) TIFFSeekFile(tif, tif->tif_dataoff, SEEK_SET); tif->tif_curdir++; dir = (TIFFDirEntry*) data; /* * Setup external form of directory * entries and write data items. */ _TIFFmemcpy(fields, td->td_fieldsset, sizeof (fields)); /* * Write out ExtraSamples tag only if * extra samples are present in the data. */ if (FieldSet(fields, FIELD_EXTRASAMPLES) && !td->td_extrasamples) { ResetFieldBit(fields, FIELD_EXTRASAMPLES); nfields--; dirsize -= sizeof (TIFFDirEntry); } /*XXX*/ for (fi = 0, nfi = tif->tif_nfields; nfi > 0; nfi--, fi++) { const TIFFFieldInfo* fip = tif->tif_fieldinfo[fi]; /* ** For custom fields, we test to see if the custom field ** is set or not. For normal fields, we just use the ** FieldSet test. */ if( fip->field_bit == FIELD_CUSTOM ) { int ci, is_set = FALSE; for( ci = 0; ci < td->td_customValueCount; ci++ ) is_set |= (td->td_customValues[ci].info == fip); if( !is_set ) continue; } else if (!FieldSet(fields, fip->field_bit)) continue; /* ** Handle other fields. */ switch (fip->field_bit) { case FIELD_STRIPOFFSETS: /* * We use one field bit for both strip and tile * offsets, and so must be careful in selecting * the appropriate field descriptor (so that tags * are written in sorted order). */ tag = isTiled(tif) ? TIFFTAG_TILEOFFSETS : TIFFTAG_STRIPOFFSETS; if (tag != fip->field_tag) continue; if (!TIFFWriteLongArray(tif, TIFF_LONG, tag, dir, (uint32) td->td_nstrips, td->td_stripoffset)) goto bad; break; case FIELD_STRIPBYTECOUNTS: /* * We use one field bit for both strip and tile * byte counts, and so must be careful in selecting * the appropriate field descriptor (so that tags * are written in sorted order). */ tag = isTiled(tif) ? TIFFTAG_TILEBYTECOUNTS : TIFFTAG_STRIPBYTECOUNTS; if (tag != fip->field_tag) continue; if (!TIFFWriteLongArray(tif, TIFF_LONG, tag, dir, (uint32) td->td_nstrips, td->td_stripbytecount)) goto bad; break; case FIELD_ROWSPERSTRIP: TIFFSetupShortLong(tif, TIFFTAG_ROWSPERSTRIP, dir, td->td_rowsperstrip); break; case FIELD_COLORMAP: if (!TIFFWriteShortTable(tif, TIFFTAG_COLORMAP, dir, 3, td->td_colormap)) goto bad; break; case FIELD_IMAGEDIMENSIONS: TIFFSetupShortLong(tif, TIFFTAG_IMAGEWIDTH, dir++, td->td_imagewidth); TIFFSetupShortLong(tif, TIFFTAG_IMAGELENGTH, dir, td->td_imagelength); break; case FIELD_TILEDIMENSIONS: TIFFSetupShortLong(tif, TIFFTAG_TILEWIDTH, dir++, td->td_tilewidth); TIFFSetupShortLong(tif, TIFFTAG_TILELENGTH, dir, td->td_tilelength); break; case FIELD_COMPRESSION: TIFFSetupShort(tif, TIFFTAG_COMPRESSION, dir, td->td_compression); break; case FIELD_PHOTOMETRIC: TIFFSetupShort(tif, TIFFTAG_PHOTOMETRIC, dir, td->td_photometric); break; case FIELD_POSITION: WriteRationalPair(TIFF_RATIONAL, TIFFTAG_XPOSITION, td->td_xposition, TIFFTAG_YPOSITION, td->td_yposition); break; case FIELD_RESOLUTION: WriteRationalPair(TIFF_RATIONAL, TIFFTAG_XRESOLUTION, td->td_xresolution, TIFFTAG_YRESOLUTION, td->td_yresolution); break; case FIELD_BITSPERSAMPLE: case FIELD_MINSAMPLEVALUE: case FIELD_MAXSAMPLEVALUE: case FIELD_SAMPLEFORMAT: if (!TIFFWritePerSampleShorts(tif, fip->field_tag, dir)) goto bad; break; case FIELD_SMINSAMPLEVALUE: case FIELD_SMAXSAMPLEVALUE: if (!TIFFWritePerSampleAnys(tif, _TIFFSampleToTagType(tif), fip->field_tag, dir)) goto bad; break; case FIELD_PAGENUMBER: case FIELD_HALFTONEHINTS: #ifdef YCBCR_SUPPORT case FIELD_YCBCRSUBSAMPLING: #endif #ifdef CMYK_SUPPORT case FIELD_DOTRANGE: #endif if (!TIFFSetupShortPair(tif, fip->field_tag, dir)) goto bad; break; #ifdef CMYK_SUPPORT case FIELD_INKNAMES: if (!TIFFWriteInkNames(tif, dir)) goto bad; break; #endif #ifdef COLORIMETRY_SUPPORT case FIELD_TRANSFERFUNCTION: if (!TIFFWriteTransferFunction(tif, dir)) goto bad; break; #endif #if SUBIFD_SUPPORT case FIELD_SUBIFD: if (!TIFFWriteNormalTag(tif, dir, fip)) goto bad; /* * Total hack: if this directory includes a SubIFD * tag then force the next <n> directories to be * written as ``sub directories'' of this one. This * is used to write things like thumbnails and * image masks that one wants to keep out of the * normal directory linkage access mechanism. */ if (dir->tdir_count > 0) { tif->tif_flags |= TIFF_INSUBIFD; tif->tif_nsubifd = (uint16) dir->tdir_count; if (dir->tdir_count > 1) tif->tif_subifdoff = dir->tdir_offset; else tif->tif_subifdoff = (uint32)( tif->tif_diroff + sizeof (uint16) + ((char*)&dir->tdir_offset-data)); } break; #endif default: if (!TIFFWriteNormalTag(tif, dir, fip)) goto bad; break; } dir++; if( fip->field_bit != FIELD_CUSTOM ) ResetFieldBit(fields, fip->field_bit); } /* * Write directory. */ dircount = (uint16) nfields; diroff = (uint32) tif->tif_nextdiroff; if (tif->tif_flags & TIFF_SWAB) { /* * The file's byte order is opposite to the * native machine architecture. We overwrite * the directory information with impunity * because it'll be released below after we * write it to the file. Note that all the * other tag construction routines assume that * we do this byte-swapping; i.e. they only * byte-swap indirect data. */ for (dir = (TIFFDirEntry*) data; dircount; dir++, dircount--) { TIFFSwabArrayOfShort(&dir->tdir_tag, 2); TIFFSwabArrayOfLong(&dir->tdir_count, 2); } dircount = (uint16) nfields; TIFFSwabShort(&dircount); TIFFSwabLong(&diroff); } (void) TIFFSeekFile(tif, tif->tif_diroff, SEEK_SET); if (!WriteOK(tif, &dircount, sizeof (dircount))) { TIFFError(tif->tif_name, "Error writing directory count"); goto bad; } if (!WriteOK(tif, data, dirsize)) { TIFFError(tif->tif_name, "Error writing directory contents"); goto bad; } if (!WriteOK(tif, &diroff, sizeof (diroff))) { TIFFError(tif->tif_name, "Error writing directory link"); goto bad; } if (done) { TIFFFreeDirectory(tif); tif->tif_flags &= ~TIFF_DIRTYDIRECT; (*tif->tif_cleanup)(tif); /* * Reset directory-related state for subsequent * directories. */ TIFFCreateDirectory(tif); } _TIFFfree(data); return (1); bad: _TIFFfree(data); return (0); }
toff_t GTIFFWriteDirectory(TIFF *hTIFF, int nSubfileType, int nXSize, int nYSize, int nBitsPerPixel, int nPlanarConfig, int nSamples, int nBlockXSize, int nBlockYSize, int bTiled, int nCompressFlag, int nPhotometric, int nSampleFormat, int nPredictor, unsigned short *panRed, unsigned short *panGreen, unsigned short *panBlue, int nExtraSamples, unsigned short *panExtraSampleValues, const char *pszMetadata ) { toff_t nBaseDirOffset; toff_t nOffset; nBaseDirOffset = TIFFCurrentDirOffset( hTIFF ); #if defined(TIFFLIB_VERSION) && TIFFLIB_VERSION >= 20051201 /* 3.8.0 */ TIFFFreeDirectory( hTIFF ); #endif TIFFCreateDirectory( hTIFF ); /* -------------------------------------------------------------------- */ /* Setup TIFF fields. */ /* -------------------------------------------------------------------- */ TIFFSetField( hTIFF, TIFFTAG_IMAGEWIDTH, nXSize ); TIFFSetField( hTIFF, TIFFTAG_IMAGELENGTH, nYSize ); if( nSamples == 1 ) TIFFSetField( hTIFF, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG ); else TIFFSetField( hTIFF, TIFFTAG_PLANARCONFIG, nPlanarConfig ); TIFFSetField( hTIFF, TIFFTAG_BITSPERSAMPLE, nBitsPerPixel ); TIFFSetField( hTIFF, TIFFTAG_SAMPLESPERPIXEL, nSamples ); TIFFSetField( hTIFF, TIFFTAG_COMPRESSION, nCompressFlag ); TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, nPhotometric ); TIFFSetField( hTIFF, TIFFTAG_SAMPLEFORMAT, nSampleFormat ); if( bTiled ) { TIFFSetField( hTIFF, TIFFTAG_TILEWIDTH, nBlockXSize ); TIFFSetField( hTIFF, TIFFTAG_TILELENGTH, nBlockYSize ); } else TIFFSetField( hTIFF, TIFFTAG_ROWSPERSTRIP, nBlockYSize ); TIFFSetField( hTIFF, TIFFTAG_SUBFILETYPE, nSubfileType ); if (panExtraSampleValues != NULL) { TIFFSetField(hTIFF, TIFFTAG_EXTRASAMPLES, nExtraSamples, panExtraSampleValues ); } if ( nCompressFlag == COMPRESSION_LZW || nCompressFlag == COMPRESSION_ADOBE_DEFLATE ) TIFFSetField( hTIFF, TIFFTAG_PREDICTOR, nPredictor ); /* -------------------------------------------------------------------- */ /* Write color table if one is present. */ /* -------------------------------------------------------------------- */ if( panRed != NULL ) { TIFFSetField( hTIFF, TIFFTAG_COLORMAP, panRed, panGreen, panBlue ); } /* -------------------------------------------------------------------- */ /* Write metadata if we have some. */ /* -------------------------------------------------------------------- */ if( pszMetadata && strlen(pszMetadata) > 0 ) TIFFSetField( hTIFF, TIFFTAG_GDAL_METADATA, pszMetadata ); /* -------------------------------------------------------------------- */ /* Write directory, and return byte offset. */ /* -------------------------------------------------------------------- */ if( TIFFWriteCheck( hTIFF, bTiled, "GTIFFWriteDirectory" ) == 0 ) { TIFFSetSubDirectory( hTIFF, nBaseDirOffset ); return 0; } TIFFWriteDirectory( hTIFF ); TIFFSetDirectory( hTIFF, (tdir_t) (TIFFNumberOfDirectories(hTIFF)-1) ); nOffset = TIFFCurrentDirOffset( hTIFF ); TIFFSetSubDirectory( hTIFF, nBaseDirOffset ); return nOffset; }
/* * Read the next TIFF directory from a file * and convert it to the internal format. * We read directories sequentially. */ int TIFFReadDirectory(TIFF* tif) { register TIFFDirEntry* dp; register int n; register TIFFDirectory* td; TIFFDirEntry* dir; int iv; long v; double dv; const TIFFFieldInfo* fip; int fix; uint16 dircount; toff_t nextdiroff; char* cp; int diroutoforderwarning = 0; tif->tif_diroff = tif->tif_nextdiroff; if (tif->tif_diroff == 0) /* no more directories */ return (0); /* * Cleanup any previous compression state. */ (*tif->tif_cleanup)(tif); tif->tif_curdir++; nextdiroff = 0; if (!isMapped(tif)) { if (!SeekOK(tif, tif->tif_diroff)) { TIFFError(tif->tif_name, "Seek error accessing TIFF directory"); return (0); } if (!ReadOK(tif, &dircount, sizeof (uint16))) { TIFFError(tif->tif_name, "Can not read TIFF directory count"); return (0); } if (tif->tif_flags & TIFF_SWAB) TIFFSwabShort(&dircount); dir = (TIFFDirEntry *)CheckMalloc(tif, dircount * sizeof (TIFFDirEntry), "to read TIFF directory"); if (dir == NULL) return (0); if (!ReadOK(tif, dir, dircount*sizeof (TIFFDirEntry))) { TIFFError(tif->tif_name, "Can not read TIFF directory"); 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) { TIFFError(tif->tif_name, "Can not read TIFF directory count"); return (0); } else _TIFFmemcpy(&dircount, tif->tif_base + off, sizeof (uint16)); off += sizeof (uint16); if (tif->tif_flags & TIFF_SWAB) TIFFSwabShort(&dircount); dir = (TIFFDirEntry *)CheckMalloc(tif, dircount * sizeof (TIFFDirEntry), "to read TIFF directory"); if (dir == NULL) return (0); if (off + dircount*sizeof (TIFFDirEntry) > tif->tif_size) { TIFFError(tif->tif_name, "Can not read TIFF directory"); 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++) { /* * Find the field information entry for this tag. * Added check for tags to ignore ... [BFC] */ if( TIFFReassignTagToIgnore(TIS_EXTRACT, dp->tdir_tag) ) dp->tdir_tag = IGNORE; if (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) { TIFFWarning(tif->tif_name, "invalid TIFF directory; tags are not sorted in ascending order"); 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) { TIFFWarning(tif->tif_name, "unknown field with tag %d (0x%x) ignored", dp->tdir_tag, dp->tdir_tag); dp->tdir_tag = IGNORE; fix = 0; /* restart search */ continue; } /* * 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 != (u_short) fip->field_type) { if (fip->field_type == TIFF_ANY) /* wildcard */ break; fip++, fix++; if (fix == tif->tif_nfields || fip->field_tag != dp->tdir_tag) { TIFFWarning(tif->tif_name, "wrong data type %d for \"%s\"; tag ignored", dp->tdir_type, fip[-1].field_name); goto ignore; } } /* * Check count if known in advance. */ if (fip->field_readcount != TIFF_VARIABLE) { 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, (int)v)) goto bad; break; } 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: if (!TIFFFetchNormalTag(tif, dp)) goto bad; dp->tdir_tag = IGNORE; break; case TIFFTAG_EXTRASAMPLES: (void) TIFFFetchExtraSamples(tif, dp); dp->tdir_tag = IGNORE; break; } } /* * Allocate directory structure and setup defaults. */ if (!TIFFFieldSet(tif, FIELD_IMAGEDIMENSIONS)) { MissingRequired(tif, "ImageLength"); goto bad; } if (!TIFFFieldSet(tif, FIELD_PLANARCONFIG)) { MissingRequired(tif, "PlanarConfiguration"); 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; } 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: /* * 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 and * BitsPerSample 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). */ if (dp->tdir_count == 1) { v = TIFFExtractData(tif, dp->tdir_type, dp->tdir_offset); if (!TIFFSetField(tif, dp->tdir_tag, (int)v)) goto bad; break; } /* fall thru... */ case TIFFTAG_DATATYPE: case TIFFTAG_SAMPLEFORMAT: if (!TIFFFetchPerSampleShorts(tif, dp, &iv) || !TIFFSetField(tif, dp->tdir_tag, iv)) goto bad; break; case TIFFTAG_SMINSAMPLEVALUE: case TIFFTAG_SMAXSAMPLEVALUE: if (!TIFFFetchPerSampleAnys(tif, dp, &dv) || !TIFFSetField(tif, dp->tdir_tag, dv)) goto bad; break; case TIFFTAG_STRIPOFFSETS: case TIFFTAG_TILEOFFSETS: if (!TIFFFetchStripThing(tif, dp, td->td_nstrips, &td->td_stripoffset)) goto bad; break; case TIFFTAG_STRIPBYTECOUNTS: case TIFFTAG_TILEBYTECOUNTS: if (!TIFFFetchStripThing(tif, dp, td->td_nstrips, &td->td_stripbytecount)) goto bad; break; case TIFFTAG_COLORMAP: case TIFFTAG_TRANSFERFUNCTION: /* * TransferFunction can have either 1x or 3x data * values; Colormap can have only 3x items. */ v = 1L<<td->td_bitspersample; if (dp->tdir_tag == TIFFTAG_COLORMAP || dp->tdir_count != (uint32) v) { if (!CheckDirCount(tif, dp, (uint32)(3*v))) break; } v *= sizeof (uint16); cp = CheckMalloc(tif, dp->tdir_count * sizeof (uint16), "to read \"TransferFunction\" tag"); if (cp != NULL) { if (TIFFFetchData(tif, dp, cp)) { /* * This deals with there being only * one array to apply to all samples. */ uint32 c = (uint32)1 << td->td_bitspersample; if (dp->tdir_count == c) v = 0; TIFFSetField(tif, dp->tdir_tag, cp, cp+v, cp+2*v); } _TIFFfree(cp); } break; case TIFFTAG_PAGENUMBER: case TIFFTAG_HALFTONEHINTS: case TIFFTAG_YCBCRSUBSAMPLING: case TIFFTAG_DOTRANGE: (void) TIFFFetchShortPair(tif, dp); break; #ifdef COLORIMETRY_SUPPORT case TIFFTAG_REFERENCEBLACKWHITE: (void) TIFFFetchRefBlackWhite(tif, dp); break; #endif /* BEGIN REV 4.0 COMPATIBILITY */ case TIFFTAG_OSUBFILETYPE: v = 0; switch (TIFFExtractData(tif, dp->tdir_type, dp->tdir_offset)) { case OFILETYPE_REDUCEDIMAGE: v = FILETYPE_REDUCEDIMAGE; break; case OFILETYPE_PAGE: v = FILETYPE_PAGE; break; } if (v) (void) TIFFSetField(tif, TIFFTAG_SUBFILETYPE, (int)v); break; /* END REV 4.0 COMPATIBILITY */ default: (void) TIFFFetchNormalTag(tif, dp); break; } } /* * Verify Palette image has a Colormap. */ if (td->td_photometric == PHOTOMETRIC_PALETTE && !TIFFFieldSet(tif, FIELD_COLORMAP)) { MissingRequired(tif, "Colormap"); goto bad; } /* * Attempt to deal with a missing StripByteCounts tag. */ if (!TIFFFieldSet(tif, FIELD_STRIPBYTECOUNTS)) { /* * Some manufacturers violate the spec by not giving * the size of the strips. In this case, assume there * is one uncompressed strip of data. */ if ((td->td_planarconfig == PLANARCONFIG_CONTIG && td->td_nstrips > 1) || (td->td_planarconfig == PLANARCONFIG_SEPARATE && td->td_nstrips != td->td_samplesperpixel)) { MissingRequired(tif, "StripByteCounts"); goto bad; } TIFFWarning(tif->tif_name, "TIFF directory is missing required \"%s\" field, calculating from imagelength", _TIFFFieldWithTag(tif,TIFFTAG_STRIPBYTECOUNTS)->field_name); EstimateStripByteCounts(tif, dir, dircount); #define BYTECOUNTLOOKSBAD \ ((td->td_stripbytecount[0] == 0 && td->td_stripoffset[0] != 0) || \ (td->td_compression == COMPRESSION_NONE && \ td->td_stripbytecount[0] > TIFFGetFileSize(tif) - td->td_stripoffset[0])) } else if (td->td_nstrips == 1 && BYTECOUNTLOOKSBAD) { /* * Plexus (and others) sometimes give a value * of zero for a tag when they don't know what * the correct value is! Try and handle the * simple case of estimating the size of a one * strip image. */ TIFFWarning(tif->tif_name, "Bogus \"%s\" field, ignoring and calculating from imagelength", _TIFFFieldWithTag(tif,TIFFTAG_STRIPBYTECOUNTS)->field_name); EstimateStripByteCounts(tif, dir, dircount); } if (dir) _TIFFfree((char *)dir); if (!TIFFFieldSet(tif, FIELD_MAXSAMPLEVALUE)) td->td_maxsamplevalue = (uint16)((1L<<td->td_bitspersample)-1); /* * Setup default compression scheme. */ if (!TIFFFieldSet(tif, FIELD_COMPRESSION)) TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE); /* * Some manufacturers make life difficult by writing * large amounts of uncompressed data as a single strip. * This is contrary to the recommendations of the spec. * The following makes an attempt at breaking such images * into strips closer to the recommended 8k bytes. A * side effect, however, is that the RowsPerStrip tag * value may be changed. */ if (td->td_nstrips == 1 && td->td_compression == COMPRESSION_NONE && (tif->tif_flags & (TIFF_STRIPCHOP|TIFF_ISTILED)) == TIFF_STRIPCHOP) ChopUpSingleUncompressedStrip(tif); /* * Reinitialize i/o since we are starting on a new directory. */ tif->tif_row = (uint32) -1; tif->tif_curstrip = (tstrip_t) -1; tif->tif_col = (uint32) -1; tif->tif_curtile = (ttile_t) -1; tif->tif_tilesize = TIFFTileSize(tif); tif->tif_scanlinesize = TIFFScanlineSize(tif); return (1); bad: if (dir) _TIFFfree(dir); return (0); }
CPL_C_END /************************************************************************/ /* GTIFFWriteDirectory() */ /* */ /* Create a new directory, without any image data for an overview */ /* or a mask */ /* Returns offset of newly created directory, but the */ /* current directory is reset to be the one in used when this */ /* function is called. */ /************************************************************************/ long GTIFFWriteDirectory(TIFF *hTIFF, int nSubfileType, int nXSize, int nYSize, int nBitsPerPixel, int nPlanarConfig, int nSamples, int nBlockXSize, int nBlockYSize, int bTiled, int nCompressFlag, int nPhotometric, int nSampleFormat, unsigned short *panRed, unsigned short *panGreen, unsigned short *panBlue, int nExtraSamples, unsigned short *panExtraSampleValues, const char *pszMetadata ) { toff_t nBaseDirOffset; toff_t nOffset; nBaseDirOffset = TIFFCurrentDirOffset( hTIFF ); #if defined(TIFFLIB_VERSION) && TIFFLIB_VERSION >= 20051201 /* 3.8.0 */ TIFFFreeDirectory( hTIFF ); #endif TIFFCreateDirectory( hTIFF ); /* -------------------------------------------------------------------- */ /* Setup TIFF fields. */ /* -------------------------------------------------------------------- */ TIFFSetField( hTIFF, TIFFTAG_IMAGEWIDTH, nXSize ); TIFFSetField( hTIFF, TIFFTAG_IMAGELENGTH, nYSize ); if( nSamples == 1 ) TIFFSetField( hTIFF, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG ); else TIFFSetField( hTIFF, TIFFTAG_PLANARCONFIG, nPlanarConfig ); TIFFSetField( hTIFF, TIFFTAG_BITSPERSAMPLE, nBitsPerPixel ); TIFFSetField( hTIFF, TIFFTAG_SAMPLESPERPIXEL, nSamples ); TIFFSetField( hTIFF, TIFFTAG_COMPRESSION, nCompressFlag ); TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, nPhotometric ); TIFFSetField( hTIFF, TIFFTAG_SAMPLEFORMAT, nSampleFormat ); if( bTiled ) { TIFFSetField( hTIFF, TIFFTAG_TILEWIDTH, nBlockXSize ); TIFFSetField( hTIFF, TIFFTAG_TILELENGTH, nBlockYSize ); } else TIFFSetField( hTIFF, TIFFTAG_ROWSPERSTRIP, nBlockYSize ); TIFFSetField( hTIFF, TIFFTAG_SUBFILETYPE, nSubfileType ); if (panExtraSampleValues != NULL) { TIFFSetField(hTIFF, TIFFTAG_EXTRASAMPLES, nExtraSamples, panExtraSampleValues ); } /* -------------------------------------------------------------------- */ /* Write color table if one is present. */ /* -------------------------------------------------------------------- */ if( panRed != NULL ) { TIFFSetField( hTIFF, TIFFTAG_COLORMAP, panRed, panGreen, panBlue ); } /* -------------------------------------------------------------------- */ /* Write metadata if we have some. */ /* -------------------------------------------------------------------- */ if( pszMetadata && strlen(pszMetadata) > 0 ) TIFFSetField( hTIFF, TIFFTAG_GDAL_METADATA, pszMetadata ); /* -------------------------------------------------------------------- */ /* Write directory, and return byte offset. */ /* -------------------------------------------------------------------- */ if( TIFFWriteCheck( hTIFF, bTiled, "GTIFFWriteDirectory" ) == 0 ) { TIFFSetSubDirectory( hTIFF, nBaseDirOffset ); return 0; } TIFFWriteDirectory( hTIFF ); TIFFSetDirectory( hTIFF, (tdir_t) (TIFFNumberOfDirectories(hTIFF)-1) ); nOffset = TIFFCurrentDirOffset( hTIFF ); TIFFSetSubDirectory( hTIFF, nBaseDirOffset ); return nOffset; }
toff_t GTIFFWriteDirectory( TIFF *hTIFF, int nSubfileType, int nXSize, int nYSize, int nBitsPerPixel, int nPlanarConfig, int nSamples, int nBlockXSize, int nBlockYSize, int bTiled, int nCompressFlag, int nPhotometric, int nSampleFormat, int nPredictor, unsigned short *panRed, unsigned short *panGreen, unsigned short *panBlue, int nExtraSamples, unsigned short *panExtraSampleValues, const char *pszMetadata, const char* pszJPEGQuality, const char* pszJPEGTablesMode, const char* pszNoData, CPL_UNUSED const uint32* panLercAddCompressionAndVersion ) { const toff_t nBaseDirOffset = TIFFCurrentDirOffset( hTIFF ); // This is a bit of a hack to cause (*tif->tif_cleanup)(tif); to be called. // See https://trac.osgeo.org/gdal/ticket/2055 TIFFSetField( hTIFF, TIFFTAG_COMPRESSION, COMPRESSION_NONE ); #if defined(TIFFLIB_VERSION) && TIFFLIB_VERSION >= 20051201 // 3.8.0 TIFFFreeDirectory( hTIFF ); #endif TIFFCreateDirectory( hTIFF ); /* -------------------------------------------------------------------- */ /* Setup TIFF fields. */ /* -------------------------------------------------------------------- */ TIFFSetField( hTIFF, TIFFTAG_IMAGEWIDTH, nXSize ); TIFFSetField( hTIFF, TIFFTAG_IMAGELENGTH, nYSize ); if( nSamples == 1 ) TIFFSetField( hTIFF, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG ); else TIFFSetField( hTIFF, TIFFTAG_PLANARCONFIG, nPlanarConfig ); TIFFSetField( hTIFF, TIFFTAG_BITSPERSAMPLE, nBitsPerPixel ); TIFFSetField( hTIFF, TIFFTAG_SAMPLESPERPIXEL, nSamples ); TIFFSetField( hTIFF, TIFFTAG_COMPRESSION, nCompressFlag ); TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, nPhotometric ); TIFFSetField( hTIFF, TIFFTAG_SAMPLEFORMAT, nSampleFormat ); if( bTiled ) { TIFFSetField( hTIFF, TIFFTAG_TILEWIDTH, nBlockXSize ); TIFFSetField( hTIFF, TIFFTAG_TILELENGTH, nBlockYSize ); } else { TIFFSetField( hTIFF, TIFFTAG_ROWSPERSTRIP, nBlockYSize ); } TIFFSetField( hTIFF, TIFFTAG_SUBFILETYPE, nSubfileType ); if( panExtraSampleValues != nullptr ) { TIFFSetField( hTIFF, TIFFTAG_EXTRASAMPLES, nExtraSamples, panExtraSampleValues ); } if( nCompressFlag == COMPRESSION_LZW || nCompressFlag == COMPRESSION_ADOBE_DEFLATE || nCompressFlag == COMPRESSION_ZSTD ) TIFFSetField( hTIFF, TIFFTAG_PREDICTOR, nPredictor ); /* -------------------------------------------------------------------- */ /* Write color table if one is present. */ /* -------------------------------------------------------------------- */ if( panRed != nullptr ) { TIFFSetField( hTIFF, TIFFTAG_COLORMAP, panRed, panGreen, panBlue ); } /* -------------------------------------------------------------------- */ /* Write metadata if we have some. */ /* -------------------------------------------------------------------- */ if( pszMetadata && strlen(pszMetadata) > 0 ) TIFFSetField( hTIFF, TIFFTAG_GDAL_METADATA, pszMetadata ); /* -------------------------------------------------------------------- */ /* Write JPEG tables if needed. */ /* -------------------------------------------------------------------- */ if( nCompressFlag == COMPRESSION_JPEG ) { GTiffWriteJPEGTables( hTIFF, (nPhotometric == PHOTOMETRIC_RGB) ? "RGB" : (nPhotometric == PHOTOMETRIC_YCBCR) ? "YCBCR" : "MINISBLACK", pszJPEGQuality, pszJPEGTablesMode ); if( nPhotometric == PHOTOMETRIC_YCBCR ) { // Explicitly register the subsampling so that JPEGFixupTags // is a no-op (helps for cloud optimized geotiffs) TIFFSetField( hTIFF, TIFFTAG_YCBCRSUBSAMPLING, 2, 2 ); } } #ifdef HAVE_LERC if( nCompressFlag == COMPRESSION_LERC && panLercAddCompressionAndVersion ) { TIFFSetField(hTIFF, TIFFTAG_LERC_PARAMETERS, 2, panLercAddCompressionAndVersion); } #endif /* -------------------------------------------------------------------- */ /* Write no data value if we have one. */ /* -------------------------------------------------------------------- */ if( pszNoData != nullptr ) { TIFFSetField( hTIFF, TIFFTAG_GDAL_NODATA, pszNoData ); } /* -------------------------------------------------------------------- */ /* Write directory, and return byte offset. */ /* -------------------------------------------------------------------- */ if( TIFFWriteCheck( hTIFF, bTiled, "GTIFFWriteDirectory" ) == 0 ) { TIFFSetSubDirectory( hTIFF, nBaseDirOffset ); return 0; } TIFFWriteDirectory( hTIFF ); TIFFSetDirectory( hTIFF, static_cast<tdir_t>(TIFFNumberOfDirectories(hTIFF) - 1) ); const toff_t nOffset = TIFFCurrentDirOffset( hTIFF ); TIFFSetSubDirectory( hTIFF, nBaseDirOffset ); return nOffset; }
void TIFFCleanup(TIFF* tif) { /* * Flush buffered data and directory (if dirty). */ if (tif->tif_mode != O_RDONLY) TIFFFlush(tif); (*tif->tif_cleanup)(tif); TIFFFreeDirectory(tif); if (tif->tif_dirlist) _TIFFfree(tif->tif_dirlist); /* * Clean up client info links. */ while( tif->tif_clientinfo ) { TIFFClientInfoLink *psLink = tif->tif_clientinfo; tif->tif_clientinfo = psLink->next; _TIFFfree( psLink->name ); _TIFFfree( psLink ); } if (tif->tif_rawdata && (tif->tif_flags&TIFF_MYBUFFER)) _TIFFfree(tif->tif_rawdata); if (isMapped(tif)) TIFFUnmapFileContents(tif, tif->tif_base, (toff_t)tif->tif_size); /* * Clean up custom fields. */ if (tif->tif_fields && tif->tif_nfields > 0) { uint32 i; for (i = 0; i < tif->tif_nfields; i++) { TIFFField *fld = tif->tif_fields[i]; if (fld->field_bit == FIELD_CUSTOM && strncmp("Tag ", fld->field_name, 4) == 0) { _TIFFfree(fld->field_name); _TIFFfree(fld); } } _TIFFfree(tif->tif_fields); } if (tif->tif_nfieldscompat > 0) { uint32 i; for (i = 0; i < tif->tif_nfieldscompat; i++) { if (tif->tif_fieldscompat[i].allocated_size) _TIFFfree(tif->tif_fieldscompat[i].fields); } _TIFFfree(tif->tif_fieldscompat); } _TIFFfree(tif); }
int main() { TIFF *tif; unsigned char buf[SPP] = { 0, 127, 255 }; uint64 dir_offset = 0, dir_offset2 = 0; uint64 read_dir_offset = 0, read_dir_offset2 = 0; uint64 *dir_offset2_ptr = NULL; char *ascii_value; uint16 count16 = 0; /* We write the main directory as a simple image. */ tif = TIFFOpen(filename, "w+"); if (!tif) { fprintf (stderr, "Can't create test TIFF file %s.\n", filename); return 1; } if (!TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width)) { fprintf (stderr, "Can't set ImageWidth tag.\n"); goto failure; } if (!TIFFSetField(tif, TIFFTAG_IMAGELENGTH, length)) { fprintf (stderr, "Can't set ImageLength tag.\n"); goto failure; } if (!TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bps)) { fprintf (stderr, "Can't set BitsPerSample tag.\n"); goto failure; } if (!TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, SPP)) { fprintf (stderr, "Can't set SamplesPerPixel tag.\n"); goto failure; } if (!TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, rows_per_strip)) { fprintf (stderr, "Can't set SamplesPerPixel tag.\n"); goto failure; } if (!TIFFSetField(tif, TIFFTAG_PLANARCONFIG, planarconfig)) { fprintf (stderr, "Can't set PlanarConfiguration tag.\n"); goto failure; } if (!TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, photometric)) { fprintf (stderr, "Can't set PhotometricInterpretation tag.\n"); goto failure; } /* Write dummy pixel data. */ if (TIFFWriteScanline(tif, buf, 0, 0) == -1) { fprintf (stderr, "Can't write image data.\n"); goto failure; } if (!TIFFWriteDirectory( tif )) { fprintf (stderr, "TIFFWriteDirectory() failed.\n"); goto failure; } /* * Now create an EXIF directory. */ if (TIFFCreateEXIFDirectory(tif) != 0) { fprintf (stderr, "TIFFCreateEXIFDirectory() failed.\n" ); goto failure; } if (!TIFFSetField( tif, EXIFTAG_SPECTRALSENSITIVITY, "EXIF Spectral Sensitivity")) { fprintf (stderr, "Can't write SPECTRALSENSITIVITY\n" ); goto failure; } if (!TIFFWriteCustomDirectory( tif, &dir_offset )) { fprintf (stderr, "TIFFWriteCustomDirectory() with EXIF failed.\n"); goto failure; } /* * Now create a custom directory with tags that conflict with mainline * TIFF tags. */ TIFFFreeDirectory( tif ); if (TIFFCreateCustomDirectory(tif, &customFieldArray) != 0) { fprintf (stderr, "TIFFCreateEXIFDirectory() failed.\n" ); goto failure; } if (!TIFFSetField( tif, TIFFTAG_IMAGEWIDTH, "*Custom1")) { /* not really IMAGEWIDTH */ fprintf (stderr, "Can't write pseudo-IMAGEWIDTH.\n" ); goto failure; } if (!TIFFSetField( tif, TIFFTAG_DOTRANGE, "*Custom2")) { /* not really DOTWIDTH */ fprintf (stderr, "Can't write pseudo-DOTWIDTH.\n" ); goto failure; } if (!TIFFWriteCustomDirectory( tif, &dir_offset2 )) { fprintf (stderr, "TIFFWriteCustomDirectory() with EXIF failed.\n"); goto failure; } /* * Go back to the first directory, and add the EXIFIFD pointer. */ TIFFSetDirectory(tif, 0); TIFFSetField(tif, TIFFTAG_EXIFIFD, dir_offset ); TIFFSetField(tif, TIFFTAG_SUBIFD, 1, &dir_offset2 ); TIFFClose(tif); /* Ok, now test whether we can read written values in the EXIF directory. */ tif = TIFFOpen(filename, "r"); TIFFGetField(tif, TIFFTAG_EXIFIFD, &read_dir_offset ); if( read_dir_offset != dir_offset ) { fprintf (stderr, "Did not get expected EXIFIFD.\n" ); goto failure; } TIFFGetField(tif, TIFFTAG_SUBIFD, &count16, &dir_offset2_ptr ); read_dir_offset2 = dir_offset2_ptr[0]; if( read_dir_offset2 != dir_offset2 || count16 != 1) { fprintf (stderr, "Did not get expected SUBIFD.\n" ); goto failure; } if( !TIFFReadEXIFDirectory(tif, read_dir_offset) ) { fprintf (stderr, "TIFFReadEXIFDirectory() failed.\n" ); goto failure; } if (!TIFFGetField( tif, EXIFTAG_SPECTRALSENSITIVITY, &ascii_value) ) { fprintf (stderr, "reading SPECTRALSENSITIVITY failed.\n" ); goto failure; } if( strcmp(ascii_value,"EXIF Spectral Sensitivity") != 0) { fprintf (stderr, "got wrong SPECTRALSENSITIVITY value.\n" ); goto failure; } /* Try reading the Custom directory */ if( !TIFFReadCustomDirectory(tif, read_dir_offset2, &customFieldArray) ) { fprintf (stderr, "TIFFReadCustomDirectory() failed.\n" ); goto failure; } if (!TIFFGetField( tif, TIFFTAG_IMAGEWIDTH, &ascii_value) ) { fprintf (stderr, "reading pseudo-IMAGEWIDTH failed.\n" ); goto failure; } if( strcmp(ascii_value,"*Custom1") != 0) { fprintf (stderr, "got wrong pseudo-IMAGEWIDTH value.\n" ); goto failure; } if (!TIFFGetField( tif, TIFFTAG_DOTRANGE, &ascii_value) ) { fprintf (stderr, "reading pseudo-DOTRANGE failed.\n" ); goto failure; } if( strcmp(ascii_value,"*Custom2") != 0) { fprintf (stderr, "got wrong pseudo-DOTRANGE value.\n" ); goto failure; } TIFFClose(tif); /* All tests passed; delete file and exit with success status. */ unlink(filename); return 0; failure: /* * Something goes wrong; close file and return unsuccessful status. * Do not remove the file for further manual investigation. */ TIFFClose(tif); return 1; }
/* * Write the contents of the current directory * to the specified file. This routine doesn't * handle overwriting a directory with auxiliary * storage that's been changed. */ static int _TIFFWriteDirectory(TIFF* tif, int done) { uint64 dircount; /* 16-bit or 64-bit directory entry count */ toff_t diroff; /* 32-bit or 64-bit directory offset */ ttag_t tag; uint32 nfields; tsize_t dirsize; char* data; TIFFDirEntry* dir; TIFFDirectory* td; unsigned long b, fields[FIELD_SETLONGS]; int fi, nfi; if (tif->tif_mode == O_RDONLY) return (1); /* * Clear write state so that subsequent images with * different characteristics get the right buffers * setup for them. */ if (done) { if (tif->tif_flags & TIFF_POSTENCODE) { tif->tif_flags &= ~TIFF_POSTENCODE; if (!(*tif->tif_postencode)(tif)) { TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Error post-encoding before directory write"); return (0); } } (*tif->tif_close)(tif); /* shutdown encoder */ /* * Flush any data that might have been written * by the compression close+cleanup routines. */ if (tif->tif_rawcc > 0 && !TIFFFlushData1(tif)) { TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Error flushing data before directory write"); return (0); } if ((tif->tif_flags & TIFF_MYBUFFER) && tif->tif_rawdata) { _TIFFfree(tif->tif_rawdata); tif->tif_rawdata = NULL; tif->tif_rawcc = 0; tif->tif_rawdatasize = 0; } tif->tif_flags &= ~(TIFF_BEENWRITING|TIFF_BUFFERSETUP); } /* * Loop to allow retry in case transition to BigTIFF required */ while (1) { /* * Directory hasn't been placed yet, put * it at the end of the file and link it * into the existing directory structure. */ if (tif->tif_diroff == 0 && !TIFFLinkDirectory(tif)) goto bad2; td = &tif->tif_dir; /* * Size the directory so that we can calculate * offsets for the data items that aren't kept * in-place in each field. */ nfields = 0; for (b = 0; b <= FIELD_LAST; b++) if (TIFFFieldSet(tif, b) && b != FIELD_CUSTOM) nfields += (b < FIELD_SUBFILETYPE ? 2 : 1); nfields += td->td_customValueCount; dirsize = nfields * TDIREntryLen(tif); data = (char*) _TIFFmalloc(dirsize); if (data == NULL) { TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Cannot write directory, out of space"); goto bad2; } _TIFFmemset(data, 0, dirsize); /* * Setup external form of directory * entries and write data items. */ _TIFFmemcpy(fields, td->td_fieldsset, sizeof (fields)); /* * Write out ExtraSamples tag only if * extra samples are present in the data. */ if (FieldSet(fields, FIELD_EXTRASAMPLES) && !td->td_extrasamples) { ResetFieldBit(fields, FIELD_EXTRASAMPLES); nfields--; dirsize -= TDIREntryLen(tif); } /*XXX*/ tif->tif_dataoff = tif->tif_diroff + TIFFDirCntLen(tif) + dirsize + TIFFDirOffLen(tif); (void) TIFFSeekFile(tif, tif->tif_dataoff, SEEK_SET); dir = (TIFFDirEntry*) data; for (fi = 0, nfi = tif->tif_nfields; nfi > 0; nfi--, fi++) { const TIFFFieldInfo* fip = tif->tif_fieldinfo[fi]; /* ** For custom fields, we test to see if the custom field ** is set or not. For normal fields, we just use the ** FieldSet test. */ if( fip->field_bit == FIELD_CUSTOM ) { int ci, is_set = FALSE; for( ci = 0; ci < td->td_customValueCount; ci++ ) is_set |= (td->td_customValues[ci].info == fip); if( !is_set ) continue; } else if (!FieldSet(fields, fip->field_bit)) continue; /* ** Handle other fields. */ switch (fip->field_bit) { case FIELD_STRIPOFFSETS: /* * We use one field bit for both strip and tile * offsets, and so must be careful in selecting * the appropriate field descriptor (so that tags * are written in sorted order). */ tag = (isTiled(tif) ? TIFFTAG_TILEOFFSETS : TIFFTAG_STRIPOFFSETS); if (tag != fip->field_tag) continue; dir->s.tdir_tag = (uint16) tag; TDIRSetEntryCount(tif,dir, (uint32) td->td_nstrips); /* * If file is BigTIFF strip/tile offsets are written as 64-bit, * else convert to array of 32-bit offsets. */ if (isBigTIFF(tif)) { dir->s.tdir_type = (uint16) TIFF_LONG8; if (!TIFFWriteLong8Array(tif, dir, td->td_stripoffset)) goto bad; } else { uint32 tdi; int status; uint32 *soff = _TIFFCheckMalloc(tif, td->td_nstrips, sizeof(uint32), "32-bit offset array"); dir->s.tdir_type = (uint16) TIFF_LONG; for (tdi = 0; tdi < td->td_nstrips; tdi++) soff[tdi] = (uint32) td->td_stripoffset[tdi]; status = TIFFWriteLongArray(tif, dir, soff); _TIFFfree(soff); if (!status) goto bad; } break; case FIELD_STRIPBYTECOUNTS: /* * We use one field bit for both strip and tile * byte counts, and so must be careful in selecting * the appropriate field descriptor (so that tags * are written in sorted order). */ tag = (isTiled(tif) ? TIFFTAG_TILEBYTECOUNTS : TIFFTAG_STRIPBYTECOUNTS); if (tag != fip->field_tag) continue; dir->s.tdir_tag = (uint16) tag; dir->s.tdir_type = (uint16) TIFF_LONG; TDIRSetEntryCount(tif,dir, (uint32) td->td_nstrips); if (!TIFFWriteLongArray(tif, dir, td->td_stripbytecount)) goto bad; break; case FIELD_ROWSPERSTRIP: TIFFSetupShortLong(tif, TIFFTAG_ROWSPERSTRIP, dir, td->td_rowsperstrip); break; case FIELD_COLORMAP: if (!TIFFWriteShortTable(tif, TIFFTAG_COLORMAP, dir, 3, td->td_colormap)) goto bad; break; case FIELD_IMAGEDIMENSIONS: TIFFSetupShortLong(tif, TIFFTAG_IMAGEWIDTH, dir, td->td_imagewidth); TDIREntryNext(tif,dir); TIFFSetupShortLong(tif, TIFFTAG_IMAGELENGTH, dir, td->td_imagelength); break; case FIELD_TILEDIMENSIONS: TIFFSetupShortLong(tif, TIFFTAG_TILEWIDTH, dir, td->td_tilewidth); TDIREntryNext(tif,dir); TIFFSetupShortLong(tif, TIFFTAG_TILELENGTH, dir, td->td_tilelength); break; case FIELD_COMPRESSION: TIFFSetupShort(tif, TIFFTAG_COMPRESSION, dir, td->td_compression); break; case FIELD_PHOTOMETRIC: TIFFSetupShort(tif, TIFFTAG_PHOTOMETRIC, dir, td->td_photometric); break; case FIELD_POSITION: WriteRationalPair(TIFF_RATIONAL, TIFFTAG_XPOSITION, td->td_xposition, TIFFTAG_YPOSITION, td->td_yposition); break; case FIELD_RESOLUTION: WriteRationalPair(TIFF_RATIONAL, TIFFTAG_XRESOLUTION, td->td_xresolution, TIFFTAG_YRESOLUTION, td->td_yresolution); break; case FIELD_BITSPERSAMPLE: case FIELD_MINSAMPLEVALUE: case FIELD_MAXSAMPLEVALUE: case FIELD_SAMPLEFORMAT: if (!TIFFWritePerSampleShorts(tif, fip->field_tag, dir)) goto bad; break; case FIELD_SMINSAMPLEVALUE: case FIELD_SMAXSAMPLEVALUE: if (!TIFFWritePerSampleAnys(tif, _TIFFSampleToTagType(tif), fip->field_tag, dir)) goto bad; break; case FIELD_PAGENUMBER: case FIELD_HALFTONEHINTS: case FIELD_YCBCRSUBSAMPLING: if (!TIFFSetupShortPair(tif, fip->field_tag, dir)) goto bad; break; case FIELD_INKNAMES: if (!TIFFWriteInkNames(tif, dir)) goto bad; break; case FIELD_TRANSFERFUNCTION: if (!TIFFWriteTransferFunction(tif, dir)) goto bad; break; case FIELD_SUBIFD: /* * Total hack: if this directory includes a SubIFD * tag then force the next <n> directories to be * written as ``sub directories'' of this one. This * is used to write things like thumbnails and * image masks that one wants to keep out of the * normal directory linkage access mechanism. * * If file is BigTIFF subdirectory offsets are written as 64-bit, * else as array of 32-bit offsets. At this point the actual * offset values are unknown (will be set in TIFFLinkDirectory). */ dir->s.tdir_tag = (uint16) fip->field_tag; TDIRSetEntryCount(tif,dir, (uint32) td->td_nsubifd); TDIRSetEntryOff(tif,dir, 0); if (td->td_nsubifd > 0) { tif->tif_flags |= TIFF_INSUBIFD; if (isBigTIFF(tif)) { toff_t *doff = _TIFFCheckMalloc(tif, td->td_nsubifd, sizeof(toff_t), "Allocate SubIFD offset array"); if (!doff) goto bad; _TIFFmemset(doff, 0, td->td_nsubifd * sizeof(toff_t)); dir->b.tdir_type = TIFF_IFD8; if (td->td_nsubifd > TIFFDirOffLen(tif) / sizeof(toff_t)) tif->tif_subifdoff = tif->tif_dataoff; else tif->tif_subifdoff = tif->tif_diroff + TIFFDirCntLen(tif) + (char*) &dir->b.tdir_offset - data; if (!TIFFWriteLong8Array(tif, dir, (toff_t*) doff)) goto bad; _TIFFfree(doff); } else { uint32 *doff = _TIFFCheckMalloc(tif, td->td_nsubifd, sizeof(uint32), "Allocate SubIFD offset array"); if (!doff) goto bad; _TIFFmemset(doff, 0, td->td_nsubifd * sizeof(uint32)); dir->b.tdir_type = TIFF_LONG; if (td->td_nsubifd > TIFFDirOffLen(tif) / sizeof(uint32)) tif->tif_subifdoff = tif->tif_dataoff; else tif->tif_subifdoff = tif->tif_diroff + TIFFDirCntLen(tif) + (char*) &dir->s.tdir_offset - data; if (!TIFFWriteLongArray(tif, dir, doff)) goto bad; _TIFFfree(doff); } } break; default: /* XXX: Should be fixed and removed. */ if (fip->field_tag == TIFFTAG_DOTRANGE) { if (!TIFFSetupShortPair(tif, fip->field_tag, dir)) goto bad; } else if (!TIFFWriteNormalTag(tif, dir, fip)) goto bad; break; } TDIREntryNext(tif,dir); if( fip->field_bit != FIELD_CUSTOM ) ResetFieldBit(fields, fip->field_bit); } /* * Check if BigTIFF now required based on data location. If so reset * data offset to overwrite already-written data for directory, then * convert file to BigTIFF and loop to recreate directory. */ if (isBigTIFF(tif) || !isBigOff(tif->tif_dataoff + sizeof(uint32))) break; _TIFFfree(data); tif->tif_dataoff = tif->tif_diroff; if (!TIFFMakeBigTIFF(tif)) goto bad2; tif->tif_diroff = 0; } /* bottom of BigTIFF retry loop */ /* * Write directory. */ tif->tif_curdir++; TIFFSetDirCnt(tif,dircount, (uint32) nfields); TIFFSetDirOff(tif,diroff,tif->tif_nextdiroff); if (tif->tif_flags & TIFF_SWAB) { /* * The file's byte order is opposite to the * native machine architecture. We overwrite * the directory information with impunity * because it'll be released below after we * write it to the file. Note that all the * other tag construction routines assume that * we do this byte-swapping; i.e. they only * byte-swap indirect data. */ uint32 di; for (dir = (TIFFDirEntry*) data, di = 0; di < nfields; TDIREntryNext(tif,dir), di++) { TIFFSwabShort(&dir->s.tdir_tag); TIFFSwabShort(&dir->s.tdir_type); TDIRSwabEntryCount(tif,dir); TDIRSwabEntryOff(tif,dir); } TIFFSwabDirCnt(tif,&dircount); TIFFSwabDirOff(tif,&diroff); } (void) TIFFSeekFile(tif, tif->tif_diroff, SEEK_SET); if (!WriteOK(tif, &dircount, TIFFDirCntLen(tif))) { TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Error writing directory count (%d)", TIFFGetErrno(tif)); goto bad; } if (!WriteOK(tif, data, dirsize)) { TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Error writing directory contents (%d)", TIFFGetErrno(tif)); goto bad; } if (!WriteOK(tif, &diroff, TIFFDirOffLen(tif))) { TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Error writing directory link (%d)", TIFFGetErrno(tif)); goto bad; } if (done) { TIFFFreeDirectory(tif); tif->tif_flags &= ~TIFF_DIRTYDIRECT; (*tif->tif_cleanup)(tif); /* * Reset directory-related state for subsequent * directories. */ TIFFCreateDirectory(tif); } _TIFFfree(data); return (1); bad: _TIFFfree(data); bad2: return (0); }