bool isXmpType(BasicIo& iIo, bool advance) { /* Make sure the file starts with and (optional) XML declaration, followed by an XMP header (<?xpacket ... ?>) or an <x:xmpmeta> element. That doesn't cover all cases, since also x:xmpmeta is optional, but let's wait and see. */ // Todo: Proper implementation const int32_t len = 10; byte buf[len]; iIo.read(buf, len); if (iIo.error() || iIo.eof()) { return false; } bool rc = false; const std::string head(reinterpret_cast<const char*>(buf), len); if ( head.substr(0, 5) == "<?xml" || head.substr(0, 9) == "<?xpacket" || head.substr(0, 10) == "<x:xmpmeta") { rc = true; } if (!advance || !rc) { iIo.seek(-len, BasicIo::cur); } return rc; }
void MemIo::transfer(BasicIo& src) { MemIo *memIo = dynamic_cast<MemIo*>(&src); if (memIo) { // Optimization if src is another instance of MemIo if (true == isMalloced_) { std::free(data_); } idx_ = 0; data_ = memIo->data_; size_ = memIo->size_; isMalloced_ = memIo->isMalloced_; memIo->idx_ = 0; memIo->data_ = 0; memIo->size_ = 0; memIo->isMalloced_ = false; } else { // Generic reopen to reset position to start if (src.open() != 0) { throw Error(9, src.path(), strError()); } idx_ = 0; write(src); src.close(); } if (error() || src.error()) throw Error(19, strError()); }
DataBuf PgfImage::readPgfHeaderStructure(BasicIo& iIo, int& width, int& height) { DataBuf header(16); long bufRead = iIo.read(header.pData_, header.size_); if (iIo.error()) throw Error(14); if (bufRead != header.size_) throw Error(20); DataBuf work(8); // don't disturb the binary data - doWriteMetadata reuses it memcpy (work.pData_,header.pData_,8); width = byteSwap_(work,0,bSwap_); height = byteSwap_(work,4,bSwap_); /* NOTE: properties not yet used byte nLevels = buffer.pData_[8]; byte quality = buffer.pData_[9]; byte bpp = buffer.pData_[10]; byte channels = buffer.pData_[11]; */ byte mode = header.pData_[12]; if (mode == 2) // Indexed color image. We pass color table (256 * 3 bytes). { header.alloc(16 + 256*3); bufRead = iIo.read(&header.pData_[16], 256*3); if (iIo.error()) throw Error(14); if (bufRead != 256*3) throw Error(20); } return header; } // PgfImage::readPgfHeaderStructure
DataBuf PgfImage::readPgfHeaderStructure(BasicIo& iIo, int* width, int* height) { DataBuf header(16); long bufRead = iIo.read(header.pData_, header.size_); if (iIo.error()) throw Error(14); if (bufRead != header.size_) throw Error(20); memcpy(width, &header.pData_[0], 4); // TODO : check endianness. memcpy(height, &header.pData_[4], 4); // TODO : check endianness. /* NOTE: properties not yet used byte nLevels = buffer.pData_[8]; byte quality = buffer.pData_[9]; byte bpp = buffer.pData_[10]; byte channels = buffer.pData_[11]; */ byte mode = header.pData_[12]; if (mode == 2) // Indexed color image. We pass color table (256 * 3 bytes). { header.alloc(16 + 256*3); bufRead = iIo.read(&header.pData_[16], 256*3); if (iIo.error()) throw Error(14); if (bufRead != 256*3) throw Error(20); } return header; } // PgfImage::readPgfHeaderStructure
int JpegImage::writeHeader(BasicIo& outIo) const { // Jpeg header byte tmpBuf[2]; tmpBuf[0] = 0xff; tmpBuf[1] = soi_; if (outIo.write(tmpBuf, 2) != 2) return 4; if (outIo.error()) return 4; return 0; }
bool isTgaType(BasicIo& iIo, bool /*advance*/) { // not all TARGA files have a signature string, so first just try to match the file name extension #ifdef EXV_UNICODE_PATH std::wstring wpath = iIo.wpath(); if( wpath.rfind(EXV_WIDEN(".tga")) != std::wstring::npos || wpath.rfind(EXV_WIDEN(".TGA")) != std::wstring::npos) { return true; } #else std::string path = iIo.path(); if( path.rfind(".tga") != std::string::npos || path.rfind(".TGA") != std::string::npos) { return true; } #endif byte buf[26]; long curPos = iIo.tell(); iIo.seek(-26, BasicIo::end); if (iIo.error() || iIo.eof()) { return false; } iIo.read(buf, sizeof(buf)); if (iIo.error()) { return false; } // some TARGA files, but not all, have a signature string at the end bool matched = (memcmp(buf + 8, "TRUEVISION-XFILE", 16) == 0); iIo.seek(curPos, BasicIo::beg); return matched; }
void FileIo::transfer(BasicIo& src) { const bool wasOpen = (fp_ != 0); const std::string lastMode(openMode_); FileIo *fileIo = dynamic_cast<FileIo*>(&src); if (fileIo) { // Optimization if src is another instance of FileIo fileIo->close(); // Check if the file can be written to, if it already exists if (open("w+b") != 0) { // Remove the (temporary) file std::remove(fileIo->path_.c_str()); throw Error(10, path_, "w+b", strError()); } close(); struct stat buf; if (::stat(path_.c_str(), &buf) == -1) { throw Error(2, path_, strError(), "stat"); } // MSVCRT rename that does not overwrite existing files if (fileExists(path_) && std::remove(path_.c_str()) != 0) { throw Error(2, path_, strError(), "std::remove"); } if (std::rename(fileIo->path_.c_str(), path_.c_str()) == -1) { throw Error(17, fileIo->path_, path_, strError()); } std::remove(fileIo->path_.c_str()); // Set original file permissions if (::chmod(path_.c_str(), buf.st_mode) == -1) { throw Error(2, fileIo->path_, strError(), "chmod"); } } else { // Generic handling, reopen both to reset to start if (open("w+b") != 0) { throw Error(10, path_, "w+b", strError()); } if (src.open() != 0) { throw Error(9, src.path(), strError()); } write(src); src.close(); } if (wasOpen) { if (open(lastMode) != 0) { throw Error(10, path_, lastMode, strError()); } } else close(); if (error() || src.error()) throw Error(18, path_, strError()); }
int ExvImage::writeHeader(BasicIo& outIo) const { // Exv header byte tmpBuf[7]; tmpBuf[0] = 0xff; tmpBuf[1] = 0x01; std::memcpy(tmpBuf + 2, exiv2Id_, 5); if (outIo.write(tmpBuf, 7) != 7) return 4; if (outIo.error()) return 4; return 0; }
bool isJpegType(BasicIo& iIo, bool advance) { bool result = true; byte tmpBuf[2]; iIo.read(tmpBuf, 2); if (iIo.error() || iIo.eof()) return false; if (0xff != tmpBuf[0] || JpegImage::soi_ != tmpBuf[1]) { result = false; } if (!advance || !result ) iIo.seek(-2, BasicIo::cur); return result; }
bool isExvType(BasicIo& iIo, bool advance) { bool result = true; byte tmpBuf[7]; iIo.read(tmpBuf, 7); if (iIo.error() || iIo.eof()) return false; if ( 0xff != tmpBuf[0] || 0x01 != tmpBuf[1] || memcmp(tmpBuf + 2, ExvImage::exiv2Id_, 5) != 0) { result = false; } if (!advance || !result) iIo.seek(-7, BasicIo::cur); return result; }
bool isMrwType(BasicIo& iIo, bool advance) { const int32_t len = 4; byte buf[len]; iIo.read(buf, len); if (iIo.error() || iIo.eof()) { return false; } int rc = memcmp(buf, "\0MRM", 4); if (!advance || rc != 0) { iIo.seek(-len, BasicIo::cur); } return rc == 0; }
long MemIo::write(BasicIo& src) { if (static_cast<BasicIo*>(this) == &src) return 0; if (!src.isopen()) return 0; byte buf[4096]; long readCount = 0; long writeTotal = 0; while ((readCount = src.read(buf, sizeof(buf)))) { write(buf, readCount); writeTotal += readCount; } return writeTotal; }
byte PgfImage::readPgfMagicNumber(BasicIo& iIo) { byte b = iIo.getb(); if (iIo.error()) throw Error(14); if (b < 0x36) // 0x36 = '6'. { // Not right Magick version. #ifdef DEBUG std::cout << "Exiv2::PgfImage::readMetadata: wrong Magick number\n"; #endif } return b; } // PgfImage::readPgfMagicNumber
bool isOrfType(BasicIo& iIo, bool advance) { const int32_t len = 8; byte buf[len]; iIo.read(buf, len); if (iIo.error() || iIo.eof()) { return false; } OrfHeader orfHeader; bool rc = orfHeader.read(buf, len); if (!advance || !rc) { iIo.seek(-len, BasicIo::cur); } return rc; }
uint32_t PgfImage::readPgfHeaderSize(BasicIo& iIo) { DataBuf buffer(4); long bufRead = iIo.read(buffer.pData_, buffer.size_); if (iIo.error()) throw Error(14); if (bufRead != buffer.size_) throw Error(20); int headerSize = (int) byteSwap_(buffer,0,bSwap_); if (headerSize <= 0 ) throw Error(22); #ifdef DEBUG std::cout << "Exiv2::PgfImage: PGF header size : " << headerSize << " bytes\n"; #endif return headerSize; } // PgfImage::readPgfHeaderSize
bool isJp2Type(BasicIo& iIo, bool advance) { const int32_t len = 12; byte buf[len]; iIo.read(buf, len); if (iIo.error() || iIo.eof()) { return false; } bool matched = (memcmp(buf, Jp2Signature, len) == 0); if (!advance || !matched) { iIo.seek(-len, BasicIo::cur); } return matched; }
bool isPgfType(BasicIo& iIo, bool advance) { const int32_t len = 3; byte buf[len]; iIo.read(buf, len); if (iIo.error() || iIo.eof()) { return false; } int rc = memcmp(buf, pgfSignature, 3); if (!advance || rc != 0) { iIo.seek(-len, BasicIo::cur); } return rc == 0; }
bool isBmpType(BasicIo& iIo, bool advance) { const int32_t len = 2; const unsigned char BmpImageId[2] = { 'B', 'M' }; byte buf[len]; iIo.read(buf, len); if (iIo.error() || iIo.eof()) { return false; } bool matched = (memcmp(buf, BmpImageId, len) == 0); if (!advance || !matched) { iIo.seek(-len, BasicIo::cur); } return matched; }
uint32_t PgfImage::readPgfHeaderSize(BasicIo& iIo) { DataBuf buffer(4); long bufRead = iIo.read(buffer.pData_, buffer.size_); if (iIo.error()) throw Error(14); if (bufRead != buffer.size_) throw Error(20); uint32_t headerSize = 0; memcpy (&headerSize, buffer.pData_, 4); // TODO : check endianness. if (headerSize <= 0 ) throw Error(22); #ifdef DEBUG std::cout << "Exiv2::PgfImage: PGF header size : " << headerSize << " bytes\n"; #endif return headerSize; } // PgfImage::readPgfHeaderSize
bool isAsfType(BasicIo& iIo, bool advance) { const int32_t len = 16; byte buf[len]; iIo.read(buf, len); if (iIo.error() || iIo.eof()) { return false; } bool matched = isASFType(buf); if (!advance || !matched) { iIo.seek(0, BasicIo::beg); } return matched; }
bool isPsdType(BasicIo& iIo, bool advance) { const int32_t len = 6; const unsigned char PsdHeader[6] = { '8', 'B', 'P', 'S', 0, 1 }; byte buf[len]; iIo.read(buf, len); if (iIo.error() || iIo.eof()) { return false; } bool matched = (memcmp(buf, PsdHeader, len) == 0); if (!advance || !matched) { iIo.seek(-len, BasicIo::cur); } return matched; }
bool isCrwType(BasicIo& iIo, bool advance) { bool result = true; byte tmpBuf[14]; iIo.read(tmpBuf, 14); if (iIo.error() || iIo.eof()) { return false; } if (!( ('I' == tmpBuf[0] && 'I' == tmpBuf[1]) || ('M' == tmpBuf[0] && 'M' == tmpBuf[1]))) { result = false; } if ( true == result && std::memcmp(tmpBuf + 6, CiffHeader::signature_, 8) != 0) { result = false; } if (!advance || !result) iIo.seek(-14, BasicIo::cur); return result; }
bool isGifType(BasicIo& iIo, bool advance) { const int32_t len = 6; const unsigned char Gif87aId[8] = { 'G', 'I', 'F', '8', '7', 'a' }; const unsigned char Gif89aId[8] = { 'G', 'I', 'F', '8', '9', 'a' }; byte buf[len]; iIo.read(buf, len); if (iIo.error() || iIo.eof()) { return false; } bool matched = (memcmp(buf, Gif87aId, len) == 0) || (memcmp(buf, Gif89aId, len) == 0); if (!advance || !matched) { iIo.seek(-len, BasicIo::cur); } return matched; }
int ImageFactory::getType(BasicIo& io) { if (io.open() != 0) return ImageType::none; IoCloser closer(io); for (unsigned int i = 0; registry_[i].imageType_ != ImageType::none; ++i) { if (registry_[i].isThisType_(io, false)) { return registry_[i].imageType_; } } return ImageType::none; } // ImageFactory::getType
bool isXmpType(BasicIo& iIo, bool advance) { /* Check if the file starts with an optional XML declaration followed by either an XMP header (<?xpacket ... ?>) or an <x:xmpmeta> element. In addition, in order for empty XmpSidecar objects as created by Exiv2 to pass the test, just an XML header is also considered ok. */ const int32_t len = 80; byte buf[len]; iIo.read(buf, xmlHdrCnt + 1); if ( iIo.eof() && 0 == strncmp(reinterpret_cast<const char*>(buf), xmlHeader, xmlHdrCnt)) { return true; } if (iIo.error() || iIo.eof()) { return false; } iIo.read(buf + xmlHdrCnt + 1, len - xmlHdrCnt - 1); if (iIo.error() || iIo.eof()) { return false; } // Skip leading BOM int32_t start = 0; if (0 == strncmp(reinterpret_cast<const char*>(buf), "\xef\xbb\xbf", 3)) { start = 3; } bool rc = false; std::string head(reinterpret_cast<const char*>(buf + start), len - start); if (head.substr(0, 5) == "<?xml") { // Forward to the next tag for (unsigned i = 5; i < head.size(); ++i) { if (head[i] == '<') { head = head.substr(i); break; } } } if ( head.size() > 9 && ( head.substr(0, 9) == "<?xpacket" || head.substr(0, 10) == "<x:xmpmeta")) { rc = true; } if (!advance || !rc) { iIo.seek(-(len - start), BasicIo::cur); // Swallow the BOM } return rc; }
uint32_t PsdImage::writeIptcData(const IptcData& iptcData, BasicIo& out) const { uint32_t resLength = 0; byte buf[8]; if (iptcData.count() > 0) { DataBuf rawIptc = IptcParser::encode(iptcData); if (rawIptc.size_ > 0) { #ifdef DEBUG std::cerr << std::hex << "write: resourceId: " << kPhotoshopResourceID_IPTC_NAA << "\n"; std::cerr << std::dec << "Writing IPTC_NAA: size: " << rawIptc.size_ << "\n"; #endif ul2Data(buf, kPhotoshopResourceType, bigEndian); if (out.write(buf, 4) != 4) throw Error(21); us2Data(buf, kPhotoshopResourceID_IPTC_NAA, bigEndian); if (out.write(buf, 2) != 2) throw Error(21); us2Data(buf, 0, bigEndian); // NULL resource name if (out.write(buf, 2) != 2) throw Error(21); ul2Data(buf, rawIptc.size_, bigEndian); if (out.write(buf, 4) != 4) throw Error(21); // Write encoded Iptc data if (out.write(rawIptc.pData_, rawIptc.size_) != rawIptc.size_) throw Error(21); resLength += rawIptc.size_ + 12; if (rawIptc.size_ & 1) // even padding { buf[0] = 0; if (out.write(buf, 1) != 1) throw Error(21); resLength++; } } } return resLength; } // PsdImage::writeIptcData
long FileIo::write(BasicIo& src) { assert(fp_ != 0); if (static_cast<BasicIo*>(this) == &src) return 0; if (!src.isopen()) return 0; if (switchMode(opWrite) != 0) return 0; byte buf[4096]; long readCount = 0; long writeCount = 0; long writeTotal = 0; while ((readCount = src.read(buf, sizeof(buf)))) { writeTotal += writeCount = (long)std::fwrite(buf, 1, readCount, fp_); if (writeCount != readCount) { // try to reset back to where write stopped src.seek(writeCount-readCount, BasicIo::cur); break; } } return writeTotal; }
Image::Type ImageFactory::getType(BasicIo& io) { IoCloser closer(io); if (io.open() != 0) return Image::none; Image::Type type = Image::none; Registry::const_iterator b = registry_->begin(); Registry::const_iterator e = registry_->end(); for (Registry::const_iterator i = b; i != e; ++i) { if (i->second.isThisType(io, false)) { type = i->first; break; } } return type; } // ImageFactory::getType
uint32_t PsdImage::writeXmpData(const XmpData& xmpData, BasicIo& out) const { std::string xmpPacket; uint32_t resLength = 0; byte buf[8]; #ifdef DEBUG std::cerr << "writeXmpFromPacket(): " << writeXmpFromPacket() << "\n"; #endif // writeXmpFromPacket(true); if (writeXmpFromPacket() == false) { if (XmpParser::encode(xmpPacket, xmpData) > 1) { #ifndef SUPPRESS_WARNINGS std::cerr << "Error: Failed to encode XMP metadata.\n"; #endif } } if (xmpPacket.size() > 0) { #ifdef DEBUG std::cerr << std::hex << "write: resourceId: " << kPhotoshopResourceID_XMPPacket << "\n"; std::cerr << std::dec << "Writing XMPPacket: size: " << xmpPacket.size() << "\n"; #endif ul2Data(buf, kPhotoshopResourceType, bigEndian); if (out.write(buf, 4) != 4) throw Error(21); us2Data(buf, kPhotoshopResourceID_XMPPacket, bigEndian); if (out.write(buf, 2) != 2) throw Error(21); us2Data(buf, 0, bigEndian); // NULL resource name if (out.write(buf, 2) != 2) throw Error(21); ul2Data(buf, xmpPacket.size(), bigEndian); if (out.write(buf, 4) != 4) throw Error(21); // Write XMPPacket if (out.write(reinterpret_cast<const byte*>(xmpPacket.data()), static_cast<long>(xmpPacket.size())) != static_cast<long>(xmpPacket.size())) throw Error(21); if (out.error()) throw Error(21); resLength += xmpPacket.size() + 12; if (xmpPacket.size() & 1) // even padding { buf[0] = 0; if (out.write(buf, 1) != 1) throw Error(21); resLength++; } } return resLength; } // PsdImage::writeXmpData
uint32_t PsdImage::writeExifData(const ExifData& exifData, BasicIo& out) { uint32_t resLength = 0; byte buf[8]; if (exifData.count() > 0) { Blob blob; ByteOrder bo = byteOrder(); if (bo == invalidByteOrder) { bo = littleEndian; setByteOrder(bo); } ExifParser::encode(blob, bo, exifData); if (blob.size() > 0) { #ifdef DEBUG std::cerr << std::hex << "write: resourceId: " << kPhotoshopResourceID_ExifInfo << "\n"; std::cerr << std::dec << "Writing ExifInfo: size: " << blob.size() << "\n"; #endif ul2Data(buf, kPhotoshopResourceType, bigEndian); if (out.write(buf, 4) != 4) throw Error(21); us2Data(buf, kPhotoshopResourceID_ExifInfo, bigEndian); if (out.write(buf, 2) != 2) throw Error(21); us2Data(buf, 0, bigEndian); // NULL resource name if (out.write(buf, 2) != 2) throw Error(21); ul2Data(buf, blob.size(), bigEndian); if (out.write(buf, 4) != 4) throw Error(21); // Write encoded Exif data if (out.write(&blob[0], blob.size()) != static_cast<long>(blob.size())) throw Error(21); resLength += blob.size() + 12; if (blob.size() & 1) // even padding { buf[0] = 0; if (out.write(buf, 1) != 1) throw Error(21); resLength++; } } } return resLength; } // PsdImage::writeExifData