diff options
Diffstat (limited to 'source/XMPFiles/FileHandlers/PNG_Handler.cpp')
-rw-r--r-- | source/XMPFiles/FileHandlers/PNG_Handler.cpp | 281 |
1 files changed, 281 insertions, 0 deletions
diff --git a/source/XMPFiles/FileHandlers/PNG_Handler.cpp b/source/XMPFiles/FileHandlers/PNG_Handler.cpp new file mode 100644 index 0000000..44a08dd --- /dev/null +++ b/source/XMPFiles/FileHandlers/PNG_Handler.cpp @@ -0,0 +1,281 @@ +// ================================================================================================= +// ADOBE SYSTEMS INCORPORATED +// Copyright 2002-2007 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 "PNG_Handler.hpp" + +#include "PNG_Support.hpp" + +using namespace std; + +// ================================================================================================= +/// \file PNG_Handler.hpp +/// \brief File format handler for PNG. +/// +/// This handler ... +/// +// ================================================================================================= + +// ================================================================================================= +// PNG_MetaHandlerCTor +// ==================== + +XMPFileHandler * PNG_MetaHandlerCTor ( XMPFiles * parent ) +{ + return new PNG_MetaHandler ( parent ); + +} // PNG_MetaHandlerCTor + +// ================================================================================================= +// PNG_CheckFormat +// =============== + +bool PNG_CheckFormat ( XMP_FileFormat format, + XMP_StringPtr filePath, + LFA_FileRef fileRef, + XMPFiles * parent ) +{ + IgnoreParam(format); IgnoreParam(fileRef); IgnoreParam(parent); + XMP_Assert ( format == kXMP_PNGFile ); + + IOBuffer ioBuf; + + LFA_Seek ( fileRef, 0, SEEK_SET ); + if ( ! CheckFileSpace ( fileRef, &ioBuf, PNG_SIGNATURE_LEN ) ) return false; // We need at least 8, the buffer is filled anyway. + + if ( ! CheckBytes ( ioBuf.ptr, PNG_SIGNATURE_DATA, PNG_SIGNATURE_LEN ) ) return false; + + return true; + +} // PNG_CheckFormat + +// ================================================================================================= +// PNG_MetaHandler::PNG_MetaHandler +// ================================== + +PNG_MetaHandler::PNG_MetaHandler ( XMPFiles * _parent ) +{ + this->parent = _parent; + this->handlerFlags = kPNG_HandlerFlags; + this->stdCharForm = kXMP_Char8Bit; + +} + +// ================================================================================================= +// PNG_MetaHandler::~PNG_MetaHandler +// =================================== + +PNG_MetaHandler::~PNG_MetaHandler() +{ +} + +// ================================================================================================= +// PNG_MetaHandler::CacheFileData +// =============================== + +void PNG_MetaHandler::CacheFileData() +{ + + this->containsXMP = false; + + LFA_FileRef fileRef ( this->parent->fileRef ); + if ( fileRef == 0) return; + + PNG_Support::ChunkState chunkState; + long numChunks = PNG_Support::OpenPNG ( fileRef, chunkState ); + if ( numChunks == 0 ) return; + + if (chunkState.xmpLen != 0) + { + // XMP present + + this->xmpPacket.reserve(chunkState.xmpLen); + this->xmpPacket.assign(chunkState.xmpLen, ' '); + + if (PNG_Support::ReadBuffer ( fileRef, chunkState.xmpPos, chunkState.xmpLen, const_cast<char *>(this->xmpPacket.data()) )) + { + this->packetInfo.offset = chunkState.xmpPos; + this->packetInfo.length = chunkState.xmpLen; + this->containsXMP = true; + } + } + else + { + // no XMP + } + +} // PNG_MetaHandler::CacheFileData + +// ================================================================================================= +// PNG_MetaHandler::ProcessTNail +// ============================== + +void PNG_MetaHandler::ProcessTNail() +{ + + XMP_Throw ( "PNG_MetaHandler::ProcessTNail isn't implemented yet", kXMPErr_Unimplemented ); + +} // PNG_MetaHandler::ProcessTNail + +// ================================================================================================= +// PNG_MetaHandler::ProcessXMP +// ============================ +// +// Process the raw XMP and legacy metadata that was previously cached. + +void PNG_MetaHandler::ProcessXMP() +{ + this->processedXMP = true; // Make sure we only come through here once. + + // Process the XMP packet. + + if ( ! this->xmpPacket.empty() ) { + + XMP_Assert ( this->containsXMP ); + XMP_StringPtr packetStr = this->xmpPacket.c_str(); + XMP_StringLen packetLen = this->xmpPacket.size(); + + this->xmpObj.ParseFromBuffer ( packetStr, packetLen ); + + this->containsXMP = true; + + } + +} // PNG_MetaHandler::ProcessXMP + +// ================================================================================================= +// PNG_MetaHandler::UpdateFile +// ============================ + +void PNG_MetaHandler::UpdateFile ( bool doSafeUpdate ) +{ + bool updated = false; + + if ( ! this->needsUpdate ) return; + if ( doSafeUpdate ) XMP_Throw ( "PNG_MetaHandler::UpdateFile: Safe update not supported", kXMPErr_Unavailable ); + + XMP_StringPtr packetStr = xmpPacket.c_str(); + XMP_StringLen packetLen = xmpPacket.size(); + if ( packetLen == 0 ) return; + + LFA_FileRef fileRef(this->parent->fileRef); + if ( fileRef == 0 ) return; + + PNG_Support::ChunkState chunkState; + long numChunks = PNG_Support::OpenPNG ( fileRef, chunkState ); + if ( numChunks == 0 ) return; + + // write/update chunk + if (chunkState.xmpLen == 0) + { + // no current chunk -> inject + updated = SafeWriteFile(); + } + else if (chunkState.xmpLen >= packetLen ) + { + // current chunk size is sufficient -> write and update CRC (in place update) + updated = PNG_Support::WriteBuffer(fileRef, chunkState.xmpPos, packetLen, packetStr ); + PNG_Support::UpdateChunkCRC(fileRef, chunkState.xmpChunk ); + } + else if (chunkState.xmpLen < packetLen) + { + // XMP is too large for current chunk -> expand + updated = SafeWriteFile(); + } + + if ( ! updated )return; // If there's an error writing the chunk, bail. + + this->needsUpdate = false; + +} // PNG_MetaHandler::UpdateFile + +// ================================================================================================= +// PNG_MetaHandler::WriteFile +// =========================== + +void PNG_MetaHandler::WriteFile ( LFA_FileRef sourceRef, const std::string & sourcePath ) +{ + LFA_FileRef destRef = this->parent->fileRef; + + PNG_Support::ChunkState chunkState; + long numChunks = PNG_Support::OpenPNG ( sourceRef, chunkState ); + if ( numChunks == 0 ) return; + + LFA_Truncate(destRef, 0); + LFA_Write(destRef, PNG_SIGNATURE_DATA, PNG_SIGNATURE_LEN); + + PNG_Support::ChunkIterator curPos = chunkState.chunks.begin(); + PNG_Support::ChunkIterator endPos = chunkState.chunks.end(); + + for (; (curPos != endPos); ++curPos) + { + PNG_Support::ChunkData chunk = *curPos; + + // discard existing XMP chunk + if (chunk.xmp) + continue; + + // copy any other chunk + PNG_Support::CopyChunk(sourceRef, destRef, chunk); + + // place XMP chunk immediately after IHDR-chunk + if (PNG_Support::CheckIHDRChunkHeader(chunk)) + { + XMP_StringPtr packetStr = xmpPacket.c_str(); + XMP_StringLen packetLen = xmpPacket.size(); + + PNG_Support::WriteXMPChunk(destRef, packetLen, packetStr ); + } + } + +} // PNG_MetaHandler::WriteFile + +// ================================================================================================= +// PNG_MetaHandler::SafeWriteFile +// =========================== + +bool PNG_MetaHandler::SafeWriteFile () +{ + bool ret = false; + + std::string origPath = this->parent->filePath; + LFA_FileRef origRef = this->parent->fileRef; + + std::string updatePath; + LFA_FileRef updateRef = 0; + + CreateTempFile ( origPath, &updatePath, kCopyMacRsrc ); + updateRef = LFA_Open ( updatePath.c_str(), 'w' ); + + this->parent->filePath = updatePath; + this->parent->fileRef = updateRef; + + try { + this->WriteFile ( origRef, origPath ); + ret = true; + } catch ( ... ) { + LFA_Close ( updateRef ); + this->parent->filePath = origPath; + this->parent->fileRef = origRef; + throw; + } + + LFA_Close ( origRef ); + LFA_Delete ( origPath.c_str() ); + + LFA_Close ( updateRef ); + LFA_Rename ( updatePath.c_str(), origPath.c_str() ); + this->parent->filePath = origPath; + + this->parent->fileRef = 0; + + return ret; + +} // PNG_MetaHandler::SafeWriteFile + +// ================================================================================================= |