Change return type of BasicIo::tell() to size_t.

main
Kevin Backhouse 3 years ago
parent 7ebf2a184e
commit ad4e13b827
No known key found for this signature in database
GPG Key ID: 9DD01852EE40366E

@ -198,10 +198,9 @@ class EXIV2API BasicIo {
//@{ //@{
/*! /*!
@brief Get the current IO position. @brief Get the current IO position.
@return Offset from the start of IO if successful;<BR> @return Offset from the start of IO
-1 if failure;
*/ */
[[nodiscard]] virtual long tell() const = 0; [[nodiscard]] virtual size_t tell() const = 0;
/*! /*!
@brief Get the current size of the IO source in bytes. @brief Get the current size of the IO source in bytes.
@return Size of the IO source in bytes;<BR> @return Size of the IO source in bytes;<BR>
@ -439,10 +438,9 @@ class EXIV2API FileIo : public BasicIo {
//@{ //@{
/*! /*!
@brief Get the current file position. @brief Get the current file position.
@return Offset from the start of the file if successful;<BR> @return Offset from the start of the file
-1 if failure;
*/ */
[[nodiscard]] long tell() const override; [[nodiscard]] size_t tell() const override;
/*! /*!
@brief Flush any buffered writes and get the current file size @brief Flush any buffered writes and get the current file size
in bytes. in bytes.
@ -624,7 +622,7 @@ class EXIV2API MemIo : public BasicIo {
@brief Get the current IO position. @brief Get the current IO position.
@return Offset from the start of the memory block @return Offset from the start of the memory block
*/ */
[[nodiscard]] long tell() const override; [[nodiscard]] size_t tell() const override;
/*! /*!
@brief Get the current memory buffer size in bytes. @brief Get the current memory buffer size in bytes.
@return Size of the in memory data in bytes;<BR> @return Size of the in memory data in bytes;<BR>
@ -874,7 +872,7 @@ class EXIV2API RemoteIo : public BasicIo {
@brief Get the current IO position. @brief Get the current IO position.
@return Offset from the start of the memory block @return Offset from the start of the memory block
*/ */
[[nodiscard]] long tell() const override; [[nodiscard]] size_t tell() const override;
/*! /*!
@brief Get the current memory buffer size in bytes. @brief Get the current memory buffer size in bytes.
@return Size of the in memory data in bytes;<BR> @return Size of the in memory data in bytes;<BR>

@ -122,13 +122,13 @@ class EXIV2API BmffImage : public Image {
@return address of next box @return address of next box
@warning This function should only be called by readMetadata() @warning This function should only be called by readMetadata()
*/ */
long boxHandler(std::ostream& out, Exiv2::PrintStructureOption option, long pbox_end, int depth); uint64_t boxHandler(std::ostream& out, Exiv2::PrintStructureOption option, uint64_t pbox_end, int depth);
[[nodiscard]] static std::string indent(int i) { [[nodiscard]] static std::string indent(int i) {
return std::string(2 * i, ' '); return std::string(2 * i, ' ');
} }
uint32_t fileType_{0}; uint32_t fileType_{0};
std::set<uint64_t> visits_; std::set<size_t> visits_;
uint64_t visits_max_{0}; uint64_t visits_max_{0};
uint16_t unknownID_{0xffff}; uint16_t unknownID_{0xffff};
uint16_t exifID_{0xffff}; uint16_t exifID_{0xffff};
@ -140,7 +140,7 @@ class EXIV2API BmffImage : public Image {
/*! /*!
@brief box utilities @brief box utilities
*/ */
static std::string toAscii(long n); static std::string toAscii(uint32_t n);
std::string boxName(uint32_t box); std::string boxName(uint32_t box);
static bool superBox(uint32_t box); static bool superBox(uint32_t box);
static bool fullBox(uint32_t box); static bool fullBox(uint32_t box);

@ -63,12 +63,13 @@ class EXIV2API WebPImage : public Image {
private: private:
void doWriteMetadata(BasicIo& outIo); void doWriteMetadata(BasicIo& outIo);
//! @name NOT Implemented
//@{ //! Finds the offset of header in data. Returns std::string::npos if the header isn't found.
static long getHeaderOffset(const byte* data, size_t data_size, const byte* header, size_t header_size); static size_t getHeaderOffset(const byte* data, size_t data_size, const byte* header, size_t header_size);
static bool equalsWebPTag(Exiv2::DataBuf& buf, const char* str); static bool equalsWebPTag(Exiv2::DataBuf& buf, const char* str);
void debugPrintHex(byte* data, long size); void debugPrintHex(byte* data, size_t size);
void decodeChunks(long filesize); void decodeChunks(uint32_t filesize);
void inject_VP8X(BasicIo& iIo, bool has_xmp, bool has_exif, bool has_alpha, bool has_icc, int width, int height); void inject_VP8X(BasicIo& iIo, bool has_xmp, bool has_exif, bool has_alpha, bool has_icc, int width, int height);
/* Misc. */ /* Misc. */
static constexpr byte WEBP_PAD_ODD = 0; static constexpr byte WEBP_PAD_ODD = 0;

@ -458,8 +458,10 @@ int FileIo::seek(int64_t offset, Position pos) {
#endif #endif
} }
long FileIo::tell() const { size_t FileIo::tell() const {
return std::ftell(p_->fp_); const long pos = std::ftell(p_->fp_);
enforce(pos >= 0, ErrorCode::kerInputDataReadFailed);
return static_cast<size_t>(pos);
} }
size_t FileIo::size() const { size_t FileIo::size() const {
@ -786,8 +788,8 @@ int MemIo::munmap() {
return 0; return 0;
} }
long MemIo::tell() const { size_t MemIo::tell() const {
return static_cast<long>(p_->idx_); return p_->idx_;
} }
size_t MemIo::size() const { size_t MemIo::size() const {
@ -1341,8 +1343,8 @@ int RemoteIo::munmap() {
return 0; return 0;
} }
long RemoteIo::tell() const { size_t RemoteIo::tell() const {
return static_cast<long>(p_->idx_); return p_->idx_;
} }
size_t RemoteIo::size() const { size_t RemoteIo::size() const {

@ -74,7 +74,7 @@ BmffImage::BmffImage(BasicIo::UniquePtr io, bool /* create */) :
Image(ImageType::bmff, mdExif | mdIptc | mdXmp, std::move(io)) { Image(ImageType::bmff, mdExif | mdIptc | mdXmp, std::move(io)) {
} // BmffImage::BmffImage } // BmffImage::BmffImage
std::string BmffImage::toAscii(long n) { std::string BmffImage::toAscii(uint32_t n) {
const auto p = reinterpret_cast<const char*>(&n); const auto p = reinterpret_cast<const char*>(&n);
std::string result; std::string result;
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
@ -152,9 +152,9 @@ std::string BmffImage::uuidName(Exiv2::DataBuf& uuid) {
return result; return result;
} }
long BmffImage::boxHandler(std::ostream& out /* = std::cout*/, Exiv2::PrintStructureOption option /* = kpsNone */, uint64_t BmffImage::boxHandler(std::ostream& out /* = std::cout*/, Exiv2::PrintStructureOption option /* = kpsNone */,
long pbox_end, int depth) { uint64_t pbox_end, int depth) {
long address = io_->tell(); const size_t address = io_->tell();
// never visit a box twice! // never visit a box twice!
if (depth == 0) if (depth == 0)
visits_.clear(); visits_.clear();
@ -198,22 +198,22 @@ long BmffImage::boxHandler(std::ostream& out /* = std::cout*/, Exiv2::PrintStruc
} }
// read data in box and restore file position // read data in box and restore file position
long restore = io_->tell(); const size_t restore = io_->tell();
enforce(box_length >= hdrsize, Exiv2::ErrorCode::kerCorruptedMetadata); enforce(box_length >= hdrsize, Exiv2::ErrorCode::kerCorruptedMetadata);
enforce(box_length - hdrsize <= static_cast<uint64_t>(pbox_end - restore), Exiv2::ErrorCode::kerCorruptedMetadata); enforce(box_length - hdrsize <= pbox_end - restore, Exiv2::ErrorCode::kerCorruptedMetadata);
const auto buffer_size = static_cast<size_t>(box_length - hdrsize); const auto buffer_size = box_length - hdrsize;
if (skipBox(box_type)) { if (skipBox(box_type)) {
if (bTrace) { if (bTrace) {
out << std::endl; out << std::endl;
} }
// The enforce() above checks that restore + buffer_size won't // The enforce() above checks that restore + buffer_size won't
// exceed pbox_end, and by implication, won't exceed LONG_MAX // exceed pbox_end, and by implication, won't exceed LONG_MAX
return restore + static_cast<long>(buffer_size); return restore + buffer_size;
} }
DataBuf data(buffer_size); DataBuf data(static_cast<size_t>(buffer_size));
const long box_end = restore + static_cast<long>(data.size()); const size_t box_end = restore + data.size();
io_->read(data.data(), data.size()); io_->read(data.data(), data.size());
io_->seek(restore, BasicIo::beg); io_->seek(restore, BasicIo::beg);
@ -478,26 +478,25 @@ long BmffImage::boxHandler(std::ostream& out /* = std::cout*/, Exiv2::PrintStruc
void BmffImage::parseTiff(uint32_t root_tag, uint64_t length, uint64_t start) { void BmffImage::parseTiff(uint32_t root_tag, uint64_t length, uint64_t start) {
enforce(start <= io_->size(), ErrorCode::kerCorruptedMetadata); enforce(start <= io_->size(), ErrorCode::kerCorruptedMetadata);
enforce(length <= io_->size() - start, ErrorCode::kerCorruptedMetadata); enforce(length <= io_->size() - start, ErrorCode::kerCorruptedMetadata);
enforce(start <= std::numeric_limits<uint64_t>::max(), ErrorCode::kerCorruptedMetadata); enforce(start <= static_cast<uint64_t>(std::numeric_limits<int64_t>::max()), ErrorCode::kerCorruptedMetadata);
enforce(length <= std::numeric_limits<uint64_t>::max(), ErrorCode::kerCorruptedMetadata); enforce(length <= std::numeric_limits<size_t>::max(), ErrorCode::kerCorruptedMetadata);
// read and parse exif data // read and parse exif data
long restore = io_->tell(); const size_t restore = io_->tell();
DataBuf exif(static_cast<size_t>(length)); DataBuf exif(static_cast<size_t>(length));
io_->seek(static_cast<long>(start), BasicIo::beg); io_->seek(static_cast<int64_t>(start), BasicIo::beg);
if (exif.size() > 8 && io_->read(exif.data(), exif.size()) == exif.size()) { if (exif.size() > 8 && io_->read(exif.data(), exif.size()) == exif.size()) {
// hunt for "II" or "MM" // hunt for "II" or "MM"
long eof = 0xffffffff; // impossible value for punt const size_t eof = std::numeric_limits<size_t>::max(); // impossible value for punt
long punt = eof; size_t punt = eof;
for (size_t i = 0; i < exif.size() - 8 && punt == eof; i += 2) { for (size_t i = 0; i < exif.size() - 8 && punt == eof; i += 2) {
if (exif.read_uint8(i) == exif.read_uint8(i + 1)) if (exif.read_uint8(i) == exif.read_uint8(i + 1))
if (exif.read_uint8(i) == 'I' || exif.read_uint8(i) == 'M') if (exif.read_uint8(i) == 'I' || exif.read_uint8(i) == 'M')
punt = static_cast<long>(i); punt = i;
} }
if (punt != eof) { if (punt != eof) {
Internal::TiffParserWorker::decode(exifData(), iptcData(), xmpData(), exif.c_data(punt), Internal::TiffParserWorker::decode(exifData(), iptcData(), xmpData(), exif.c_data(punt), exif.size() - punt,
static_cast<uint32_t>(exif.size() - punt), root_tag, root_tag, Internal::TiffMapping::findDecoder);
Internal::TiffMapping::findDecoder);
} }
} }
io_->seek(restore, BasicIo::beg); io_->seek(restore, BasicIo::beg);
@ -506,7 +505,7 @@ void BmffImage::parseTiff(uint32_t root_tag, uint64_t length, uint64_t start) {
void BmffImage::parseTiff(uint32_t root_tag, uint64_t length) { void BmffImage::parseTiff(uint32_t root_tag, uint64_t length) {
if (length > 8) { if (length > 8) {
enforce(length - 8 <= io_->size() - io_->tell(), ErrorCode::kerCorruptedMetadata); enforce(length - 8 <= io_->size() - io_->tell(), ErrorCode::kerCorruptedMetadata);
enforce(length - 8 <= std::numeric_limits<uint64_t>::max(), ErrorCode::kerCorruptedMetadata); enforce(length - 8 <= std::numeric_limits<size_t>::max(), ErrorCode::kerCorruptedMetadata);
DataBuf data(static_cast<size_t>(length - 8u)); DataBuf data(static_cast<size_t>(length - 8u));
const size_t bufRead = io_->read(data.data(), data.size()); const size_t bufRead = io_->read(data.data(), data.size());
@ -524,8 +523,8 @@ void BmffImage::parseXmp(uint64_t length, uint64_t start) {
enforce(start <= io_->size(), ErrorCode::kerCorruptedMetadata); enforce(start <= io_->size(), ErrorCode::kerCorruptedMetadata);
enforce(length <= io_->size() - start, ErrorCode::kerCorruptedMetadata); enforce(length <= io_->size() - start, ErrorCode::kerCorruptedMetadata);
long restore = io_->tell(); const size_t restore = io_->tell();
io_->seek(static_cast<long>(start), BasicIo::beg); io_->seek(static_cast<int64_t>(start), BasicIo::beg);
auto lengthSizeT = static_cast<size_t>(length); auto lengthSizeT = static_cast<size_t>(length);
DataBuf xmp(lengthSizeT + 1); DataBuf xmp(lengthSizeT + 1);
@ -547,9 +546,8 @@ void BmffImage::parseXmp(uint64_t length, uint64_t start) {
void BmffImage::parseCr3Preview(DataBuf& data, std::ostream& out, bool bTrace, uint8_t version, size_t width_offset, void BmffImage::parseCr3Preview(DataBuf& data, std::ostream& out, bool bTrace, uint8_t version, size_t width_offset,
size_t height_offset, size_t size_offset, size_t relative_position) { size_t height_offset, size_t size_offset, size_t relative_position) {
// Derived from https://github.com/lclevy/canon_cr3 // Derived from https://github.com/lclevy/canon_cr3
long here = io_->tell(); const size_t here = io_->tell();
enforce(here >= 0 && here <= std::numeric_limits<long>::max() - static_cast<long>(relative_position), enforce(here <= std::numeric_limits<size_t>::max() - relative_position, ErrorCode::kerCorruptedMetadata);
ErrorCode::kerCorruptedMetadata);
NativePreview nativePreview; NativePreview nativePreview;
nativePreview.position_ = here + relative_position; nativePreview.position_ = here + relative_position;
nativePreview.width_ = data.read_uint16(width_offset, endian_); nativePreview.width_ = data.read_uint16(width_offset, endian_);
@ -600,8 +598,8 @@ void BmffImage::readMetadata() {
exifID_ = unknownID_; exifID_ = unknownID_;
xmpID_ = unknownID_; xmpID_ = unknownID_;
long address = 0; uint64_t address = 0;
const auto file_end = static_cast<long>(io_->size()); const auto file_end = io_->size();
while (address < file_end) { while (address < file_end) {
io_->seek(address, BasicIo::beg); io_->seek(address, BasicIo::beg);
address = boxHandler(std::cout, kpsNone, file_end, 0); address = boxHandler(std::cout, kpsNone, file_end, 0);
@ -635,8 +633,8 @@ void BmffImage::printStructure(std::ostream& out, Exiv2::PrintStructureOption op
openOrThrow(); openOrThrow();
IoCloser closer(*io_); IoCloser closer(*io_);
long address = 0; uint64_t address = 0;
const auto file_end = static_cast<long>(io_->size()); const auto file_end = io_->size();
while (address < file_end) { while (address < file_end) {
io_->seek(address, BasicIo::beg); io_->seek(address, BasicIo::beg);
address = boxHandler(out, option, file_end, depth); address = boxHandler(out, option, file_end, depth);
@ -682,7 +680,7 @@ bool isBmffType(BasicIo& iIo, bool advance) {
bool const is_video = (buf[8] == 'q' && buf[9] == 't' && buf[10] == ' ' && buf[11] == ' '); bool const is_video = (buf[8] == 'q' && buf[9] == 't' && buf[10] == ' ' && buf[11] == ' ');
bool matched = is_jxl || (is_ftyp && !is_video); bool matched = is_jxl || (is_ftyp && !is_video);
if (!advance || !matched) { if (!advance || !matched) {
iIo.seek(static_cast<long>(0), BasicIo::beg); iIo.seek(0, BasicIo::beg);
} }
return matched; return matched;
} }

@ -11,6 +11,7 @@
#include "config.h" #include "config.h"
#include "basicio.hpp" #include "basicio.hpp"
#include "enforce.hpp"
#include "epsimage.hpp" #include "epsimage.hpp"
#include "error.hpp" #include "error.hpp"
#include "futils.hpp" #include "futils.hpp"
@ -101,13 +102,8 @@ void writeTemp(BasicIo& tempIo, const std::string& data) {
//! Get the current write position of temp file, taking care of errors //! Get the current write position of temp file, taking care of errors
uint32_t posTemp(const BasicIo& tempIo) { uint32_t posTemp(const BasicIo& tempIo) {
const long pos = tempIo.tell(); const size_t pos = tempIo.tell();
if (pos == -1) { enforce(pos <= std::numeric_limits<uint32_t>::max(), ErrorCode::kerImageWriteFailed);
#ifndef SUPPRESS_WARNINGS
EXV_WARNING << "Internal error while determining current write position in temporary file.\n";
#endif
throw Error(ErrorCode::kerImageWriteFailed);
}
return static_cast<uint32_t>(pos); return static_cast<uint32_t>(pos);
} }
@ -1167,7 +1163,7 @@ bool isEpsType(BasicIo& iIo, bool advance) {
bufSize = i.size(); bufSize = i.size();
} }
} }
const long restore = iIo.tell(); // save const size_t restore = iIo.tell(); // save
DataBuf buf = iIo.read(bufSize); DataBuf buf = iIo.read(bufSize);
if (iIo.error() || buf.size() != bufSize) { if (iIo.error() || buf.size() != bufSize) {
iIo.seek(restore, BasicIo::beg); iIo.seek(restore, BasicIo::beg);

@ -287,7 +287,7 @@ static bool typeValid(uint16_t type) {
return type >= 1 && type <= 13; return type >= 1 && type <= 13;
} }
static std::set<long> visits; // #547 static std::set<size_t> visits; // #547
void Image::printIFDStructure(BasicIo& io, std::ostream& out, Exiv2::PrintStructureOption option, size_t start, void Image::printIFDStructure(BasicIo& io, std::ostream& out, Exiv2::PrintStructureOption option, size_t start,
bool bSwap, char c, int depth) { bool bSwap, char c, int depth) {
@ -370,7 +370,7 @@ void Image::printIFDStructure(BasicIo& io, std::ostream& out, Exiv2::PrintStruct
const bool bOffsetIsPointer = count_x_size > 4; const bool bOffsetIsPointer = count_x_size > 4;
if (bOffsetIsPointer) { // read into buffer if (bOffsetIsPointer) { // read into buffer
const long restore = io.tell(); // save const size_t restore = io.tell(); // save
io.seekOrThrow(offset, BasicIo::beg, ErrorCode::kerCorruptedMetadata); // position io.seekOrThrow(offset, BasicIo::beg, ErrorCode::kerCorruptedMetadata); // position
io.readOrThrow(buf.data(), count_x_size, ErrorCode::kerCorruptedMetadata); // read io.readOrThrow(buf.data(), count_x_size, ErrorCode::kerCorruptedMetadata); // read
io.seekOrThrow(restore, BasicIo::beg, ErrorCode::kerCorruptedMetadata); // restore io.seekOrThrow(restore, BasicIo::beg, ErrorCode::kerCorruptedMetadata); // restore
@ -410,7 +410,7 @@ void Image::printIFDStructure(BasicIo& io, std::ostream& out, Exiv2::PrintStruct
if (option == kpsRecursive && (tag == 0x8769 /* ExifTag */ || tag == 0x014a /*SubIFDs*/ || type == tiffIfd)) { if (option == kpsRecursive && (tag == 0x8769 /* ExifTag */ || tag == 0x014a /*SubIFDs*/ || type == tiffIfd)) {
for (size_t k = 0; k < count; k++) { for (size_t k = 0; k < count; k++) {
const long restore = io.tell(); const size_t restore = io.tell();
offset = byteSwap4(buf, k * size, bSwap); offset = byteSwap4(buf, k * size, bSwap);
printIFDStructure(io, out, option, offset, bSwap, c, depth); printIFDStructure(io, out, option, offset, bSwap, c, depth);
io.seekOrThrow(restore, BasicIo::beg, ErrorCode::kerCorruptedMetadata); io.seekOrThrow(restore, BasicIo::beg, ErrorCode::kerCorruptedMetadata);
@ -421,7 +421,7 @@ void Image::printIFDStructure(BasicIo& io, std::ostream& out, Exiv2::PrintStruct
throw Error(ErrorCode::kerCorruptedMetadata); throw Error(ErrorCode::kerCorruptedMetadata);
} }
const long restore = io.tell(); const size_t restore = io.tell();
io.seekOrThrow(offset, BasicIo::beg, ErrorCode::kerCorruptedMetadata); // position io.seekOrThrow(offset, BasicIo::beg, ErrorCode::kerCorruptedMetadata); // position
std::vector<byte> bytes(count); // allocate memory std::vector<byte> bytes(count); // allocate memory
// TODO: once we have C++11 use bytes.data() // TODO: once we have C++11 use bytes.data()
@ -431,7 +431,7 @@ void Image::printIFDStructure(BasicIo& io, std::ostream& out, Exiv2::PrintStruct
IptcData::printStructure(out, makeSliceUntil(bytes.data(), count), depth); IptcData::printStructure(out, makeSliceUntil(bytes.data(), count), depth);
} }
} else if (option == kpsRecursive && tag == 0x927c /* MakerNote */ && count > 10) { } else if (option == kpsRecursive && tag == 0x927c /* MakerNote */ && count > 10) {
const long restore = io.tell(); // save const size_t restore = io.tell(); // save
uint32_t jump = 10; uint32_t jump = 10;
byte bytes[20]; byte bytes[20];

@ -151,7 +151,7 @@ void Jp2Image::readMetadata() {
while (io_->read(reinterpret_cast<byte*>(&box), boxHSize) == boxHSize) { while (io_->read(reinterpret_cast<byte*>(&box), boxHSize) == boxHSize) {
boxes_check(boxesCount++, boxem); boxes_check(boxesCount++, boxem);
long position = io_->tell(); const size_t position = io_->tell();
box.length = getLong(reinterpret_cast<byte*>(&box.length), bigEndian); box.length = getLong(reinterpret_cast<byte*>(&box.length), bigEndian);
box.type = getLong(reinterpret_cast<byte*>(&box.type), bigEndian); box.type = getLong(reinterpret_cast<byte*>(&box.type), bigEndian);
#ifdef EXIV2_DEBUG_MESSAGES #ifdef EXIV2_DEBUG_MESSAGES
@ -191,7 +191,7 @@ void Jp2Image::readMetadata() {
#ifdef EXIV2_DEBUG_MESSAGES #ifdef EXIV2_DEBUG_MESSAGES
std::cout << "Exiv2::Jp2Image::readMetadata: JP2Header box found" << std::endl; std::cout << "Exiv2::Jp2Image::readMetadata: JP2Header box found" << std::endl;
#endif #endif
long restore = io_->tell(); size_t restore = io_->tell();
while (io_->read(reinterpret_cast<byte*>(&subBox), boxHSize) == boxHSize && subBox.length) { while (io_->read(reinterpret_cast<byte*>(&subBox), boxHSize) == boxHSize && subBox.length) {
boxes_check(boxesCount++, boxem); boxes_check(boxesCount++, boxem);
@ -210,7 +210,7 @@ void Jp2Image::readMetadata() {
<< "Color data found" << std::endl; << "Color data found" << std::endl;
#endif #endif
const long pad = 3; // 3 padding bytes 2 0 0 const size_t pad = 3; // 3 padding bytes 2 0 0
const size_t data_length = Safe::add(subBox.length, 8u); const size_t data_length = Safe::add(subBox.length, 8u);
// data_length makes no sense if it is larger than the rest of the file // data_length makes no sense if it is larger than the rest of the file
if (data_length > io_->size() - io_->tell()) { if (data_length > io_->size() - io_->tell()) {
@ -291,13 +291,14 @@ void Jp2Image::readMetadata() {
// Find the position of Exif header in bytes array. // Find the position of Exif header in bytes array.
const char a = rawData.read_uint8(0); const char a = rawData.read_uint8(0);
const char b = rawData.read_uint8(1); const char b = rawData.read_uint8(1);
long pos = (a == b && (a == 'I' || a == 'M')) ? 0 : -1; const size_t notfound = std::numeric_limits<size_t>::max();
size_t pos = (a == b && (a == 'I' || a == 'M')) ? 0 : notfound;
// #1242 Forgive having Exif\0\0 in rawData.pData_ // #1242 Forgive having Exif\0\0 in rawData.pData_
std::array<byte, 6> exifHeader{0x45, 0x78, 0x69, 0x66, 0x00, 0x00}; std::array<byte, 6> exifHeader{0x45, 0x78, 0x69, 0x66, 0x00, 0x00};
for (size_t i = 0; pos < 0 && i < (rawData.size() - exifHeader.size()); i++) { for (size_t i = 0; pos == notfound && i < (rawData.size() - exifHeader.size()); i++) {
if (rawData.cmpBytes(i, exifHeader.data(), exifHeader.size()) == 0) { if (rawData.cmpBytes(i, exifHeader.data(), exifHeader.size()) == 0) {
pos = static_cast<long>(i + sizeof(exifHeader)); pos = i + sizeof(exifHeader);
#ifndef SUPPRESS_WARNINGS #ifndef SUPPRESS_WARNINGS
EXV_WARNING << "Reading non-standard UUID-EXIF_bad box in " << io_->path() << std::endl; EXV_WARNING << "Reading non-standard UUID-EXIF_bad box in " << io_->path() << std::endl;
#endif #endif
@ -305,7 +306,7 @@ void Jp2Image::readMetadata() {
} }
// If found it, store only these data at from this place. // If found it, store only these data at from this place.
if (pos >= 0) { if (pos != notfound) {
#ifdef EXIV2_DEBUG_MESSAGES #ifdef EXIV2_DEBUG_MESSAGES
std::cout << "Exiv2::Jp2Image::readMetadata: Exif header found at position " << pos << std::endl; std::cout << "Exiv2::Jp2Image::readMetadata: Exif header found at position " << pos << std::endl;
#endif #endif
@ -380,7 +381,7 @@ void Jp2Image::readMetadata() {
lastBoxTypeRead = box.type; lastBoxTypeRead = box.type;
// Move to the next box. // Move to the next box.
io_->seek(static_cast<long>(position - boxHSize + box.length), BasicIo::beg); io_->seek(static_cast<int64_t>(position - boxHSize + box.length), BasicIo::beg);
if (io_->error()) if (io_->error())
throw Error(ErrorCode::kerFailedToReadImageData); throw Error(ErrorCode::kerFailedToReadImageData);
} }
@ -418,7 +419,7 @@ void Jp2Image::printStructure(std::ostream& out, PrintStructureOption option, in
while (box.length && box.type != kJp2BoxTypeClose && while (box.length && box.type != kJp2BoxTypeClose &&
io_->read(reinterpret_cast<byte*>(&box), boxHSize) == boxHSize) { io_->read(reinterpret_cast<byte*>(&box), boxHSize) == boxHSize) {
long position = io_->tell(); const size_t position = io_->tell();
box.length = getLong(reinterpret_cast<byte*>(&box.length), bigEndian); box.length = getLong(reinterpret_cast<byte*>(&box.length), bigEndian);
box.type = getLong(reinterpret_cast<byte*>(&box.type), bigEndian); box.type = getLong(reinterpret_cast<byte*>(&box.type), bigEndian);
enforce(box.length <= boxHSize + io_->size() - io_->tell(), ErrorCode::kerCorruptedMetadata); enforce(box.length <= boxHSize + io_->size() - io_->tell(), ErrorCode::kerCorruptedMetadata);
@ -454,7 +455,7 @@ void Jp2Image::printStructure(std::ostream& out, PrintStructureOption option, in
/// \todo All files shall contain one and only one Header box. /// \todo All files shall contain one and only one Header box.
while (io_->read(reinterpret_cast<byte*>(&subBox), boxHSize) == boxHSize && while (io_->read(reinterpret_cast<byte*>(&subBox), boxHSize) == boxHSize &&
io_->tell() < position + static_cast<long>(box.length)) // don't read beyond the box! io_->tell() < position + box.length) // don't read beyond the box!
{ {
const size_t address = io_->tell() - boxHSize; const size_t address = io_->tell() - boxHSize;
subBox.length = getLong(reinterpret_cast<byte*>(&subBox.length), bigEndian); subBox.length = getLong(reinterpret_cast<byte*>(&subBox.length), bigEndian);
@ -571,7 +572,7 @@ void Jp2Image::printStructure(std::ostream& out, PrintStructureOption option, in
} }
// Move to the next box. // Move to the next box.
io_->seek(static_cast<long>(position - boxHSize + box.length), BasicIo::beg); io_->seek(static_cast<int64_t>(position - boxHSize + box.length), BasicIo::beg);
if (io_->error()) if (io_->error())
throw Error(ErrorCode::kerFailedToReadImageData); throw Error(ErrorCode::kerFailedToReadImageData);
if (bPrint) if (bPrint)
@ -704,7 +705,7 @@ void Jp2Image::doWriteMetadata(BasicIo& outIo) {
byte boxUUIDtype[4]; byte boxUUIDtype[4];
DataBuf bheaderBuf(8); DataBuf bheaderBuf(8);
while (io_->tell() < static_cast<long>(io_->size())) { while (io_->tell() < io_->size()) {
#ifdef EXIV2_DEBUG_MESSAGES #ifdef EXIV2_DEBUG_MESSAGES
std::cout << "Exiv2::Jp2Image::doWriteMetadata: Position: " << io_->tell() << " / " << io_->size() << std::endl; std::cout << "Exiv2::Jp2Image::doWriteMetadata: Position: " << io_->tell() << " / " << io_->size() << std::endl;
#endif #endif
@ -893,7 +894,7 @@ bool isJp2Type(BasicIo& iIo, bool advance) {
} }
bool matched = (memcmp(buf, Jp2Signature.data(), Jp2Signature.size()) == 0); bool matched = (memcmp(buf, Jp2Signature.data(), Jp2Signature.size()) == 0);
if (!advance || !matched) { if (!advance || !matched) {
iIo.seek(-static_cast<long>(Jp2Signature.size()), BasicIo::cur); // Return to original position iIo.seek(-static_cast<int64_t>(Jp2Signature.size()), BasicIo::cur); // Return to original position
} }
return matched; return matched;
} }

@ -304,7 +304,7 @@ void JpegBase::printStructure(std::ostream& out, PrintStructureOption option, in
} }
bool bPrint = option == kpsBasic || option == kpsRecursive; bool bPrint = option == kpsBasic || option == kpsRecursive;
std::vector<long> iptcDataSegs; std::vector<size_t> iptcDataSegs;
if (bPrint || option == kpsXMP || option == kpsIccProfile || option == kpsIptcErase) { if (bPrint || option == kpsXMP || option == kpsIccProfile || option == kpsIptcErase) {
// mnemonic for markers // mnemonic for markers
@ -618,7 +618,7 @@ void JpegBase::doWriteMetadata(BasicIo& outIo) {
// Used to initialize search variables such as skipCom. // Used to initialize search variables such as skipCom.
static const size_t notfound = std::numeric_limits<size_t>::max(); static const size_t notfound = std::numeric_limits<size_t>::max();
const long seek = io_->tell(); const size_t seek = io_->tell();
size_t count = 0; size_t count = 0;
size_t search = 0; size_t search = 0;
size_t insertPos = 0; size_t insertPos = 0;
@ -809,7 +809,7 @@ void JpegBase::doWriteMetadata(BasicIo& outIo) {
tmpBuf[0] = 0xff; tmpBuf[0] = 0xff;
tmpBuf[1] = app2_; tmpBuf[1] = app2_;
const long chunk_size = 256 * 256 - 40; // leave bytes for marker, header and padding const size_t chunk_size = 256 * 256 - 40; // leave bytes for marker, header and padding
size_t size = iccProfile_.size(); size_t size = iccProfile_.size();
if (size >= 255 * chunk_size) if (size >= 255 * chunk_size)
throw Error(ErrorCode::kerTooLargeJpegSegment, "IccProfile"); throw Error(ErrorCode::kerTooLargeJpegSegment, "IccProfile");
@ -844,7 +844,7 @@ void JpegBase::doWriteMetadata(BasicIo& outIo) {
// Set the new IPTC IRB, keeps existing IRBs but removes the // Set the new IPTC IRB, keeps existing IRBs but removes the
// IPTC block if there is no new IPTC data to write // IPTC block if there is no new IPTC data to write
DataBuf newPsData = Photoshop::setIptcIrb(psBlob.data(), psBlob.size(), iptcData_); DataBuf newPsData = Photoshop::setIptcIrb(psBlob.data(), psBlob.size(), iptcData_);
const long maxChunkSize = 0xffff - 16; const size_t maxChunkSize = 0xffff - 16;
const byte* chunkStart = newPsData.empty() ? nullptr : newPsData.c_data(); const byte* chunkStart = newPsData.empty() ? nullptr : newPsData.c_data();
const byte* chunkEnd = newPsData.empty() ? nullptr : newPsData.c_data(newPsData.size() - 1); const byte* chunkEnd = newPsData.empty() ? nullptr : newPsData.c_data(newPsData.size() - 1);
while (chunkStart < chunkEnd) { while (chunkStart < chunkEnd) {
@ -853,7 +853,7 @@ void JpegBase::doWriteMetadata(BasicIo& outIo) {
if (chunkSize > maxChunkSize) { if (chunkSize > maxChunkSize) {
chunkSize = maxChunkSize; chunkSize = maxChunkSize;
// Don't break at a valid IRB boundary // Don't break at a valid IRB boundary
const auto writtenSize = static_cast<long>(chunkStart - newPsData.c_data()); const auto writtenSize = chunkStart - newPsData.c_data();
if (Photoshop::valid(newPsData.c_data(), writtenSize + chunkSize)) { if (Photoshop::valid(newPsData.c_data(), writtenSize + chunkSize)) {
// Since an IRB has minimum size 12, // Since an IRB has minimum size 12,
// (chunkSize - 8) can't be also a IRB boundary // (chunkSize - 8) can't be also a IRB boundary

@ -90,7 +90,7 @@ void PgfImage::readMetadata() {
// And now, the most interesting, the user data byte array where metadata are stored as small image. // And now, the most interesting, the user data byte array where metadata are stored as small image.
enforce(headerSize <= std::numeric_limits<size_t>::max() - 8, ErrorCode::kerCorruptedMetadata); enforce(headerSize <= std::numeric_limits<size_t>::max() - 8, ErrorCode::kerCorruptedMetadata);
size_t size = headerSize + 8 - static_cast<size_t>(io_->tell()); size_t size = headerSize + 8 - io_->tell();
#ifdef EXIV2_DEBUG_MESSAGES #ifdef EXIV2_DEBUG_MESSAGES
std::cout << "Exiv2::PgfImage::readMetadata: Found Image data (" << size << " bytes)\n"; std::cout << "Exiv2::PgfImage::readMetadata: Found Image data (" << size << " bytes)\n";

@ -72,8 +72,8 @@ std::string PngImage::mimeType() const {
return "image/png"; return "image/png";
} }
static bool zlibToDataBuf(const byte* bytes, long length, DataBuf& result) { static bool zlibToDataBuf(const byte* bytes, uLongf length, DataBuf& result) {
uLongf uncompressedLen = length * 2; // just a starting point uLongf uncompressedLen = length; // just a starting point
int zlibResult = Z_BUF_ERROR; int zlibResult = Z_BUF_ERROR;
do { do {
@ -101,7 +101,7 @@ static bool zlibToDataBuf(const byte* bytes, long length, DataBuf& result) {
return zlibResult == Z_OK; return zlibResult == Z_OK;
} }
static bool zlibToCompressed(const byte* bytes, long length, DataBuf& result) { static bool zlibToCompressed(const byte* bytes, uLongf length, DataBuf& result) {
uLongf compressedLen = length; // just a starting point uLongf compressedLen = length; // just a starting point
int zlibResult = Z_BUF_ERROR; int zlibResult = Z_BUF_ERROR;
@ -122,7 +122,7 @@ static bool zlibToCompressed(const byte* bytes, long length, DataBuf& result) {
return zlibResult == Z_OK; return zlibResult == Z_OK;
} }
static bool tEXtToDataBuf(const byte* bytes, long length, DataBuf& result) { static bool tEXtToDataBuf(const byte* bytes, size_t length, DataBuf& result) {
static std::array<int, 256> value; static std::array<int, 256> value;
static bool bFirst = true; static bool bFirst = true;
if (bFirst) { if (bFirst) {
@ -137,21 +137,21 @@ static bool tEXtToDataBuf(const byte* bytes, long length, DataBuf& result) {
// calculate length and allocate result; // calculate length and allocate result;
// count: number of \n in the header // count: number of \n in the header
long count = 0; size_t count = 0;
// p points to the current position in the array bytes // p points to the current position in the array bytes
const byte* p = bytes; const byte* p = bytes;
// header is '\nsomething\n number\n hex' // header is '\nsomething\n number\n hex'
// => increment p until it points to the byte after the last \n // => increment p until it points to the byte after the last \n
// p must stay within bounds of the bytes array! // p must stay within bounds of the bytes array!
while ((count < 3) && (p - bytes < length)) { while (count < 3 && 0 < length) {
// length is later used for range checks of p => decrement it for each increment of p // length is later used for range checks of p => decrement it for each increment of p
--length; --length;
if (*p++ == '\n') { if (*p++ == '\n') {
count++; count++;
} }
} }
for (long i = 0; i < length; i++) for (size_t i = 0; i < length; i++)
if (value[p[i]]) if (value[p[i]])
++count; ++count;
result.alloc((count + 1) / 2); result.alloc((count + 1) / 2);
@ -160,7 +160,7 @@ static bool tEXtToDataBuf(const byte* bytes, long length, DataBuf& result) {
count = 0; count = 0;
byte* r = result.data(); byte* r = result.data();
int n = 0; // nibble int n = 0; // nibble
for (long i = 0; i < length; i++) { for (size_t i = 0; i < length; i++) {
if (value[p[i]]) { if (value[p[i]]) {
int v = value[p[i]] - 1; int v = value[p[i]] - 1;
if (++count % 2) if (++count % 2)
@ -208,7 +208,7 @@ void PngImage::printStructure(std::ostream& out, PrintStructureOption option, in
DataBuf cheaderBuf(8); DataBuf cheaderBuf(8);
while (!io_->eof() && ::strcmp(chType, "IEND") != 0) { while (!io_->eof() && ::strcmp(chType, "IEND") != 0) {
size_t address = io_->tell(); const size_t address = io_->tell();
size_t bufRead = io_->read(cheaderBuf.data(), cheaderBuf.size()); size_t bufRead = io_->read(cheaderBuf.data(), cheaderBuf.size());
if (io_->error()) if (io_->error())
@ -223,8 +223,8 @@ void PngImage::printStructure(std::ostream& out, PrintStructureOption option, in
} }
// test that we haven't hit EOF, or wanting to read excessive data // test that we haven't hit EOF, or wanting to read excessive data
long restore = io_->tell(); const size_t restore = io_->tell();
if (restore == -1 || dataOffset > static_cast<uint32_t>(0x7FFFFFFF) || dataOffset > imgSize - restore) { if (dataOffset > imgSize - restore) {
throw Exiv2::Error(ErrorCode::kerFailedToReadImageData); throw Exiv2::Error(ErrorCode::kerFailedToReadImageData);
} }
@ -297,10 +297,11 @@ void PngImage::printStructure(std::ostream& out, PrintStructureOption option, in
// decode the chunk // decode the chunk
bool bGood = false; bool bGood = false;
if (tEXt) { if (tEXt) {
bGood = tEXtToDataBuf(data.c_data(name_l), static_cast<long>(dataOffset - name_l), dataBuf); bGood = tEXtToDataBuf(data.c_data(name_l), dataOffset - name_l, dataBuf);
} }
if (zTXt || iCCP) { if (zTXt || iCCP) {
bGood = zlibToDataBuf(data.c_data(name_l + 1), static_cast<long>(dataOffset - name_l - 1), enforce(dataOffset - name_l - 1 <= std::numeric_limits<uLongf>::max(), ErrorCode::kerCorruptedMetadata);
bGood = zlibToDataBuf(data.c_data(name_l + 1), static_cast<uLongf>(dataOffset - name_l - 1),
dataBuf); // +1 = 'compressed' flag dataBuf); // +1 = 'compressed' flag
} }
if (iTXt) { if (iTXt) {
@ -407,8 +408,8 @@ void PngImage::readMetadata() {
// Decode chunk data length. // Decode chunk data length.
uint32_t chunkLength = cheaderBuf.read_uint32(0, Exiv2::bigEndian); uint32_t chunkLength = cheaderBuf.read_uint32(0, Exiv2::bigEndian);
long pos = io_->tell(); const size_t pos = io_->tell();
if (pos == -1 || chunkLength > static_cast<uint32_t>(0x7FFFFFFF) || chunkLength > imgSize - pos) { if (chunkLength > imgSize - pos) {
throw Exiv2::Error(ErrorCode::kerFailedToReadImageData); throw Exiv2::Error(ErrorCode::kerFailedToReadImageData);
} }
@ -451,7 +452,7 @@ void PngImage::readMetadata() {
++iccOffset; // +1 = 'compressed' flag ++iccOffset; // +1 = 'compressed' flag
enforce(iccOffset <= chunkLength, Exiv2::ErrorCode::kerCorruptedMetadata); enforce(iccOffset <= chunkLength, Exiv2::ErrorCode::kerCorruptedMetadata);
zlibToDataBuf(chunkData.c_data(iccOffset), chunkLength - iccOffset, iccProfile_); zlibToDataBuf(chunkData.c_data(iccOffset), static_cast<uLongf>(chunkLength - iccOffset), iccProfile_);
#ifdef EXIV2_DEBUG_MESSAGES #ifdef EXIV2_DEBUG_MESSAGES
std::cout << "Exiv2::PngImage::readMetadata: profile name: " << profileName_ << std::endl; std::cout << "Exiv2::PngImage::readMetadata: profile name: " << profileName_ << std::endl;
std::cout << "Exiv2::PngImage::readMetadata: iccProfile.size_ (uncompressed) : " << iccProfile_.size() std::cout << "Exiv2::PngImage::readMetadata: iccProfile.size_ (uncompressed) : " << iccProfile_.size()
@ -594,7 +595,8 @@ void PngImage::doWriteMetadata(BasicIo& outIo) {
if (iccProfileDefined()) { if (iccProfileDefined()) {
DataBuf compressed; DataBuf compressed;
if (zlibToCompressed(iccProfile_.c_data(), static_cast<long>(iccProfile_.size()), compressed)) { enforce(iccProfile_.size() <= std::numeric_limits<uLongf>::max(), ErrorCode::kerCorruptedMetadata);
if (zlibToCompressed(iccProfile_.c_data(), static_cast<uLongf>(iccProfile_.size()), compressed)) {
const auto nameLength = static_cast<uint32_t>(profileName_.size()); const auto nameLength = static_cast<uint32_t>(profileName_.size());
const uint32_t chunkLength = nameLength + 2 + static_cast<uint32_t>(compressed.size()); const uint32_t chunkLength = nameLength + 2 + static_cast<uint32_t>(compressed.size());
byte length[4]; byte length[4];

@ -194,7 +194,7 @@ void PsdImage::readMetadata() {
throw Error(ErrorCode::kerNotAnImage, "Photoshop"); throw Error(ErrorCode::kerNotAnImage, "Photoshop");
} }
uint32_t resourceSize = getULong(buf, bigEndian); uint32_t resourceSize = getULong(buf, bigEndian);
uint32_t curOffset = io_->tell(); const size_t curOffset = io_->tell();
#ifdef EXIV2_DEBUG_MESSAGES #ifdef EXIV2_DEBUG_MESSAGES
std::cerr << std::hex << "resourceId: " << resourceId << std::dec << " length: " << resourceSize << std::hex std::cerr << std::hex << "resourceId: " << resourceId << std::dec << " length: " << resourceSize << std::hex
@ -382,7 +382,7 @@ void PsdImage::doWriteMetadata(BasicIo& outIo) {
if (outIo.error()) if (outIo.error())
throw Error(ErrorCode::kerImageWriteFailed); throw Error(ErrorCode::kerImageWriteFailed);
uint32_t resLenOffset = io_->tell(); // remember for later update const size_t resLenOffset = io_->tell(); // remember for later update
// Read length of all resource blocks from original PSD // Read length of all resource blocks from original PSD
if (io_->read(buf, 4) != 4) if (io_->read(buf, 4) != 4)
@ -433,7 +433,7 @@ void PsdImage::doWriteMetadata(BasicIo& outIo) {
uint32_t resourceSize = getULong(buf, bigEndian); uint32_t resourceSize = getULong(buf, bigEndian);
uint32_t pResourceSize = (resourceSize + 1) & ~1; // padded resource size uint32_t pResourceSize = (resourceSize + 1) & ~1; // padded resource size
uint32_t curOffset = io_->tell(); const size_t curOffset = io_->tell();
// Write IPTC_NAA resource block // Write IPTC_NAA resource block
if ((resourceId == kPhotoshopResourceID_IPTC_NAA || resourceId > kPhotoshopResourceID_IPTC_NAA) && !iptcDone) { if ((resourceId == kPhotoshopResourceID_IPTC_NAA || resourceId > kPhotoshopResourceID_IPTC_NAA) && !iptcDone) {

@ -103,7 +103,7 @@ bool isTgaType(BasicIo& iIo, bool /*advance*/) {
return true; return true;
} }
byte buf[26]; byte buf[26];
long curPos = iIo.tell(); const size_t curPos = iIo.tell();
if (curPos < 26) if (curPos < 26)
return false; return false;

@ -154,13 +154,11 @@ void WebPImage::doWriteMetadata(BasicIo& outIo) {
/* Verify for a VP8X Chunk First before writing in /* Verify for a VP8X Chunk First before writing in
case we have any exif or xmp data, also check case we have any exif or xmp data, also check
for any chunks with alpha frame/layer set */ for any chunks with alpha frame/layer set */
while (!io_->eof() && static_cast<uint64_t>(io_->tell()) < filesize) { while (!io_->eof() && io_->tell() < filesize) {
io_->readOrThrow(chunkId.data(), WEBP_TAG_SIZE, Exiv2::ErrorCode::kerCorruptedMetadata); io_->readOrThrow(chunkId.data(), WEBP_TAG_SIZE, Exiv2::ErrorCode::kerCorruptedMetadata);
io_->readOrThrow(size_buff, WEBP_TAG_SIZE, Exiv2::ErrorCode::kerCorruptedMetadata); io_->readOrThrow(size_buff, WEBP_TAG_SIZE, Exiv2::ErrorCode::kerCorruptedMetadata);
const uint32_t size_u32 = Exiv2::getULong(size_buff, littleEndian); const uint32_t size_u32 = Exiv2::getULong(size_buff, littleEndian);
// Check that `size_u32` is safe to cast to `long`.
enforce(size_u32 <= std::numeric_limits<uint32_t>::max(), Exiv2::ErrorCode::kerCorruptedMetadata);
DataBuf payload(size_u32); DataBuf payload(size_u32);
if (!payload.empty()) { if (!payload.empty()) {
io_->readOrThrow(payload.data(), payload.size(), Exiv2::ErrorCode::kerCorruptedMetadata); io_->readOrThrow(payload.data(), payload.size(), Exiv2::ErrorCode::kerCorruptedMetadata);
@ -286,15 +284,11 @@ void WebPImage::doWriteMetadata(BasicIo& outIo) {
} }
io_->seek(12, BasicIo::beg); io_->seek(12, BasicIo::beg);
while (!io_->eof() && static_cast<uint64_t>(io_->tell()) < filesize) { while (!io_->eof() && io_->tell() < filesize) {
io_->readOrThrow(chunkId.data(), 4, Exiv2::ErrorCode::kerCorruptedMetadata); io_->readOrThrow(chunkId.data(), 4, Exiv2::ErrorCode::kerCorruptedMetadata);
io_->readOrThrow(size_buff, 4, Exiv2::ErrorCode::kerCorruptedMetadata); io_->readOrThrow(size_buff, 4, Exiv2::ErrorCode::kerCorruptedMetadata);
const uint32_t size_u32 = Exiv2::getULong(size_buff, littleEndian); const uint32_t size_u32 = Exiv2::getULong(size_buff, littleEndian);
// Check that `size_u32` is safe to cast to `long`.
enforce(size_u32 <= std::numeric_limits<uint32_t>::max(), Exiv2::ErrorCode::kerCorruptedMetadata);
DataBuf payload(size_u32); DataBuf payload(size_u32);
io_->readOrThrow(payload.data(), size_u32, Exiv2::ErrorCode::kerCorruptedMetadata); io_->readOrThrow(payload.data(), size_u32, Exiv2::ErrorCode::kerCorruptedMetadata);
if (io_->tell() % 2) if (io_->tell() % 2)
@ -438,19 +432,18 @@ void WebPImage::printStructure(std::ostream& out, PrintStructureOption option, i
} }
io_->seek(0, BasicIo::beg); // rewind io_->seek(0, BasicIo::beg); // rewind
while (!io_->eof() && static_cast<uint64_t>(io_->tell()) < filesize) { while (!io_->eof() && io_->tell() < filesize) {
auto offset = static_cast<uint64_t>(io_->tell()); auto offset = io_->tell();
byte size_buff[WEBP_TAG_SIZE]; byte size_buff[WEBP_TAG_SIZE];
io_->read(chunkId.data(), WEBP_TAG_SIZE); io_->read(chunkId.data(), WEBP_TAG_SIZE);
io_->read(size_buff, WEBP_TAG_SIZE); io_->read(size_buff, WEBP_TAG_SIZE);
long size = Exiv2::getULong(size_buff, littleEndian); const uint32_t size = Exiv2::getULong(size_buff, littleEndian);
DataBuf payload(offset ? size : WEBP_TAG_SIZE); // header is different from chunks DataBuf payload(offset ? size : WEBP_TAG_SIZE); // header is different from chunks
io_->read(payload.data(), payload.size()); io_->read(payload.data(), payload.size());
if (bPrint) { if (bPrint) {
out << Internal::indent(depth) out << Internal::indent(depth)
<< Internal::stringFormat(" %s | %8u | %8u | ", chunkId.c_str(), static_cast<uint32_t>(size), << Internal::stringFormat(" %s | %8u | %8u | ", chunkId.c_str(), size, static_cast<uint32_t>(offset))
static_cast<uint32_t>(offset))
<< Internal::binaryToString(makeSlice(payload, 0, payload.size() > 32 ? 32 : payload.size())) << std::endl; << Internal::binaryToString(makeSlice(payload, 0, payload.size() > 32 ? 32 : payload.size())) << std::endl;
} }
@ -492,18 +485,14 @@ void WebPImage::readMetadata() {
io_->readOrThrow(data, WEBP_TAG_SIZE * 3, Exiv2::ErrorCode::kerCorruptedMetadata); io_->readOrThrow(data, WEBP_TAG_SIZE * 3, Exiv2::ErrorCode::kerCorruptedMetadata);
const uint32_t filesize_u32 = Safe::add(Exiv2::getULong(data + WEBP_TAG_SIZE, littleEndian), 8U); const uint32_t filesize = Safe::add(Exiv2::getULong(data + WEBP_TAG_SIZE, littleEndian), 8U);
enforce(filesize_u32 <= io_->size(), Exiv2::ErrorCode::kerCorruptedMetadata); enforce(filesize <= io_->size(), Exiv2::ErrorCode::kerCorruptedMetadata);
// Check that `filesize_u32` is safe to cast to `long`. WebPImage::decodeChunks(filesize);
enforce(filesize_u32 <= static_cast<uint32_t>(std::numeric_limits<long>::max()),
Exiv2::ErrorCode::kerCorruptedMetadata);
WebPImage::decodeChunks(static_cast<long>(filesize_u32));
} // WebPImage::readMetadata } // WebPImage::readMetadata
void WebPImage::decodeChunks(long filesize) { void WebPImage::decodeChunks(uint32_t filesize) {
DataBuf chunkId(5); DataBuf chunkId(5);
byte size_buff[WEBP_TAG_SIZE]; byte size_buff[WEBP_TAG_SIZE];
bool has_canvas_data = false; bool has_canvas_data = false;
@ -517,12 +506,7 @@ void WebPImage::decodeChunks(long filesize) {
io_->readOrThrow(chunkId.data(), WEBP_TAG_SIZE, Exiv2::ErrorCode::kerCorruptedMetadata); io_->readOrThrow(chunkId.data(), WEBP_TAG_SIZE, Exiv2::ErrorCode::kerCorruptedMetadata);
io_->readOrThrow(size_buff, WEBP_TAG_SIZE, Exiv2::ErrorCode::kerCorruptedMetadata); io_->readOrThrow(size_buff, WEBP_TAG_SIZE, Exiv2::ErrorCode::kerCorruptedMetadata);
const uint32_t size_u32 = Exiv2::getULong(size_buff, littleEndian); const uint32_t size = Exiv2::getULong(size_buff, littleEndian);
// Check that `size_u32` is safe to cast to `long`.
enforce(size_u32 <= static_cast<uint32_t>(std::numeric_limits<long>::max()),
Exiv2::ErrorCode::kerCorruptedMetadata);
const auto size = static_cast<long>(size_u32);
// Check that `size` is within bounds. // Check that `size` is within bounds.
enforce(io_->tell() <= filesize, Exiv2::ErrorCode::kerCorruptedMetadata); enforce(io_->tell() <= filesize, Exiv2::ErrorCode::kerCorruptedMetadata);
@ -619,23 +603,23 @@ void WebPImage::decodeChunks(long filesize) {
bool s_header = false; bool s_header = false;
bool le_header = false; bool le_header = false;
bool be_header = false; bool be_header = false;
long pos = getHeaderOffset(payload.c_data(), payload.size(), reinterpret_cast<byte*>(&exifLongHeader), 4); size_t pos = getHeaderOffset(payload.c_data(), payload.size(), reinterpret_cast<byte*>(&exifLongHeader), 4);
if (pos == -1) { if (pos == std::string::npos) {
pos = getHeaderOffset(payload.c_data(), payload.size(), reinterpret_cast<byte*>(&exifLongHeader), 6); pos = getHeaderOffset(payload.c_data(), payload.size(), reinterpret_cast<byte*>(&exifLongHeader), 6);
if (pos != -1) { if (pos != std::string::npos) {
s_header = true; s_header = true;
} }
} }
if (pos == -1) { if (pos == std::string::npos) {
pos = getHeaderOffset(payload.c_data(), payload.size(), reinterpret_cast<byte*>(&exifTiffLEHeader), 3); pos = getHeaderOffset(payload.c_data(), payload.size(), reinterpret_cast<byte*>(&exifTiffLEHeader), 3);
if (pos != -1) { if (pos != std::string::npos) {
le_header = true; le_header = true;
} }
} }
if (pos == -1) { if (pos == std::string::npos) {
pos = getHeaderOffset(payload.c_data(), payload.size(), reinterpret_cast<byte*>(&exifTiffBEHeader), 4); pos = getHeaderOffset(payload.c_data(), payload.size(), reinterpret_cast<byte*>(&exifTiffBEHeader), 4);
if (pos != -1) { if (pos != std::string::npos) {
be_header = true; be_header = true;
} }
} }
@ -666,11 +650,11 @@ void WebPImage::decodeChunks(long filesize) {
std::copy(payload.begin(), payload.end(), rawExifData.begin() + offset); std::copy(payload.begin(), payload.end(), rawExifData.begin() + offset);
#ifdef EXIV2_DEBUG_MESSAGES #ifdef EXIV2_DEBUG_MESSAGES
std::cout << "Display Hex Dump [size:" << static_cast<unsigned long>(sizePayload) << "]" << std::endl; std::cout << "Display Hex Dump [size:" << sizePayload << "]" << std::endl;
std::cout << binaryToHex(rawExifData.c_data(), sizePayload); std::cout << binaryToHex(rawExifData.c_data(), sizePayload);
#endif #endif
if (pos != -1) { if (pos != std::string::npos) {
XmpData xmpData; XmpData xmpData;
ByteOrder bo = ExifParser::decode(exifData_, payload.c_data(pos), payload.size() - pos); ByteOrder bo = ExifParser::decode(exifData_, payload.c_data(pos), payload.size() - pos);
setByteOrder(bo); setByteOrder(bo);
@ -689,7 +673,7 @@ void WebPImage::decodeChunks(long filesize) {
#endif #endif
} else { } else {
#ifdef EXIV2_DEBUG_MESSAGES #ifdef EXIV2_DEBUG_MESSAGES
std::cout << "Display Hex Dump [size:" << static_cast<unsigned long>(payload.size()) << "]" << std::endl; std::cout << "Display Hex Dump [size:" << payload.size() << "]" << std::endl;
std::cout << binaryToHex(payload.c_data(), payload.size()); std::cout << binaryToHex(payload.c_data(), payload.size());
#endif #endif
} }
@ -807,14 +791,14 @@ void WebPImage::inject_VP8X(BasicIo& iIo, bool has_xmp, bool has_exif, bool has_
} }
} }
long WebPImage::getHeaderOffset(const byte* data, size_t data_size, const byte* header, size_t header_size) { size_t WebPImage::getHeaderOffset(const byte* data, size_t data_size, const byte* header, size_t header_size) {
size_t pos = std::string::npos; // error value
if (data_size < header_size) { if (data_size < header_size) {
return -1; return pos;
} }
long pos = -1;
for (size_t i = 0; i < data_size - header_size; i++) { for (size_t i = 0; i < data_size - header_size; i++) {
if (memcmp(header, &data[i], header_size) == 0) { if (memcmp(header, &data[i], header_size) == 0) {
pos = static_cast<long>(i); pos = i;
break; break;
} }
} }

Loading…
Cancel
Save