/* * Read the next TIFF directory from a file * and convert it to the internal format. * We read directories sequentially. */ static uint64 ReadDirectory(int fd, unsigned int ix, uint64 off) { uint16 dircount; uint32 direntrysize; void* dirmem = NULL; uint64 nextdiroff = 0; uint32 n; uint8* dp; if (off == 0) /* no more directories */ goto done; if (_TIFF_lseek_f(fd, (_TIFF_off_t)off, SEEK_SET) != (_TIFF_off_t)off) { Fatal("Seek error accessing TIFF directory"); goto done; } if (!bigtiff) { if (read(fd, (char*) &dircount, sizeof (uint16)) != sizeof (uint16)) { ReadError("directory count"); goto done; } if (swabflag) TIFFSwabShort(&dircount); direntrysize = 12; } else { uint64 dircount64 = 0; if (read(fd, (char*) &dircount64, sizeof (uint64)) != sizeof (uint64)) { ReadError("directory count"); goto done; } if (swabflag) TIFFSwabLong8(&dircount64); if (dircount64>0xFFFF) { Error("Sanity check on directory count failed"); goto done; } dircount = (uint16)dircount64; direntrysize = 20; } dirmem = _TIFFmalloc(TIFFSafeMultiply(tmsize_t,dircount,direntrysize)); if (dirmem == NULL) { Fatal("No space for TIFF directory"); goto done; } n = read(fd, (char*) dirmem, dircount*direntrysize); if (n != dircount*direntrysize) { n /= direntrysize; Error( #if defined(__WIN32__) && defined(_MSC_VER) "Could only read %lu of %u entries in directory at offset %#I64x", (unsigned long)n, dircount, (unsigned __int64) off); #else "Could only read %lu of %u entries in directory at offset %#llx", (unsigned long)n, dircount, (unsigned long long) off); #endif dircount = n; nextdiroff = 0; } else {
TIFF* TIFFClientOpen( const char* name, const char* mode, thandle_t clientdata, TIFFReadWriteProc readproc, TIFFReadWriteProc writeproc, TIFFSeekProc seekproc, TIFFCloseProc closeproc, TIFFSizeProc sizeproc, TIFFMapFileProc mapproc, TIFFUnmapFileProc unmapproc ) { static const char module[] = "TIFFClientOpen"; TIFF *tif; int m; const char* cp; /* The following are configuration checks. They should be redundant, but should not * compile to any actual code in an optimised release build anyway. If any of them * fail, (makefile-based or other) configuration is not correct */ assert(sizeof(uint8)==1); assert(sizeof(int8)==1); assert(sizeof(uint16)==2); assert(sizeof(int16)==2); assert(sizeof(uint32)==4); assert(sizeof(int32)==4); assert(sizeof(uint64)==8); assert(sizeof(int64)==8); assert(sizeof(tmsize_t)==sizeof(void*)); { union{ uint8 a8[2]; uint16 a16; } n; n.a8[0]=1; n.a8[1]=0; #ifdef WORDS_BIGENDIAN assert(n.a16==256); #else assert(n.a16==1); #endif } m = _TIFFgetMode(mode, module); if (m == -1) goto bad2; tif = (TIFF *)_TIFFmalloc((tmsize_t)(sizeof (TIFF) + strlen(name) + 1)); if (tif == NULL) { TIFFErrorExt(clientdata, module, "%s: Out of memory (TIFF structure)", name); goto bad2; } _TIFFmemset(tif, 0, sizeof (*tif)); tif->tif_name = (char *)tif + sizeof (TIFF); strcpy(tif->tif_name, name); tif->tif_mode = m &~ (O_CREAT|O_TRUNC); tif->tif_curdir = (uint16) -1; /* non-existent directory */ tif->tif_curoff = 0; tif->tif_curstrip = (uint32) -1; /* invalid strip */ tif->tif_row = (uint32) -1; /* read/write pre-increment */ tif->tif_clientdata = clientdata; if (!readproc || !writeproc || !seekproc || !closeproc || !sizeproc) { TIFFErrorExt(clientdata, module, "One of the client procedures is NULL pointer."); goto bad2; } tif->tif_readproc = readproc; tif->tif_writeproc = writeproc; tif->tif_seekproc = seekproc; tif->tif_closeproc = closeproc; tif->tif_sizeproc = sizeproc; if (mapproc) tif->tif_mapproc = mapproc; else tif->tif_mapproc = _tiffDummyMapProc; if (unmapproc) tif->tif_unmapproc = unmapproc; else tif->tif_unmapproc = _tiffDummyUnmapProc; _TIFFSetDefaultCompressionState(tif); /* setup default state */ /* * Default is to return data MSB2LSB and enable the * use of memory-mapped files and strip chopping when * a file is opened read-only. */ tif->tif_flags = FILLORDER_MSB2LSB; if (m == O_RDONLY ) tif->tif_flags |= TIFF_MAPPED; #ifdef STRIPCHOP_DEFAULT if (m == O_RDONLY || m == O_RDWR) tif->tif_flags |= STRIPCHOP_DEFAULT; #endif /* * Process library-specific flags in the open mode string. * The following flags may be used to control intrinsic library * behaviour that may or may not be desirable (usually for * compatibility with some application that claims to support * TIFF but only supports some braindead idea of what the * vendor thinks TIFF is): * * 'l' use little-endian byte order for creating a file * 'b' use big-endian byte order for creating a file * 'L' read/write information using LSB2MSB bit order * 'B' read/write information using MSB2LSB bit order * 'H' read/write information using host bit order * 'M' enable use of memory-mapped files when supported * 'm' disable use of memory-mapped files * 'C' enable strip chopping support when reading * 'c' disable strip chopping support * 'h' read TIFF header only, do not load the first IFD * '4' ClassicTIFF for creating a file (default) * '8' BigTIFF for creating a file * * The use of the 'l' and 'b' flags is strongly discouraged. * These flags are provided solely because numerous vendors, * typically on the PC, do not correctly support TIFF; they * only support the Intel little-endian byte order. This * support is not configured by default because it supports * the violation of the TIFF spec that says that readers *MUST* * support both byte orders. It is strongly recommended that * you not use this feature except to deal with busted apps * that write invalid TIFF. And even in those cases you should * bang on the vendors to fix their software. * * The 'L', 'B', and 'H' flags are intended for applications * that can optimize operations on data by using a particular * bit order. By default the library returns data in MSB2LSB * bit order for compatibiltiy with older versions of this * library. Returning data in the bit order of the native cpu * makes the most sense but also requires applications to check * the value of the FillOrder tag; something they probably do * not do right now. * * The 'M' and 'm' flags are provided because some virtual memory * systems exhibit poor behaviour when large images are mapped. * These options permit clients to control the use of memory-mapped * files on a per-file basis. * * The 'C' and 'c' flags are provided because the library support * for chopping up large strips into multiple smaller strips is not * application-transparent and as such can cause problems. The 'c' * option permits applications that only want to look at the tags, * for example, to get the unadulterated TIFF tag information. */ for (cp = mode; *cp; cp++) switch (*cp) { case 'b': #ifndef WORDS_BIGENDIAN if (m&O_CREAT) tif->tif_flags |= TIFF_SWAB; #endif break; case 'l': #ifdef WORDS_BIGENDIAN if ((m&O_CREAT)) tif->tif_flags |= TIFF_SWAB; #endif break; case 'B': tif->tif_flags = (tif->tif_flags &~ TIFF_FILLORDER) | FILLORDER_MSB2LSB; break; case 'L': tif->tif_flags = (tif->tif_flags &~ TIFF_FILLORDER) | FILLORDER_LSB2MSB; break; case 'H': tif->tif_flags = (tif->tif_flags &~ TIFF_FILLORDER) | HOST_FILLORDER; break; case 'M': if (m == O_RDONLY) tif->tif_flags |= TIFF_MAPPED; break; case 'm': if (m == O_RDONLY) tif->tif_flags &= ~TIFF_MAPPED; break; case 'C': if (m == O_RDONLY) tif->tif_flags |= TIFF_STRIPCHOP; break; case 'c': if (m == O_RDONLY) tif->tif_flags &= ~TIFF_STRIPCHOP; break; case 'h': tif->tif_flags |= TIFF_HEADERONLY; break; case '8': if (m&O_CREAT) tif->tif_flags |= TIFF_BIGTIFF; break; } /* * Read in TIFF header. */ if ((m & O_TRUNC) || !ReadOK(tif, &tif->tif_header, sizeof (TIFFHeaderClassic))) { if (tif->tif_mode == O_RDONLY) { TIFFErrorExt(tif->tif_clientdata, name, "Cannot read TIFF header"); goto bad; } /* * Setup header and write. */ #ifdef WORDS_BIGENDIAN tif->tif_header.common.tiff_magic = tif->tif_flags & TIFF_SWAB ? TIFF_LITTLEENDIAN : TIFF_BIGENDIAN; #else tif->tif_header.common.tiff_magic = tif->tif_flags & TIFF_SWAB ? TIFF_BIGENDIAN : TIFF_LITTLEENDIAN; #endif if (!(tif->tif_flags&TIFF_BIGTIFF)) { tif->tif_header.common.tiff_version = TIFF_VERSION_CLASSIC; tif->tif_header.classic.tiff_diroff = 0; if (tif->tif_flags & TIFF_SWAB) TIFFSwabShort(&tif->tif_header.common.tiff_version); tif->tif_header_size = sizeof(TIFFHeaderClassic); } else { tif->tif_header.common.tiff_version = TIFF_VERSION_BIG; tif->tif_header.big.tiff_offsetsize = 8; tif->tif_header.big.tiff_unused = 0; tif->tif_header.big.tiff_diroff = 0; if (tif->tif_flags & TIFF_SWAB) { TIFFSwabShort(&tif->tif_header.common.tiff_version); TIFFSwabShort(&tif->tif_header.big.tiff_offsetsize); } tif->tif_header_size = sizeof (TIFFHeaderBig); } /* * The doc for "fopen" for some STD_C_LIBs says that if you * open a file for modify ("+"), then you must fseek (or * fflush?) between any freads and fwrites. This is not * necessary on most systems, but has been shown to be needed * on Solaris. */ TIFFSeekFile( tif, 0, SEEK_SET ); if (!WriteOK(tif, &tif->tif_header, (tmsize_t)(tif->tif_header_size))) { TIFFErrorExt(tif->tif_clientdata, name, "Error writing TIFF header"); goto bad; } /* * Setup the byte order handling. */ if (tif->tif_header.common.tiff_magic == TIFF_BIGENDIAN) { #ifndef WORDS_BIGENDIAN tif->tif_flags |= TIFF_SWAB; #endif } else { #ifdef WORDS_BIGENDIAN tif->tif_flags |= TIFF_SWAB; #endif } /* * Setup default directory. */ if (!TIFFDefaultDirectory(tif)) goto bad; tif->tif_diroff = 0; tif->tif_dirlist = NULL; tif->tif_dirlistsize = 0; tif->tif_dirnumber = 0; return (tif); } /* * Setup the byte order handling. */ if (tif->tif_header.common.tiff_magic != TIFF_BIGENDIAN && tif->tif_header.common.tiff_magic != TIFF_LITTLEENDIAN #if MDI_SUPPORT && #if HOST_BIGENDIAN tif->tif_header.common.tiff_magic != MDI_BIGENDIAN #else tif->tif_header.common.tiff_magic != MDI_LITTLEENDIAN #endif ) { TIFFErrorExt(tif->tif_clientdata, name, "Not a TIFF or MDI file, bad magic number %d (0x%x)", #else ) { TIFFErrorExt(tif->tif_clientdata, name, "Not a TIFF file, bad magic number %d (0x%x)", #endif tif->tif_header.common.tiff_magic, tif->tif_header.common.tiff_magic); goto bad; } if (tif->tif_header.common.tiff_magic == TIFF_BIGENDIAN) { #ifndef WORDS_BIGENDIAN tif->tif_flags |= TIFF_SWAB; #endif } else { #ifdef WORDS_BIGENDIAN tif->tif_flags |= TIFF_SWAB; #endif } if (tif->tif_flags & TIFF_SWAB) TIFFSwabShort(&tif->tif_header.common.tiff_version); if ((tif->tif_header.common.tiff_version != TIFF_VERSION_CLASSIC)&& (tif->tif_header.common.tiff_version != TIFF_VERSION_BIG)) { TIFFErrorExt(tif->tif_clientdata, name, "Not a TIFF file, bad version number %d (0x%x)", tif->tif_header.common.tiff_version, tif->tif_header.common.tiff_version); goto bad; } if (tif->tif_header.common.tiff_version == TIFF_VERSION_CLASSIC) { if (tif->tif_flags & TIFF_SWAB) TIFFSwabLong(&tif->tif_header.classic.tiff_diroff); tif->tif_header_size = sizeof(TIFFHeaderClassic); } else { if (!ReadOK(tif, ((uint8*)(&tif->tif_header) + sizeof(TIFFHeaderClassic)), (sizeof(TIFFHeaderBig)-sizeof(TIFFHeaderClassic)))) { TIFFErrorExt(tif->tif_clientdata, name, "Cannot read TIFF header"); goto bad; } if (tif->tif_flags & TIFF_SWAB) { TIFFSwabShort(&tif->tif_header.big.tiff_offsetsize); TIFFSwabLong8(&tif->tif_header.big.tiff_diroff); } if (tif->tif_header.big.tiff_offsetsize != 8) { TIFFErrorExt(tif->tif_clientdata, name, "Not a TIFF file, bad BigTIFF offsetsize %d (0x%x)", tif->tif_header.big.tiff_offsetsize, tif->tif_header.big.tiff_offsetsize); goto bad; } if (tif->tif_header.big.tiff_unused != 0) { TIFFErrorExt(tif->tif_clientdata, name, "Not a TIFF file, bad BigTIFF unused %d (0x%x)", tif->tif_header.big.tiff_unused, tif->tif_header.big.tiff_unused); goto bad; } tif->tif_header_size = sizeof(TIFFHeaderBig); tif->tif_flags |= TIFF_BIGTIFF; } tif->tif_flags |= TIFF_MYBUFFER; tif->tif_rawcp = tif->tif_rawdata = 0; tif->tif_rawdatasize = 0; tif->tif_rawdataoff = 0; tif->tif_rawdataloaded = 0; switch (mode[0]) { case 'r': if (!(tif->tif_flags&TIFF_BIGTIFF)) tif->tif_nextdiroff = tif->tif_header.classic.tiff_diroff; else tif->tif_nextdiroff = tif->tif_header.big.tiff_diroff; /* * Try to use a memory-mapped file if the client * has not explicitly suppressed usage with the * 'm' flag in the open mode (see above). */ if (tif->tif_flags & TIFF_MAPPED) { toff_t n; if (TIFFMapFileContents(tif,(void**)(&tif->tif_base),&n)) { tif->tif_size=(tmsize_t)n; assert((toff_t)tif->tif_size==n); } else tif->tif_flags &= ~TIFF_MAPPED; } /* * Sometimes we do not want to read the first directory (for example, * it may be broken) and want to proceed to other directories. I this * case we use the TIFF_HEADERONLY flag to open file and return * immediately after reading TIFF header. */ if (tif->tif_flags & TIFF_HEADERONLY) return (tif); /* * Setup initial directory. */ if (TIFFReadDirectory(tif)) { tif->tif_rawcc = (tmsize_t)-1; tif->tif_flags |= TIFF_BUFFERSETUP; return (tif); } break; case 'a': /* * New directories are automatically append * to the end of the directory chain when they * are written out (see TIFFWriteDirectory). */ if (!TIFFDefaultDirectory(tif)) goto bad; return (tif); } bad: tif->tif_mode = O_RDONLY; /* XXX avoid flush */ TIFFCleanup(tif); bad2: return ((TIFF*)0); }
static void dump(int fd, uint64 diroff) { unsigned i; lseek(fd, (off_t) 0, 0); if (read(fd, (char*) &hdr, sizeof (TIFFHeaderCommon)) != sizeof (TIFFHeaderCommon)) ReadError("TIFF header"); if (hdr.common.tiff_magic != TIFF_BIGENDIAN && hdr.common.tiff_magic != TIFF_LITTLEENDIAN && #if HOST_BIGENDIAN /* MDI is sensitive to the host byte order, unlike TIFF */ MDI_BIGENDIAN != hdr.common.tiff_magic #else MDI_LITTLEENDIAN != hdr.common.tiff_magic #endif ) { Fatal("Not a TIFF or MDI file, bad magic number %u (%#x)", hdr.common.tiff_magic, hdr.common.tiff_magic); } if (hdr.common.tiff_magic == TIFF_BIGENDIAN || hdr.common.tiff_magic == MDI_BIGENDIAN) swabflag = !bigendian; else swabflag = bigendian; if (swabflag) TIFFSwabShort(&hdr.common.tiff_version); if (hdr.common.tiff_version==42) { if (read(fd, (char*) &hdr.classic.tiff_diroff, 4) != 4) ReadError("TIFF header"); if (swabflag) TIFFSwabLong(&hdr.classic.tiff_diroff); printf("Magic: %#x <%s-endian> Version: %#x <%s>\n", hdr.classic.tiff_magic, hdr.classic.tiff_magic == TIFF_BIGENDIAN ? "big" : "little", 42,"ClassicTIFF"); if (diroff == 0) diroff = hdr.classic.tiff_diroff; } else if (hdr.common.tiff_version==43) { if (read(fd, (char*) &hdr.big.tiff_offsetsize, 12) != 12) ReadError("TIFF header"); if (swabflag) { TIFFSwabShort(&hdr.big.tiff_offsetsize); TIFFSwabShort(&hdr.big.tiff_unused); TIFFSwabLong8(&hdr.big.tiff_diroff); } printf("Magic: %#x <%s-endian> Version: %#x <%s>\n", hdr.big.tiff_magic, hdr.big.tiff_magic == TIFF_BIGENDIAN ? "big" : "little", 43,"BigTIFF"); printf("OffsetSize: %#x Unused: %#x\n", hdr.big.tiff_offsetsize,hdr.big.tiff_unused); if (diroff == 0) diroff = hdr.big.tiff_diroff; bigtiff = 1; } else Fatal("Not a TIFF file, bad version number %u (%#x)", hdr.common.tiff_version, hdr.common.tiff_version); for (i = 0; diroff != 0; i++) { if (i > 0) putchar('\n'); diroff = ReadDirectory(fd, i, diroff); } }
static void dump(int fd, uint64 diroff) { unsigned i, j; uint64* visited_diroff = NULL; unsigned int count_visited_dir = 0; _TIFF_lseek_f(fd, (_TIFF_off_t) 0, 0); if (read(fd, (char*) &hdr, sizeof (TIFFHeaderCommon)) != sizeof (TIFFHeaderCommon)) ReadError("TIFF header"); if (hdr.common.tiff_magic != TIFF_BIGENDIAN && hdr.common.tiff_magic != TIFF_LITTLEENDIAN && #if HOST_BIGENDIAN /* MDI is sensitive to the host byte order, unlike TIFF */ MDI_BIGENDIAN != hdr.common.tiff_magic #else MDI_LITTLEENDIAN != hdr.common.tiff_magic #endif ) { Fatal("Not a TIFF or MDI file, bad magic number %u (%#x)", hdr.common.tiff_magic, hdr.common.tiff_magic); } if (hdr.common.tiff_magic == TIFF_BIGENDIAN || hdr.common.tiff_magic == MDI_BIGENDIAN) swabflag = !bigendian; else swabflag = bigendian; if (swabflag) TIFFSwabShort(&hdr.common.tiff_version); if (hdr.common.tiff_version==42) { if (read(fd, (char*) &hdr.classic.tiff_diroff, 4) != 4) ReadError("TIFF header"); if (swabflag) TIFFSwabLong(&hdr.classic.tiff_diroff); printf("Magic: %#x <%s-endian> Version: %#x <%s>\n", hdr.classic.tiff_magic, hdr.classic.tiff_magic == TIFF_BIGENDIAN ? "big" : "little", 42,"ClassicTIFF"); if (diroff == 0) diroff = hdr.classic.tiff_diroff; } else if (hdr.common.tiff_version==43) { if (read(fd, (char*) &hdr.big.tiff_offsetsize, 12) != 12) ReadError("TIFF header"); if (swabflag) { TIFFSwabShort(&hdr.big.tiff_offsetsize); TIFFSwabShort(&hdr.big.tiff_unused); TIFFSwabLong8(&hdr.big.tiff_diroff); } printf("Magic: %#x <%s-endian> Version: %#x <%s>\n", hdr.big.tiff_magic, hdr.big.tiff_magic == TIFF_BIGENDIAN ? "big" : "little", 43,"BigTIFF"); printf("OffsetSize: %#x Unused: %#x\n", hdr.big.tiff_offsetsize,hdr.big.tiff_unused); if (diroff == 0) diroff = hdr.big.tiff_diroff; bigtiff = 1; } else Fatal("Not a TIFF file, bad version number %u (%#x)", hdr.common.tiff_version, hdr.common.tiff_version); for (i = 0; diroff != 0; i++) { for(j=0; j<count_visited_dir; j++) { if( visited_diroff[j] == diroff ) { free(visited_diroff); Fatal("Cycle detected in chaining of TIFF directories!"); } } { size_t alloc_size; alloc_size=TIFFSafeMultiply(tmsize_t,(count_visited_dir + 1), sizeof(uint64)); if (alloc_size == 0) { if (visited_diroff) free(visited_diroff); visited_diroff = 0; } else { visited_diroff = (uint64*) realloc(visited_diroff,alloc_size); } } if( !visited_diroff ) Fatal("Out of memory"); visited_diroff[count_visited_dir] = diroff; count_visited_dir ++; if (i > 0) putchar('\n'); diroff = ReadDirectory(fd, i, diroff); } if( visited_diroff ) free(visited_diroff); }
/* * 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); }