Example #1
0
static tsize_t
TIFFReadRawStrip1(TIFF* tif,
    tstrip_t strip, tdata_t buf, tsize_t size, const char* module)
{
	TIFFDirectory *td = &tif->tif_dir;

	assert((tif->tif_flags&TIFF_NOREADRAW)==0);
	if (!isMapped(tif)) {
		tsize_t cc;

		if (!SeekOK(tif, td->td_stripoffset[strip])) {
			TIFFErrorExt(tif->tif_clientdata, module,
			    "%s: Seek error at scanline %lu, strip %lu",
			    tif->tif_name,
			    (unsigned long) tif->tif_row, (unsigned long) strip);
			return (-1);
		}
		cc = TIFFReadFile(tif, buf, size);
		if (cc != size) {
			TIFFErrorExt(tif->tif_clientdata, module,
		"%s: Read error at scanline %lu; got %lu bytes, expected %lu",
			    tif->tif_name,
			    (unsigned long) tif->tif_row,
			    (unsigned long) cc,
			    (unsigned long) size);
			return (-1);
		}
	} else {
		if (td->td_stripoffset[strip] + size > tif->tif_size) {
			TIFFErrorExt(tif->tif_clientdata, module,
    "%s: Read error at scanline %lu, strip %lu; got %lu bytes, expected %lu",
			    tif->tif_name,
			    (unsigned long) tif->tif_row,
			    (unsigned long) strip,
			    (unsigned long) tif->tif_size - td->td_stripoffset[strip],
			    (unsigned long) size);
			return (-1);
		}
		_TIFFmemcpy(buf, tif->tif_base + td->td_stripoffset[strip],
                            size);
	}
	return (size);
}
Example #2
0
static tsize_t
TIFFReadRawStrip1(TIFF* tif,
    tstrip_t strip, tdata_t buf, tsize_t size, const char* module)
{
	TIFFDirectory *td = &tif->tif_dir;

	if (!isMapped(tif)) {
		tsize_t cc;

		if (!SeekOK(tif, td->td_stripoffset[strip])) {
			TIFFError(module,
			    "%s: Seek error at scanline %lu, strip %lu",
			    tif->tif_name,
			    (u_long) tif->tif_row, (u_long) strip);
			return (-1);
		}
		cc = TIFFReadFile(tif, buf, size);
		if (cc != size) {
			TIFFError(module,
		"%s: Read error at scanline %lu; got %lu bytes, expected %lu",
			    tif->tif_name,
			    (u_long) tif->tif_row,
			    (u_long) cc,
			    (u_long) size);
			// return (-1); //<DP> To decode some nasty images
		}
	} else {
		if (td->td_stripoffset[strip] + size > tif->tif_size) {
			TIFFError(module,
    "%s: Read error at scanline %lu, strip %lu; got %lu bytes, expected %lu",
			    tif->tif_name,
			    (u_long) tif->tif_row,
			    (u_long) strip,
			    (u_long) tif->tif_size - td->td_stripoffset[strip],
			    (u_long) size);
			return (-1);
		}
		_TIFFmemcpy(buf, tif->tif_base + td->td_stripoffset[strip], size);
	}
	return (size);
}
Example #3
0
static tmsize_t
TIFFReadRawStrip1(TIFF* tif, uint32 strip, void* buf, tmsize_t size,
    const char* module)
{
	TIFFDirectory *td = &tif->tif_dir;

    if (!_TIFFFillStriles( tif ))
        return ((tmsize_t)(-1));
        
	assert((tif->tif_flags&TIFF_NOREADRAW)==0);
	if (!isMapped(tif)) {
		tmsize_t cc;

		if (!SeekOK(tif, td->td_stripoffset[strip])) {
			TIFFErrorExt(tif->tif_clientdata, module,
			    "Seek error at scanline %lu, strip %lu",
			    (unsigned long) tif->tif_row, (unsigned long) strip);
			return ((tmsize_t)(-1));
		}
		cc = TIFFReadFile(tif, buf, size);
		if (cc != size) {
#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__))
			TIFFErrorExt(tif->tif_clientdata, module,
		"Read error at scanline %lu; got %I64u bytes, expected %I64u",
				     (unsigned long) tif->tif_row,
				     (unsigned __int64) cc,
				     (unsigned __int64) size);
#else
			TIFFErrorExt(tif->tif_clientdata, module,
		"Read error at scanline %lu; got %llu bytes, expected %llu",
				     (unsigned long) tif->tif_row,
				     (unsigned long long) cc,
				     (unsigned long long) size);
#endif
			return ((tmsize_t)(-1));
		}
	} else {
		tmsize_t ma = 0;
		tmsize_t n;
		if ((td->td_stripoffset[strip] > (uint64)TIFF_TMSIZE_T_MAX)||
                    ((ma=(tmsize_t)td->td_stripoffset[strip])>tif->tif_size))
                {
                    n=0;
                }
                else if( ma > TIFF_TMSIZE_T_MAX - size )
                {
                    n=0;
                }
                else
                {
                    tmsize_t mb=ma+size;
                    if (mb>tif->tif_size)
                            n=tif->tif_size-ma;
                    else
                            n=size;
                }
		if (n!=size) {
#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__))
			TIFFErrorExt(tif->tif_clientdata, module,
	"Read error at scanline %lu, strip %lu; got %I64u bytes, expected %I64u",
				     (unsigned long) tif->tif_row,
				     (unsigned long) strip,
				     (unsigned __int64) n,
				     (unsigned __int64) size);
#else
			TIFFErrorExt(tif->tif_clientdata, module,
	"Read error at scanline %lu, strip %lu; got %llu bytes, expected %llu",
				     (unsigned long) tif->tif_row,
				     (unsigned long) strip,
				     (unsigned long long) n,
				     (unsigned long long) size);
#endif
			return ((tmsize_t)(-1));
		}
		_TIFFmemcpy(buf, tif->tif_base + ma,
			    size);
	}
	return (size);
}
Example #4
0
/* Read 'size' bytes in tif_rawdata buffer starting at offset 'rawdata_offset'
 * Returns 1 in case of success, 0 otherwise. */
