void _TIFFSwab64BitData(TIFF* tif, tidata_t buf, tsize_t cc) { (void) tif; assert((cc & 7) == 0); TIFFSwabArrayOfDouble((double*) buf, cc/8); }
void swabData(int type, long size, void* data) { if (!swabflag) return; if ( (type == TIFF_SHORT) || (type == TIFF_SSHORT) ) TIFFSwabArrayOfShort( (uint16*) data, size/2 ); if ( (type == TIFF_LONG) || (type == TIFF_SLONG) || (type == TIFF_FLOAT) ) TIFFSwabArrayOfLong( (uint32*) data, size/4 ); if (type == TIFF_RATIONAL) TIFFSwabArrayOfLong( (uint32*) data, size/4 ); if (type == TIFF_DOUBLE) TIFFSwabArrayOfDouble( (double*) data, size/8 ); }
/* * 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); }
/* * Fetch a contiguous directory item. */ static tsize_t TIFFFetchData(TIFF* tif, TIFFDirEntry* dir, char* cp) { int w = tiffDataWidth[dir->tdir_type]; tsize_t cc = dir->tdir_count * w; if (!isMapped(tif)) { if (!SeekOK(tif, dir->tdir_offset)) goto bad; if (!ReadOK(tif, cp, cc)) goto bad; } else { if (dir->tdir_offset + cc > tif->tif_size) goto bad; _TIFFmemcpy(cp, tif->tif_base + dir->tdir_offset, cc); } if (tif->tif_flags & TIFF_SWAB) { switch (dir->tdir_type) { case TIFF_SHORT: case TIFF_SSHORT: TIFFSwabArrayOfShort((uint16*) cp, dir->tdir_count); break; case TIFF_LONG: case TIFF_SLONG: case TIFF_FLOAT: TIFFSwabArrayOfLong((uint32*) cp, dir->tdir_count); break; case TIFF_RATIONAL: case TIFF_SRATIONAL: TIFFSwabArrayOfLong((uint32*) cp, 2*dir->tdir_count); break; case TIFF_DOUBLE: TIFFSwabArrayOfDouble((double*) cp, dir->tdir_count); break; } } return (cc); bad: TIFFError(tif->tif_name, "Error fetching data for field \"%s\"", _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name); return ((tsize_t) 0); }
static void swapBytesInScanline(void *buf, uint32 width, TIFFDataType dtype) { switch (dtype) { case TIFF_SHORT: case TIFF_SSHORT: TIFFSwabArrayOfShort((uint16*)buf, (unsigned long)width); break; case TIFF_LONG: case TIFF_SLONG: TIFFSwabArrayOfLong((uint32*)buf, (unsigned long)width); break; /* case TIFF_FLOAT: */ /* FIXME */ case TIFF_DOUBLE: TIFFSwabArrayOfDouble((double*)buf, (unsigned long)width); break; default: break; } }
/* * 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->tdir_type) { case TIFF_SHORT: case TIFF_SSHORT: TIFFSwabArrayOfShort((uint16*) cp, dir->tdir_count); break; case TIFF_LONG: case TIFF_SLONG: case TIFF_FLOAT: TIFFSwabArrayOfLong((uint32*) cp, dir->tdir_count); break; case TIFF_RATIONAL: case TIFF_SRATIONAL: TIFFSwabArrayOfLong((uint32*) cp, 2*dir->tdir_count); break; case TIFF_DOUBLE: TIFFSwabArrayOfDouble((double*) cp, dir->tdir_count); break; } } dir->tdir_offset = tif->tif_dataoff; cc = dir->tdir_count * TIFFDataWidth((TIFFDataType) dir->tdir_type); if (SeekOK(tif, dir->tdir_offset) && 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\"", _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name); return (0); }
CPLErr EXIFExtractMetadata(char**& papszMetadata, void *fpInL, int nOffset, int bSwabflag, int nTIFFHEADER, int& nExifOffset, int& nInterOffset, int& nGPSOffset) { GUInt16 nEntryCount; int space; unsigned int n,i; char pszTemp[MAXSTRINGLENGTH]; char pszName[128]; VSILFILE* fp = (VSILFILE* )fpInL; TIFFDirEntry *poTIFFDirEntry; TIFFDirEntry *poTIFFDir; const struct tagname *poExifTags ; const struct intr_tag *poInterTags = intr_tags; const struct gpsname *poGPSTags; /* -------------------------------------------------------------------- */ /* Read number of entry in directory */ /* -------------------------------------------------------------------- */ if( VSIFSeekL(fp, nOffset+nTIFFHEADER, SEEK_SET) != 0 || VSIFReadL(&nEntryCount,1,sizeof(GUInt16),fp) != sizeof(GUInt16) ) { CPLError( CE_Failure, CPLE_AppDefined, "Error reading EXIF Directory count at %d.", nOffset + nTIFFHEADER ); return CE_Failure; } if (bSwabflag) TIFFSwabShort(&nEntryCount); // Some apps write empty directories - see bug 1523. if( nEntryCount == 0 ) return CE_None; // Some files are corrupt, a large entry count is a sign of this. if( nEntryCount > 125 ) { CPLError( CE_Warning, CPLE_AppDefined, "Ignoring EXIF directory with unlikely entry count (%d).", nEntryCount ); return CE_Warning; } poTIFFDir = (TIFFDirEntry *)CPLMalloc(nEntryCount * sizeof(TIFFDirEntry)); /* -------------------------------------------------------------------- */ /* Read all directory entries */ /* -------------------------------------------------------------------- */ n = VSIFReadL(poTIFFDir, 1,nEntryCount*sizeof(TIFFDirEntry),fp); if (n != nEntryCount*sizeof(TIFFDirEntry)) { CPLError( CE_Failure, CPLE_AppDefined, "Could not read all directories"); CPLFree(poTIFFDir); return CE_Failure; } /* -------------------------------------------------------------------- */ /* Parse all entry information in this directory */ /* -------------------------------------------------------------------- */ for(poTIFFDirEntry = poTIFFDir,i=nEntryCount; i > 0; i--,poTIFFDirEntry++) { if (bSwabflag) { TIFFSwabShort(&poTIFFDirEntry->tdir_tag); TIFFSwabShort(&poTIFFDirEntry->tdir_type); TIFFSwabLong (&poTIFFDirEntry->tdir_count); TIFFSwabLong (&poTIFFDirEntry->tdir_offset); } /* -------------------------------------------------------------------- */ /* Find Tag name in table */ /* -------------------------------------------------------------------- */ pszName[0] = '\0'; pszTemp[0] = '\0'; for (poExifTags = tagnames; poExifTags->tag; poExifTags++) if(poExifTags->tag == poTIFFDirEntry->tdir_tag) { CPLAssert( NULL != poExifTags && NULL != poExifTags->name ); strcpy(pszName, poExifTags->name); break; } if( nOffset == nGPSOffset) { for( poGPSTags = gpstags; poGPSTags->tag != 0xffff; poGPSTags++ ) if( poGPSTags->tag == poTIFFDirEntry->tdir_tag ) { CPLAssert( NULL != poGPSTags && NULL != poGPSTags->name ); strcpy(pszName, poGPSTags->name); break; } } /* -------------------------------------------------------------------- */ /* If the tag was not found, look into the interoperability table */ /* -------------------------------------------------------------------- */ if( nOffset == nInterOffset ) { for(poInterTags = intr_tags; poInterTags->tag; poInterTags++) if(poInterTags->tag == poTIFFDirEntry->tdir_tag) { CPLAssert( NULL != poInterTags && NULL != poInterTags->name ); strcpy(pszName, poInterTags->name); break; } } /* -------------------------------------------------------------------- */ /* Save important directory tag offset */ /* -------------------------------------------------------------------- */ if( poTIFFDirEntry->tdir_tag == EXIFOFFSETTAG ) nExifOffset=poTIFFDirEntry->tdir_offset; if( poTIFFDirEntry->tdir_tag == INTEROPERABILITYOFFSET ) nInterOffset=poTIFFDirEntry->tdir_offset; if( poTIFFDirEntry->tdir_tag == GPSOFFSETTAG ) { nGPSOffset=poTIFFDirEntry->tdir_offset; } /* -------------------------------------------------------------------- */ /* If we didn't recognise the tag just ignore it. To see all */ /* tags comment out the continue. */ /* -------------------------------------------------------------------- */ if( pszName[0] == '\0' ) { sprintf( pszName, "EXIF_%d", poTIFFDirEntry->tdir_tag ); continue; } /* -------------------------------------------------------------------- */ /* For UserComment we need to ignore the language binding and */ /* just return the actual contents. */ /* -------------------------------------------------------------------- */ if( EQUAL(pszName,"EXIF_UserComment") ) { poTIFFDirEntry->tdir_type = TIFF_ASCII; if( poTIFFDirEntry->tdir_count >= 8 ) { poTIFFDirEntry->tdir_count -= 8; poTIFFDirEntry->tdir_offset += 8; } } /* -------------------------------------------------------------------- */ /* Make some UNDEFINED or BYTE fields ASCII for readability. */ /* -------------------------------------------------------------------- */ if( EQUAL(pszName,"EXIF_ExifVersion") || EQUAL(pszName,"EXIF_FlashPixVersion") || EQUAL(pszName,"EXIF_MakerNote") || EQUAL(pszName,"GPSProcessingMethod") ) poTIFFDirEntry->tdir_type = TIFF_ASCII; /* -------------------------------------------------------------------- */ /* Print tags */ /* -------------------------------------------------------------------- */ int nDataWidth = TIFFDataWidth((TIFFDataType) poTIFFDirEntry->tdir_type); space = poTIFFDirEntry->tdir_count * nDataWidth; /* Previous multiplication could overflow, hence this additional check */ if (poTIFFDirEntry->tdir_count > MAXSTRINGLENGTH) { CPLError( CE_Warning, CPLE_AppDefined, "Too many bytes in tag: %u, ignoring tag.", poTIFFDirEntry->tdir_count ); } else if (nDataWidth == 0 || poTIFFDirEntry->tdir_type >= TIFF_IFD ) { CPLError( CE_Warning, CPLE_AppDefined, "Invalid or unhandled EXIF data type: %d, ignoring tag.", poTIFFDirEntry->tdir_type ); } /* -------------------------------------------------------------------- */ /* This is at most 4 byte data so we can read it from tdir_offset */ /* -------------------------------------------------------------------- */ else if (space >= 0 && space <= 4) { unsigned char data[4]; memcpy(data, &poTIFFDirEntry->tdir_offset, 4); if (bSwabflag) { // Unswab 32bit value, and reswab per data type. TIFFSwabLong((GUInt32*) data); switch (poTIFFDirEntry->tdir_type) { case TIFF_LONG: case TIFF_SLONG: case TIFF_FLOAT: TIFFSwabLong((GUInt32*) data); break; case TIFF_SSHORT: case TIFF_SHORT: TIFFSwabArrayOfShort((GUInt16*) data, poTIFFDirEntry->tdir_count); break; default: break; } } EXIFPrintData(pszTemp, poTIFFDirEntry->tdir_type, poTIFFDirEntry->tdir_count, data); } /* -------------------------------------------------------------------- */ /* The data is being read where tdir_offset point to in the file */ /* -------------------------------------------------------------------- */ else if (space > 0 && space < MAXSTRINGLENGTH) { unsigned char *data = (unsigned char *)VSIMalloc(space); if (data) { VSIFSeekL(fp,poTIFFDirEntry->tdir_offset+nTIFFHEADER,SEEK_SET); VSIFReadL(data, 1, space, fp); if (bSwabflag) { switch (poTIFFDirEntry->tdir_type) { case TIFF_SHORT: case TIFF_SSHORT: TIFFSwabArrayOfShort((GUInt16*) data, poTIFFDirEntry->tdir_count); break; case TIFF_LONG: case TIFF_SLONG: case TIFF_FLOAT: TIFFSwabArrayOfLong((GUInt32*) data, poTIFFDirEntry->tdir_count); break; case TIFF_RATIONAL: case TIFF_SRATIONAL: TIFFSwabArrayOfLong((GUInt32*) data, 2*poTIFFDirEntry->tdir_count); break; case TIFF_DOUBLE: TIFFSwabArrayOfDouble((double*) data, poTIFFDirEntry->tdir_count); break; default: break; } } EXIFPrintData(pszTemp, poTIFFDirEntry->tdir_type, poTIFFDirEntry->tdir_count, data); CPLFree(data); } } else { CPLError( CE_Warning, CPLE_AppDefined, "Invalid EXIF header size: %ld, ignoring tag.", (long) space ); } papszMetadata = CSLSetNameValue(papszMetadata, pszName, pszTemp); } CPLFree(poTIFFDir); return CE_None; }
static void TIFFWriteOvrRow( TIFFOvrCache * psCache ) { int nRet, iTileX, iTileY = psCache->nBlockOffset; unsigned char *pabyData; uint32 nBaseDirOffset; uint32 RowsInStrip; /* -------------------------------------------------------------------- */ /* If the output cache is multi-byte per sample, and the file */ /* being written to is of a different byte order than the current */ /* platform, we will need to byte swap the data. */ /* -------------------------------------------------------------------- */ if( TIFFIsByteSwapped(psCache->hTIFF) ) { if( psCache->nBitsPerPixel == 16 ) TIFFSwabArrayOfShort( (uint16 *) psCache->pabyRow1Blocks, (psCache->nBytesPerBlock * psCache->nSamples) / 2 ); else if( psCache->nBitsPerPixel == 32 ) TIFFSwabArrayOfLong( (uint32 *) psCache->pabyRow1Blocks, (psCache->nBytesPerBlock * psCache->nSamples) / 4 ); else if( psCache->nBitsPerPixel == 64 ) TIFFSwabArrayOfDouble( (double *) psCache->pabyRow1Blocks, (psCache->nBytesPerBlock * psCache->nSamples) / 8 ); } /* -------------------------------------------------------------------- */ /* Record original directory position, so we can restore it at */ /* end. */ /* -------------------------------------------------------------------- */ nBaseDirOffset = TIFFCurrentDirOffset( psCache->hTIFF ); nRet = TIFFSetSubDirectory( psCache->hTIFF, psCache->nDirOffset ); assert( nRet == 1 ); /* -------------------------------------------------------------------- */ /* Write blocks to TIFF file. */ /* -------------------------------------------------------------------- */ for( iTileX = 0; iTileX < psCache->nBlocksPerRow; iTileX++ ) { int nTileID; if (psCache->nPlanarConfig == PLANARCONFIG_SEPARATE) { int iSample; for( iSample = 0; iSample < psCache->nSamples; iSample++ ) { pabyData = TIFFGetOvrBlock( psCache, iTileX, iTileY, iSample ); if( psCache->bTiled ) { nTileID = TIFFComputeTile( psCache->hTIFF, iTileX * psCache->nBlockXSize, iTileY * psCache->nBlockYSize, 0, (tsample_t) iSample ); TIFFWriteEncodedTile( psCache->hTIFF, nTileID, pabyData, TIFFTileSize(psCache->hTIFF) ); } else { nTileID = TIFFComputeStrip( psCache->hTIFF, iTileY * psCache->nBlockYSize, (tsample_t) iSample ); RowsInStrip=psCache->nBlockYSize; if ((iTileY+1)*psCache->nBlockYSize>psCache->nYSize) RowsInStrip=psCache->nYSize-iTileY*psCache->nBlockYSize; TIFFWriteEncodedStrip( psCache->hTIFF, nTileID, pabyData, TIFFVStripSize(psCache->hTIFF,RowsInStrip) ); } } } else { pabyData = TIFFGetOvrBlock( psCache, iTileX, iTileY, 0 ); if( psCache->bTiled ) { nTileID = TIFFComputeTile( psCache->hTIFF, iTileX * psCache->nBlockXSize, iTileY * psCache->nBlockYSize, 0, 0 ); TIFFWriteEncodedTile( psCache->hTIFF, nTileID, pabyData, TIFFTileSize(psCache->hTIFF) ); } else { nTileID = TIFFComputeStrip( psCache->hTIFF, iTileY * psCache->nBlockYSize, 0 ); RowsInStrip=psCache->nBlockYSize; if ((iTileY+1)*psCache->nBlockYSize>psCache->nYSize) RowsInStrip=psCache->nYSize-iTileY*psCache->nBlockYSize; TIFFWriteEncodedStrip( psCache->hTIFF, nTileID, pabyData, TIFFVStripSize(psCache->hTIFF,RowsInStrip) ); } } } /* TODO: add checks on error status return of TIFFWriteEncodedTile and TIFFWriteEncodedStrip */ /* -------------------------------------------------------------------- */ /* Rotate buffers. */ /* -------------------------------------------------------------------- */ pabyData = psCache->pabyRow1Blocks; psCache->pabyRow1Blocks = psCache->pabyRow2Blocks; psCache->pabyRow2Blocks = pabyData; _TIFFmemset( pabyData, 0, psCache->nBytesPerRow ); psCache->nBlockOffset++; /* -------------------------------------------------------------------- */ /* Restore access to original directory. */ /* -------------------------------------------------------------------- */ TIFFFlush( psCache->hTIFF ); /* TODO: add checks on error status return of TIFFFlush */ TIFFSetSubDirectory( psCache->hTIFF, nBaseDirOffset ); /* TODO: add checks on error status return of TIFFSetSubDirectory */ }