/* * Write a contiguous directory item. */ static int TIFFWriteData(TIFF* tif, TIFFDirEntry* dir, char* cp) { tsize_t cc; if (tif->tif_flags & TIFF_SWAB) { switch (dir->s.tdir_type) { case TIFF_SHORT: case TIFF_SSHORT: TIFFSwabArrayOfShort((uint16*) cp, TDIRGetEntryCount(tif,dir)); break; case TIFF_LONG: case TIFF_SLONG: case TIFF_IFD: case TIFF_FLOAT: TIFFSwabArrayOfLong((uint32*) cp, TDIRGetEntryCount(tif,dir)); break; case TIFF_LONG8: case TIFF_SLONG8: case TIFF_IFD8: TIFFSwabArrayOfLong8((uint64*) cp, TDIRGetEntryCount(tif,dir)); break; case TIFF_RATIONAL: case TIFF_SRATIONAL: TIFFSwabArrayOfLong((uint32*) cp, 2 * TDIRGetEntryCount(tif,dir)); break; case TIFF_DOUBLE: TIFFSwabArrayOfDouble((double*) cp, TDIRGetEntryCount(tif,dir)); break; } } TDIRSetEntryOff(tif,dir,tif->tif_dataoff); cc = TDIRGetEntryCount(tif,dir) * TIFFDataWidth((TIFFDataType) dir->s.tdir_type); if (SeekOK(tif, tif->tif_dataoff) && WriteOK(tif, cp, cc)) { tif->tif_dataoff += ((cc + 1) & ~1); return (1); } TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Error writing data for field \"%s\" (%d)", _TIFFFieldWithTag(tif, dir->s.tdir_tag)->field_name, TIFFGetErrno(tif)); return (0); }
/* * Append the data to the specified strip. */ static int TIFFAppendToStrip(TIFF* tif, tstrip_t strip, tidata_t data, tsize_t cc) { TIFFDirectory *td = &tif->tif_dir; static const char module[] = "TIFFAppendToStrip"; if (_TIFFGetOffset(tif, strip) == 0 || tif->tif_curoff == 0) { /* * No current offset, set the current strip. */ assert(td->td_nstrips > 0); if (_TIFFGetOffset(tif, strip) != 0) { /* * Prevent overlapping of the data chunks. We need * this to enable in place updating of the compressed * images. Larger blocks will be moved at the end of * the file without any optimization of the spare * space, so such scheme is not too much effective. */ if (td->td_stripbytecountsorted) { if (strip == td->td_nstrips - 1 || _TIFFGetOffset(tif, strip + 1) < _TIFFGetOffset(tif, strip) + cc) { _TIFFSetOffset(tif, strip, TIFFSeekFile(tif, (toff_t)0, SEEK_END)); } } else { tstrip_t i; for (i = 0; i < td->td_nstrips; i++) { if (_TIFFGetOffset(tif, i) > _TIFFGetOffset(tif, strip) && _TIFFGetOffset(tif, i) < _TIFFGetOffset(tif, strip) + cc) { _TIFFSetOffset(tif, strip, TIFFSeekFile(tif, (toff_t)0, SEEK_END)); break; } } } /* check if block will overlap offsets or bytes counts arrays */ if ((td->td_stripoffsoff && _TIFFGetOffset(tif, strip) < td->td_stripoffsoff && _TIFFGetOffset(tif, strip) + cc > td->td_stripoffsoff) || (td->td_stripbcsoff && _TIFFGetOffset(tif, strip) < td->td_stripbcsoff && _TIFFGetOffset(tif, strip) + cc > td->td_stripbcsoff)) _TIFFSetOffset(tif, strip, TIFFSeekFile(tif, (toff_t)0, SEEK_END)); if (!SeekOK(tif, _TIFFGetOffset(tif, strip))) { TIFFErrorExt(tif->tif_clientdata, module, "%s: Seek error at scanline %lu", tif->tif_name, (unsigned long)tif->tif_row); return (0); } } else _TIFFSetOffset(tif, strip, TIFFSeekFile(tif, (toff_t) 0, SEEK_END)); tif->tif_curoff = _TIFFGetOffset(tif, strip); } if (!WriteOK(tif, data, cc)) { TIFFErrorExt(tif->tif_clientdata, module, "%s: Write error at scanline %lu (%d)", tif->tif_name, (unsigned long) tif->tif_row, TIFFGetErrno(tif)); return (0); } tif->tif_curoff += cc; _TIFFSetByteCount(tif, strip, _TIFFGetByteCount(tif, strip) + cc); 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); }
/* * Function to convert standard TIFF file to BigTIFF file. Loop through all directories in * current file (including subdirectories linked via SubIFD arrays) and create corresponding * new directories with 64-bit arrays. The old 32-bit directories are left in the file as * dead space. The data for directory entries are reused by default. Some directory entries * require new data with 64-bit offsets (e.g. stripe/tile offsets and SubIFD arrays). * * Returns 1 if successful, 0 if cannot convert to BigTIFF (TIFF_NOBIGTIFF set * or 32-bit API called). */ static int TIFFMakeBigTIFF(TIFF *tif) { uint32 dirlink = TIFF_HEADER_DIROFF_S, diroff = tif->tif_header.s.tiff_diroff; toff_t dirlinkB = TIFF_HEADER_DIROFF_B, diroffB; uint16 dircount, dirindex; uint64 dircountB; tsize_t dirsize, dirsizeB; int issubifd = 0; uint32 subifdcnt = 0; uint32 subifdlink; toff_t subifdlinkB; char *data, *dataB; TIFFDirEntry *dir, *dirB; /* * Update flags and file header */ if (noBigTIFF(tif)) { TIFFErrorExt((tif)->tif_clientdata, "TIFFCheckBigTIFF", "File > 2^32 and NO BigTIFF specified"); return (0); } tif->tif_flags |= TIFF_ISBIGTIFF; tif->tif_header.b.tiff_version = TIFF_BIGTIFF_VERSION; tif->tif_header.b.tiff_offsize = 8; tif->tif_header.b.tiff_fill = 0; tif->tif_header.b.tiff_diroff = 0; if (tif->tif_flags & TIFF_SWAB) { TIFFSwabShort(&tif->tif_header.b.tiff_version); TIFFSwabShort(&tif->tif_header.b.tiff_offsize); } if (!SeekOK(tif, 0) || !WriteOK(tif, &tif->tif_header, sizeof(TIFFHeader))) { TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Error updating TIFF header (%d)", TIFFGetErrno(tif)); return (0); } if (tif->tif_flags & TIFF_SWAB) { TIFFSwabShort(&tif->tif_header.b.tiff_version); TIFFSwabShort(&tif->tif_header.b.tiff_offsize); } /* * Loop through all directories and rewrite as BigTIFF with 64-bit offsets. This * begins with main IFD chain but may divert to SubIFD arrays as needed. */ while (diroff != 0 && diroff != tif->tif_diroff) { if (!SeekOK(tif, diroff) || !ReadOK(tif, &dircount, sizeof(dircount))) { TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Error reading TIFF directory (%d)", TIFFGetErrno(tif)); return (0); } if (tif->tif_flags & TIFF_SWAB) TIFFSwabShort(&dircount); dircountB = dircount; if (!(data = _TIFFmalloc(dirsize = dircount * TIFFDirEntryLenS)) || !(dataB = _TIFFmalloc(dirsizeB = dircount * TIFFDirEntryLenB))) { TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Error allocating space for directory"); return (0); } if (!SeekOK(tif, diroff + sizeof(dircount)) || !ReadOK(tif, data, dirsize)) { TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Error reading TIFF directory (%d)", TIFFGetErrno(tif)); goto error; } diroffB = tif->tif_dataoff; tif->tif_dataoff += sizeof(dircountB) + dirsizeB + sizeof(toff_t); for (dirindex = 0; dirindex < dircount; dirindex++) { dir = (TIFFDirEntry*) (data + dirindex * TIFFDirEntryLenS); dirB = (TIFFDirEntry*) (dataB + dirindex * TIFFDirEntryLenB); if (tif->tif_flags & TIFF_SWAB) { TIFFSwabShort(&dir->s.tdir_tag); TIFFSwabShort(&dir->s.tdir_type); TIFFSwabLong(&dir->s.tdir_count); TIFFSwabLong(&dir->s.tdir_offset); } dirB->b.tdir_tag = dir->s.tdir_tag; dirB->b.tdir_type = dir->s.tdir_type; dirB->b.tdir_count = dir->s.tdir_count; dirB->b.tdir_offset = 0; /* * If data are in directory entry itself, copy data, else (data are pointed * to by directory entry) copy pointer. This is complicated by the fact that * the old entry had 32-bits of space, and the new has 64-bits, so may have * to read data pointed at by the old entry directly into the new entry. */ switch (dir->s.tdir_type) { case TIFF_UNDEFINED: case TIFF_BYTE: case TIFF_SBYTE: case TIFF_ASCII: if (dir->s.tdir_count <= sizeof(dir->s.tdir_offset)) _TIFFmemcpy(&dirB->b.tdir_offset, &dir->s.tdir_offset, dir->s.tdir_count); else if (dir->s.tdir_count <= sizeof(dirB->b.tdir_count)) { TIFFSeekFile(tif, dir->s.tdir_offset, SEEK_SET); TIFFReadFile(tif, &dirB->b.tdir_offset, dir->s.tdir_count); } else dirB->b.tdir_offset = dir->s.tdir_offset; break; case TIFF_SHORT: case TIFF_SSHORT: if (dir->s.tdir_count <= sizeof(dir->s.tdir_offset) / sizeof(uint16)) _TIFFmemcpy(&dirB->b.tdir_offset, &dir->s.tdir_offset, dir->s.tdir_count * sizeof(uint16)); else if (dir->s.tdir_count <= sizeof(dirB->b.tdir_count) / sizeof(uint16)) { TIFFSeekFile(tif, dir->s.tdir_offset, SEEK_SET); TIFFReadFile(tif, &dirB->b.tdir_offset, dir->s.tdir_count * sizeof(uint16)); if (tif->tif_flags & TIFF_SWAB) TIFFSwabArrayOfShort((uint16*) &dirB->b.tdir_offset, dir->s.tdir_count); } else dirB->b.tdir_offset = dir->s.tdir_offset; break; case TIFF_LONG: case TIFF_FLOAT: case TIFF_IFD: if (dir->s.tdir_count <= sizeof(dir->s.tdir_offset) / sizeof(uint32)) _TIFFmemcpy(&dirB->b.tdir_offset, &dir->s.tdir_offset, dir->s.tdir_count * sizeof(uint32)); else if (dir->s.tdir_count <= sizeof(dirB->b.tdir_count) / sizeof(uint32)) { TIFFSeekFile(tif, dir->s.tdir_offset, SEEK_SET); TIFFReadFile(tif, &dirB->b.tdir_offset, dir->s.tdir_count * sizeof(uint32)); if (tif->tif_flags & TIFF_SWAB) TIFFSwabArrayOfLong((uint32*) &dirB->b.tdir_offset, dir->s.tdir_count); } else dirB->b.tdir_offset = dir->s.tdir_offset; break; case TIFF_RATIONAL: case TIFF_SRATIONAL: if (dir->s.tdir_count * 2 <= sizeof(dirB->b.tdir_offset) / sizeof(uint32)) { TIFFSeekFile(tif, dir->s.tdir_offset, SEEK_SET); TIFFReadFile(tif, &dirB->b.tdir_offset, dir->s.tdir_count * 2 * sizeof(uint32)); if (tif->tif_flags & TIFF_SWAB) TIFFSwabArrayOfLong((uint32*) &dirB->b.tdir_offset, dir->s.tdir_count * 2); } else dirB->b.tdir_offset = dir->s.tdir_offset; break; default: dirB->b.tdir_offset = dir->s.tdir_offset; break; } /* * Process special case of SUBIFD; must change data from 32-bit to 64-bit in * case new 64-bit directory offsets need to be added. */ switch (dirB->b.tdir_tag) { case TIFFTAG_SUBIFD: dirB->b.tdir_type = TIFF_IFD8; subifdcnt = dir->s.tdir_count; /* * Set pointer to existing SubIFD array */ if (subifdcnt <= sizeof(dir->s.tdir_offset) / sizeof(uint32)) subifdlink = diroff + sizeof(dircount) + (char*) &dir->s.tdir_offset - (char*) dir; else subifdlink = dir->s.tdir_offset; /* * Initialize new SubIFD array, set pointer to it */ if (subifdcnt <= sizeof(dir->b.tdir_offset) / sizeof(toff_t)) { dir->b.tdir_offset = 0; subifdlinkB = diroffB + sizeof(dircountB) + (char*) &dir->b.tdir_offset - (char*) dirB; } else { toff_t *offB; if (!(offB = _TIFFmalloc(subifdcnt * sizeof(toff_t)))) { TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Error allocating space for 64-bit SubIFDs"); goto error; } _TIFFmemset(offB, 0, subifdcnt * sizeof(toff_t)); TIFFWriteLong8Array(tif, dirB, offB); _TIFFfree(offB); subifdlinkB = dirB->b.tdir_offset; } break; } if (tif->tif_flags & TIFF_SWAB) { TIFFSwabShort(&dirB->b.tdir_tag); TIFFSwabShort(&dirB->b.tdir_type); TIFFSwabLong8(&dirB->b.tdir_count); TIFFSwabLong8(&dirB->b.tdir_offset); } } /* * Write out new directory and chain to previous */ if (tif->tif_flags & TIFF_SWAB) TIFFSwabLong8(&dircountB); if (!SeekOK(tif, diroffB) || !WriteOK(tif, &dircountB, sizeof(dircountB)) || !SeekOK(tif, diroffB + sizeof(dircountB)) || !WriteOK(tif, dataB, dirsizeB)) { TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Error writing TIFF directory (%d)", TIFFGetErrno(tif)); goto error; } /* * If directory is SubIFD update array in host directory, else add to * main directory chain */ if (tif->tif_nsubifd && tif->tif_subifdoff == subifdlink) tif->tif_subifdoff = subifdlinkB; if (!issubifd && dirlinkB == TIFF_HEADER_DIROFF_B) tif->tif_header.b.tiff_diroff = diroffB; if (tif->tif_flags & TIFF_SWAB) TIFFSwabLong8(&diroffB); if (!SeekOK(tif, (issubifd ? subifdlinkB++ : dirlinkB)) || !WriteOK(tif, &diroffB, sizeof(diroffB))) { TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Error writing directory link (%d)", TIFFGetErrno(tif)); goto error; } if (issubifd) subifdcnt--; else { dirlink = diroff + sizeof(dircount) + dirsize; dirlinkB = diroffB + sizeof(dircountB) + dirsizeB; } issubifd = (subifdcnt > 0); if (!SeekOK(tif, (issubifd ? subifdlink++ : dirlink)) || !ReadOK(tif, &diroff, sizeof(diroff))) { TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Error reading directory link (%d)", TIFFGetErrno(tif)); goto error; } if (tif->tif_flags & TIFF_SWAB) TIFFSwabLong(&diroff); _TIFFfree(dataB); _TIFFfree(data); } /* * Mark end of directory chain */ diroffB = 0; if (dirlinkB == TIFF_HEADER_DIROFF_B) tif->tif_header.b.tiff_diroff = diroffB; if (tif->tif_flags & TIFF_SWAB) TIFFSwabLong8(&diroffB); if (!SeekOK(tif, dirlinkB) || !WriteOK(tif, &diroffB, sizeof(diroffB))) { TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Error writing directory link (%d)", TIFFGetErrno(tif)); goto error; } return (1); error: _TIFFfree(dataB); _TIFFfree(data); return (0); }
/* * Link the current directory into the * directory chain for the file. */ static int TIFFLinkDirectory(TIFF* tif) { static const char module[] = "TIFFLinkDirectory"; toff_t currdir, nextdir; toff_t diroff, nextdiroff; /* 32-bit or 64-bit dir offsets */ /* * New directory will go at end of file; if file not BigTIFF and * size is beyond 2^32, convert to BigTIFF now. */ tif->tif_diroff = ((TIFFSeekFile(tif, 0, SEEK_END) + 1) & ~(toff_t) 1); if (!isBigTIFF(tif) && isBigOff(tif->tif_diroff)) { if (!TIFFMakeBigTIFF(tif)) return (0); tif->tif_diroff = ((TIFFSeekFile(tif, 0, SEEK_END) + 1) & ~(toff_t) 1); } TIFFSetDirOff(tif,diroff,tif->tif_diroff); if (tif->tif_flags & TIFF_SWAB) TIFFSwabDirOff(tif,&diroff); /* * Handle SubIFDs */ if (tif->tif_flags & TIFF_INSUBIFD) { (void) TIFFSeekFile(tif, tif->tif_subifdoff, SEEK_SET); if (!WriteOK(tif, &diroff, TIFFDirOffLen(tif))) { TIFFErrorExt(tif->tif_clientdata, module, "%s: Error writing SubIFD directory link (%d)", tif->tif_name, TIFFGetErrno(tif)); return (0); } /* * Advance to the next SubIFD or, if this is * the last one configured, revert back to the * normal directory linkage. */ if (--tif->tif_nsubifd) tif->tif_subifdoff += TIFFDirOffLen(tif); else tif->tif_flags &= ~TIFF_INSUBIFD; return (1); } /* * First directory, overwrite offset in header. */ nextdir = TIFFGetHdrDirOff(tif,tif->tif_header); if (nextdir == 0) { TIFFSetHdrDirOff(tif,tif->tif_header, tif->tif_diroff); if (!SeekOK(tif, 0) || !WriteOK(tif, &tif->tif_header, sizeof(TIFFHeader)) ) { TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Error writing TIFF header (%d)", TIFFGetErrno(tif)); return (0); } return (1); } /* * Not the first directory, search to the last and append. */ do { uint64 dircount; /* 16-bit or 64-bit directory count */ if (!SeekOK(tif, nextdir) || !ReadOK(tif, &dircount, TIFFDirCntLen(tif))) { TIFFErrorExt(tif->tif_clientdata, module, "Error fetching directory count (%d)", TIFFGetErrno(tif)); return (0); } if (tif->tif_flags & TIFF_SWAB) TIFFSwabDirCnt(tif,&dircount); currdir = nextdir + TIFFDirCntLen(tif) + TIFFGetDirCnt(tif,dircount) * TDIREntryLen(tif); TIFFSeekFile(tif, currdir, SEEK_SET); if (!ReadOK(tif, &nextdiroff, TIFFDirOffLen(tif)) ) { TIFFErrorExt(tif->tif_clientdata, module, "Error fetching directory link (%d)", TIFFGetErrno(tif)); return (0); } if (tif->tif_flags & TIFF_SWAB) TIFFSwabDirOff(tif,&nextdiroff); nextdir = TIFFGetDirOff(tif,nextdiroff); } while (nextdir != 0); TIFFSeekFile(tif, currdir, SEEK_SET); if (!WriteOK(tif, &diroff, TIFFDirOffLen(tif)) ) { TIFFErrorExt(tif->tif_clientdata, module, "Error writing directory link (%d)", TIFFGetErrno(tif)); return (0); } return (1); }
/* * Similar to TIFFWriteDirectory(), but if the directory has already * been written once, it is relocated to the end of the file, in case it * has changed in size. Note that this will result in the loss of the * previously used directory space. */ int TIFFRewriteDirectory( TIFF *tif ) { static const char module[] = "TIFFRewriteDirectory"; /* We don't need to do anything special if it hasn't been written. */ if( tif->tif_diroff == 0 ) return TIFFWriteDirectory( tif ); /* ** Find and zero the pointer to this directory, so that TIFFLinkDirectory ** will cause it to be added after this directories current pre-link. */ /* Is it the first directory in the file? */ if (TIFFGetHdrDirOff(tif,tif->tif_header) == tif->tif_diroff) { TIFFSetHdrDirOff(tif,tif->tif_header,0); tif->tif_diroff = 0; if (!SeekOK(tif, 0) || !WriteOK(tif, &tif->tif_header, sizeof(TIFFHeader))) { TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Error updating TIFF header (%d)", TIFFGetErrno(tif)); return (0); } } else { toff_t nextdir, off; toff_t nextdiroff; /* 32-bit or 64-bit directory offset */ nextdir = TIFFGetHdrDirOff(tif,tif->tif_header); do { uint16 dircount; if (!SeekOK(tif, nextdir) || !ReadOK(tif, &dircount, sizeof (dircount))) { TIFFErrorExt(tif->tif_clientdata, module, "Error fetching directory count (%d)", TIFFGetErrno(tif)); return (0); } if (tif->tif_flags & TIFF_SWAB) TIFFSwabShort(&dircount); (void) TIFFSeekFile(tif, TIFFGetDirCnt(tif,dircount) * TDIREntryLen(tif), SEEK_CUR); if (!ReadOK(tif, &nextdiroff, TIFFDirOffLen(tif))) { TIFFErrorExt(tif->tif_clientdata, module, "Error fetching directory link (%d)", TIFFGetErrno(tif)); return (0); } if (tif->tif_flags & TIFF_SWAB) TIFFSwabDirOff(tif,&nextdiroff); nextdir = TIFFGetDirOff(tif,nextdiroff); } while (nextdir != tif->tif_diroff && nextdir != 0); off = TIFFSeekFile(tif, 0, SEEK_CUR); /* get current offset */ (void) TIFFSeekFile(tif, off - TIFFDirOffLen(tif), SEEK_SET); tif->tif_diroff = 0; if (!WriteOK(tif, &(tif->tif_diroff), TIFFDirOffLen(tif))) { TIFFErrorExt(tif->tif_clientdata, module, "Error writing directory link (%d)", TIFFGetErrno(tif)); return (0); } } /* ** Now use TIFFWriteDirectory() normally. */ return TIFFWriteDirectory( tif ); }