Exemple #1
0
/*
 * 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);
}
Exemple #2
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);
}
Exemple #3
0
/*
 * 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);
}
Exemple #4
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);
}
Exemple #5
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);
}
Exemple #6
0
/*
 * 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 );
}