static int TIFFReadAndRealloc( TIFF* tif, tmsize_t size,
                               tmsize_t rawdata_offset,
                               int is_strip, uint32 strip_or_tile,
                               const char* module )
{
#if SIZEOF_SIZE_T == 8
        tmsize_t threshold = INITIAL_THRESHOLD;
#endif
        tmsize_t already_read = 0;

        /* On 64 bit processes, read first a maximum of 1 MB, then 10 MB, etc */
        /* so as to avoid allocating too much memory in case the file is too */
        /* short. We could ask for the file size, but this might be */
        /* expensive with some I/O layers (think of reading a gzipped file) */
        /* Restrict to 64 bit processes, so as to avoid reallocs() */
        /* on 32 bit processes where virtual memory is scarce.  */
        while( already_read < size )
        {
            tmsize_t bytes_read;
            tmsize_t to_read = size - already_read;
#if SIZEOF_SIZE_T == 8
            if( to_read >= threshold && threshold < MAX_THRESHOLD &&
                already_read + to_read + rawdata_offset > tif->tif_rawdatasize )
            {
                to_read = threshold;
                threshold *= THRESHOLD_MULTIPLIER;
            }
#endif
            if (already_read + to_read + rawdata_offset > tif->tif_rawdatasize) {
                uint8* new_rawdata;
                assert((tif->tif_flags & TIFF_MYBUFFER) != 0);
                tif->tif_rawdatasize = (tmsize_t)TIFFroundup_64(
                        (uint64)already_read + to_read + rawdata_offset, 1024);
                if (tif->tif_rawdatasize==0) {
                    TIFFErrorExt(tif->tif_clientdata, module,
                                "Invalid buffer size");
                    return 0;
                }
                new_rawdata = (uint8*) _TIFFrealloc(
                                tif->tif_rawdata, tif->tif_rawdatasize);
                if( new_rawdata == 0 )
                {
                    TIFFErrorExt(tif->tif_clientdata, module,
                        "No space for data buffer at scanline %lu",
                        (unsigned long) tif->tif_row);
                    _TIFFfree(tif->tif_rawdata);
                    tif->tif_rawdata = 0;
                    tif->tif_rawdatasize = 0;
                    return 0;
                }
                tif->tif_rawdata = new_rawdata;
            }

            bytes_read = TIFFReadFile(tif,
                tif->tif_rawdata + rawdata_offset + already_read, to_read);
            already_read += bytes_read;
            if (bytes_read != to_read) {
                memset( tif->tif_rawdata + rawdata_offset + already_read, 0,
                        tif->tif_rawdatasize - rawdata_offset - already_read );
#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__))
                if( is_strip )
                {
                    TIFFErrorExt(tif->tif_clientdata, module,
                        "Read error at scanline %lu; got %I64u bytes, "
                        "expected %I64u",
                                        (unsigned long) tif->tif_row,
                                        (unsigned __int64) already_read,
                                        (unsigned __int64) size);
                }
                else
                {
                    TIFFErrorExt(tif->tif_clientdata, module,
                        "Read error at row %lu, col %lu, tile %lu; "
                        "got %I64u bytes, expected %I64u",
                                        (unsigned long) tif->tif_row,
                                        (unsigned long) tif->tif_col,
                                        (unsigned long) strip_or_tile,
                                        (unsigned __int64) already_read,
                                        (unsigned __int64) size);
                }
#else
                if( is_strip )
                {
                    TIFFErrorExt(tif->tif_clientdata, module,
                        "Read error at scanline %lu; got %llu bytes, "
                        "expected %llu",
                                        (unsigned long) tif->tif_row,
                                        (unsigned long long) already_read,
                                        (unsigned long long) size);
                }
                else
                {
                    TIFFErrorExt(tif->tif_clientdata, module,
                        "Read error at row %lu, col %lu, tile %lu; "
                        "got %llu bytes, expected %llu",
                                        (unsigned long) tif->tif_row,
                                        (unsigned long) tif->tif_col,
                                        (unsigned long) strip_or_tile,
                                        (unsigned long long) already_read,
                                        (unsigned long long) size);
                }
#endif
                return 0;
            }
        }
        return 1;
}
Example #5
0
static tmsize_t
TIFFReadRawTile1(TIFF* tif, uint32 tile, void* buf, tmsize_t size, const char* module)
{
	TIFFDirectory *td = &tif->tif_dir;

    if (!_TIFFFillStriles( tif ))
        return ((tmsize_t)(-1));

	assert((tif->tif_flags&TIFF_NOREADRAW)==0);
	if (!isMapped(tif)) {
		tmsize_t cc;

		if (!SeekOK(tif, td->td_stripoffset[tile])) {
			TIFFErrorExt(tif->tif_clientdata, module,
			    "Seek error at row %lu, col %lu, tile %lu",
			    (unsigned long) tif->tif_row,
			    (unsigned long) tif->tif_col,
			    (unsigned long) tile);
			return ((tmsize_t)(-1));
		}
		cc = TIFFReadFile(tif, buf, size);
		if (cc != size) {
#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__))
			TIFFErrorExt(tif->tif_clientdata, module,
	"Read error at row %lu, col %lu; got %I64u bytes, expected %I64u",
				     (unsigned long) tif->tif_row,
				     (unsigned long) tif->tif_col,
				     (unsigned __int64) cc,
				     (unsigned __int64) size);
#else
			TIFFErrorExt(tif->tif_clientdata, module,
	"Read error at row %lu, col %lu; got %llu bytes, expected %llu",
				     (unsigned long) tif->tif_row,
				     (unsigned long) tif->tif_col,
				     (unsigned long long) cc,
				     (unsigned long long) size);
#endif
			return ((tmsize_t)(-1));
		}
	} else {
		tmsize_t ma,mb;
		tmsize_t n;
		ma=(tmsize_t)td->td_stripoffset[tile];
		mb=ma+size;
		if (((uint64)ma!=td->td_stripoffset[tile])||(ma>tif->tif_size))
			n=0;
		else if ((mb<ma)||(mb<size)||(mb>tif->tif_size))
			n=tif->tif_size-ma;
		else
			n=size;
		if (n!=size) {
#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__))
			TIFFErrorExt(tif->tif_clientdata, module,
"Read error at row %lu, col %lu, tile %lu; got %I64u bytes, expected %I64u",
				     (unsigned long) tif->tif_row,
				     (unsigned long) tif->tif_col,
				     (unsigned long) tile,
				     (unsigned __int64) n,
				     (unsigned __int64) size);
#else
			TIFFErrorExt(tif->tif_clientdata, module,
"Read error at row %lu, col %lu, tile %lu; got %llu bytes, expected %llu",
				     (unsigned long) tif->tif_row,
				     (unsigned long) tif->tif_col,
				     (unsigned long) tile,
				     (unsigned long long) n,
				     (unsigned long long) size);
#endif
			return ((tmsize_t)(-1));
		}
		_TIFFmemcpy(buf, tif->tif_base + ma, size);
	}
	return (size);
}
Example #6
0
static int
TIFFFillStripPartial( TIFF *tif, int strip, tmsize_t read_ahead, int restart )
{
	static const char module[] = "TIFFFillStripPartial";
	register TIFFDirectory *td = &tif->tif_dir;
        tmsize_t unused_data;
        uint64 read_offset;
        tmsize_t cc, to_read;
        /* tmsize_t bytecountm; */
        
        if (!_TIFFFillStriles( tif ) || !tif->tif_dir.td_stripbytecount)
            return 0;
        
        /*
         * Expand raw data buffer, if needed, to hold data
         * strip coming from file (perhaps should set upper
         * bound on the size of a buffer we'll use?).
         */

        /* bytecountm=(tmsize_t) td->td_stripbytecount[strip]; */
        if (read_ahead*2 > tif->tif_rawdatasize) {
                assert( restart );
                
                tif->tif_curstrip = NOSTRIP;
                if ((tif->tif_flags & TIFF_MYBUFFER) == 0) {
                        TIFFErrorExt(tif->tif_clientdata, module,
                                     "Data buffer too small to hold part of strip %lu",
                                     (unsigned long) strip);
                        return (0);
                }
                if (!TIFFReadBufferSetup(tif, 0, read_ahead*2))
                        return (0);
        }

        if( restart )
        {
                tif->tif_rawdataloaded = 0;
                tif->tif_rawdataoff = 0;
        }

        /*
        ** If we are reading more data, move any unused data to the
        ** start of the buffer.
        */
        if( tif->tif_rawdataloaded > 0 )
                unused_data = tif->tif_rawdataloaded - (tif->tif_rawcp - tif->tif_rawdata);
        else
                unused_data = 0;
        
        if( unused_data > 0 )
        {
		assert((tif->tif_flags&TIFF_BUFFERMMAP)==0);
                memmove( tif->tif_rawdata, tif->tif_rawcp, unused_data );
        }

        /*
        ** Seek to the point in the file where more data should be read.
        */
        read_offset = td->td_stripoffset[strip]
                + tif->tif_rawdataoff + tif->tif_rawdataloaded;

        if (!SeekOK(tif, read_offset)) {
                TIFFErrorExt(tif->tif_clientdata, module,
                             "Seek error at scanline %lu, strip %lu",
                             (unsigned long) tif->tif_row, (unsigned long) strip);
                return 0;
        }

        /*
        ** How much do we want to read?
        */
        to_read = tif->tif_rawdatasize - unused_data;
        if( (uint64) to_read > td->td_stripbytecount[strip] 
            - tif->tif_rawdataoff - tif->tif_rawdataloaded )
        {
                to_read = (tmsize_t) td->td_stripbytecount[strip]
                        - tif->tif_rawdataoff - tif->tif_rawdataloaded;
        }

	assert((tif->tif_flags&TIFF_BUFFERMMAP)==0);
        cc = TIFFReadFile(tif, tif->tif_rawdata + unused_data, to_read);

        if (cc != to_read) {
#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__))
                TIFFErrorExt(tif->tif_clientdata, module,
                             "Read error at scanline %lu; got %I64u bytes, expected %I64u",
                             (unsigned long) tif->tif_row,
                             (unsigned __int64) cc,
                             (unsigned __int64) to_read);
#else
                TIFFErrorExt(tif->tif_clientdata, module,
                             "Read error at scanline %lu; got %llu bytes, expected %llu",
                             (unsigned long) tif->tif_row,
                             (unsigned long long) cc,
                             (unsigned long long) to_read);
#endif
                return 0;
        }
        
        tif->tif_rawdataoff = tif->tif_rawdataoff + tif->tif_rawdataloaded - unused_data ;
        tif->tif_rawdataloaded = unused_data + to_read;

        tif->tif_rawcp = tif->tif_rawdata;
                        
        if (!isFillOrder(tif, td->td_fillorder) &&
            (tif->tif_flags & TIFF_NOBITREV) == 0) {
		assert((tif->tif_flags&TIFF_BUFFERMMAP)==0);
                TIFFReverseBits(tif->tif_rawdata + unused_data, to_read );
	}

        /*
        ** When starting a strip from the beginning we need to
        ** restart the decoder.
        */
        if( restart )
                return TIFFStartStrip(tif, strip);
        else
                return 1;
}
Example #7
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);
}