diff options
Diffstat (limited to 'XMPFiles/source/FormatSupport/PSIR_MemoryReader.cpp')
-rw-r--r-- | XMPFiles/source/FormatSupport/PSIR_MemoryReader.cpp | 112 |
1 files changed, 112 insertions, 0 deletions
diff --git a/XMPFiles/source/FormatSupport/PSIR_MemoryReader.cpp b/XMPFiles/source/FormatSupport/PSIR_MemoryReader.cpp new file mode 100644 index 0000000..7432554 --- /dev/null +++ b/XMPFiles/source/FormatSupport/PSIR_MemoryReader.cpp @@ -0,0 +1,112 @@ +// ================================================================================================= +// ADOBE SYSTEMS INCORPORATED +// Copyright 2006 Adobe Systems Incorporated +// All Rights Reserved +// +// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms +// of the Adobe license agreement accompanying it. +// ================================================================================================= + +#include "public/include/XMP_Environment.h" // ! XMP_Environment.h must be the first included header. +#include "public/include/XMP_Const.h" + +#include "XMPFiles/source/FormatSupport/PSIR_Support.hpp" +#include "source/EndianUtils.hpp" +#include "source/XIO.hpp" + +#include <string.h> + +// ================================================================================================= +/// \file PSIR_MemoryReader.cpp +/// \brief Implementation of the memory-based read-only form of PSIR_Manager. +// ================================================================================================= + +// ================================================================================================= +// PSIR_MemoryReader::GetImgRsrc +// ============================= + +bool PSIR_MemoryReader::GetImgRsrc ( XMP_Uns16 id, ImgRsrcInfo* info ) const +{ + ImgRsrcMap::const_iterator rsrcPos = this->imgRsrcs.find ( id ); + if ( rsrcPos == this->imgRsrcs.end() ) return false; + + if ( info != 0 ) *info = rsrcPos->second; + return true; + +} // PSIR_MemoryReader::GetImgRsrc + +// ================================================================================================= +// PSIR_MemoryReader::ParseMemoryResources +// ======================================= + +void PSIR_MemoryReader::ParseMemoryResources ( const void* data, XMP_Uns32 length, bool copyData /* = true */ ) +{ + // Get rid of any existing image resources. + + if ( this->ownedContent ) free ( this->psirContent ); + this->ownedContent = false; + this->psirContent = 0; + this->psirLength = 0; + this->imgRsrcs.clear(); + + if ( length == 0 ) return; + + // Allocate space for the full in-memory data and copy it. + + if ( ! copyData ) { + this->psirContent = (XMP_Uns8*) data; + XMP_Assert ( ! this->ownedContent ); + } else { + if ( length > 100*1024*1024 ) XMP_Throw ( "Outrageous length for memory-based PSIR", kXMPErr_BadPSIR ); + this->psirContent = (XMP_Uns8*) malloc(length); + if ( this->psirContent == 0 ) XMP_Throw ( "Out of memory", kXMPErr_NoMemory ); + memcpy ( this->psirContent, data, length ); // AUDIT: Safe, malloc'ed length bytes above. + this->ownedContent = true; + } + + this->psirLength = length; + + // Capture the info for all of the resources. We're using a map keyed by ID, so only one + // resource of each ID is recognized. Redundant resources are not legit, but have been seen in + // the field. In particular, one case has been seen of a duplicate IIM block with one empty. + // In general we keep the first seen copy to be compatible with Photoshop. A later non-empty + // copy will be taken though if the current one is empty. + + // ! Don't use map[id] to lookup, that creates a default entry if none exists! + + XMP_Uns8* psirPtr = this->psirContent; + XMP_Uns8* psirEnd = psirPtr + length; + XMP_Uns8* psirLimit = psirEnd - kMinImgRsrcSize; + + while ( psirPtr <= psirLimit ) { + + XMP_Uns32 type = GetUns32BE(psirPtr); + XMP_Uns16 id = GetUns16BE(psirPtr+4); + psirPtr += 6; // Advance to the resource name. + + XMP_Uns16 nameLen = psirPtr[0]; // ! The length for the Pascal string, w/ room for "+2". + psirPtr += ((nameLen + 2) & 0xFFFE); // ! Round up to an even offset. Yes, +2! + + if ( psirPtr > psirEnd-4 ) break; // Bad image resource. Throw instead? + + XMP_Uns32 dataLen = GetUns32BE(psirPtr); + psirPtr += 4; // Advance to the resource data. + XMP_Uns32 psirOffset = (XMP_Uns32) (psirPtr - this->psirContent); + + if ( (dataLen > length) || (psirPtr > psirEnd-dataLen) ) break; // Bad image resource. Throw instead? + + if ( type == k8BIM ) { // For read-only usage we ignore everything other than '8BIM' resources. + ImgRsrcInfo newInfo ( id, dataLen, psirPtr, psirOffset ); + ImgRsrcMap::iterator rsrcPos = this->imgRsrcs.find ( id ); + if ( rsrcPos == this->imgRsrcs.end() ) { + this->imgRsrcs.insert ( rsrcPos, ImgRsrcMap::value_type ( id, newInfo ) ); + } else if ( (rsrcPos->second.dataLen == 0) && (newInfo.dataLen != 0) ) { + rsrcPos->second = newInfo; + } + } + + psirPtr += ((dataLen + 1) & 0xFFFFFFFEUL); // ! Round up to an even offset. + + } + +} // PSIR_MemoryReader::ParseMemoryResources |