From 92469f4c270b999afc91f01c28beadaddf065447 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Kov=C3=A1=C5=99?= Date: Sun, 24 Jan 2021 15:09:57 +0100 Subject: [PATCH 01/79] [WIP] Add ISO/IEC Base Media File Format --- CMakeLists.txt | 1 + cmake/config.h.cmake | 3 + cmake/generateConfigFile.cmake | 1 + cmake/printSummary.cmake | 1 + include/exiv2/CMakeLists.txt | 1 + include/exiv2/exiv2.hpp | 3 + include/exiv2/isobmff.hpp | 126 +++++++++++++++++++++++++ include/exiv2/jp2image.hpp | 2 +- src/CMakeLists.txt | 1 + src/exiv2.cpp | 4 + src/image.cpp | 6 ++ src/isobmff.cpp | 168 +++++++++++++++++++++++++++++++++ 12 files changed, 316 insertions(+), 1 deletion(-) create mode 100644 include/exiv2/isobmff.hpp create mode 100644 src/isobmff.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index a8332d9ffc..b5cdacfe6b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,6 +25,7 @@ option( EXIV2_ENABLE_WIN_UNICODE "Use Unicode paths (wstring) on Windows" option( EXIV2_ENABLE_WEBREADY "Build webready support into library" OFF ) option( EXIV2_ENABLE_CURL "USE Libcurl for HttpIo (WEBREADY)" OFF ) option( EXIV2_ENABLE_SSH "USE Libssh for SshIo (WEBREADY)" OFF ) +option( EXIV2_ENABLE_ISOBMFF "Build with ISO BMFF support" OFF ) option( EXIV2_BUILD_SAMPLES "Build sample applications" ON ) option( EXIV2_BUILD_EXIV2_COMMAND "Build exiv2 command-line executable" ON ) diff --git a/cmake/config.h.cmake b/cmake/config.h.cmake index 4694d99e87..cee33398ca 100644 --- a/cmake/config.h.cmake +++ b/cmake/config.h.cmake @@ -18,6 +18,9 @@ // Define if you want translation of program messages to the user's native language #cmakedefine EXV_ENABLE_NLS +// Define if you want ISO BMFF support. +#cmakedefine EXV_ENABLE_ISOBMFF + // Define if you want video support. #cmakedefine EXV_ENABLE_VIDEO diff --git a/cmake/generateConfigFile.cmake b/cmake/generateConfigFile.cmake index 58a632ca5a..c8ee83f5e1 100644 --- a/cmake/generateConfigFile.cmake +++ b/cmake/generateConfigFile.cmake @@ -7,6 +7,7 @@ if (${EXIV2_ENABLE_WEBREADY}) set(EXV_USE_SSH ${EXIV2_ENABLE_SSH}) set(EXV_USE_CURL ${EXIV2_ENABLE_CURL}) endif() +set(EXV_ENABLE_ISOBMFF ${EXIV2_ENABLE_ISOBMFF}) set(EXV_ENABLE_VIDEO ${EXIV2_ENABLE_VIDEO}) set(EXV_ENABLE_WEBREADY ${EXIV2_ENABLE_WEBREADY}) set(EXV_HAVE_LENSDATA ${EXIV2_ENABLE_LENSDATA}) diff --git a/cmake/printSummary.cmake b/cmake/printSummary.cmake index 8b9e18230f..fd3a545dbc 100644 --- a/cmake/printSummary.cmake +++ b/cmake/printSummary.cmake @@ -50,6 +50,7 @@ if ( EXIV2_ENABLE_EXTERNAL_XMP ) else() OptionOutput( "XMP metadata support: " EXIV2_ENABLE_XMP ) endif() +OptionOutput( "Building ISO BMFF support: " EXIV2_ENABLE_ISOBMFF ) OptionOutput( "Native language support: " EXIV2_ENABLE_NLS ) OptionOutput( "Conversion of Windows XP tags: " EXIV2_ENABLE_PRINTUCS2 ) OptionOutput( "Nikon lens database: " EXIV2_ENABLE_LENSDATA ) diff --git a/include/exiv2/CMakeLists.txt b/include/exiv2/CMakeLists.txt index ccd9dfc604..4fd0e80241 100644 --- a/include/exiv2/CMakeLists.txt +++ b/include/exiv2/CMakeLists.txt @@ -18,6 +18,7 @@ install(FILES image.hpp ini.hpp iptc.hpp + isobmff.hpp jp2image.hpp jpgimage.hpp matroskavideo.hpp diff --git a/include/exiv2/exiv2.hpp b/include/exiv2/exiv2.hpp index e25733caf6..ec0f214ac2 100644 --- a/include/exiv2/exiv2.hpp +++ b/include/exiv2/exiv2.hpp @@ -46,6 +46,9 @@ #include "exiv2/image.hpp" #include "exiv2/ini.hpp" #include "exiv2/iptc.hpp" +#ifdef EXV_ENABLE_ISOBMFF +#include "isobmff.hpp" +#endif // EXV_ENABLE_ISOBMFF #include "exiv2/jp2image.hpp" #include "exiv2/jpgimage.hpp" #include "exiv2/metadatum.hpp" diff --git a/include/exiv2/isobmff.hpp b/include/exiv2/isobmff.hpp new file mode 100644 index 0000000000..f94baf03ed --- /dev/null +++ b/include/exiv2/isobmff.hpp @@ -0,0 +1,126 @@ +// ***************************************************************** -*- C++ -*- +/* + * Copyright (C) 2021 Exiv2 authors + * This program is part of the Exiv2 distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. + */ + +#pragma once + +// ***************************************************************************** +#include "exiv2lib_export.h" + +// included header files +#include "image.hpp" + +// ***************************************************************************** +// namespace extensions +namespace Exiv2 +{ + EXIV2API bool enableISOBMFF(bool enable = true); + +// ***************************************************************************** +// class definitions + + // Add ISO Base Media File Format to the supported image formats + namespace ImageType { + const int bmff = 15; //!< ISO BMFF (bmff) image type (see class ISOBMFF) + } + + /*! + @brief Class to access ISO BMFF images. + */ + class EXIV2API ISOBMFF : public Image { + public: + //! @name Creators + //@{ + /*! + @brief Constructor to open a ISOBMFF image. Since the + constructor can not return a result, callers should check the + good() method after object construction to determine success + or failure. + @param io An auto-pointer that owns a BasicIo instance used for + reading and writing image metadata. \b Important: The constructor + takes ownership of the passed in BasicIo instance through the + auto-pointer. Callers should not continue to use the BasicIo + instance after it is passed to this method. Use the Image::io() + method to get a temporary reference. + @param create Specifies if an existing image should be read (false) + or if a new file should be created (true). + */ + ISOBMFF(BasicIo::AutoPtr io, bool create); + //@} + + //! @name Manipulators + //@{ + void readMetadata() override; + void writeMetadata() override; + + /*! + @brief Print out the structure of image file. + @throw Error if reading of the file fails or the image data is + not valid (does not look like data of the specific image type). + @warning This function is not thread safe and intended for exiv2 -pS for debugging. + */ + void printStructure(std::ostream& out, PrintStructureOption option,int depth) override; + + /*! + @brief Todo: Not supported yet(?). Calling this function will throw + an instance of Error(kerInvalidSettingForImage). + */ + void setComment(const std::string& comment) override; + //@} + + //! @name Accessors + //@{ + std::string mimeType() const override; + //@} + + ISOBMFF& operator=(const ISOBMFF& rhs) = delete; + ISOBMFF& operator=(const ISOBMFF&& rhs) = delete; + ISOBMFF(const ISOBMFF& rhs) = delete; + ISOBMFF(const ISOBMFF&& rhs) = delete; + + private: + int fileType = ImageType::bmff; + + /*! + @brief Provides the main implementation of writeMetadata() by + writing all buffered metadata to the provided BasicIo. + @param oIo BasicIo instance to write to (a temporary location). + + @return 4 if opening or writing to the associated BasicIo fails + */ + void doWriteMetadata(BasicIo& outIo); + //@} + + }; // class ISOBMFF + +// ***************************************************************************** +// template, inline and free functions + + // These could be static private functions on Image subclasses but then + // ImageFactory needs to be made a friend. + /*! + @brief Create a new ISO BMFF instance and return an auto-pointer to it. + Caller owns the returned object and the auto-pointer ensures that + it will be deleted. + */ + EXIV2API Image::AutoPtr newBmffInstance(BasicIo::AutoPtr io, bool create); + + //! Check if the file iIo is a ISO BMFF image. + EXIV2API bool isBmffType(BasicIo& iIo, bool advance); +} // namespace Exiv2 diff --git a/include/exiv2/jp2image.hpp b/include/exiv2/jp2image.hpp index 308c76bfa0..b8dc4c55a3 100644 --- a/include/exiv2/jp2image.hpp +++ b/include/exiv2/jp2image.hpp @@ -42,7 +42,7 @@ namespace Exiv2 // Add JPEG-2000 to the supported image formats namespace ImageType { - const int jp2 = 15; //!< JPEG-2000 image type + const int jp2 = 16; //!< JPEG-2000 image type } /*! diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 10235579b3..0079e00623 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -61,6 +61,7 @@ add_library( exiv2lib image.cpp ../include/exiv2/image.hpp ini.cpp ../include/exiv2/ini.hpp iptc.cpp ../include/exiv2/iptc.hpp + isobmff.cpp ../include/exiv2/isobmff.hpp jp2image.cpp ../include/exiv2/jp2image.hpp jpgimage.cpp ../include/exiv2/jpgimage.hpp metadatum.cpp ../include/exiv2/metadatum.hpp diff --git a/src/exiv2.cpp b/src/exiv2.cpp index 0754cd78ce..764e5235e8 100644 --- a/src/exiv2.cpp +++ b/src/exiv2.cpp @@ -137,6 +137,10 @@ int main(int argc, char* const argv[]) textdomain(EXV_PACKAGE_NAME); #endif +#ifdef EXV_ENABLE_ISOBMFF + Exiv2::enableISOBMFF(); +#endif + // Handle command line arguments Params& params = Params::instance(); if (params.getopt(argc, argv)) { diff --git a/src/image.cpp b/src/image.cpp index c0d0633a59..a2f9fd1dfe 100644 --- a/src/image.cpp +++ b/src/image.cpp @@ -34,6 +34,9 @@ #include "cr2image.hpp" #include "crwimage.hpp" #include "epsimage.hpp" +#ifdef EXV_ENABLE_ISOBMFF +#include "isobmff.hpp" +#endif // EXV_ENABLE_ISOBMFF #include "jpgimage.hpp" #include "mrwimage.hpp" #ifdef EXV_HAVE_LIBZ @@ -130,6 +133,9 @@ namespace { { ImageType::psd, newPsdInstance, isPsdType, amReadWrite, amReadWrite, amReadWrite, amNone }, { ImageType::tga, newTgaInstance, isTgaType, amNone, amNone, amNone, amNone }, { ImageType::bmp, newBmpInstance, isBmpType, amNone, amNone, amNone, amNone }, +#ifdef EXV_ENABLE_ISOBMFF + { ImageType::bmff, newBmffInstance, isBmffType, amRead, amRead, amRead, amNone }, +#endif // EXV_ENABLE_ISOBMFF { ImageType::jp2, newJp2Instance, isJp2Type, amReadWrite, amReadWrite, amReadWrite, amNone }, #ifdef EXV_ENABLE_VIDEO { ImageType::qtime,newQTimeInstance,isQTimeType,amRead, amNone, amRead, amNone }, diff --git a/src/isobmff.cpp b/src/isobmff.cpp new file mode 100644 index 0000000000..6f2cd0d256 --- /dev/null +++ b/src/isobmff.cpp @@ -0,0 +1,168 @@ +// ***************************************************************** -*- C++ -*- +/* + * Copyright (C) 2021 Exiv2 authors + * This program is part of the Exiv2 distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. + */ + +// ***************************************************************************** + +// included header files +#include "config.h" + +#include "isobmff.hpp" +#include "tiffimage.hpp" +#include "image.hpp" +#include "image_int.hpp" +#include "basicio.hpp" +#include "error.hpp" +#include "futils.hpp" +#include "types.hpp" +#include "safe_op.hpp" + +// + standard includes +#include +#include +#include +#include +#include + +// ***************************************************************************** +// class member definitions +namespace Exiv2 +{ + static bool enabled = false; + + EXIV2API bool enableISOBMFF(bool enable) + { +#ifdef EXV_ENABLE_ISOBMFF + enabled = enable; +#endif // EXV_ENABLE_ISOBMFF + return enabled; + } + + ISOBMFF::ISOBMFF(BasicIo::AutoPtr io, bool /* create */) + : Image(ImageType::bmff, mdExif | mdIptc | mdXmp, std::move(io)) + { + } // ISOBMFF::ISOBMFF + + std::string ISOBMFF::mimeType() const + { + /* + switch (fileType) + { + case ImageType::avif: + return "image/avif"; + + case ImageType::heif: + return "image/heif"; + + default: + return "image/unknown"; + } + */ + } + + void ISOBMFF::setComment(const std::string& /*comment*/) + { + // Todo: implement me! + throw(Error(kerInvalidSettingForImage, "Image comment", "ISO BMFF")); + } // ISOBMFF::setComment + + static void lf(std::ostream& out, bool& bLF) + { + if ( bLF ) { + out << std::endl; + out.flush(); + bLF = false ; + } + } + + static bool isBigEndian() + { + union { + uint32_t i; + char c[4]; + } e = { 0x01000000 }; + + return e.c[0] != 0; + } + + static std::string toAscii(long n) + { + const auto p = reinterpret_cast(&n); + std::string result; + bool bBigEndian = isBigEndian(); + for ( int i = 0 ; i < 4 ; i++) { + result += p[ bBigEndian ? i : (3-i) ]; + } + return result; + } + + void ISOBMFF::readMetadata() + { + } // ISOBMFF::readMetadata + + void ISOBMFF::printStructure(std::ostream& out, PrintStructureOption option, int depth) + { + if (io_->open() != 0) + throw Error(kerDataSourceOpenFailed, io_->path(), strError()); + + // Ensure that this is the correct image type + if (!isBmffType(*io_, false)) { + if (io_->error() || io_->eof()) + throw Error(kerFailedToReadImageData); + throw Error(kerNotAnImage); + } + } // ISOBMFF::printStructure + + void ISOBMFF::writeMetadata() + { + } // ISOBMFF::writeMetadata + + // ************************************************************************* + // free functions + Image::AutoPtr newBmffInstance(BasicIo::AutoPtr io, bool create) + { + Image::AutoPtr image(new ISOBMFF(std::move(io), create)); + if (!image->good()) + { + image.reset(); + } + return image; + } + + bool isBmffType(BasicIo& iIo, bool advance) + { + if (!enabled) + { + return false; + } + const int32_t len = 12; + byte buf[len]; + iIo.read(buf, len); + if (iIo.error() || iIo.eof()) + { + return false; + } + bool isobmffMatched = buf[4] == 'f' && buf[5] == 't' && buf[6] == 'y' && buf[7] == 'p'; + if (!advance) + { + iIo.seek(-len, BasicIo::cur); + } + return isobmffMatched; + } +} // namespace Exiv2 From 460a802671ecf9b549cff308744d420c2159a980 Mon Sep 17 00:00:00 2001 From: Robin Mills Date: Sun, 24 Jan 2021 22:20:42 +0000 Subject: [PATCH 02/79] Fix image handler to give jp2image code higher priority than the next isobmff code. --- include/exiv2/jp2image.hpp | 2 +- src/image.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/exiv2/jp2image.hpp b/include/exiv2/jp2image.hpp index b8dc4c55a3..511c8b7b52 100644 --- a/include/exiv2/jp2image.hpp +++ b/include/exiv2/jp2image.hpp @@ -42,7 +42,7 @@ namespace Exiv2 // Add JPEG-2000 to the supported image formats namespace ImageType { - const int jp2 = 16; //!< JPEG-2000 image type + const int jp2 = 19; //!< JPEG-2000 image type } /*! diff --git a/src/image.cpp b/src/image.cpp index a2f9fd1dfe..a3a36fcb45 100644 --- a/src/image.cpp +++ b/src/image.cpp @@ -133,10 +133,10 @@ namespace { { ImageType::psd, newPsdInstance, isPsdType, amReadWrite, amReadWrite, amReadWrite, amNone }, { ImageType::tga, newTgaInstance, isTgaType, amNone, amNone, amNone, amNone }, { ImageType::bmp, newBmpInstance, isBmpType, amNone, amNone, amNone, amNone }, + { ImageType::jp2, newJp2Instance, isJp2Type, amReadWrite, amReadWrite, amReadWrite, amNone }, #ifdef EXV_ENABLE_ISOBMFF { ImageType::bmff, newBmffInstance, isBmffType, amRead, amRead, amRead, amNone }, #endif // EXV_ENABLE_ISOBMFF - { ImageType::jp2, newJp2Instance, isJp2Type, amReadWrite, amReadWrite, amReadWrite, amNone }, #ifdef EXV_ENABLE_VIDEO { ImageType::qtime,newQTimeInstance,isQTimeType,amRead, amNone, amRead, amNone }, { ImageType::riff, newRiffInstance, isRiffType, amRead, amNone, amRead, amNone }, From 0844e1bbfb03025f9d2fa913d8d028ee7ecbc1e8 Mon Sep 17 00:00:00 2001 From: Robin Mills Date: Mon, 25 Jan 2021 16:15:55 +0000 Subject: [PATCH 03/79] Rename class ISOBMFF => class bmffImage to match other image handlers. Removed C++11 style code. Removed unused code. --- include/exiv2/{isobmff.hpp => bmffimage.hpp} | 29 ++++---- include/exiv2/exiv2.hpp | 6 +- src/CMakeLists.txt | 2 +- src/{isobmff.cpp => bmffimage.cpp} | 69 +++++++------------- src/image.cpp | 14 ++-- 5 files changed, 50 insertions(+), 70 deletions(-) rename include/exiv2/{isobmff.hpp => bmffimage.hpp} (86%) rename src/{isobmff.cpp => bmffimage.cpp} (71%) diff --git a/include/exiv2/isobmff.hpp b/include/exiv2/bmffimage.hpp similarity index 86% rename from include/exiv2/isobmff.hpp rename to include/exiv2/bmffimage.hpp index f94baf03ed..7001f54abd 100644 --- a/include/exiv2/isobmff.hpp +++ b/include/exiv2/bmffimage.hpp @@ -43,7 +43,7 @@ namespace Exiv2 /*! @brief Class to access ISO BMFF images. */ - class EXIV2API ISOBMFF : public Image { + class EXIV2API BmffImage : public Image { public: //! @name Creators //@{ @@ -61,13 +61,13 @@ namespace Exiv2 @param create Specifies if an existing image should be read (false) or if a new file should be created (true). */ - ISOBMFF(BasicIo::AutoPtr io, bool create); + BmffImage(BasicIo::AutoPtr io, bool create); //@} //! @name Manipulators //@{ - void readMetadata() override; - void writeMetadata() override; + void readMetadata() /* override */ ; + void writeMetadata() /* override */ ; /*! @brief Print out the structure of image file. @@ -75,27 +75,28 @@ namespace Exiv2 not valid (does not look like data of the specific image type). @warning This function is not thread safe and intended for exiv2 -pS for debugging. */ - void printStructure(std::ostream& out, PrintStructureOption option,int depth) override; + void printStructure(std::ostream& out, PrintStructureOption option,int depth) /* override */ ; /*! @brief Todo: Not supported yet(?). Calling this function will throw an instance of Error(kerInvalidSettingForImage). */ - void setComment(const std::string& comment) override; + void setComment(const std::string& comment) /* override */ ; //@} //! @name Accessors //@{ - std::string mimeType() const override; + std::string mimeType() const /* override */ ; //@} - - ISOBMFF& operator=(const ISOBMFF& rhs) = delete; - ISOBMFF& operator=(const ISOBMFF&& rhs) = delete; - ISOBMFF(const ISOBMFF& rhs) = delete; - ISOBMFF(const ISOBMFF&& rhs) = delete; +#if 0 + BmffImage& operator=(const BmffImage& rhs) /* = delete*/ ; + BmffImage& operator=(const BmffImage&& rhs) /* = delete */ ; + BmffImage(const BmffImage& rhs) /* = delete */; + BmffImage(const BmffImage&& rhs) /* = delete */; +#endif private: - int fileType = ImageType::bmff; + int fileType /* = ImageType::bmff*/ ; /*! @brief Provides the main implementation of writeMetadata() by @@ -107,7 +108,7 @@ namespace Exiv2 void doWriteMetadata(BasicIo& outIo); //@} - }; // class ISOBMFF + }; // class BmffImage // ***************************************************************************** // template, inline and free functions diff --git a/include/exiv2/exiv2.hpp b/include/exiv2/exiv2.hpp index ec0f214ac2..1313ad3b41 100644 --- a/include/exiv2/exiv2.hpp +++ b/include/exiv2/exiv2.hpp @@ -46,9 +46,9 @@ #include "exiv2/image.hpp" #include "exiv2/ini.hpp" #include "exiv2/iptc.hpp" -#ifdef EXV_ENABLE_ISOBMFF -#include "isobmff.hpp" -#endif // EXV_ENABLE_ISOBMFF +#ifdef EXV_ENABLE_ISOBMFF +#include "bmffimage.hpp" +#endif// EXV_ENABLE_ISOBMFF #include "exiv2/jp2image.hpp" #include "exiv2/jpgimage.hpp" #include "exiv2/metadatum.hpp" diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0079e00623..3b2c32bdae 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -46,6 +46,7 @@ add_library( exiv2lib ../include/exiv2/rwlock.hpp ../include/exiv2/slice.hpp basicio.cpp ../include/exiv2/basicio.hpp + bmffimage.cpp ../include/exiv2/bmffimage.hpp bmpimage.cpp ../include/exiv2/bmpimage.hpp convert.cpp ../include/exiv2/convert.hpp cr2image.cpp ../include/exiv2/cr2image.hpp @@ -61,7 +62,6 @@ add_library( exiv2lib image.cpp ../include/exiv2/image.hpp ini.cpp ../include/exiv2/ini.hpp iptc.cpp ../include/exiv2/iptc.hpp - isobmff.cpp ../include/exiv2/isobmff.hpp jp2image.cpp ../include/exiv2/jp2image.hpp jpgimage.cpp ../include/exiv2/jpgimage.hpp metadatum.cpp ../include/exiv2/metadatum.hpp diff --git a/src/isobmff.cpp b/src/bmffimage.cpp similarity index 71% rename from src/isobmff.cpp rename to src/bmffimage.cpp index 6f2cd0d256..cdec815700 100644 --- a/src/isobmff.cpp +++ b/src/bmffimage.cpp @@ -23,7 +23,7 @@ // included header files #include "config.h" -#include "isobmff.hpp" +#include "bmffimage.hpp" #include "tiffimage.hpp" #include "image.hpp" #include "image_int.hpp" @@ -32,6 +32,7 @@ #include "futils.hpp" #include "types.hpp" #include "safe_op.hpp" +#include "unused.h" // + standard includes #include @@ -48,18 +49,20 @@ namespace Exiv2 EXIV2API bool enableISOBMFF(bool enable) { -#ifdef EXV_ENABLE_ISOBMFF +#ifdef EXV_ENABLE_ISOBMFF enabled = enable; -#endif // EXV_ENABLE_ISOBMFF - return enabled; + return true; +#endif//EXV_ENABLE_ISOBMFF + enable = false ; + return enable ; } - ISOBMFF::ISOBMFF(BasicIo::AutoPtr io, bool /* create */) + BmffImage::BmffImage(BasicIo::AutoPtr io, bool /* create */) : Image(ImageType::bmff, mdExif | mdIptc | mdXmp, std::move(io)) { - } // ISOBMFF::ISOBMFF + } // BmffImage::BmffImage - std::string ISOBMFF::mimeType() const + std::string BmffImage::mimeType() const { /* switch (fileType) @@ -74,49 +77,21 @@ namespace Exiv2 return "image/unknown"; } */ + return "image/bmff"; + } - void ISOBMFF::setComment(const std::string& /*comment*/) + void BmffImage::setComment(const std::string& /*comment*/) { // Todo: implement me! throw(Error(kerInvalidSettingForImage, "Image comment", "ISO BMFF")); } // ISOBMFF::setComment - static void lf(std::ostream& out, bool& bLF) - { - if ( bLF ) { - out << std::endl; - out.flush(); - bLF = false ; - } - } - - static bool isBigEndian() - { - union { - uint32_t i; - char c[4]; - } e = { 0x01000000 }; - - return e.c[0] != 0; - } - - static std::string toAscii(long n) - { - const auto p = reinterpret_cast(&n); - std::string result; - bool bBigEndian = isBigEndian(); - for ( int i = 0 ; i < 4 ; i++) { - result += p[ bBigEndian ? i : (3-i) ]; - } - return result; - } - - void ISOBMFF::readMetadata() + void BmffImage::readMetadata() { } // ISOBMFF::readMetadata - void ISOBMFF::printStructure(std::ostream& out, PrintStructureOption option, int depth) + void BmffImage::printStructure(std::ostream& out, PrintStructureOption option, int depth) { if (io_->open() != 0) throw Error(kerDataSourceOpenFailed, io_->path(), strError()); @@ -127,17 +102,20 @@ namespace Exiv2 throw Error(kerFailedToReadImageData); throw Error(kerNotAnImage); } + UNUSED(out); + UNUSED(option); + UNUSED(depth); } // ISOBMFF::printStructure - void ISOBMFF::writeMetadata() + void BmffImage::writeMetadata() { - } // ISOBMFF::writeMetadata + } // BmffImage::writeMetadata // ************************************************************************* // free functions Image::AutoPtr newBmffInstance(BasicIo::AutoPtr io, bool create) { - Image::AutoPtr image(new ISOBMFF(std::move(io), create)); + Image::AutoPtr image(new BmffImage(std::move(io), create)); if (!image->good()) { image.reset(); @@ -158,11 +136,12 @@ namespace Exiv2 { return false; } - bool isobmffMatched = buf[4] == 'f' && buf[5] == 't' && buf[6] == 'y' && buf[7] == 'p'; + + bool result = buf[4] == 'f' && buf[5] == 't' && buf[6] == 'y' && buf[7] == 'p'; if (!advance) { iIo.seek(-len, BasicIo::cur); } - return isobmffMatched; + return result; } } // namespace Exiv2 diff --git a/src/image.cpp b/src/image.cpp index a3a36fcb45..d5cef01612 100644 --- a/src/image.cpp +++ b/src/image.cpp @@ -31,17 +31,17 @@ #include "safe_op.hpp" #include "slice.hpp" +#ifdef EXV_ENABLE_ISOBMFF +#include "bmffimage.hpp" +#endif// EXV_ENABLE_ISOBMFF #include "cr2image.hpp" #include "crwimage.hpp" #include "epsimage.hpp" -#ifdef EXV_ENABLE_ISOBMFF -#include "isobmff.hpp" -#endif // EXV_ENABLE_ISOBMFF #include "jpgimage.hpp" #include "mrwimage.hpp" -#ifdef EXV_HAVE_LIBZ +#ifdef EXV_HAVE_LIBZ # include "pngimage.hpp" -#endif // EXV_HAVE_LIBZ +#endif// EXV_HAVE_LIBZ #include "rafimage.hpp" #include "tiffimage.hpp" #include "tiffimage_int.hpp" @@ -56,12 +56,12 @@ #include "jp2image.hpp" #include "nikonmn_int.hpp" -#ifdef EXV_ENABLE_VIDEO +#ifdef EXV_ENABLE_VIDEO #include "matroskavideo.hpp" #include "quicktimevideo.hpp" #include "riffvideo.hpp" #include "asfvideo.hpp" -#endif // EXV_ENABLE_VIDEO +#endif// EXV_ENABLE_VIDEO #include "rw2image.hpp" #include "pgfimage.hpp" #include "xmpsidecar.hpp" From fa3923427521b4849b9cdc258debba2588f7f13c Mon Sep 17 00:00:00 2001 From: Robin Mills Date: Mon, 25 Jan 2021 16:54:28 +0000 Subject: [PATCH 04/79] Fixing Linux build/test issues. --- include/exiv2/CMakeLists.txt | 2 +- src/bmffimage.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/exiv2/CMakeLists.txt b/include/exiv2/CMakeLists.txt index 4fd0e80241..c8900b56e6 100644 --- a/include/exiv2/CMakeLists.txt +++ b/include/exiv2/CMakeLists.txt @@ -1,6 +1,7 @@ install(FILES asfvideo.hpp basicio.hpp + bmffimage.hpp bmpimage.hpp config.h convert.hpp @@ -18,7 +19,6 @@ install(FILES image.hpp ini.hpp iptc.hpp - isobmff.hpp jp2image.hpp jpgimage.hpp matroskavideo.hpp diff --git a/src/bmffimage.cpp b/src/bmffimage.cpp index cdec815700..b7826ed37d 100644 --- a/src/bmffimage.cpp +++ b/src/bmffimage.cpp @@ -53,12 +53,12 @@ namespace Exiv2 enabled = enable; return true; #endif//EXV_ENABLE_ISOBMFF - enable = false ; - return enable ; + return false; + enable=false;// unused } BmffImage::BmffImage(BasicIo::AutoPtr io, bool /* create */) - : Image(ImageType::bmff, mdExif | mdIptc | mdXmp, std::move(io)) + : Image(ImageType::bmff, mdExif | mdIptc | mdXmp, io) { } // BmffImage::BmffImage @@ -115,7 +115,7 @@ namespace Exiv2 // free functions Image::AutoPtr newBmffInstance(BasicIo::AutoPtr io, bool create) { - Image::AutoPtr image(new BmffImage(std::move(io), create)); + Image::AutoPtr image(new BmffImage(io, create)); if (!image->good()) { image.reset(); From f5c6e7595fcbf8782ff2f72e0b62107a3096867e Mon Sep 17 00:00:00 2001 From: Robin Mills Date: Mon, 25 Jan 2021 20:38:43 +0000 Subject: [PATCH 05/79] Fix Linux build-breaker when ENABLE_ISOBMFF=False and EXIV2_TEAM_WARNINGS_AS_ERRORS=On --- src/bmffimage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bmffimage.cpp b/src/bmffimage.cpp index b7826ed37d..f9f9c872bb 100644 --- a/src/bmffimage.cpp +++ b/src/bmffimage.cpp @@ -53,8 +53,8 @@ namespace Exiv2 enabled = enable; return true; #endif//EXV_ENABLE_ISOBMFF - return false; enable=false;// unused + return enable; } BmffImage::BmffImage(BasicIo::AutoPtr io, bool /* create */) From e19fca6640cf7b0fecf1f165189f0df214c2d32a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Kov=C3=A1=C5=99?= Date: Tue, 26 Jan 2021 16:00:00 +0100 Subject: [PATCH 06/79] Small corrections --- include/exiv2/bmffimage.hpp | 2 +- src/bmffimage.cpp | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/include/exiv2/bmffimage.hpp b/include/exiv2/bmffimage.hpp index 7001f54abd..24144b340b 100644 --- a/include/exiv2/bmffimage.hpp +++ b/include/exiv2/bmffimage.hpp @@ -48,7 +48,7 @@ namespace Exiv2 //! @name Creators //@{ /*! - @brief Constructor to open a ISOBMFF image. Since the + @brief Constructor to open a ISO/IEC BMFF image. Since the constructor can not return a result, callers should check the good() method after object construction to determine success or failure. diff --git a/src/bmffimage.cpp b/src/bmffimage.cpp index f9f9c872bb..e6b1257825 100644 --- a/src/bmffimage.cpp +++ b/src/bmffimage.cpp @@ -49,11 +49,11 @@ namespace Exiv2 EXIV2API bool enableISOBMFF(bool enable) { -#ifdef EXV_ENABLE_ISOBMFF +#ifdef EXV_ENABLE_ISOBMFF enabled = enable; return true; -#endif//EXV_ENABLE_ISOBMFF - enable=false;// unused +#endif // EXV_ENABLE_ISOBMFF + enable = false; // unused return enable; } @@ -85,11 +85,11 @@ namespace Exiv2 { // Todo: implement me! throw(Error(kerInvalidSettingForImage, "Image comment", "ISO BMFF")); - } // ISOBMFF::setComment + } // BmffImage::setComment void BmffImage::readMetadata() { - } // ISOBMFF::readMetadata + } // BmffImage::readMetadata void BmffImage::printStructure(std::ostream& out, PrintStructureOption option, int depth) { @@ -105,7 +105,7 @@ namespace Exiv2 UNUSED(out); UNUSED(option); UNUSED(depth); - } // ISOBMFF::printStructure + } // BmffImage::printStructure void BmffImage::writeMetadata() { From 2104665faff6375048fcc0fee0a092dd81013580 Mon Sep 17 00:00:00 2001 From: Robin Mills Date: Tue, 26 Jan 2021 16:39:23 +0000 Subject: [PATCH 07/79] Modified ci/install.sh to install cmake before dependencies. Reason: clang/ubuntu fails saying "Package cmake is not available, but is referred to by another package.". --- ci/install.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ci/install.sh b/ci/install.sh index 599dbce1be..6d520d27bd 100755 --- a/ci/install.sh +++ b/ci/install.sh @@ -10,11 +10,12 @@ python3 --version if [[ "$(uname -s)" == 'Linux' ]]; then sudo apt-get update + sudo apt-get install cmake if [[ "$(lsb_release -cs)" == 'focal' ]]; then # In Ubuntu 20.04 python-pip does not exist. Furthermore we need to have the alias python for python3 - sudo apt-get install cmake zlib1g-dev libssh-dev python3-pip python-is-python3 libxml2-utils + sudo apt-get install zlib1g-dev libssh-dev python3-pip python-is-python3 libxml2-utils else - sudo apt-get install cmake zlib1g-dev libssh-dev python-pip libxml2-utils + sudo apt-get install zlib1g-dev libssh-dev python-pip libxml2-utils fi if [ -n "$WITH_VALGRIND" ]; then From c608148820a2787d7b21bf572ea1819584915778 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Kov=C3=A1=C5=99?= Date: Wed, 27 Jan 2021 12:40:32 +0100 Subject: [PATCH 08/79] [WIP] Added box types --- include/exiv2/bmffimage.hpp | 2 +- src/bmffimage.cpp | 195 +++++++++++++++++++++++++++++++++--- 2 files changed, 181 insertions(+), 16 deletions(-) diff --git a/include/exiv2/bmffimage.hpp b/include/exiv2/bmffimage.hpp index 24144b340b..96f1b7e401 100644 --- a/include/exiv2/bmffimage.hpp +++ b/include/exiv2/bmffimage.hpp @@ -96,7 +96,7 @@ namespace Exiv2 #endif private: - int fileType /* = ImageType::bmff*/ ; + uint32_t fileType; /*! @brief Provides the main implementation of writeMetadata() by diff --git a/src/bmffimage.cpp b/src/bmffimage.cpp index e6b1257825..0efac584b9 100644 --- a/src/bmffimage.cpp +++ b/src/bmffimage.cpp @@ -20,6 +20,8 @@ // ***************************************************************************** +#define EXIV2_DEBUG_MESSAGES + // included header files #include "config.h" @@ -41,6 +43,36 @@ #include #include +struct BmffBoxHeader +{ + uint32_t length; + uint32_t type; +}; + +#if defined(__BIG_ENDIAN__) +#define ID(string) ((string[0] << 24) | (string[1] << 16) | (string[2] << 8) | string[3]) +#elif defined(__LITTLE_ENDIAN__) +#define ID(string) (string[0] | (string[1] << 8) | (string[2] << 16) | (string[3] << 24)) +#else +#error "Unknown endian" +#endif + +static const uint32_t ftyp = ID("ftyp"); /**< File type box */ +static const uint32_t avif = ID("avif"); /**< AVIF */ +static const uint32_t heic = ID("heic"); /**< HEIF */ +static const uint32_t heif = ID("heif"); /**< HEIF */ +static const uint32_t crx = ID("crx "); /**< Canon CR3 */ +static const uint32_t moov = ID("moov"); /**< Movie */ +static const uint32_t meta = ID("meta"); /**< Metadata */ +static const uint32_t mdat = ID("mdat"); /**< Media data */ +static const uint32_t uuid = ID("uuid"); /**< UUID */ +static const uint32_t dinf = ID("dinf"); /**< Data information */ +static const uint32_t iprp = ID("iprp"); /**< Item properties */ +static const uint32_t ipco = ID("ipco"); /**< Item property container */ +static const uint32_t iinf = ID("iinf"); /**< Item info */ +static const uint32_t iloc = ID("iloc"); /**< Item location */ +static const uint32_t ispe = ID("ispe"); /**< Image spatial extents */ + // ***************************************************************************** // class member definitions namespace Exiv2 @@ -62,23 +94,81 @@ namespace Exiv2 { } // BmffImage::BmffImage + static bool isBigEndian() + { + union { + uint32_t i; + char c[4]; + } e = { 0x01000000 }; + + return e.c[0]?true:false; + } + + static std::string toAscii(long n) + { + const char* p = (const char*) &n; + std::string result; + bool bBigEndian = isBigEndian(); + for ( int i = 0 ; i < 4 ; i++) { + result += p[ bBigEndian ? i : (3-i) ]; + } + return result; + } + + std::string boxName(uint32_t box) + { + char name[5]; + std::memcpy (name,&box,4); + name[4] = 0 ; + return std::string(name) ; + } + + static void boxes_check(size_t b, size_t m) + { + if ( b > m ) { +#ifdef EXIV2_DEBUG_MESSAGES + std::cout << "Exiv2::BmffImage::readMetadata box maximum exceeded" << std::endl; +#endif + throw Error(kerCorruptedMetadata); + } + } + + bool superBox(uint32_t box) + { + return box == moov + || box == dinf + || box == iprp + || box == ipco + || box == meta + || box == iinf + || box == iloc + ; + } + bool fullBox(uint32_t box) + { + return box == meta + || box == iinf + || box == iloc + ; + } + std::string BmffImage::mimeType() const { - /* switch (fileType) { - case ImageType::avif: + case avif: return "image/avif"; - case ImageType::heif: + case heic: + case heif: return "image/heif"; + case crx: + return "image/x-canon-cr3"; + default: - return "image/unknown"; + return "image/generic"; } - */ - return "image/bmff"; - } void BmffImage::setComment(const std::string& /*comment*/) @@ -89,6 +179,83 @@ namespace Exiv2 void BmffImage::readMetadata() { + if (io_->open() != 0) + { + throw Error(kerDataSourceOpenFailed, io_->path(), strError()); + } + IoCloser closer(*io_); + // Ensure that this is the correct image type + if (!isBmffType(*io_, false)) { + if (io_->error() || io_->eof()) throw Error(kerFailedToReadImageData); + throw Error(kerNotAnImage, "ISO BMFF"); + } + + long position = 0; + BmffBoxHeader box = {0,0}; + BmffBoxHeader subBox = {0,0}; + size_t boxes = 0 ; + size_t boxem = 1000 ; // boxes max + + while (io_->read((byte*)&box, sizeof(box)) == sizeof(box)) + { + boxes_check(boxes++, boxem); + position = io_->tell(); + uint32_t length = getLong((byte*)&box.length, bigEndian); + uint32_t type = getLong((byte*)&box.type, bigEndian); +#ifdef EXIV2_DEBUG_MESSAGES + std::cout << "Exiv2::BmffImage::readMetadata: " + << "Position: " << position + << " box type: " << toAscii(type) + << " length: " << length + << std::endl; +#endif + + if (length == 0) return ; + + if (length == 1) + { + } + + switch (box.type) + { + case ftyp: + { + io().read((byte*)&fileType,4); + std::string brand_ = boxName(fileType); +#ifdef EXIV2_DEBUG_MESSAGES + std::cout << "Exiv2::BmffImage::readMetadata: " + << "Brand: " << brand_ + << std::endl; +#endif + break; + } + + case meta: + { +#ifdef EXIV2_DEBUG_MESSAGES + std::cout << "Exiv2::BmffImage::readMetadata: metadata" + << std::endl; +#endif + break; + } + + default: + { +#ifdef EXIV2_DEBUG_MESSAGES + std::cout << " box type: " << toAscii(type) + << " length: " << length + << std::endl; +#endif + break; + } + } + + // Move to the next box. + io_->seek(static_cast(position - sizeof(box) + length), BasicIo::beg); + if (io_->error()) + throw Error(kerFailedToReadImageData); + } + } // BmffImage::readMetadata void BmffImage::printStructure(std::ostream& out, PrintStructureOption option, int depth) @@ -132,16 +299,14 @@ namespace Exiv2 const int32_t len = 12; byte buf[len]; iIo.read(buf, len); - if (iIo.error() || iIo.eof()) - { + if (iIo.error() || iIo.eof()) { return false; } - - bool result = buf[4] == 'f' && buf[5] == 't' && buf[6] == 'y' && buf[7] == 'p'; - if (!advance) - { - iIo.seek(-len, BasicIo::cur); + + bool matched = buf[4] == 'f' && buf[5] == 't' && buf[6] == 'y' && buf[7] == 'p'; + if (!advance || !matched) { + iIo.seek(static_cast(0), BasicIo::beg); } - return result; + return matched; } } // namespace Exiv2 From f0a321dedbf221a84d2a30d821caf91dd595d620 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Kov=C3=A1=C5=99?= Date: Tue, 16 Feb 2021 10:10:00 +0100 Subject: [PATCH 09/79] [WIP] Base Media File Format --- CMakeLists.txt | 2 +- cmake/config.h.cmake | 4 +- cmake/generateConfigFile.cmake | 2 +- cmake/printSummary.cmake | 2 +- include/exiv2/bmffimage.hpp | 16 +-- include/exiv2/exiv2.hpp | 4 +- src/bmffimage.cpp | 178 ++++++++++++++++++--------------- src/exiv2.cpp | 4 +- src/image.cpp | 8 +- src/version.cpp | 6 ++ 10 files changed, 126 insertions(+), 100 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b5cdacfe6b..8e267d4954 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,7 +25,7 @@ option( EXIV2_ENABLE_WIN_UNICODE "Use Unicode paths (wstring) on Windows" option( EXIV2_ENABLE_WEBREADY "Build webready support into library" OFF ) option( EXIV2_ENABLE_CURL "USE Libcurl for HttpIo (WEBREADY)" OFF ) option( EXIV2_ENABLE_SSH "USE Libssh for SshIo (WEBREADY)" OFF ) -option( EXIV2_ENABLE_ISOBMFF "Build with ISO BMFF support" OFF ) +option( EXIV2_ENABLE_BMFF "Build with BMFF support" OFF ) option( EXIV2_BUILD_SAMPLES "Build sample applications" ON ) option( EXIV2_BUILD_EXIV2_COMMAND "Build exiv2 command-line executable" ON ) diff --git a/cmake/config.h.cmake b/cmake/config.h.cmake index cee33398ca..b633d12778 100644 --- a/cmake/config.h.cmake +++ b/cmake/config.h.cmake @@ -18,8 +18,8 @@ // Define if you want translation of program messages to the user's native language #cmakedefine EXV_ENABLE_NLS -// Define if you want ISO BMFF support. -#cmakedefine EXV_ENABLE_ISOBMFF +// Define if you want BMFF support. +#cmakedefine EXV_ENABLE_BMFF // Define if you want video support. #cmakedefine EXV_ENABLE_VIDEO diff --git a/cmake/generateConfigFile.cmake b/cmake/generateConfigFile.cmake index c8ee83f5e1..fe1cabbd82 100644 --- a/cmake/generateConfigFile.cmake +++ b/cmake/generateConfigFile.cmake @@ -7,7 +7,7 @@ if (${EXIV2_ENABLE_WEBREADY}) set(EXV_USE_SSH ${EXIV2_ENABLE_SSH}) set(EXV_USE_CURL ${EXIV2_ENABLE_CURL}) endif() -set(EXV_ENABLE_ISOBMFF ${EXIV2_ENABLE_ISOBMFF}) +set(EXV_ENABLE_BMFF ${EXIV2_ENABLE_BMFF}) set(EXV_ENABLE_VIDEO ${EXIV2_ENABLE_VIDEO}) set(EXV_ENABLE_WEBREADY ${EXIV2_ENABLE_WEBREADY}) set(EXV_HAVE_LENSDATA ${EXIV2_ENABLE_LENSDATA}) diff --git a/cmake/printSummary.cmake b/cmake/printSummary.cmake index fd3a545dbc..2f3e1fc496 100644 --- a/cmake/printSummary.cmake +++ b/cmake/printSummary.cmake @@ -50,7 +50,7 @@ if ( EXIV2_ENABLE_EXTERNAL_XMP ) else() OptionOutput( "XMP metadata support: " EXIV2_ENABLE_XMP ) endif() -OptionOutput( "Building ISO BMFF support: " EXIV2_ENABLE_ISOBMFF ) +OptionOutput( "Building BMFF support: " EXIV2_ENABLE_BMFF ) OptionOutput( "Native language support: " EXIV2_ENABLE_NLS ) OptionOutput( "Conversion of Windows XP tags: " EXIV2_ENABLE_PRINTUCS2 ) OptionOutput( "Nikon lens database: " EXIV2_ENABLE_LENSDATA ) diff --git a/include/exiv2/bmffimage.hpp b/include/exiv2/bmffimage.hpp index 96f1b7e401..783005c908 100644 --- a/include/exiv2/bmffimage.hpp +++ b/include/exiv2/bmffimage.hpp @@ -30,25 +30,25 @@ // namespace extensions namespace Exiv2 { - EXIV2API bool enableISOBMFF(bool enable = true); + EXIV2API bool enableBMFF(bool enable = true); // ***************************************************************************** // class definitions - // Add ISO Base Media File Format to the supported image formats + // Add Base Media File Format to the supported image formats namespace ImageType { - const int bmff = 15; //!< ISO BMFF (bmff) image type (see class ISOBMFF) + const int bmff = 15; //!< BMFF (bmff) image type (see class BMFF) } /*! - @brief Class to access ISO BMFF images. + @brief Class to access BMFF images. */ class EXIV2API BmffImage : public Image { public: //! @name Creators //@{ /*! - @brief Constructor to open a ISO/IEC BMFF image. Since the + @brief Constructor to open a BMFF image. Since the constructor can not return a result, callers should check the good() method after object construction to determine success or failure. @@ -108,6 +108,8 @@ namespace Exiv2 void doWriteMetadata(BasicIo& outIo); //@} + std::string toAscii(long n); + }; // class BmffImage // ***************************************************************************** @@ -116,12 +118,12 @@ namespace Exiv2 // These could be static private functions on Image subclasses but then // ImageFactory needs to be made a friend. /*! - @brief Create a new ISO BMFF instance and return an auto-pointer to it. + @brief Create a new BMFF instance and return an auto-pointer to it. Caller owns the returned object and the auto-pointer ensures that it will be deleted. */ EXIV2API Image::AutoPtr newBmffInstance(BasicIo::AutoPtr io, bool create); - //! Check if the file iIo is a ISO BMFF image. + //! Check if the file iIo is a BMFF image. EXIV2API bool isBmffType(BasicIo& iIo, bool advance); } // namespace Exiv2 diff --git a/include/exiv2/exiv2.hpp b/include/exiv2/exiv2.hpp index 1313ad3b41..ef9b60afa7 100644 --- a/include/exiv2/exiv2.hpp +++ b/include/exiv2/exiv2.hpp @@ -46,9 +46,9 @@ #include "exiv2/image.hpp" #include "exiv2/ini.hpp" #include "exiv2/iptc.hpp" -#ifdef EXV_ENABLE_ISOBMFF +#ifdef EXV_ENABLE_BMFF #include "bmffimage.hpp" -#endif// EXV_ENABLE_ISOBMFF +#endif// EXV_ENABLE_BMFF #include "exiv2/jp2image.hpp" #include "exiv2/jpgimage.hpp" #include "exiv2/metadatum.hpp" diff --git a/src/bmffimage.cpp b/src/bmffimage.cpp index 0efac584b9..1894eb0d8a 100644 --- a/src/bmffimage.cpp +++ b/src/bmffimage.cpp @@ -49,29 +49,23 @@ struct BmffBoxHeader uint32_t type; }; -#if defined(__BIG_ENDIAN__) #define ID(string) ((string[0] << 24) | (string[1] << 16) | (string[2] << 8) | string[3]) -#elif defined(__LITTLE_ENDIAN__) -#define ID(string) (string[0] | (string[1] << 8) | (string[2] << 16) | (string[3] << 24)) -#else -#error "Unknown endian" -#endif -static const uint32_t ftyp = ID("ftyp"); /**< File type box */ -static const uint32_t avif = ID("avif"); /**< AVIF */ -static const uint32_t heic = ID("heic"); /**< HEIF */ -static const uint32_t heif = ID("heif"); /**< HEIF */ -static const uint32_t crx = ID("crx "); /**< Canon CR3 */ -static const uint32_t moov = ID("moov"); /**< Movie */ -static const uint32_t meta = ID("meta"); /**< Metadata */ -static const uint32_t mdat = ID("mdat"); /**< Media data */ -static const uint32_t uuid = ID("uuid"); /**< UUID */ -static const uint32_t dinf = ID("dinf"); /**< Data information */ -static const uint32_t iprp = ID("iprp"); /**< Item properties */ -static const uint32_t ipco = ID("ipco"); /**< Item property container */ -static const uint32_t iinf = ID("iinf"); /**< Item info */ -static const uint32_t iloc = ID("iloc"); /**< Item location */ -static const uint32_t ispe = ID("ispe"); /**< Image spatial extents */ +#define TAG_ftyp ID("ftyp") /**< File type box */ +#define TAG_avif ID("avif") /**< AVIF */ +#define TAG_heic ID("heic") /**< HEIF */ +#define TAG_heif ID("heif") /**< HEIF */ +#define TAG_crx ID("crx ") /**< Canon CR3 */ +#define TAG_moov ID("moov") /**< Movie */ +#define TAG_meta ID("meta") /**< Metadata */ +#define TAG_mdat ID("mdat") /**< Media data */ +#define TAG_uuid ID("uuid") /**< UUID */ +#define TAG_dinf ID("dinf") /**< Data information */ +#define TAG_iprp ID("iprp") /**< Item properties */ +#define TAG_ipco ID("ipco") /**< Item property container */ +#define TAG_iinf ID("iinf") /**< Item info */ +#define TAG_iloc ID("iloc") /**< Item location */ +#define TAG_ispe ID("ispe") /**< Image spatial extents */ // ***************************************************************************** // class member definitions @@ -79,12 +73,12 @@ namespace Exiv2 { static bool enabled = false; - EXIV2API bool enableISOBMFF(bool enable) + EXIV2API bool enableBMFF(bool enable) { -#ifdef EXV_ENABLE_ISOBMFF +#ifdef EXV_ENABLE_BMFF enabled = enable; return true; -#endif // EXV_ENABLE_ISOBMFF +#endif // EXV_ENABLE_BMFF enable = false; // unused return enable; } @@ -94,21 +88,11 @@ namespace Exiv2 { } // BmffImage::BmffImage - static bool isBigEndian() - { - union { - uint32_t i; - char c[4]; - } e = { 0x01000000 }; - - return e.c[0]?true:false; - } - - static std::string toAscii(long n) + std::string BmffImage::toAscii(long n) { const char* p = (const char*) &n; std::string result; - bool bBigEndian = isBigEndian(); + bool bBigEndian = isBigEndianPlatform(); for ( int i = 0 ; i < 4 ; i++) { result += p[ bBigEndian ? i : (3-i) ]; } @@ -135,20 +119,21 @@ namespace Exiv2 bool superBox(uint32_t box) { - return box == moov - || box == dinf - || box == iprp - || box == ipco - || box == meta - || box == iinf - || box == iloc + return box == TAG_moov + || box == TAG_dinf + || box == TAG_iprp + || box == TAG_ipco + || box == TAG_meta + || box == TAG_iinf + || box == TAG_iloc ; } + bool fullBox(uint32_t box) { - return box == meta - || box == iinf - || box == iloc + return box == TAG_meta + || box == TAG_iinf + || box == TAG_iloc ; } @@ -156,14 +141,14 @@ namespace Exiv2 { switch (fileType) { - case avif: + case TAG_avif: return "image/avif"; - case heic: - case heif: + case TAG_heic: + case TAG_heif: return "image/heif"; - case crx: + case TAG_crx: return "image/x-canon-cr3"; default: @@ -174,7 +159,7 @@ namespace Exiv2 void BmffImage::setComment(const std::string& /*comment*/) { // Todo: implement me! - throw(Error(kerInvalidSettingForImage, "Image comment", "ISO BMFF")); + throw(Error(kerInvalidSettingForImage, "Image comment", "BMFF")); } // BmffImage::setComment void BmffImage::readMetadata() @@ -187,7 +172,7 @@ namespace Exiv2 // Ensure that this is the correct image type if (!isBmffType(*io_, false)) { if (io_->error() || io_->eof()) throw Error(kerFailedToReadImageData); - throw Error(kerNotAnImage, "ISO BMFF"); + throw Error(kerNotAnImage, "BMFF"); } long position = 0; @@ -200,58 +185,91 @@ namespace Exiv2 { boxes_check(boxes++, boxem); position = io_->tell(); - uint32_t length = getLong((byte*)&box.length, bigEndian); - uint32_t type = getLong((byte*)&box.type, bigEndian); + box.length = getLong((byte*)&box.length, bigEndian); + box.type = getLong((byte*)&box.type, bigEndian); #ifdef EXIV2_DEBUG_MESSAGES std::cout << "Exiv2::BmffImage::readMetadata: " << "Position: " << position - << " box type: " << toAscii(type) - << " length: " << length + << " box type: " << toAscii(box.type) + << " box length: " << box.length << std::endl; #endif - if (length == 0) return ; + if (box.length == 0) return ; - if (length == 1) + if (box.length == 1) { } - switch (box.type) + if (box.length > 8 && (position + box.length) <= io().size() ) { - case ftyp: + switch (box.type) { - io().read((byte*)&fileType,4); - std::string brand_ = boxName(fileType); + case TAG_ftyp: + { + DataBuf data(box.length); + io().read(data.pData_, data.size_); + fileType = getLong(data.pData_, bigEndian); #ifdef EXIV2_DEBUG_MESSAGES - std::cout << "Exiv2::BmffImage::readMetadata: " - << "Brand: " << brand_ - << std::endl; + std::string brand_ = toAscii(fileType); + std::cout << "Exiv2::BmffImage::readMetadata: " + << "Brand: " << brand_ + << std::endl; #endif - break; - } + break; + } - case meta: - { + case TAG_meta: + { + DataBuf data(box.length); + io().read(data.pData_, data.size_); #ifdef EXIV2_DEBUG_MESSAGES - std::cout << "Exiv2::BmffImage::readMetadata: metadata" - << std::endl; + std::cout << "Exiv2::BmffImage::readMetadata: metadata " + << data.size_ << " bytes " << std::endl; + std::cout << std::hex; + for (unsigned i = 0; i < data.size_; i++) + { + std::cout << " " << data.pData_[i]; + } + std::cout << std::dec; + std::cout << std::endl; #endif - break; - } + break; + } + + case TAG_ispe: + { + DataBuf data(box.length); + io().read(data.pData_, data.size_); + + uint32_t flags = getLong(data.pData_, bigEndian); + uint8_t version = (uint8_t) flags >> 24; + flags &= 0x00ffffff; + pixelWidth_ = getLong(data.pData_ + 4, bigEndian); + pixelHeight_ = getLong(data.pData_ + 8, bigEndian); +#ifdef EXIV2_DEBUG_MESSAGES + std::cout << "Exiv2::BmffImage::readMetadata: Image spatial extents " + << "version: " << version + << "flags: " << flags + << std::endl; +#endif + break; + } - default: - { + default: + { #ifdef EXIV2_DEBUG_MESSAGES - std::cout << " box type: " << toAscii(type) - << " length: " << length - << std::endl; + std::cout << " box type: " << toAscii(box.type) + << " box length: " << box.length + << std::endl; #endif - break; + break; + } } } // Move to the next box. - io_->seek(static_cast(position - sizeof(box) + length), BasicIo::beg); + io_->seek(static_cast(position - sizeof(box) + box.length), BasicIo::beg); if (io_->error()) throw Error(kerFailedToReadImageData); } diff --git a/src/exiv2.cpp b/src/exiv2.cpp index 764e5235e8..f823368b85 100644 --- a/src/exiv2.cpp +++ b/src/exiv2.cpp @@ -137,8 +137,8 @@ int main(int argc, char* const argv[]) textdomain(EXV_PACKAGE_NAME); #endif -#ifdef EXV_ENABLE_ISOBMFF - Exiv2::enableISOBMFF(); +#ifdef EXV_ENABLE_BMFF + Exiv2::enableBMFF(); #endif // Handle command line arguments diff --git a/src/image.cpp b/src/image.cpp index d5cef01612..9267c8e4bf 100644 --- a/src/image.cpp +++ b/src/image.cpp @@ -31,9 +31,9 @@ #include "safe_op.hpp" #include "slice.hpp" -#ifdef EXV_ENABLE_ISOBMFF +#ifdef EXV_ENABLE_BMFF #include "bmffimage.hpp" -#endif// EXV_ENABLE_ISOBMFF +#endif// EXV_ENABLE_BMFF #include "cr2image.hpp" #include "crwimage.hpp" #include "epsimage.hpp" @@ -134,9 +134,9 @@ namespace { { ImageType::tga, newTgaInstance, isTgaType, amNone, amNone, amNone, amNone }, { ImageType::bmp, newBmpInstance, isBmpType, amNone, amNone, amNone, amNone }, { ImageType::jp2, newJp2Instance, isJp2Type, amReadWrite, amReadWrite, amReadWrite, amNone }, -#ifdef EXV_ENABLE_ISOBMFF +#ifdef EXV_ENABLE_BMFF { ImageType::bmff, newBmffInstance, isBmffType, amRead, amRead, amRead, amNone }, -#endif // EXV_ENABLE_ISOBMFF +#endif // EXV_ENABLE_BMFF #ifdef EXV_ENABLE_VIDEO { ImageType::qtime,newQTimeInstance,isQTimeType,amRead, amNone, amRead, amNone }, { ImageType::riff, newRiffInstance, isRiffType, amRead, amNone, amRead, amNone }, diff --git a/src/version.cpp b/src/version.cpp index ea8d504c74..a3b53e08cf 100644 --- a/src/version.cpp +++ b/src/version.cpp @@ -345,6 +345,7 @@ void Exiv2::dumpLibraryInfo(std::ostream& os,const exv_grep_keys_t& keys) int have_unistd =0; int have_unicode_path=0; + int enable_bmff =0; int enable_video =0; int enable_webready =0; int enable_nls =0; @@ -461,6 +462,10 @@ void Exiv2::dumpLibraryInfo(std::ostream& os,const exv_grep_keys_t& keys) have_unicode_path=1; #endif +#ifdef EXV_ENABLE_BMFF + enable_bmff=1; +#endif + #ifdef EXV_ENABLE_VIDEO enable_video=1; #endif @@ -544,6 +549,7 @@ void Exiv2::dumpLibraryInfo(std::ostream& os,const exv_grep_keys_t& keys) output(os,keys,"have_sys_types" ,have_sys_types ); output(os,keys,"have_unistd" ,have_unistd ); output(os,keys,"have_unicode_path" ,have_unicode_path); + output(os,keys,"enable_bmff" ,enable_bmff ); output(os,keys,"enable_video" ,enable_video ); output(os,keys,"enable_webready" ,enable_webready ); output(os,keys,"enable_nls" ,enable_nls ); From 7b5854e26e929b59440464a78f101bcce280c0cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Kov=C3=A1=C5=99?= Date: Tue, 16 Feb 2021 11:47:15 +0100 Subject: [PATCH 10/79] [WIP] Redefine tags --- src/bmffimage.cpp | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/src/bmffimage.cpp b/src/bmffimage.cpp index 1894eb0d8a..0f7549b3ef 100644 --- a/src/bmffimage.cpp +++ b/src/bmffimage.cpp @@ -49,23 +49,21 @@ struct BmffBoxHeader uint32_t type; }; -#define ID(string) ((string[0] << 24) | (string[1] << 16) | (string[2] << 8) | string[3]) - -#define TAG_ftyp ID("ftyp") /**< File type box */ -#define TAG_avif ID("avif") /**< AVIF */ -#define TAG_heic ID("heic") /**< HEIF */ -#define TAG_heif ID("heif") /**< HEIF */ -#define TAG_crx ID("crx ") /**< Canon CR3 */ -#define TAG_moov ID("moov") /**< Movie */ -#define TAG_meta ID("meta") /**< Metadata */ -#define TAG_mdat ID("mdat") /**< Media data */ -#define TAG_uuid ID("uuid") /**< UUID */ -#define TAG_dinf ID("dinf") /**< Data information */ -#define TAG_iprp ID("iprp") /**< Item properties */ -#define TAG_ipco ID("ipco") /**< Item property container */ -#define TAG_iinf ID("iinf") /**< Item info */ -#define TAG_iloc ID("iloc") /**< Item location */ -#define TAG_ispe ID("ispe") /**< Image spatial extents */ +#define TAG_ftyp 0x66747970 /**< "ftyp" File type box */ +#define TAG_avif 0x61766966 /**< "avif" AVIF */ +#define TAG_heic 0x68656963 /**< "heic" HEIF */ +#define TAG_heif 0x68656966 /**< "heif" HEIF */ +#define TAG_crx 0x63727820 /**< "crx " Canon CR3 */ +#define TAG_moov 0x6d6f6f76 /**< "moov" Movie */ +#define TAG_meta 0x6d657461 /**< "meta" Metadata */ +#define TAG_mdat 0x6d646174 /**< "mdat" Media data */ +#define TAG_uuid 0x75756964 /**< "uuid" UUID */ +#define TAG_dinf 0x64696e66 /**< "dinf" Data information */ +#define TAG_iprp 0x69707270 /**< "iprp" Item properties */ +#define TAG_ipco 0x6970636f /**< "ipco" Item property container */ +#define TAG_iinf 0x69696e66 /**< "iinf" Item info */ +#define TAG_iloc 0x696c6f63 /**< "iloc" Item location */ +#define TAG_ispe 0x69737065 /**< "ispe" Image spatial extents */ // ***************************************************************************** // class member definitions @@ -201,7 +199,7 @@ namespace Exiv2 { } - if (box.length > 8 && (position + box.length) <= io().size() ) + if ((box.length > 8) && (static_cast(position) + box.length) <= io().size()) { switch (box.type) { From 81e0f992545b67df6789897035991371364f0d4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Kov=C3=A1=C5=99?= Date: Tue, 16 Feb 2021 12:11:11 +0100 Subject: [PATCH 11/79] [WIP] Another try --- src/bmffimage.cpp | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/bmffimage.cpp b/src/bmffimage.cpp index 0f7549b3ef..47905a49ea 100644 --- a/src/bmffimage.cpp +++ b/src/bmffimage.cpp @@ -175,7 +175,7 @@ namespace Exiv2 long position = 0; BmffBoxHeader box = {0,0}; - BmffBoxHeader subBox = {0,0}; + // BmffBoxHeader subBox = {0,0}; size_t boxes = 0 ; size_t boxem = 1000 ; // boxes max @@ -223,14 +223,8 @@ namespace Exiv2 io().read(data.pData_, data.size_); #ifdef EXIV2_DEBUG_MESSAGES std::cout << "Exiv2::BmffImage::readMetadata: metadata " - << data.size_ << " bytes " << std::endl; - std::cout << std::hex; - for (unsigned i = 0; i < data.size_; i++) - { - std::cout << " " << data.pData_[i]; - } - std::cout << std::dec; - std::cout << std::endl; + << data.size_ << " bytes" + << std::endl; #endif break; } @@ -257,7 +251,7 @@ namespace Exiv2 default: { #ifdef EXIV2_DEBUG_MESSAGES - std::cout << " box type: " << toAscii(box.type) + std::cout << "Exiv2::BmffImage::readMetadata: box type: " << toAscii(box.type) << " box length: " << box.length << std::endl; #endif From 4fa0a880978dd3fafa8949e75af99f9817266564 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Kov=C3=A1=C5=99?= Date: Tue, 16 Feb 2021 13:35:32 +0100 Subject: [PATCH 12/79] [WIP] Correction https://ci.appveyor.com/project/piponazo/exiv2-wutfp/builds/37795261/job/23l6a0u0wt6ax79l --- src/bmffimage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bmffimage.cpp b/src/bmffimage.cpp index 47905a49ea..e4c62c9ca5 100644 --- a/src/bmffimage.cpp +++ b/src/bmffimage.cpp @@ -235,7 +235,7 @@ namespace Exiv2 io().read(data.pData_, data.size_); uint32_t flags = getLong(data.pData_, bigEndian); - uint8_t version = (uint8_t) flags >> 24; + uint8_t version = (uint8_t)(flags >> 24); flags &= 0x00ffffff; pixelWidth_ = getLong(data.pData_ + 4, bigEndian); pixelHeight_ = getLong(data.pData_ + 8, bigEndian); From 04481dd75356368f665a4c980e9c38845a86077f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Kov=C3=A1=C5=99?= Date: Mon, 22 Feb 2021 11:01:34 +0100 Subject: [PATCH 13/79] [WIP] 64-bit length --- include/exiv2/bmffimage.hpp | 4 +++ src/bmffimage.cpp | 67 ++++++++++++++++++++++++------------- 2 files changed, 48 insertions(+), 23 deletions(-) diff --git a/include/exiv2/bmffimage.hpp b/include/exiv2/bmffimage.hpp index 783005c908..30f979ae13 100644 --- a/include/exiv2/bmffimage.hpp +++ b/include/exiv2/bmffimage.hpp @@ -64,6 +64,10 @@ namespace Exiv2 BmffImage(BasicIo::AutoPtr io, bool create); //@} + //@{ + BmffImage(BasicIo::AutoPtr io, size_t start, size_t count); + //@} + //! @name Manipulators //@{ void readMetadata() /* override */ ; diff --git a/src/bmffimage.cpp b/src/bmffimage.cpp index e4c62c9ca5..1d9309f53a 100644 --- a/src/bmffimage.cpp +++ b/src/bmffimage.cpp @@ -86,6 +86,11 @@ namespace Exiv2 { } // BmffImage::BmffImage + BmffImage::BmffImage(BasicIo::AutoPtr io, size_t start, size_t count) + : Image(ImageType::bmff, mdExif | mdIptc | mdXmp, io) + { + } // BmffImage::BmffImage + std::string BmffImage::toAscii(long n) { const char* p = (const char*) &n; @@ -173,39 +178,51 @@ namespace Exiv2 throw Error(kerNotAnImage, "BMFF"); } - long position = 0; - BmffBoxHeader box = {0,0}; - // BmffBoxHeader subBox = {0,0}; - size_t boxes = 0 ; - size_t boxem = 1000 ; // boxes max + long position = 0; + BmffBoxHeader box = { 0, 0 }; + size_t boxes = 0 ; + size_t boxem = 1000 ; // boxes max + uint64_t address = position; + uint64_t length = 8; + uint32_t type; while (io_->read((byte*)&box, sizeof(box)) == sizeof(box)) { boxes_check(boxes++, boxem); - position = io_->tell(); - box.length = getLong((byte*)&box.length, bigEndian); - box.type = getLong((byte*)&box.type, bigEndian); + position = io_->tell(); + length = getLong((byte*)&box.length, bigEndian); + type = getLong((byte*)&box.type, bigEndian); #ifdef EXIV2_DEBUG_MESSAGES std::cout << "Exiv2::BmffImage::readMetadata: " << "Position: " << position - << " box type: " << toAscii(box.type) - << " box length: " << box.length + << " box type: " << toAscii(type) + << " box length: " << length << std::endl; #endif + if (length == 0) + { + return; + } - if (box.length == 0) return ; - - if (box.length == 1) + if (length == 1) { + DataBuf data(sizeof(length)); + io().read(data.pData_, data.size_); + length = getULongLong(data.pData_, bigEndian); +#ifdef EXIV2_DEBUG_MESSAGES + std::cout << "Exiv2::BmffImage::readMetadata: " + << "length " << length + << std::endl; +#endif } - if ((box.length > 8) && (static_cast(position) + box.length) <= io().size()) + if ((length > 8) && (static_cast(position) + length) <= io().size()) { - switch (box.type) + switch (type) { case TAG_ftyp: { - DataBuf data(box.length); + DataBuf data(length); io().read(data.pData_, data.size_); fileType = getLong(data.pData_, bigEndian); #ifdef EXIV2_DEBUG_MESSAGES @@ -219,7 +236,7 @@ namespace Exiv2 case TAG_meta: { - DataBuf data(box.length); + DataBuf data(length); io().read(data.pData_, data.size_); #ifdef EXIV2_DEBUG_MESSAGES std::cout << "Exiv2::BmffImage::readMetadata: metadata " @@ -231,7 +248,7 @@ namespace Exiv2 case TAG_ispe: { - DataBuf data(box.length); + DataBuf data(length); io().read(data.pData_, data.size_); uint32_t flags = getLong(data.pData_, bigEndian); @@ -251,8 +268,8 @@ namespace Exiv2 default: { #ifdef EXIV2_DEBUG_MESSAGES - std::cout << "Exiv2::BmffImage::readMetadata: box type: " << toAscii(box.type) - << " box length: " << box.length + std::cout << "Exiv2::BmffImage::readMetadata: box type: " << toAscii(type) + << " box length: " << length << std::endl; #endif break; @@ -261,11 +278,12 @@ namespace Exiv2 } // Move to the next box. - io_->seek(static_cast(position - sizeof(box) + box.length), BasicIo::beg); + io_->seek(static_cast(position - sizeof(box) + length), BasicIo::beg); if (io_->error()) + { throw Error(kerFailedToReadImageData); + } } - } // BmffImage::readMetadata void BmffImage::printStructure(std::ostream& out, PrintStructureOption option, int depth) @@ -274,9 +292,12 @@ namespace Exiv2 throw Error(kerDataSourceOpenFailed, io_->path(), strError()); // Ensure that this is the correct image type - if (!isBmffType(*io_, false)) { + if (!isBmffType(*io_, false)) + { if (io_->error() || io_->eof()) + { throw Error(kerFailedToReadImageData); + } throw Error(kerNotAnImage); } UNUSED(out); From a75ac74417a7aeebbe386d5e00e1f33ac924b8dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Kov=C3=A1=C5=99?= Date: Mon, 22 Feb 2021 11:27:16 +0100 Subject: [PATCH 14/79] [WIP] Correction to make Travis CI happy --- src/bmffimage.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/bmffimage.cpp b/src/bmffimage.cpp index 1d9309f53a..6b208ae9ef 100644 --- a/src/bmffimage.cpp +++ b/src/bmffimage.cpp @@ -89,6 +89,8 @@ namespace Exiv2 BmffImage::BmffImage(BasicIo::AutoPtr io, size_t start, size_t count) : Image(ImageType::bmff, mdExif | mdIptc | mdXmp, io) { + UNUSED(start); + UNUSED(count); } // BmffImage::BmffImage std::string BmffImage::toAscii(long n) @@ -284,6 +286,7 @@ namespace Exiv2 throw Error(kerFailedToReadImageData); } } + UNUSED(address); } // BmffImage::readMetadata void BmffImage::printStructure(std::ostream& out, PrintStructureOption option, int depth) From 0360a7ded501a1f045829bd2e9bdbb8fb31ad1fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Kov=C3=A1=C5=99?= Date: Mon, 22 Feb 2021 11:50:32 +0100 Subject: [PATCH 15/79] [WIP] Yet another type cast correction to make Travis CI happy --- src/bmffimage.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/bmffimage.cpp b/src/bmffimage.cpp index 6b208ae9ef..be86f91870 100644 --- a/src/bmffimage.cpp +++ b/src/bmffimage.cpp @@ -224,7 +224,7 @@ namespace Exiv2 { case TAG_ftyp: { - DataBuf data(length); + DataBuf data(static_cast(length)); io().read(data.pData_, data.size_); fileType = getLong(data.pData_, bigEndian); #ifdef EXIV2_DEBUG_MESSAGES @@ -238,7 +238,7 @@ namespace Exiv2 case TAG_meta: { - DataBuf data(length); + DataBuf data(static_cast(length)); io().read(data.pData_, data.size_); #ifdef EXIV2_DEBUG_MESSAGES std::cout << "Exiv2::BmffImage::readMetadata: metadata " @@ -250,7 +250,7 @@ namespace Exiv2 case TAG_ispe: { - DataBuf data(length); + DataBuf data(static_cast(length)); io().read(data.pData_, data.size_); uint32_t flags = getLong(data.pData_, bigEndian); From 6d13e44e5ac377c9d6bca88d919f4a40d895a85f Mon Sep 17 00:00:00 2001 From: Robin Mills Date: Tue, 23 Feb 2021 20:05:18 +0000 Subject: [PATCH 16/79] WIP: Refactored readMetadata() into recursive boxHandler() --- include/exiv2/bmffimage.hpp | 24 ++- src/bmffimage.cpp | 320 +++++++++++++++++++++--------------- 2 files changed, 215 insertions(+), 129 deletions(-) diff --git a/include/exiv2/bmffimage.hpp b/include/exiv2/bmffimage.hpp index 30f979ae13..24817fa623 100644 --- a/include/exiv2/bmffimage.hpp +++ b/include/exiv2/bmffimage.hpp @@ -100,7 +100,22 @@ namespace Exiv2 #endif private: - uint32_t fileType; + /*! + @brief recursiveBoxHandler + @throw Error if we visit a box more than once + @warning This function should only be called by readMetadata() + */ + long boxHandler(int indent=0); + + uint32_t fileType ; + std::set visits_ ; + uint64_t visits_max_; + std::string indenter(int i) { std::string r; while ( i-- > 0 ) r+=std::string(" "); return r; } + + uint16_t unknownID_ ; // 0xffff + uint16_t exifID_ ; + uint32_t exifStart_ ; + uint32_t exifLength_; /*! @brief Provides the main implementation of writeMetadata() by @@ -112,7 +127,14 @@ namespace Exiv2 void doWriteMetadata(BasicIo& outIo); //@} + /*! + @brief box utilities + */ std::string toAscii(long n); + std::string boxName(uint32_t box); + bool superBox(uint32_t box); + bool fullBox(uint32_t box); + }; // class BmffImage diff --git a/src/bmffimage.cpp b/src/bmffimage.cpp index be86f91870..710efc92bc 100644 --- a/src/bmffimage.cpp +++ b/src/bmffimage.cpp @@ -25,10 +25,10 @@ // included header files #include "config.h" -#include "bmffimage.hpp" -#include "tiffimage.hpp" #include "image.hpp" #include "image_int.hpp" +#include "tiffimage.hpp" +#include "bmffimage.hpp" #include "basicio.hpp" #include "error.hpp" #include "futils.hpp" @@ -64,6 +64,7 @@ struct BmffBoxHeader #define TAG_iinf 0x69696e66 /**< "iinf" Item info */ #define TAG_iloc 0x696c6f63 /**< "iloc" Item location */ #define TAG_ispe 0x69737065 /**< "ispe" Image spatial extents */ +#define TAG_infe 0x696e6665 /**< "infe" */ // ***************************************************************************** // class member definitions @@ -87,7 +88,7 @@ namespace Exiv2 } // BmffImage::BmffImage BmffImage::BmffImage(BasicIo::AutoPtr io, size_t start, size_t count) - : Image(ImageType::bmff, mdExif | mdIptc | mdXmp, io) + : Image(ImageType::bmff, mdExif | mdIptc | mdXmp, io) { UNUSED(start); UNUSED(count); @@ -104,7 +105,7 @@ namespace Exiv2 return result; } - std::string boxName(uint32_t box) + std::string BmffImage::boxName(uint32_t box) { char name[5]; std::memcpy (name,&box,4); @@ -112,17 +113,7 @@ namespace Exiv2 return std::string(name) ; } - static void boxes_check(size_t b, size_t m) - { - if ( b > m ) { -#ifdef EXIV2_DEBUG_MESSAGES - std::cout << "Exiv2::BmffImage::readMetadata box maximum exceeded" << std::endl; -#endif - throw Error(kerCorruptedMetadata); - } - } - - bool superBox(uint32_t box) + bool BmffImage::superBox(uint32_t box) { return box == TAG_moov || box == TAG_dinf @@ -134,7 +125,7 @@ namespace Exiv2 ; } - bool fullBox(uint32_t box) + bool BmffImage::fullBox(uint32_t box) { return box == TAG_meta || box == TAG_iinf @@ -146,147 +137,223 @@ namespace Exiv2 { switch (fileType) { - case TAG_avif: - return "image/avif"; - + case TAG_avif: return "image/avif"; case TAG_heic: - case TAG_heif: - return "image/heif"; - - case TAG_crx: - return "image/x-canon-cr3"; - - default: - return "image/generic"; + case TAG_heif: return "image/heif"; + case TAG_crx : return "image/x-canon-cr3"; + default : return "image/generic"; } } - void BmffImage::setComment(const std::string& /*comment*/) + long BmffImage::boxHandler(int indent /* =0 */) { - // Todo: implement me! - throw(Error(kerInvalidSettingForImage, "Image comment", "BMFF")); - } // BmffImage::setComment + long result = io_->size(); + long address = io_->tell(); + BmffBoxHeader box = {0,0}; - void BmffImage::readMetadata() - { - if (io_->open() != 0) - { - throw Error(kerDataSourceOpenFailed, io_->path(), strError()); + if ( io_->read((byte*)&box, sizeof(box)) != sizeof(box)) return result; + + box.length = getLong((byte*)&box.length, bigEndian); + box.type = getLong((byte*)&box.type, bigEndian); +#ifdef EXIV2_DEBUG_MESSAGES + bool bLF = true; + std::cout << indenter(indent) << "Exiv2::BmffImage::boxHandler: " << toAscii(box.type) + << Internal::stringFormat(" %8d->%d ",address,box.length) + ; +#endif + // TODO: This isn't right. We should check the visits earlier. + // TAG_mdat should not be processed twice + if ( box.type == TAG_mdat ) { + std::cout << std::endl; + return io_->size(); } - IoCloser closer(*io_); - // Ensure that this is the correct image type - if (!isBmffType(*io_, false)) { - if (io_->error() || io_->eof()) throw Error(kerFailedToReadImageData); - throw Error(kerNotAnImage, "BMFF"); + if ( visits_.find(address) != visits_.end() || visits_.size() > visits_max_ ) { + throw Error(kerCorruptedMetadata); + } + visits_.insert(address); + + if ( box.length == 1 ) { + DataBuf data(8); + io_->read(data.pData_,data.size_ ); + result = address + (long) getULongLong(data.pData_,littleEndian); } - long position = 0; - BmffBoxHeader box = { 0, 0 }; - size_t boxes = 0 ; - size_t boxem = 1000 ; // boxes max - uint64_t address = position; - uint64_t length = 8; - uint32_t type; + // read data in box and restore file position + long restore = io_->tell(); + DataBuf data(box.length-8); + io_->read(data.pData_,data.size_ ); + io_->seek(restore ,BasicIo::beg); + + uint32_t skip = 0 ; + uint8_t version = 0 ; + uint32_t flags = 0 ; + + if ( fullBox(box.type) ) { + flags = getLong(data.pData_+skip,bigEndian) ; // version/flags + version = (int8_t ) flags >> 24 ; + version &= 0x00ffffff ; + skip += 4 ; + } - while (io_->read((byte*)&box, sizeof(box)) == sizeof(box)) + switch (box.type) { - boxes_check(boxes++, boxem); - position = io_->tell(); - length = getLong((byte*)&box.length, bigEndian); - type = getLong((byte*)&box.type, bigEndian); + case TAG_ftyp: + { + fileType = getLong(data.pData_, bigEndian); #ifdef EXIV2_DEBUG_MESSAGES - std::cout << "Exiv2::BmffImage::readMetadata: " - << "Position: " << position - << " box type: " << toAscii(type) - << " box length: " << length - << std::endl; + std::cout << "Brand: " << toAscii(fileType); #endif - if (length == 0) - { - return; - } + } break; - if (length == 1) + + // 8.11.6.1 + case TAG_iinf: { - DataBuf data(sizeof(length)); - io().read(data.pData_, data.size_); - length = getULongLong(data.pData_, bigEndian); #ifdef EXIV2_DEBUG_MESSAGES - std::cout << "Exiv2::BmffImage::readMetadata: " - << "length " << length - << std::endl; + std::cout << std::endl; + bLF=false; #endif - } - if ((length > 8) && (static_cast(position) + length) <= io().size()) - { - switch (type) - { - case TAG_ftyp: - { - DataBuf data(static_cast(length)); - io().read(data.pData_, data.size_); - fileType = getLong(data.pData_, bigEndian); + int n = getShort(data.pData_+skip,bigEndian) ; + skip+= 2 ; + + io_->seek(skip,BasicIo::cur); + while ( n-- > 0 ) + io_->seek(boxHandler(indent+1),BasicIo::beg); + } break; + + // 8.11.6.2 + case TAG_infe : { // .__._.__hvc1_ 2 0 0 1 0 1 0 0 104 118 99 49 0 + getLong (data.pData_+skip,bigEndian) ; skip+=4; + uint16_t ID = getShort(data.pData_+skip,bigEndian) ; skip+=2; + getShort(data.pData_+skip,bigEndian) ; skip+=2; // protection + std::string name((const char*)data.pData_+skip); + if ( name.find("Exif")== 0 || name.find("Exif")== 0 ) { // "Exif" or "ExifExif" + exifID_ = ID ; + } #ifdef EXIV2_DEBUG_MESSAGES - std::string brand_ = toAscii(fileType); - std::cout << "Exiv2::BmffImage::readMetadata: " - << "Brand: " << brand_ - << std::endl; + std::cout << Internal::stringFormat("%3d ",ID) << name << " "; #endif - break; - } + } break; + + case TAG_iprp: + case TAG_ipco: + case TAG_meta: { +#ifdef EXIV2_DEBUG_MESSAGES + std::cout << std::endl; + bLF=false; +#endif + io_->seek(skip,BasicIo::cur); + while ( io_->tell() < address + skip + box.length ) { + io_->seek(boxHandler(indent+1),BasicIo::beg); + } + } break; + + // 8.11.3.1 + case TAG_iloc: { + uint8_t u = data.pData_[skip++]; + uint16_t offsetSize = u >> 4 ; + uint16_t lengthSize = u & 0xF ; + + uint16_t indexSize = 0 ; + u = data.pData_[skip++]; + if ( version == 1 || version == 2 ) { + indexSize = u & 0xF ; + } - case TAG_meta: - { - DataBuf data(static_cast(length)); - io().read(data.pData_, data.size_); + uint32_t itemCount = version < 2 ? getShort(data.pData_+skip,bigEndian) : getLong(data.pData_+skip,bigEndian); + skip += version < 2 ? 2 : 4 ; + if ( offsetSize == 4 && lengthSize == 4 && ((box.length-16) % itemCount) == 0 ) { +#ifdef EXIV2_DEBUG_MESSAGES + std::cout << std::endl; + bLF=false; +#endif + uint64_t step = (box.length-16)/itemCount ; // length of data per item. + uint64_t base = skip; + for ( uint64_t i = 0 ; i < itemCount ; i++ ) { + skip=base+i*step ; // move in 16 or 14 byte steps + uint32_t ID = version > 2 ? getLong(data.pData_+skip,bigEndian) : getShort(data.pData_+skip,bigEndian); + uint32_t offset = getLong(data.pData_+skip+step-8,bigEndian); + uint32_t ldata = getLong(data.pData_+skip+step-4,bigEndian); #ifdef EXIV2_DEBUG_MESSAGES - std::cout << "Exiv2::BmffImage::readMetadata: metadata " - << data.size_ << " bytes" - << std::endl; + std::cout << indenter(indent) + << Internal::stringFormat("%8d | %8d | ext | %4d | %6d,%6d",address+skip,step,ID,offset,ldata) + << std::endl + ; #endif - break; + if ( ID == exifID_) { + exifStart_ = offset; + exifLength_ = ldata; + } } + } + } break; - case TAG_ispe: - { - DataBuf data(static_cast(length)); - io().read(data.pData_, data.size_); + case TAG_ispe: { +#ifdef EXIV2_DEBUG_MESSAGES + pixelWidth_ = getLong(data.pData_ + skip, bigEndian); skip+=4; + pixelHeight_ = getLong(data.pData_ + skip, bigEndian); skip+=8; + std::cout << "pixelWidth, pixelHeight_ = " + << Internal::stringFormat("%d,%d",pixelWidth_, pixelHeight_) + ; +#endif + } break; - uint32_t flags = getLong(data.pData_, bigEndian); - uint8_t version = (uint8_t)(flags >> 24); - flags &= 0x00ffffff; - pixelWidth_ = getLong(data.pData_ + 4, bigEndian); - pixelHeight_ = getLong(data.pData_ + 8, bigEndian); + case TAG_mdat: { #ifdef EXIV2_DEBUG_MESSAGES - std::cout << "Exiv2::BmffImage::readMetadata: Image spatial extents " - << "version: " << version - << "flags: " << flags - << std::endl; + std::cout << "MDAT" ; #endif - break; - } + } break; - default: - { + default: {} ; /* do nothing */ + } #ifdef EXIV2_DEBUG_MESSAGES - std::cout << "Exiv2::BmffImage::readMetadata: box type: " << toAscii(type) - << " box length: " << length - << std::endl; + if ( bLF ) std::cout << std::endl; + if ( exifID_ != unknownID_ && exifStart_ && exifLength_ ) { + std::cout << indenter(indent) << Internal::stringFormat("Exif: %d->%d",exifStart_,exifLength_) << std::endl; + exifID_ = unknownID_; + } #endif - break; - } - } - } - // Move to the next box. - io_->seek(static_cast(position - sizeof(box) + length), BasicIo::beg); - if (io_->error()) - { - throw Error(kerFailedToReadImageData); - } + // return address of next box + if ( box.length != 1 ) result = static_cast(address + box.length); + + return result ; + } + + void BmffImage::setComment(const std::string& /*comment*/) + { + // Todo: implement me! + throw(Error(kerInvalidSettingForImage, "Image comment", "BMFF")); + } // BmffImage::setComment + + void BmffImage::readMetadata() + { + if (io_->open() != 0) + { + throw Error(kerDataSourceOpenFailed, io_->path(), strError()); + } + IoCloser closer(*io_); + // Ensure that this is the correct image type + if (!isBmffType(*io_, false)) { + if (io_->error() || io_->eof()) throw Error(kerFailedToReadImageData); + throw Error(kerNotAnImage, "BMFF"); } - UNUSED(address); + + visits_.clear(); + visits_max_ = io_->size() / 16; + + unknownID_ = 0xffff ; + exifID_ = unknownID_ ; + exifStart_ = 0; + exifLength_ = 0; + + long address = 0 ; + while ( address < (long) io_->size() ) { + io_->seek(address,BasicIo::beg); + address = boxHandler(); + } + } // BmffImage::readMetadata void BmffImage::printStructure(std::ostream& out, PrintStructureOption option, int depth) @@ -295,12 +362,9 @@ namespace Exiv2 throw Error(kerDataSourceOpenFailed, io_->path(), strError()); // Ensure that this is the correct image type - if (!isBmffType(*io_, false)) - { + if (!isBmffType(*io_, false)) { if (io_->error() || io_->eof()) - { throw Error(kerFailedToReadImageData); - } throw Error(kerNotAnImage); } UNUSED(out); From 630fb230462c5cbb212dbbced98d30858e3ac267 Mon Sep 17 00:00:00 2001 From: Robin Mills Date: Tue, 23 Feb 2021 20:57:41 +0000 Subject: [PATCH 17/79] Fixing a build breaker. --- src/bmffimage.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bmffimage.cpp b/src/bmffimage.cpp index 710efc92bc..5d1b80f40f 100644 --- a/src/bmffimage.cpp +++ b/src/bmffimage.cpp @@ -254,13 +254,13 @@ namespace Exiv2 uint8_t u = data.pData_[skip++]; uint16_t offsetSize = u >> 4 ; uint16_t lengthSize = u & 0xF ; - +#if 0 uint16_t indexSize = 0 ; u = data.pData_[skip++]; if ( version == 1 || version == 2 ) { indexSize = u & 0xF ; } - +#endif uint32_t itemCount = version < 2 ? getShort(data.pData_+skip,bigEndian) : getLong(data.pData_+skip,bigEndian); skip += version < 2 ? 2 : 4 ; if ( offsetSize == 4 && lengthSize == 4 && ((box.length-16) % itemCount) == 0 ) { From ea968149f26afe81256b722c5fa6e9c9a564838c Mon Sep 17 00:00:00 2001 From: Robin Mills Date: Wed, 24 Feb 2021 11:55:59 +0000 Subject: [PATCH 18/79] Fix linux/CI build breaker. --- cmake/compilerFlagsExiv2.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/compilerFlagsExiv2.cmake b/cmake/compilerFlagsExiv2.cmake index 76f00fe680..d352e38ff8 100644 --- a/cmake/compilerFlagsExiv2.cmake +++ b/cmake/compilerFlagsExiv2.cmake @@ -2,7 +2,7 @@ if (COMPILER_IS_GCC OR COMPILER_IS_CLANG) # MINGW, Linux, APPLE, CYGWIN if ( EXIV2_TEAM_WARNINGS_AS_ERRORS ) - add_compile_options(-Werror -Wno-error=deprecated-declarations) + add_compile_options(-Werror -Wno-error=deprecated-declarations -Wno-error=deprecated-copy) endif () if ( EXIV2_TEAM_EXTRA_WARNINGS ) From 0b4b7c695e6a0fd81e8c6acd43caeb2fa46ad402 Mon Sep 17 00:00:00 2001 From: Robin Mills Date: Wed, 24 Feb 2021 11:56:39 +0000 Subject: [PATCH 19/79] Fix msvc/CI build breakers. --- src/bmffimage.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) mode change 100644 => 100755 src/bmffimage.cpp diff --git a/src/bmffimage.cpp b/src/bmffimage.cpp old mode 100644 new mode 100755 index 5d1b80f40f..7b0c009e31 --- a/src/bmffimage.cpp +++ b/src/bmffimage.cpp @@ -147,8 +147,8 @@ namespace Exiv2 long BmffImage::boxHandler(int indent /* =0 */) { - long result = io_->size(); - long address = io_->tell(); + long result = (long) io_->size(); + long address = (long) io_->tell(); BmffBoxHeader box = {0,0}; if ( io_->read((byte*)&box, sizeof(box)) != sizeof(box)) return result; @@ -165,7 +165,7 @@ namespace Exiv2 // TAG_mdat should not be processed twice if ( box.type == TAG_mdat ) { std::cout << std::endl; - return io_->size(); + return result ; } if ( visits_.find(address) != visits_.end() || visits_.size() > visits_max_ ) { throw Error(kerCorruptedMetadata); @@ -244,7 +244,7 @@ namespace Exiv2 bLF=false; #endif io_->seek(skip,BasicIo::cur); - while ( io_->tell() < address + skip + box.length ) { + while ( (long) io_->tell() < (long)(address + skip + box.length) ) { io_->seek(boxHandler(indent+1),BasicIo::beg); } } break; @@ -263,14 +263,14 @@ namespace Exiv2 #endif uint32_t itemCount = version < 2 ? getShort(data.pData_+skip,bigEndian) : getLong(data.pData_+skip,bigEndian); skip += version < 2 ? 2 : 4 ; - if ( offsetSize == 4 && lengthSize == 4 && ((box.length-16) % itemCount) == 0 ) { + if ( itemCount && offsetSize == 4 && lengthSize == 4 && ((box.length-16) % itemCount) == 0 ) { #ifdef EXIV2_DEBUG_MESSAGES std::cout << std::endl; bLF=false; #endif - uint64_t step = (box.length-16)/itemCount ; // length of data per item. - uint64_t base = skip; - for ( uint64_t i = 0 ; i < itemCount ; i++ ) { + uint32_t step = (box.length-16)/itemCount ; // length of data per item. + uint32_t base = skip; + for ( uint32_t i = 0 ; i < itemCount ; i++ ) { skip=base+i*step ; // move in 16 or 14 byte steps uint32_t ID = version > 2 ? getLong(data.pData_+skip,bigEndian) : getShort(data.pData_+skip,bigEndian); uint32_t offset = getLong(data.pData_+skip+step-8,bigEndian); From 1b47e1e8f6675e4d03603259c6d91cfa6010986d Mon Sep 17 00:00:00 2001 From: Robin Mills Date: Wed, 24 Feb 2021 12:15:21 +0000 Subject: [PATCH 20/79] Fix linux/CI build breaker. --- cmake/compilerFlagsExiv2.cmake | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/cmake/compilerFlagsExiv2.cmake b/cmake/compilerFlagsExiv2.cmake index d352e38ff8..d364b69558 100644 --- a/cmake/compilerFlagsExiv2.cmake +++ b/cmake/compilerFlagsExiv2.cmake @@ -1,8 +1,14 @@ # These flags only applies to exiv2lib, and the applications, but not to the xmp code +include(CheckCXXCompilerFlag) + if (COMPILER_IS_GCC OR COMPILER_IS_CLANG) # MINGW, Linux, APPLE, CYGWIN if ( EXIV2_TEAM_WARNINGS_AS_ERRORS ) - add_compile_options(-Werror -Wno-error=deprecated-declarations -Wno-error=deprecated-copy) + add_compile_options(-Werror -Wno-error=deprecated-declarations) + check_cxx_compiler_flag(-Wno-error=deprecated-copy DEPRECATED_COPY) + if ( DEPRECATED_COPY) + add_compile_options(-Wno-error=deprecated-copy) + endif () endif () if ( EXIV2_TEAM_EXTRA_WARNINGS ) From 64866cc568190386c094de81c3ff055ffb5a9fed Mon Sep 17 00:00:00 2001 From: Robin Mills Date: Wed, 24 Feb 2021 13:11:42 +0000 Subject: [PATCH 21/79] Fixing warnings from LGTM/CI. --- src/bmffimage.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/bmffimage.cpp b/src/bmffimage.cpp index 7b0c009e31..0439dc32b7 100755 --- a/src/bmffimage.cpp +++ b/src/bmffimage.cpp @@ -158,7 +158,7 @@ namespace Exiv2 #ifdef EXIV2_DEBUG_MESSAGES bool bLF = true; std::cout << indenter(indent) << "Exiv2::BmffImage::boxHandler: " << toAscii(box.type) - << Internal::stringFormat(" %8d->%d ",address,box.length) + << Internal::stringFormat(" %8ld->%ld ",address,box.length) ; #endif // TODO: This isn't right. We should check the visits earlier. @@ -224,9 +224,9 @@ namespace Exiv2 // 8.11.6.2 case TAG_infe : { // .__._.__hvc1_ 2 0 0 1 0 1 0 0 104 118 99 49 0 - getLong (data.pData_+skip,bigEndian) ; skip+=4; - uint16_t ID = getShort(data.pData_+skip,bigEndian) ; skip+=2; - getShort(data.pData_+skip,bigEndian) ; skip+=2; // protection + /* getLong (data.pData_+skip,bigEndian) ; */ skip+=4; + uint16_t ID = getShort(data.pData_+skip,bigEndian) ; skip+=2; + /* getShort(data.pData_+skip,bigEndian) ; */ skip+=2; // protection std::string name((const char*)data.pData_+skip); if ( name.find("Exif")== 0 || name.find("Exif")== 0 ) { // "Exif" or "ExifExif" exifID_ = ID ; @@ -277,7 +277,7 @@ namespace Exiv2 uint32_t ldata = getLong(data.pData_+skip+step-4,bigEndian); #ifdef EXIV2_DEBUG_MESSAGES std::cout << indenter(indent) - << Internal::stringFormat("%8d | %8d | ext | %4d | %6d,%6d",address+skip,step,ID,offset,ldata) + << Internal::stringFormat("%8ld | %8lu | ext | %4ld | %6ld,%6ld",address+skip,step,ID,offset,ldata) << std::endl ; #endif From 8976a23f2d73453b79b705d0e0200d09a61e6d16 Mon Sep 17 00:00:00 2001 From: Robin Mills Date: Wed, 24 Feb 2021 13:44:31 +0000 Subject: [PATCH 22/79] More fixes for LGTM/CI warnings. --- src/bmffimage.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bmffimage.cpp b/src/bmffimage.cpp index 0439dc32b7..e3048e4fb3 100755 --- a/src/bmffimage.cpp +++ b/src/bmffimage.cpp @@ -158,7 +158,7 @@ namespace Exiv2 #ifdef EXIV2_DEBUG_MESSAGES bool bLF = true; std::cout << indenter(indent) << "Exiv2::BmffImage::boxHandler: " << toAscii(box.type) - << Internal::stringFormat(" %8ld->%ld ",address,box.length) + << Internal::stringFormat(" %8ld->%u ",address,box.length) ; #endif // TODO: This isn't right. We should check the visits earlier. @@ -277,7 +277,7 @@ namespace Exiv2 uint32_t ldata = getLong(data.pData_+skip+step-4,bigEndian); #ifdef EXIV2_DEBUG_MESSAGES std::cout << indenter(indent) - << Internal::stringFormat("%8ld | %8lu | ext | %4ld | %6ld,%6ld",address+skip,step,ID,offset,ldata) + << Internal::stringFormat("%8ld | %8u | ext | %4u | %6u,%6u",address+skip,step,ID,offset,ldata) << std::endl ; #endif From 8d7133d7bcb690c4595dd63c85064e15ab4edfbb Mon Sep 17 00:00:00 2001 From: Robin Mills Date: Wed, 24 Feb 2021 19:11:55 +0000 Subject: [PATCH 23/79] WIP: Added class Iloc and related code. --- include/exiv2/bmffimage.hpp | 11 +++++---- src/bmffimage.cpp | 46 +++++++++++++++++++++++++++---------- 2 files changed, 40 insertions(+), 17 deletions(-) diff --git a/include/exiv2/bmffimage.hpp b/include/exiv2/bmffimage.hpp index 24817fa623..8b9f9a552b 100644 --- a/include/exiv2/bmffimage.hpp +++ b/include/exiv2/bmffimage.hpp @@ -32,6 +32,8 @@ namespace Exiv2 { EXIV2API bool enableBMFF(bool enable = true); + class Iloc ;// We'll define this in bmffimage.cpp + // ***************************************************************************** // class definitions @@ -114,8 +116,7 @@ namespace Exiv2 uint16_t unknownID_ ; // 0xffff uint16_t exifID_ ; - uint32_t exifStart_ ; - uint32_t exifLength_; + std::map ilocs_; /*! @brief Provides the main implementation of writeMetadata() by @@ -130,10 +131,10 @@ namespace Exiv2 /*! @brief box utilities */ - std::string toAscii(long n); - std::string boxName(uint32_t box); + std::string toAscii (long n); + std::string boxName (uint32_t box); bool superBox(uint32_t box); - bool fullBox(uint32_t box); + bool fullBox (uint32_t box); }; // class BmffImage diff --git a/src/bmffimage.cpp b/src/bmffimage.cpp index e3048e4fb3..e029a774ee 100755 --- a/src/bmffimage.cpp +++ b/src/bmffimage.cpp @@ -51,7 +51,7 @@ struct BmffBoxHeader #define TAG_ftyp 0x66747970 /**< "ftyp" File type box */ #define TAG_avif 0x61766966 /**< "avif" AVIF */ -#define TAG_heic 0x68656963 /**< "heic" HEIF */ +#define TAG_heic 0x68656963 /**< "heic" HEIC */ #define TAG_heif 0x68656966 /**< "heif" HEIF */ #define TAG_crx 0x63727820 /**< "crx " Canon CR3 */ #define TAG_moov 0x6d6f6f76 /**< "moov" Movie */ @@ -64,7 +64,8 @@ struct BmffBoxHeader #define TAG_iinf 0x69696e66 /**< "iinf" Item info */ #define TAG_iloc 0x696c6f63 /**< "iloc" Item location */ #define TAG_ispe 0x69737065 /**< "ispe" Image spatial extents */ -#define TAG_infe 0x696e6665 /**< "infe" */ +#define TAG_infe 0x696e6665 /**< "infe" Item Info Extention */ +#define TAG_ipma 0x69706d61 /**< "ipma" Item Property Association */ // ***************************************************************************** // class member definitions @@ -82,6 +83,26 @@ namespace Exiv2 return enable; } + class Iloc + { + public: + Iloc(uint32_t ID,uint32_t start,uint32_t length) + : ID_ (ID) + , start_ (start ) + , length_ (length) + {}; + Iloc() : ID_(0),start_(0),length_(0) {}; // code won't compile without this on macOS + virtual ~Iloc() {} ; + + uint32_t ID_ ; + uint32_t start_ ; + uint32_t length_ ; + + std::string toString() { + return Internal::stringFormat("ID = %d from,length = %d,%d", ID_,start_,length_); + } + }; // class Iloc + BmffImage::BmffImage(BasicIo::AutoPtr io, bool /* create */) : Image(ImageType::bmff, mdExif | mdIptc | mdXmp, io) { @@ -260,10 +281,12 @@ namespace Exiv2 if ( version == 1 || version == 2 ) { indexSize = u & 0xF ; } +#else + skip++; #endif uint32_t itemCount = version < 2 ? getShort(data.pData_+skip,bigEndian) : getLong(data.pData_+skip,bigEndian); skip += version < 2 ? 2 : 4 ; - if ( itemCount && offsetSize == 4 && lengthSize == 4 && ((box.length-16) % itemCount) == 0 ) { + if ( itemCount && itemCount < box.length/14 && offsetSize == 4 && lengthSize == 4 && ((box.length-16) % itemCount) == 0 ) { #ifdef EXIV2_DEBUG_MESSAGES std::cout << std::endl; bLF=false; @@ -281,10 +304,7 @@ namespace Exiv2 << std::endl ; #endif - if ( ID == exifID_) { - exifStart_ = offset; - exifLength_ = ldata; - } + ilocs_[ID] = Iloc(ID,offset,ldata); } } } break; @@ -299,6 +319,10 @@ namespace Exiv2 #endif } break; + case TAG_ipma: { + std::cout << "IPMA" ; + } break; + case TAG_mdat: { #ifdef EXIV2_DEBUG_MESSAGES std::cout << "MDAT" ; @@ -309,8 +333,8 @@ namespace Exiv2 } #ifdef EXIV2_DEBUG_MESSAGES if ( bLF ) std::cout << std::endl; - if ( exifID_ != unknownID_ && exifStart_ && exifLength_ ) { - std::cout << indenter(indent) << Internal::stringFormat("Exif: %d->%d",exifStart_,exifLength_) << std::endl; + if ( ilocs_.find(exifID_) != ilocs_.end() ) { + std::cout << indenter(indent) << "Exiv2::BMFF Exif: " << ilocs_.find(exifID_)->second.toString() << std::endl; exifID_ = unknownID_; } #endif @@ -339,14 +363,12 @@ namespace Exiv2 if (io_->error() || io_->eof()) throw Error(kerFailedToReadImageData); throw Error(kerNotAnImage, "BMFF"); } - + ilocs_ .clear() ; visits_.clear(); visits_max_ = io_->size() / 16; unknownID_ = 0xffff ; exifID_ = unknownID_ ; - exifStart_ = 0; - exifLength_ = 0; long address = 0 ; while ( address < (long) io_->size() ) { From bafea0f1b86c65c7abecfbf597e5808bd784dd69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Kov=C3=A1=C5=99?= Date: Wed, 24 Feb 2021 21:08:53 +0100 Subject: [PATCH 24/79] [WIP] Fixed Image Spatial Extents Property Handling --- src/bmffimage.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/bmffimage.cpp b/src/bmffimage.cpp index e029a774ee..74bc370209 100755 --- a/src/bmffimage.cpp +++ b/src/bmffimage.cpp @@ -310,11 +310,12 @@ namespace Exiv2 } break; case TAG_ispe: { -#ifdef EXIV2_DEBUG_MESSAGES + skip+=4; pixelWidth_ = getLong(data.pData_ + skip, bigEndian); skip+=4; - pixelHeight_ = getLong(data.pData_ + skip, bigEndian); skip+=8; - std::cout << "pixelWidth, pixelHeight_ = " - << Internal::stringFormat("%d,%d",pixelWidth_, pixelHeight_) + pixelHeight_ = getLong(data.pData_ + skip, bigEndian); skip+=4; +#ifdef EXIV2_DEBUG_MESSAGES + std::cout << "pixelWidth_, pixelHeight_ = " + << Internal::stringFormat("%d, %d", pixelWidth_, pixelHeight_) ; #endif } break; From 4a960252949a7a54a4793d86b86bf675c17f53a0 Mon Sep 17 00:00:00 2001 From: Robin Mills Date: Wed, 24 Feb 2021 22:33:49 +0000 Subject: [PATCH 25/79] Fixed recursion issue in the meta box. --- src/bmffimage.cpp | 38 ++++++++++++++------------------------ 1 file changed, 14 insertions(+), 24 deletions(-) diff --git a/src/bmffimage.cpp b/src/bmffimage.cpp index 74bc370209..71236c53a7 100755 --- a/src/bmffimage.cpp +++ b/src/bmffimage.cpp @@ -170,8 +170,12 @@ namespace Exiv2 { long result = (long) io_->size(); long address = (long) io_->tell(); - BmffBoxHeader box = {0,0}; + if ( visits_.find(address) != visits_.end() || visits_.size() > visits_max_ ) { + throw Error(kerCorruptedMetadata); + } + visits_.insert(address); + BmffBoxHeader box = {0,0}; if ( io_->read((byte*)&box, sizeof(box)) != sizeof(box)) return result; box.length = getLong((byte*)&box.length, bigEndian); @@ -182,21 +186,16 @@ namespace Exiv2 << Internal::stringFormat(" %8ld->%u ",address,box.length) ; #endif - // TODO: This isn't right. We should check the visits earlier. - // TAG_mdat should not be processed twice - if ( box.type == TAG_mdat ) { - std::cout << std::endl; - return result ; - } - if ( visits_.find(address) != visits_.end() || visits_.size() > visits_max_ ) { - throw Error(kerCorruptedMetadata); - } - visits_.insert(address); - if ( box.length == 1 ) { DataBuf data(8); io_->read(data.pData_,data.size_ ); result = address + (long) getULongLong(data.pData_,littleEndian); + // sanity check + if ( result < 0 || result > (long) io_->size() ) { + result = (long) io_->size(); + box.length = result - address; + } + std::cout << Internal::stringFormat(" (%lu)",result); } // read data in box and restore file position @@ -205,7 +204,7 @@ namespace Exiv2 io_->read(data.pData_,data.size_ ); io_->seek(restore ,BasicIo::beg); - uint32_t skip = 0 ; + uint32_t skip = 0 ; // read position in data.pData_ uint8_t version = 0 ; uint32_t flags = 0 ; @@ -257,6 +256,7 @@ namespace Exiv2 #endif } break; + case TAG_iprp: case TAG_ipco: case TAG_meta: { @@ -265,7 +265,7 @@ namespace Exiv2 bLF=false; #endif io_->seek(skip,BasicIo::cur); - while ( (long) io_->tell() < (long)(address + skip + box.length) ) { + while ( (long) io_->tell() < (long)(address + box.length) ) { io_->seek(boxHandler(indent+1),BasicIo::beg); } } break; @@ -320,16 +320,6 @@ namespace Exiv2 #endif } break; - case TAG_ipma: { - std::cout << "IPMA" ; - } break; - - case TAG_mdat: { -#ifdef EXIV2_DEBUG_MESSAGES - std::cout << "MDAT" ; -#endif - } break; - default: {} ; /* do nothing */ } #ifdef EXIV2_DEBUG_MESSAGES From f190f496d1903a01e295257ba103c2dea33104d5 Mon Sep 17 00:00:00 2001 From: Robin Mills Date: Thu, 25 Feb 2021 05:50:54 +0000 Subject: [PATCH 26/79] Tidying up. 1. pixelHeight_. 2. refactored indenter() -> indent(). 3. EXIV2_DEBUG_MESSAGES outputs to std::cerr --- include/exiv2/bmffimage.hpp | 5 ++-- src/bmffimage.cpp | 52 ++++++++++++++++++------------------- 2 files changed, 29 insertions(+), 28 deletions(-) diff --git a/include/exiv2/bmffimage.hpp b/include/exiv2/bmffimage.hpp index 8b9f9a552b..7784e7cb12 100644 --- a/include/exiv2/bmffimage.hpp +++ b/include/exiv2/bmffimage.hpp @@ -105,14 +105,15 @@ namespace Exiv2 /*! @brief recursiveBoxHandler @throw Error if we visit a box more than once + @return address of next box @warning This function should only be called by readMetadata() */ - long boxHandler(int indent=0); + long boxHandler(int depth=0); uint32_t fileType ; std::set visits_ ; uint64_t visits_max_; - std::string indenter(int i) { std::string r; while ( i-- > 0 ) r+=std::string(" "); return r; } + std::string indent(int i) { std::string r; while ( i-- > 0 ) r+=std::string(" "); return r; } uint16_t unknownID_ ; // 0xffff uint16_t exifID_ ; diff --git a/src/bmffimage.cpp b/src/bmffimage.cpp index 71236c53a7..f190054eab 100755 --- a/src/bmffimage.cpp +++ b/src/bmffimage.cpp @@ -86,12 +86,11 @@ namespace Exiv2 class Iloc { public: - Iloc(uint32_t ID,uint32_t start,uint32_t length) + Iloc(uint32_t ID=0,uint32_t start=0,uint32_t length=0) : ID_ (ID) , start_ (start ) , length_ (length) {}; - Iloc() : ID_(0),start_(0),length_(0) {}; // code won't compile without this on macOS virtual ~Iloc() {} ; uint32_t ID_ ; @@ -106,13 +105,8 @@ namespace Exiv2 BmffImage::BmffImage(BasicIo::AutoPtr io, bool /* create */) : Image(ImageType::bmff, mdExif | mdIptc | mdXmp, io) { - } // BmffImage::BmffImage - - BmffImage::BmffImage(BasicIo::AutoPtr io, size_t start, size_t count) - : Image(ImageType::bmff, mdExif | mdIptc | mdXmp, io) - { - UNUSED(start); - UNUSED(count); + pixelWidth_ =0; + pixelHeight_ =0; } // BmffImage::BmffImage std::string BmffImage::toAscii(long n) @@ -166,7 +160,7 @@ namespace Exiv2 } } - long BmffImage::boxHandler(int indent /* =0 */) + long BmffImage::boxHandler(int depth /* =0 */) { long result = (long) io_->size(); long address = (long) io_->tell(); @@ -182,7 +176,7 @@ namespace Exiv2 box.type = getLong((byte*)&box.type, bigEndian); #ifdef EXIV2_DEBUG_MESSAGES bool bLF = true; - std::cout << indenter(indent) << "Exiv2::BmffImage::boxHandler: " << toAscii(box.type) + std::cerr << indent(depth) << "Exiv2::BmffImage::boxHandler: " << toAscii(box.type) << Internal::stringFormat(" %8ld->%u ",address,box.length) ; #endif @@ -195,7 +189,7 @@ namespace Exiv2 result = (long) io_->size(); box.length = result - address; } - std::cout << Internal::stringFormat(" (%lu)",result); + std::cerr << Internal::stringFormat(" (%lu)",result); } // read data in box and restore file position @@ -221,7 +215,7 @@ namespace Exiv2 { fileType = getLong(data.pData_, bigEndian); #ifdef EXIV2_DEBUG_MESSAGES - std::cout << "Brand: " << toAscii(fileType); + std::cerr << "Brand: " << toAscii(fileType); #endif } break; @@ -230,7 +224,7 @@ namespace Exiv2 case TAG_iinf: { #ifdef EXIV2_DEBUG_MESSAGES - std::cout << std::endl; + std::cerr << std::endl; bLF=false; #endif @@ -239,7 +233,7 @@ namespace Exiv2 io_->seek(skip,BasicIo::cur); while ( n-- > 0 ) - io_->seek(boxHandler(indent+1),BasicIo::beg); + io_->seek(boxHandler(depth+1),BasicIo::beg); } break; // 8.11.6.2 @@ -252,7 +246,7 @@ namespace Exiv2 exifID_ = ID ; } #ifdef EXIV2_DEBUG_MESSAGES - std::cout << Internal::stringFormat("%3d ",ID) << name << " "; + std::cerr << Internal::stringFormat("%3d ",ID) << name << " "; #endif } break; @@ -261,12 +255,12 @@ namespace Exiv2 case TAG_ipco: case TAG_meta: { #ifdef EXIV2_DEBUG_MESSAGES - std::cout << std::endl; + std::cerr << std::endl; bLF=false; #endif io_->seek(skip,BasicIo::cur); while ( (long) io_->tell() < (long)(address + box.length) ) { - io_->seek(boxHandler(indent+1),BasicIo::beg); + io_->seek(boxHandler(depth+1),BasicIo::beg); } } break; @@ -288,7 +282,7 @@ namespace Exiv2 skip += version < 2 ? 2 : 4 ; if ( itemCount && itemCount < box.length/14 && offsetSize == 4 && lengthSize == 4 && ((box.length-16) % itemCount) == 0 ) { #ifdef EXIV2_DEBUG_MESSAGES - std::cout << std::endl; + std::cerr << std::endl; bLF=false; #endif uint32_t step = (box.length-16)/itemCount ; // length of data per item. @@ -299,7 +293,7 @@ namespace Exiv2 uint32_t offset = getLong(data.pData_+skip+step-8,bigEndian); uint32_t ldata = getLong(data.pData_+skip+step-4,bigEndian); #ifdef EXIV2_DEBUG_MESSAGES - std::cout << indenter(indent) + std::cerr << indent(depth) << Internal::stringFormat("%8ld | %8u | ext | %4u | %6u,%6u",address+skip,step,ID,offset,ldata) << std::endl ; @@ -311,21 +305,27 @@ namespace Exiv2 case TAG_ispe: { skip+=4; - pixelWidth_ = getLong(data.pData_ + skip, bigEndian); skip+=4; - pixelHeight_ = getLong(data.pData_ + skip, bigEndian); skip+=4; + int width = (int) getLong(data.pData_ + skip, bigEndian); skip+=4; + int height = (int) getLong(data.pData_ + skip, bigEndian); skip+=4; #ifdef EXIV2_DEBUG_MESSAGES - std::cout << "pixelWidth_, pixelHeight_ = " - << Internal::stringFormat("%d, %d", pixelWidth_, pixelHeight_) + std::cerr << "pixelWidth_, pixelHeight_ = " + << Internal::stringFormat("%d, %d", width, height) ; + // HEIC files can have multiple ispe records + // Store largest width/height + if ( width > pixelWidth_ && height > pixelHeight_ ) { + pixelWidth_ = width ; + pixelHeight_ = height ; + } #endif } break; default: {} ; /* do nothing */ } #ifdef EXIV2_DEBUG_MESSAGES - if ( bLF ) std::cout << std::endl; + if ( bLF ) std::cerr << std::endl; if ( ilocs_.find(exifID_) != ilocs_.end() ) { - std::cout << indenter(indent) << "Exiv2::BMFF Exif: " << ilocs_.find(exifID_)->second.toString() << std::endl; + std::cerr << indent(depth) << "Exiv2::BMFF Exif: " << ilocs_.find(exifID_)->second.toString() << std::endl; exifID_ = unknownID_; } #endif From 29f3d5cac979fa1790271fa75f6f259708e84d9d Mon Sep 17 00:00:00 2001 From: Christoph Hasse Date: Thu, 25 Feb 2021 10:38:26 +0100 Subject: [PATCH 27/79] introduce parseTiff method to parse exif --- include/exiv2/bmffimage.hpp | 3 +- src/bmffimage.cpp | 76 ++++++++++++++++++++++++++++++++----- src/tiffcomposite_int.hpp | 15 +++++--- src/tiffimage_int.cpp | 6 +++ 4 files changed, 84 insertions(+), 16 deletions(-) diff --git a/include/exiv2/bmffimage.hpp b/include/exiv2/bmffimage.hpp index 7784e7cb12..5e2a8601c0 100644 --- a/include/exiv2/bmffimage.hpp +++ b/include/exiv2/bmffimage.hpp @@ -70,6 +70,7 @@ namespace Exiv2 BmffImage(BasicIo::AutoPtr io, size_t start, size_t count); //@} + void parseTiff(uint32_t root_tag,uint32_t length); //! @name Manipulators //@{ void readMetadata() /* override */ ; @@ -136,7 +137,7 @@ namespace Exiv2 std::string boxName (uint32_t box); bool superBox(uint32_t box); bool fullBox (uint32_t box); - + std::string uuidName(Exiv2::DataBuf& uuid); }; // class BmffImage diff --git a/src/bmffimage.cpp b/src/bmffimage.cpp index f190054eab..eeb32d5465 100755 --- a/src/bmffimage.cpp +++ b/src/bmffimage.cpp @@ -28,6 +28,7 @@ #include "image.hpp" #include "image_int.hpp" #include "tiffimage.hpp" +#include "tiffimage_int.hpp" #include "bmffimage.hpp" #include "basicio.hpp" #include "error.hpp" @@ -66,6 +67,11 @@ struct BmffBoxHeader #define TAG_ispe 0x69737065 /**< "ispe" Image spatial extents */ #define TAG_infe 0x696e6665 /**< "infe" Item Info Extention */ #define TAG_ipma 0x69706d61 /**< "ipma" Item Property Association */ +#define TAG_cmt1 0x434d5431 /**< ifd0Id */ +#define TAG_cmt2 0x434D5432 /**< exifID */ +#define TAG_cmt3 0x434D5433 /**< canonID */ +#define TAG_cmt4 0x434D5434 /**< gpsID */ + // ***************************************************************************** // class member definitions @@ -97,8 +103,8 @@ namespace Exiv2 uint32_t start_ ; uint32_t length_ ; - std::string toString() { - return Internal::stringFormat("ID = %d from,length = %d,%d", ID_,start_,length_); + std::string toString(long address=0) const { + return Internal::stringFormat("ID = %d from,length = %d,%d", ID_,start_+address,length_); } }; // class Iloc @@ -160,6 +166,18 @@ namespace Exiv2 } } + std::string BmffImage::uuidName(Exiv2::DataBuf& uuid) + { + const char* uuidCano = "\x85\xC0\xB6\x87\x82\xF\x11\xE0\x81\x11\xF4\xCE\x46\x2B\x6A\x48"; + const char* uuidXmp = "\xBE\x7A\xCF\xCB\x97\xA9\x42\xE8\x9C\x71\x99\x94\x91\xE3\xAF\xAC"; + const char* uuidCanp = "\xEA\xF4\x2B\x5E\x1C\x98\x4B\x88\xB9\xFB\xB7\xDC\x40\x6E\x4D\x16"; + const char* result = std::memcmp(uuid.pData_, uuidCano, 16) == 0 ? "cano" + : std::memcmp(uuid.pData_, uuidXmp, 16) == 0 ? "xmp" + : std::memcmp(uuid.pData_, uuidCanp, 16) == 0 ? "canp" + : "" ; + return result; + } + long BmffImage::boxHandler(int depth /* =0 */) { long result = (long) io_->size(); @@ -219,7 +237,6 @@ namespace Exiv2 #endif } break; - // 8.11.6.1 case TAG_iinf: { @@ -242,7 +259,7 @@ namespace Exiv2 uint16_t ID = getShort(data.pData_+skip,bigEndian) ; skip+=2; /* getShort(data.pData_+skip,bigEndian) ; */ skip+=2; // protection std::string name((const char*)data.pData_+skip); - if ( name.find("Exif")== 0 || name.find("Exif")== 0 ) { // "Exif" or "ExifExif" + if ( name.find("Exif")== 0 ) { // "Exif" or "ExifExif" exifID_ = ID ; } #ifdef EXIV2_DEBUG_MESSAGES @@ -251,6 +268,7 @@ namespace Exiv2 } break; + case TAG_moov: case TAG_iprp: case TAG_ipco: case TAG_meta: { @@ -262,6 +280,14 @@ namespace Exiv2 while ( (long) io_->tell() < (long)(address + box.length) ) { io_->seek(boxHandler(depth+1),BasicIo::beg); } + if ( box.type == TAG_meta && ilocs_.find(exifID_) != ilocs_.end() ) { + const Iloc& iloc = ilocs_.find(exifID_)->second; +#ifdef EXIV2_DEBUG_MESSAGES + std::cerr << indent(depth) << "Exiv2::BMFF Exif: " << iloc.toString(address+20) << std::endl; +#endif + // parseTiff(Internal::Tag::root,iloc.length_,iloc.start_+address); + exifID_ = unknownID_; + } } break; // 8.11.3.1 @@ -320,22 +346,54 @@ namespace Exiv2 #endif } break; + case TAG_uuid: + { + DataBuf uuid(16); + io_->read(uuid.pData_, uuid.size_); + std::string name = uuidName(uuid); +#ifdef EXIV2_DEBUG_MESSAGES + std::cout << " uuidName " << name; +#endif + // if we are in uuid cano we want to jump past box(8) + uuid(16) + // and enter the uuid + if (name == "cano") { + box.length = 24; + } + } break; + + case TAG_cmt1: parseTiff(Internal::Tag::root ,box.length); break; + case TAG_cmt2: parseTiff(Internal::Tag::cr3_exif,box.length); break; + case TAG_cmt3: parseTiff(Internal::Tag::cr3_mn ,box.length); break; + case TAG_cmt4: parseTiff(Internal::Tag::cr3_gps ,box.length); break; + default: {} ; /* do nothing */ } #ifdef EXIV2_DEBUG_MESSAGES if ( bLF ) std::cerr << std::endl; - if ( ilocs_.find(exifID_) != ilocs_.end() ) { - std::cerr << indent(depth) << "Exiv2::BMFF Exif: " << ilocs_.find(exifID_)->second.toString() << std::endl; - exifID_ = unknownID_; - } #endif - // return address of next box if ( box.length != 1 ) result = static_cast(address + box.length); return result ; } + void BmffImage::parseTiff(uint32_t root_tag,uint32_t length) + { + if ( length > 8 ) { + DataBuf data(length - 8); + // rawData.alloc(length - 8); + long bufRead = io_->read(data.pData_, data.size_); + + if (io_->error()) + throw Error(kerFailedToReadImageData); + if (bufRead != data.size_) + throw Error(kerInputDataReadFailed); + + Internal::TiffParserWorker::decode(exifData(), iptcData(), xmpData(), data.pData_, data.size_, root_tag, + Internal::TiffMapping::findDecoder); + } + } + void BmffImage::setComment(const std::string& /*comment*/) { // Todo: implement me! diff --git a/src/tiffcomposite_int.hpp b/src/tiffcomposite_int.hpp index 7153243b53..b23f4dd905 100644 --- a/src/tiffcomposite_int.hpp +++ b/src/tiffcomposite_int.hpp @@ -76,12 +76,15 @@ namespace Exiv2 { Special TIFF tags for the use in TIFF structures only */ namespace Tag { - const uint32_t none = 0x10000; //!< Dummy tag - const uint32_t root = 0x20000; //!< Special tag: root IFD - const uint32_t next = 0x30000; //!< Special tag: next IFD - const uint32_t all = 0x40000; //!< Special tag: all tags in a group - const uint32_t pana = 0x80000; //!< Special tag: root IFD of Panasonic RAW images - const uint32_t fuji = 0x100000; //!< Special tag: root IFD of Fujifilm RAF images + const uint32_t none = 0x10000; //!< Dummy tag + const uint32_t root = 0x20000; //!< Special tag: root IFD + const uint32_t next = 0x30000; //!< Special tag: next IFD + const uint32_t all = 0x40000; //!< Special tag: all tags in a group + const uint32_t pana = 0x80000; //!< Special tag: root IFD of Panasonic RAW images + const uint32_t fuji = 0x100000; //!< Special tag: root IFD of Fujifilm RAF images + const uint32_t cr3_exif = 0x110000; //!< Special tag: root IFD of CR3 images + const uint32_t cr3_mn = 0x120000; //!< Special tag: root IFD of CR3 images + const uint32_t cr3_gps = 0x130000; //!< Special tag: root IFD of CR3 images } /*! diff --git a/src/tiffimage_int.cpp b/src/tiffimage_int.cpp index 8007a3b385..05d32621aa 100644 --- a/src/tiffimage_int.cpp +++ b/src/tiffimage_int.cpp @@ -3,6 +3,7 @@ #include "error.hpp" #include "makernote_int.hpp" #include "sonymn_int.hpp" +#include "tags_int.hpp" #include "tiffvisitor_int.hpp" #include "i18n.h" // NLS support. @@ -1125,6 +1126,11 @@ namespace Exiv2 { { Tag::fuji, ifdIdNotSet, newTiffDirectory }, { 0xf000, fujiId, newTiffSubIfd }, + + // CR3 images + { Tag::cr3_exif, ifdIdNotSet, newTiffDirectory }, + { Tag::cr3_mn, ifdIdNotSet, newTiffDirectory }, + { Tag::cr3_gps, ifdIdNotSet, newTiffDirectory }, // IFD0 { 0x8769, ifd0Id, newTiffSubIfd }, { 0x8825, ifd0Id, newTiffSubIfd }, From 28b41f59bd954fde31f9143843616d41bb2bcc56 Mon Sep 17 00:00:00 2001 From: Christoph Hasse Date: Thu, 25 Feb 2021 10:42:38 +0100 Subject: [PATCH 28/79] run clang-format on new files --- include/exiv2/bmffimage.hpp | 68 ++++--- src/bmffimage.cpp | 351 ++++++++++++++++++------------------ 2 files changed, 212 insertions(+), 207 deletions(-) mode change 100755 => 100644 src/bmffimage.cpp diff --git a/include/exiv2/bmffimage.hpp b/include/exiv2/bmffimage.hpp index 5e2a8601c0..f29dfdff09 100644 --- a/include/exiv2/bmffimage.hpp +++ b/include/exiv2/bmffimage.hpp @@ -32,20 +32,22 @@ namespace Exiv2 { EXIV2API bool enableBMFF(bool enable = true); - class Iloc ;// We'll define this in bmffimage.cpp + class Iloc; // We'll define this in bmffimage.cpp -// ***************************************************************************** -// class definitions + // ***************************************************************************** + // class definitions // Add Base Media File Format to the supported image formats - namespace ImageType { - const int bmff = 15; //!< BMFF (bmff) image type (see class BMFF) + namespace ImageType + { + const int bmff = 15; //!< BMFF (bmff) image type (see class BMFF) } /*! @brief Class to access BMFF images. */ - class EXIV2API BmffImage : public Image { + class EXIV2API BmffImage : public Image + { public: //! @name Creators //@{ @@ -70,11 +72,11 @@ namespace Exiv2 BmffImage(BasicIo::AutoPtr io, size_t start, size_t count); //@} - void parseTiff(uint32_t root_tag,uint32_t length); + void parseTiff(uint32_t root_tag, uint32_t length); //! @name Manipulators //@{ - void readMetadata() /* override */ ; - void writeMetadata() /* override */ ; + void readMetadata() /* override */; + void writeMetadata() /* override */; /*! @brief Print out the structure of image file. @@ -82,18 +84,18 @@ namespace Exiv2 not valid (does not look like data of the specific image type). @warning This function is not thread safe and intended for exiv2 -pS for debugging. */ - void printStructure(std::ostream& out, PrintStructureOption option,int depth) /* override */ ; + void printStructure(std::ostream& out, PrintStructureOption option, int depth) /* override */; /*! @brief Todo: Not supported yet(?). Calling this function will throw an instance of Error(kerInvalidSettingForImage). */ - void setComment(const std::string& comment) /* override */ ; + void setComment(const std::string& comment) /* override */; //@} //! @name Accessors //@{ - std::string mimeType() const /* override */ ; + std::string mimeType() const /* override */; //@} #if 0 BmffImage& operator=(const BmffImage& rhs) /* = delete*/ ; @@ -109,16 +111,22 @@ namespace Exiv2 @return address of next box @warning This function should only be called by readMetadata() */ - long boxHandler(int depth=0); - - uint32_t fileType ; - std::set visits_ ; - uint64_t visits_max_; - std::string indent(int i) { std::string r; while ( i-- > 0 ) r+=std::string(" "); return r; } - - uint16_t unknownID_ ; // 0xffff - uint16_t exifID_ ; - std::map ilocs_; + long boxHandler(int depth = 0); + + uint32_t fileType; + std::set visits_; + uint64_t visits_max_; + std::string indent(int i) + { + std::string r; + while (i-- > 0) + r += std::string(" "); + return r; + } + + uint16_t unknownID_; // 0xffff + uint16_t exifID_; + std::map ilocs_; /*! @brief Provides the main implementation of writeMetadata() by @@ -133,16 +141,16 @@ namespace Exiv2 /*! @brief box utilities */ - std::string toAscii (long n); - std::string boxName (uint32_t box); - bool superBox(uint32_t box); - bool fullBox (uint32_t box); + std::string toAscii(long n); + std::string boxName(uint32_t box); + bool superBox(uint32_t box); + bool fullBox(uint32_t box); std::string uuidName(Exiv2::DataBuf& uuid); - }; // class BmffImage + }; // class BmffImage -// ***************************************************************************** -// template, inline and free functions + // ***************************************************************************** + // template, inline and free functions // These could be static private functions on Image subclasses but then // ImageFactory needs to be made a friend. @@ -155,4 +163,4 @@ namespace Exiv2 //! Check if the file iIo is a BMFF image. EXIV2API bool isBmffType(BasicIo& iIo, bool advance); -} // namespace Exiv2 +} // namespace Exiv2 diff --git a/src/bmffimage.cpp b/src/bmffimage.cpp old mode 100755 new mode 100644 index eeb32d5465..42b4dde578 --- a/src/bmffimage.cpp +++ b/src/bmffimage.cpp @@ -23,26 +23,26 @@ #define EXIV2_DEBUG_MESSAGES // included header files -#include "config.h" +#include "bmffimage.hpp" +#include "basicio.hpp" +#include "config.h" +#include "error.hpp" +#include "futils.hpp" #include "image.hpp" #include "image_int.hpp" +#include "safe_op.hpp" #include "tiffimage.hpp" #include "tiffimage_int.hpp" -#include "bmffimage.hpp" -#include "basicio.hpp" -#include "error.hpp" -#include "futils.hpp" #include "types.hpp" -#include "safe_op.hpp" #include "unused.h" // + standard includes -#include -#include -#include #include #include +#include +#include +#include struct BmffBoxHeader { @@ -54,7 +54,7 @@ struct BmffBoxHeader #define TAG_avif 0x61766966 /**< "avif" AVIF */ #define TAG_heic 0x68656963 /**< "heic" HEIC */ #define TAG_heif 0x68656966 /**< "heif" HEIF */ -#define TAG_crx 0x63727820 /**< "crx " Canon CR3 */ +#define TAG_crx 0x63727820 /**< "crx " Canon CR3 */ #define TAG_moov 0x6d6f6f76 /**< "moov" Movie */ #define TAG_meta 0x6d657461 /**< "meta" Metadata */ #define TAG_mdat 0x6d646174 /**< "mdat" Media data */ @@ -72,7 +72,6 @@ struct BmffBoxHeader #define TAG_cmt3 0x434D5433 /**< canonID */ #define TAG_cmt4 0x434D5434 /**< gpsID */ - // ***************************************************************************** // class member definitions namespace Exiv2 @@ -84,153 +83,141 @@ namespace Exiv2 #ifdef EXV_ENABLE_BMFF enabled = enable; return true; -#endif // EXV_ENABLE_BMFF - enable = false; // unused +#endif // EXV_ENABLE_BMFF + enable = false; // unused return enable; } - class Iloc + class Iloc { public: - Iloc(uint32_t ID=0,uint32_t start=0,uint32_t length=0) - : ID_ (ID) - , start_ (start ) - , length_ (length) - {}; - virtual ~Iloc() {} ; - - uint32_t ID_ ; - uint32_t start_ ; - uint32_t length_ ; - - std::string toString(long address=0) const { - return Internal::stringFormat("ID = %d from,length = %d,%d", ID_,start_+address,length_); + Iloc(uint32_t ID = 0, uint32_t start = 0, uint32_t length = 0) : ID_(ID), start_(start), length_(length){}; + virtual ~Iloc(){}; + + uint32_t ID_; + uint32_t start_; + uint32_t length_; + + std::string toString(long address = 0) const + { + return Internal::stringFormat("ID = %d from,length = %d,%d", ID_, start_ + address, length_); } - }; // class Iloc + }; // class Iloc - BmffImage::BmffImage(BasicIo::AutoPtr io, bool /* create */) - : Image(ImageType::bmff, mdExif | mdIptc | mdXmp, io) + BmffImage::BmffImage(BasicIo::AutoPtr io, bool /* create */) : Image(ImageType::bmff, mdExif | mdIptc | mdXmp, io) { - pixelWidth_ =0; - pixelHeight_ =0; - } // BmffImage::BmffImage + pixelWidth_ = 0; + pixelHeight_ = 0; + } // BmffImage::BmffImage std::string BmffImage::toAscii(long n) { - const char* p = (const char*) &n; + const char* p = (const char*)&n; std::string result; bool bBigEndian = isBigEndianPlatform(); - for ( int i = 0 ; i < 4 ; i++) { - result += p[ bBigEndian ? i : (3-i) ]; + for (int i = 0; i < 4; i++) { + result += p[bBigEndian ? i : (3 - i)]; } return result; } std::string BmffImage::boxName(uint32_t box) { - char name[5]; - std::memcpy (name,&box,4); - name[4] = 0 ; - return std::string(name) ; + char name[5]; + std::memcpy(name, &box, 4); + name[4] = 0; + return std::string(name); } bool BmffImage::superBox(uint32_t box) { - return box == TAG_moov - || box == TAG_dinf - || box == TAG_iprp - || box == TAG_ipco - || box == TAG_meta - || box == TAG_iinf - || box == TAG_iloc - ; + return box == TAG_moov || box == TAG_dinf || box == TAG_iprp || box == TAG_ipco || box == TAG_meta || + box == TAG_iinf || box == TAG_iloc; } bool BmffImage::fullBox(uint32_t box) { - return box == TAG_meta - || box == TAG_iinf - || box == TAG_iloc - ; + return box == TAG_meta || box == TAG_iinf || box == TAG_iloc; } std::string BmffImage::mimeType() const { - switch (fileType) - { - case TAG_avif: return "image/avif"; + switch (fileType) { + case TAG_avif: + return "image/avif"; case TAG_heic: - case TAG_heif: return "image/heif"; - case TAG_crx : return "image/x-canon-cr3"; - default : return "image/generic"; + case TAG_heif: + return "image/heif"; + case TAG_crx: + return "image/x-canon-cr3"; + default: + return "image/generic"; } } std::string BmffImage::uuidName(Exiv2::DataBuf& uuid) { const char* uuidCano = "\x85\xC0\xB6\x87\x82\xF\x11\xE0\x81\x11\xF4\xCE\x46\x2B\x6A\x48"; - const char* uuidXmp = "\xBE\x7A\xCF\xCB\x97\xA9\x42\xE8\x9C\x71\x99\x94\x91\xE3\xAF\xAC"; + const char* uuidXmp = "\xBE\x7A\xCF\xCB\x97\xA9\x42\xE8\x9C\x71\x99\x94\x91\xE3\xAF\xAC"; const char* uuidCanp = "\xEA\xF4\x2B\x5E\x1C\x98\x4B\x88\xB9\xFB\xB7\xDC\x40\x6E\x4D\x16"; - const char* result = std::memcmp(uuid.pData_, uuidCano, 16) == 0 ? "cano" - : std::memcmp(uuid.pData_, uuidXmp, 16) == 0 ? "xmp" + const char* result = std::memcmp(uuid.pData_, uuidCano, 16) == 0 ? "cano" + : std::memcmp(uuid.pData_, uuidXmp, 16) == 0 ? "xmp" : std::memcmp(uuid.pData_, uuidCanp, 16) == 0 ? "canp" - : "" ; + : ""; return result; } long BmffImage::boxHandler(int depth /* =0 */) { - long result = (long) io_->size(); - long address = (long) io_->tell(); - if ( visits_.find(address) != visits_.end() || visits_.size() > visits_max_ ) { + long result = (long)io_->size(); + long address = (long)io_->tell(); + if (visits_.find(address) != visits_.end() || visits_.size() > visits_max_) { throw Error(kerCorruptedMetadata); } visits_.insert(address); - BmffBoxHeader box = {0,0}; - if ( io_->read((byte*)&box, sizeof(box)) != sizeof(box)) return result; + BmffBoxHeader box = {0, 0}; + if (io_->read((byte*)&box, sizeof(box)) != sizeof(box)) + return result; box.length = getLong((byte*)&box.length, bigEndian); - box.type = getLong((byte*)&box.type, bigEndian); + box.type = getLong((byte*)&box.type, bigEndian); #ifdef EXIV2_DEBUG_MESSAGES bool bLF = true; std::cerr << indent(depth) << "Exiv2::BmffImage::boxHandler: " << toAscii(box.type) - << Internal::stringFormat(" %8ld->%u ",address,box.length) - ; + << Internal::stringFormat(" %8ld->%u ", address, box.length); #endif - if ( box.length == 1 ) { + if (box.length == 1) { DataBuf data(8); - io_->read(data.pData_,data.size_ ); - result = address + (long) getULongLong(data.pData_,littleEndian); + io_->read(data.pData_, data.size_); + result = address + (long)getULongLong(data.pData_, littleEndian); // sanity check - if ( result < 0 || result > (long) io_->size() ) { - result = (long) io_->size(); - box.length = result - address; + if (result < 0 || result > (long)io_->size()) { + result = (long)io_->size(); + box.length = result - address; } - std::cerr << Internal::stringFormat(" (%lu)",result); + std::cerr << Internal::stringFormat(" (%lu)", result); } // read data in box and restore file position - long restore = io_->tell(); - DataBuf data(box.length-8); - io_->read(data.pData_,data.size_ ); - io_->seek(restore ,BasicIo::beg); - - uint32_t skip = 0 ; // read position in data.pData_ - uint8_t version = 0 ; - uint32_t flags = 0 ; - - if ( fullBox(box.type) ) { - flags = getLong(data.pData_+skip,bigEndian) ; // version/flags - version = (int8_t ) flags >> 24 ; - version &= 0x00ffffff ; - skip += 4 ; + long restore = io_->tell(); + DataBuf data(box.length - 8); + io_->read(data.pData_, data.size_); + io_->seek(restore, BasicIo::beg); + + uint32_t skip = 0; // read position in data.pData_ + uint8_t version = 0; + uint32_t flags = 0; + + if (fullBox(box.type)) { + flags = getLong(data.pData_ + skip, bigEndian); // version/flags + version = (int8_t)flags >> 24; + version &= 0x00ffffff; + skip += 4; } - switch (box.type) - { - case TAG_ftyp: - { + switch (box.type) { + case TAG_ftyp: { fileType = getLong(data.pData_, bigEndian); #ifdef EXIV2_DEBUG_MESSAGES std::cerr << "Brand: " << toAscii(fileType); @@ -238,52 +225,51 @@ namespace Exiv2 } break; // 8.11.6.1 - case TAG_iinf: - { + case TAG_iinf: { #ifdef EXIV2_DEBUG_MESSAGES std::cerr << std::endl; - bLF=false; + bLF = false; #endif - int n = getShort(data.pData_+skip,bigEndian) ; - skip+= 2 ; + int n = getShort(data.pData_ + skip, bigEndian); + skip += 2; - io_->seek(skip,BasicIo::cur); - while ( n-- > 0 ) - io_->seek(boxHandler(depth+1),BasicIo::beg); + io_->seek(skip, BasicIo::cur); + while (n-- > 0) + io_->seek(boxHandler(depth + 1), BasicIo::beg); } break; // 8.11.6.2 - case TAG_infe : { // .__._.__hvc1_ 2 0 0 1 0 1 0 0 104 118 99 49 0 - /* getLong (data.pData_+skip,bigEndian) ; */ skip+=4; - uint16_t ID = getShort(data.pData_+skip,bigEndian) ; skip+=2; - /* getShort(data.pData_+skip,bigEndian) ; */ skip+=2; // protection - std::string name((const char*)data.pData_+skip); - if ( name.find("Exif")== 0 ) { // "Exif" or "ExifExif" - exifID_ = ID ; + case TAG_infe: { // .__._.__hvc1_ 2 0 0 1 0 1 0 0 104 118 99 49 0 + /* getLong (data.pData_+skip,bigEndian) ; */ skip += 4; + uint16_t ID = getShort(data.pData_ + skip, bigEndian); + skip += 2; + /* getShort(data.pData_+skip,bigEndian) ; */ skip += 2; // protection + std::string name((const char*)data.pData_ + skip); + if (name.find("Exif") == 0) { // "Exif" or "ExifExif" + exifID_ = ID; } #ifdef EXIV2_DEBUG_MESSAGES - std::cerr << Internal::stringFormat("%3d ",ID) << name << " "; + std::cerr << Internal::stringFormat("%3d ", ID) << name << " "; #endif } break; - case TAG_moov: case TAG_iprp: case TAG_ipco: case TAG_meta: { #ifdef EXIV2_DEBUG_MESSAGES std::cerr << std::endl; - bLF=false; + bLF = false; #endif - io_->seek(skip,BasicIo::cur); - while ( (long) io_->tell() < (long)(address + box.length) ) { - io_->seek(boxHandler(depth+1),BasicIo::beg); + io_->seek(skip, BasicIo::cur); + while ((long)io_->tell() < (long)(address + box.length)) { + io_->seek(boxHandler(depth + 1), BasicIo::beg); } - if ( box.type == TAG_meta && ilocs_.find(exifID_) != ilocs_.end() ) { + if (box.type == TAG_meta && ilocs_.find(exifID_) != ilocs_.end()) { const Iloc& iloc = ilocs_.find(exifID_)->second; #ifdef EXIV2_DEBUG_MESSAGES - std::cerr << indent(depth) << "Exiv2::BMFF Exif: " << iloc.toString(address+20) << std::endl; + std::cerr << indent(depth) << "Exiv2::BMFF Exif: " << iloc.toString(address + 20) << std::endl; #endif // parseTiff(Internal::Tag::root,iloc.length_,iloc.start_+address); exifID_ = unknownID_; @@ -292,9 +278,9 @@ namespace Exiv2 // 8.11.3.1 case TAG_iloc: { - uint8_t u = data.pData_[skip++]; - uint16_t offsetSize = u >> 4 ; - uint16_t lengthSize = u & 0xF ; + uint8_t u = data.pData_[skip++]; + uint16_t offsetSize = u >> 4; + uint16_t lengthSize = u & 0xF; #if 0 uint16_t indexSize = 0 ; u = data.pData_[skip++]; @@ -304,50 +290,52 @@ namespace Exiv2 #else skip++; #endif - uint32_t itemCount = version < 2 ? getShort(data.pData_+skip,bigEndian) : getLong(data.pData_+skip,bigEndian); - skip += version < 2 ? 2 : 4 ; - if ( itemCount && itemCount < box.length/14 && offsetSize == 4 && lengthSize == 4 && ((box.length-16) % itemCount) == 0 ) { + uint32_t itemCount = + version < 2 ? getShort(data.pData_ + skip, bigEndian) : getLong(data.pData_ + skip, bigEndian); + skip += version < 2 ? 2 : 4; + if (itemCount && itemCount < box.length / 14 && offsetSize == 4 && lengthSize == 4 && + ((box.length - 16) % itemCount) == 0) { #ifdef EXIV2_DEBUG_MESSAGES std::cerr << std::endl; - bLF=false; + bLF = false; #endif - uint32_t step = (box.length-16)/itemCount ; // length of data per item. + uint32_t step = (box.length - 16) / itemCount; // length of data per item. uint32_t base = skip; - for ( uint32_t i = 0 ; i < itemCount ; i++ ) { - skip=base+i*step ; // move in 16 or 14 byte steps - uint32_t ID = version > 2 ? getLong(data.pData_+skip,bigEndian) : getShort(data.pData_+skip,bigEndian); - uint32_t offset = getLong(data.pData_+skip+step-8,bigEndian); - uint32_t ldata = getLong(data.pData_+skip+step-4,bigEndian); + for (uint32_t i = 0; i < itemCount; i++) { + skip = base + i * step; // move in 16 or 14 byte steps + uint32_t ID = version > 2 ? getLong(data.pData_ + skip, bigEndian) + : getShort(data.pData_ + skip, bigEndian); + uint32_t offset = getLong(data.pData_ + skip + step - 8, bigEndian); + uint32_t ldata = getLong(data.pData_ + skip + step - 4, bigEndian); #ifdef EXIV2_DEBUG_MESSAGES std::cerr << indent(depth) - << Internal::stringFormat("%8ld | %8u | ext | %4u | %6u,%6u",address+skip,step,ID,offset,ldata) - << std::endl - ; + << Internal::stringFormat("%8ld | %8u | ext | %4u | %6u,%6u", address + skip, step, + ID, offset, ldata) + << std::endl; #endif - ilocs_[ID] = Iloc(ID,offset,ldata); + ilocs_[ID] = Iloc(ID, offset, ldata); } } } break; case TAG_ispe: { - skip+=4; - int width = (int) getLong(data.pData_ + skip, bigEndian); skip+=4; - int height = (int) getLong(data.pData_ + skip, bigEndian); skip+=4; + skip += 4; + int width = (int)getLong(data.pData_ + skip, bigEndian); + skip += 4; + int height = (int)getLong(data.pData_ + skip, bigEndian); + skip += 4; #ifdef EXIV2_DEBUG_MESSAGES - std::cerr << "pixelWidth_, pixelHeight_ = " - << Internal::stringFormat("%d, %d", width, height) - ; + std::cerr << "pixelWidth_, pixelHeight_ = " << Internal::stringFormat("%d, %d", width, height); // HEIC files can have multiple ispe records // Store largest width/height - if ( width > pixelWidth_ && height > pixelHeight_ ) { - pixelWidth_ = width ; - pixelHeight_ = height ; + if (width > pixelWidth_ && height > pixelHeight_) { + pixelWidth_ = width; + pixelHeight_ = height; } #endif } break; - case TAG_uuid: - { + case TAG_uuid: { DataBuf uuid(16); io_->read(uuid.pData_, uuid.size_); std::string name = uuidName(uuid); @@ -361,26 +349,37 @@ namespace Exiv2 } } break; - case TAG_cmt1: parseTiff(Internal::Tag::root ,box.length); break; - case TAG_cmt2: parseTiff(Internal::Tag::cr3_exif,box.length); break; - case TAG_cmt3: parseTiff(Internal::Tag::cr3_mn ,box.length); break; - case TAG_cmt4: parseTiff(Internal::Tag::cr3_gps ,box.length); break; - - default: {} ; /* do nothing */ + case TAG_cmt1: + parseTiff(Internal::Tag::root, box.length); + break; + case TAG_cmt2: + parseTiff(Internal::Tag::cr3_exif, box.length); + break; + case TAG_cmt3: + parseTiff(Internal::Tag::cr3_mn, box.length); + break; + case TAG_cmt4: + parseTiff(Internal::Tag::cr3_gps, box.length); + break; + + default: { + }; /* do nothing */ } #ifdef EXIV2_DEBUG_MESSAGES - if ( bLF ) std::cerr << std::endl; + if (bLF) + std::cerr << std::endl; #endif // return address of next box - if ( box.length != 1 ) result = static_cast(address + box.length); + if (box.length != 1) + result = static_cast(address + box.length); - return result ; + return result; } - void BmffImage::parseTiff(uint32_t root_tag,uint32_t length) + void BmffImage::parseTiff(uint32_t root_tag, uint32_t length) { - if ( length > 8 ) { - DataBuf data(length - 8); + if (length > 8) { + DataBuf data(length - 8); // rawData.alloc(length - 8); long bufRead = io_->read(data.pData_, data.size_); @@ -390,7 +389,7 @@ namespace Exiv2 throw Error(kerInputDataReadFailed); Internal::TiffParserWorker::decode(exifData(), iptcData(), xmpData(), data.pData_, data.size_, root_tag, - Internal::TiffMapping::findDecoder); + Internal::TiffMapping::findDecoder); } } @@ -398,34 +397,34 @@ namespace Exiv2 { // Todo: implement me! throw(Error(kerInvalidSettingForImage, "Image comment", "BMFF")); - } // BmffImage::setComment + } // BmffImage::setComment void BmffImage::readMetadata() { - if (io_->open() != 0) - { + if (io_->open() != 0) { throw Error(kerDataSourceOpenFailed, io_->path(), strError()); } IoCloser closer(*io_); // Ensure that this is the correct image type if (!isBmffType(*io_, false)) { - if (io_->error() || io_->eof()) throw Error(kerFailedToReadImageData); + if (io_->error() || io_->eof()) + throw Error(kerFailedToReadImageData); throw Error(kerNotAnImage, "BMFF"); } - ilocs_ .clear() ; + ilocs_.clear(); visits_.clear(); visits_max_ = io_->size() / 16; - unknownID_ = 0xffff ; - exifID_ = unknownID_ ; + unknownID_ = 0xffff; + exifID_ = unknownID_; - long address = 0 ; - while ( address < (long) io_->size() ) { - io_->seek(address,BasicIo::beg); + long address = 0; + while (address < (long)io_->size()) { + io_->seek(address, BasicIo::beg); address = boxHandler(); } - } // BmffImage::readMetadata + } // BmffImage::readMetadata void BmffImage::printStructure(std::ostream& out, PrintStructureOption option, int depth) { @@ -441,19 +440,18 @@ namespace Exiv2 UNUSED(out); UNUSED(option); UNUSED(depth); - } // BmffImage::printStructure + } // BmffImage::printStructure void BmffImage::writeMetadata() { - } // BmffImage::writeMetadata + } // BmffImage::writeMetadata // ************************************************************************* // free functions Image::AutoPtr newBmffInstance(BasicIo::AutoPtr io, bool create) { Image::AutoPtr image(new BmffImage(io, create)); - if (!image->good()) - { + if (!image->good()) { image.reset(); } return image; @@ -461,8 +459,7 @@ namespace Exiv2 bool isBmffType(BasicIo& iIo, bool advance) { - if (!enabled) - { + if (!enabled) { return false; } const int32_t len = 12; @@ -478,4 +475,4 @@ namespace Exiv2 } return matched; } -} // namespace Exiv2 +} // namespace Exiv2 From 108670b30994f5c2d92b550d4bf5648caaa169ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Kov=C3=A1=C5=99?= Date: Thu, 25 Feb 2021 11:18:51 +0100 Subject: [PATCH 29/79] Corrected format string --- src/bmffimage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bmffimage.cpp b/src/bmffimage.cpp index 42b4dde578..28973ee2bb 100644 --- a/src/bmffimage.cpp +++ b/src/bmffimage.cpp @@ -100,7 +100,7 @@ namespace Exiv2 std::string toString(long address = 0) const { - return Internal::stringFormat("ID = %d from,length = %d,%d", ID_, start_ + address, length_); + return Internal::stringFormat("ID = %d from,length = %ld,%d", ID_, start_ + address, length_); } }; // class Iloc From 4ff8fcdb5d87e30ee2cc57f3f7b563f91cd3c01d Mon Sep 17 00:00:00 2001 From: Robin Mills Date: Thu, 25 Feb 2021 12:27:43 +0000 Subject: [PATCH 30/79] Updating .gitignore. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 66f2fe2588..d3090138aa 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ xcode_build* msvc_build* cygwin_build* mingw_build* +linux_build* po/POTFILES po/remove-potcdate.sed po/stamp-po From 913ee33372317ba75a4e3e8e07ce9e18db7414aa Mon Sep 17 00:00:00 2001 From: Robin Mills Date: Thu, 25 Feb 2021 12:28:50 +0000 Subject: [PATCH 31/79] Parse Exif in .HEIC/.AVIF --- include/exiv2/bmffimage.hpp | 1 + src/bmffimage.cpp | 38 ++++++++++++++++++++++++++++++------- 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/include/exiv2/bmffimage.hpp b/include/exiv2/bmffimage.hpp index f29dfdff09..bc9ccb0d40 100644 --- a/include/exiv2/bmffimage.hpp +++ b/include/exiv2/bmffimage.hpp @@ -73,6 +73,7 @@ namespace Exiv2 //@} void parseTiff(uint32_t root_tag, uint32_t length); + void parseTiff(uint32_t root_tag, uint32_t length,uint32_t start); //! @name Manipulators //@{ void readMetadata() /* override */; diff --git a/src/bmffimage.cpp b/src/bmffimage.cpp index 28973ee2bb..f2ba6e821b 100644 --- a/src/bmffimage.cpp +++ b/src/bmffimage.cpp @@ -98,9 +98,9 @@ namespace Exiv2 uint32_t start_; uint32_t length_; - std::string toString(long address = 0) const + std::string toString() const { - return Internal::stringFormat("ID = %d from,length = %ld,%d", ID_, start_ + address, length_); + return Internal::stringFormat("ID = %d from,length = %ld,%d", ID_, start_, length_); } }; // class Iloc @@ -269,10 +269,10 @@ namespace Exiv2 if (box.type == TAG_meta && ilocs_.find(exifID_) != ilocs_.end()) { const Iloc& iloc = ilocs_.find(exifID_)->second; #ifdef EXIV2_DEBUG_MESSAGES - std::cerr << indent(depth) << "Exiv2::BMFF Exif: " << iloc.toString(address + 20) << std::endl; + std::cerr << indent(depth) << "Exiv2::BMFF Exif: " << iloc.toString() << std::endl; #endif - // parseTiff(Internal::Tag::root,iloc.length_,iloc.start_+address); - exifID_ = unknownID_; + parseTiff(Internal::Tag::root,iloc.length_,iloc.start_); + exifID_ = unknownID_; // don't do this again! } } break; @@ -376,11 +376,34 @@ namespace Exiv2 return result; } + void BmffImage::parseTiff(uint32_t root_tag, uint32_t length,uint32_t start) + { + // read and parse exif data + long restore = io_->tell(); + DataBuf exif(length); + io_->seek(start,BasicIo::beg); + if ( exif.size_ > 8 && io_->read(exif.pData_,exif.size_) == exif.size_ ) { + // hunt for "II" or "MM" + long eof = 0xffffffff; // impossible value for punt + long punt = eof; + for ( long i = 0 ; i < exif.size_ -8 && punt==eof ; i+=2) { + if ( exif.pData_[i] == exif.pData_[i+1] ) + if ( exif.pData_[i] == 'I' || exif.pData_[i] == 'M' ) + punt = i; + } + if ( punt != eof ) { + Internal::TiffParserWorker::decode(exifData(), iptcData(), xmpData(), + exif.pData_+punt, exif.size_-punt, root_tag, + Internal::TiffMapping::findDecoder); + } + } + io_->seek(restore,BasicIo::beg); + } + void BmffImage::parseTiff(uint32_t root_tag, uint32_t length) { if (length > 8) { DataBuf data(length - 8); - // rawData.alloc(length - 8); long bufRead = io_->read(data.pData_, data.size_); if (io_->error()) @@ -388,7 +411,8 @@ namespace Exiv2 if (bufRead != data.size_) throw Error(kerInputDataReadFailed); - Internal::TiffParserWorker::decode(exifData(), iptcData(), xmpData(), data.pData_, data.size_, root_tag, + Internal::TiffParserWorker::decode(exifData(), iptcData(), xmpData(), + data.pData_, data.size_, root_tag, Internal::TiffMapping::findDecoder); } } From 9515e4658b6008f3c5048d273e89e5aa5121bef0 Mon Sep 17 00:00:00 2001 From: Robin Mills Date: Thu, 25 Feb 2021 14:47:20 +0000 Subject: [PATCH 32/79] Cleanup. 1. Recursively process uuid/cano box. 2. Fix LGTM/CI sprintf grumbles. 3. Comment parseTiff() in bmffimage.hpp. --- include/exiv2/bmffimage.hpp | 10 ++++++++++ src/bmffimage.cpp | 18 +++++++++--------- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/include/exiv2/bmffimage.hpp b/include/exiv2/bmffimage.hpp index bc9ccb0d40..cfefea132b 100644 --- a/include/exiv2/bmffimage.hpp +++ b/include/exiv2/bmffimage.hpp @@ -72,8 +72,18 @@ namespace Exiv2 BmffImage(BasicIo::AutoPtr io, size_t start, size_t count); //@} + //@{ + /*! + @brief parse embedded tiff file + @param root_tag root of parse tree Tag::root, Tag::cr3_exif etc. + @param length tiff block length + @param start offset in file (default, io_->tell()) + @ + */ void parseTiff(uint32_t root_tag, uint32_t length); void parseTiff(uint32_t root_tag, uint32_t length,uint32_t start); + //@} + //! @name Manipulators //@{ void readMetadata() /* override */; diff --git a/src/bmffimage.cpp b/src/bmffimage.cpp index f2ba6e821b..595ccf7df6 100644 --- a/src/bmffimage.cpp +++ b/src/bmffimage.cpp @@ -100,7 +100,7 @@ namespace Exiv2 std::string toString() const { - return Internal::stringFormat("ID = %d from,length = %ld,%d", ID_, start_, length_); + return Internal::stringFormat("ID = %u from,length = %u,%u", ID_, start_, length_); } }; // class Iloc @@ -220,7 +220,7 @@ namespace Exiv2 case TAG_ftyp: { fileType = getLong(data.pData_, bigEndian); #ifdef EXIV2_DEBUG_MESSAGES - std::cerr << "Brand: " << toAscii(fileType); + std::cerr << "brand: " << toAscii(fileType); #endif } break; @@ -336,16 +336,17 @@ namespace Exiv2 } break; case TAG_uuid: { - DataBuf uuid(16); + DataBuf uuid(16); io_->read(uuid.pData_, uuid.size_); std::string name = uuidName(uuid); #ifdef EXIV2_DEBUG_MESSAGES - std::cout << " uuidName " << name; + std::cerr << " uuidName " << name << std::endl; + bLF = false; #endif - // if we are in uuid cano we want to jump past box(8) + uuid(16) - // and enter the uuid if (name == "cano") { - box.length = 24; + while ((long)io_->tell() < (long)(address + box.length)) { + io_->seek(boxHandler(depth + 1), BasicIo::beg); + } } } break; @@ -362,8 +363,7 @@ namespace Exiv2 parseTiff(Internal::Tag::cr3_gps, box.length); break; - default: { - }; /* do nothing */ + default: break ; /* do nothing */ } #ifdef EXIV2_DEBUG_MESSAGES if (bLF) From 4ae0a1d2a36fb11a88753eab718791c318953fd2 Mon Sep 17 00:00:00 2001 From: Robin Mills Date: Thu, 25 Feb 2021 15:25:09 +0000 Subject: [PATCH 33/79] Tidy up. Rename Tag::cr3_exif -> Tag:cmt2 --- include/exiv2/bmffimage.hpp | 2 +- src/bmffimage.cpp | 6 +++--- src/tiffcomposite_int.hpp | 6 +++--- src/tiffimage_int.cpp | 8 ++++---- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/include/exiv2/bmffimage.hpp b/include/exiv2/bmffimage.hpp index cfefea132b..67e09e3e2a 100644 --- a/include/exiv2/bmffimage.hpp +++ b/include/exiv2/bmffimage.hpp @@ -75,7 +75,7 @@ namespace Exiv2 //@{ /*! @brief parse embedded tiff file - @param root_tag root of parse tree Tag::root, Tag::cr3_exif etc. + @param root_tag root of parse tree Tag::root, Tag::cmt2 etc. @param length tiff block length @param start offset in file (default, io_->tell()) @ diff --git a/src/bmffimage.cpp b/src/bmffimage.cpp index 595ccf7df6..b99f7dee2f 100644 --- a/src/bmffimage.cpp +++ b/src/bmffimage.cpp @@ -354,13 +354,13 @@ namespace Exiv2 parseTiff(Internal::Tag::root, box.length); break; case TAG_cmt2: - parseTiff(Internal::Tag::cr3_exif, box.length); + parseTiff(Internal::Tag::cmt2, box.length); break; case TAG_cmt3: - parseTiff(Internal::Tag::cr3_mn, box.length); + parseTiff(Internal::Tag::cmt3, box.length); break; case TAG_cmt4: - parseTiff(Internal::Tag::cr3_gps, box.length); + parseTiff(Internal::Tag::cmt4, box.length); break; default: break ; /* do nothing */ diff --git a/src/tiffcomposite_int.hpp b/src/tiffcomposite_int.hpp index b23f4dd905..f51bbbf3cc 100644 --- a/src/tiffcomposite_int.hpp +++ b/src/tiffcomposite_int.hpp @@ -82,9 +82,9 @@ namespace Exiv2 { const uint32_t all = 0x40000; //!< Special tag: all tags in a group const uint32_t pana = 0x80000; //!< Special tag: root IFD of Panasonic RAW images const uint32_t fuji = 0x100000; //!< Special tag: root IFD of Fujifilm RAF images - const uint32_t cr3_exif = 0x110000; //!< Special tag: root IFD of CR3 images - const uint32_t cr3_mn = 0x120000; //!< Special tag: root IFD of CR3 images - const uint32_t cr3_gps = 0x130000; //!< Special tag: root IFD of CR3 images + const uint32_t cmt2 = 0x110000; //!< Special tag: root IFD of CR3 images + const uint32_t cmt3 = 0x120000; //!< Special tag: root IFD of CR3 images + const uint32_t cmt4 = 0x130000; //!< Special tag: root IFD of CR3 images } /*! diff --git a/src/tiffimage_int.cpp b/src/tiffimage_int.cpp index 05d32621aa..c31ed754f9 100644 --- a/src/tiffimage_int.cpp +++ b/src/tiffimage_int.cpp @@ -1126,11 +1126,11 @@ namespace Exiv2 { { Tag::fuji, ifdIdNotSet, newTiffDirectory }, { 0xf000, fujiId, newTiffSubIfd }, + // CR3 images #1475 + { Tag::cmt2, ifdIdNotSet, newTiffDirectory }, + { Tag::cmt3, ifdIdNotSet, newTiffDirectory }, + { Tag::cmt4, ifdIdNotSet, newTiffDirectory }, - // CR3 images - { Tag::cr3_exif, ifdIdNotSet, newTiffDirectory }, - { Tag::cr3_mn, ifdIdNotSet, newTiffDirectory }, - { Tag::cr3_gps, ifdIdNotSet, newTiffDirectory }, // IFD0 { 0x8769, ifd0Id, newTiffSubIfd }, { 0x8825, ifd0Id, newTiffSubIfd }, From 4d3af08ad8a2cbb48943ec2117358f1184c0ddf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Kov=C3=A1=C5=99?= Date: Thu, 25 Feb 2021 18:42:34 +0100 Subject: [PATCH 34/79] Add CR3 image dimensions --- include/exiv2/bmffimage.hpp | 2 ++ src/bmffimage.cpp | 20 +++++++++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/include/exiv2/bmffimage.hpp b/include/exiv2/bmffimage.hpp index 67e09e3e2a..f241afe861 100644 --- a/include/exiv2/bmffimage.hpp +++ b/include/exiv2/bmffimage.hpp @@ -107,6 +107,8 @@ namespace Exiv2 //! @name Accessors //@{ std::string mimeType() const /* override */; + int pixelWidth() const; + int pixelHeight() const; //@} #if 0 BmffImage& operator=(const BmffImage& rhs) /* = delete*/ ; diff --git a/src/bmffimage.cpp b/src/bmffimage.cpp index b99f7dee2f..954366ce4b 100644 --- a/src/bmffimage.cpp +++ b/src/bmffimage.cpp @@ -155,6 +155,25 @@ namespace Exiv2 } } + int BmffImage::pixelWidth() const + { + ExifData::const_iterator imageWidth = exifData_.findKey(Exiv2::ExifKey("Exif.Photo.PixelXDimension")); + if (imageWidth != exifData_.end() && imageWidth->count() > 0) { + return imageWidth->toLong(); + } + return 0; + } + + int BmffImage::pixelHeight() const + { + ExifData::const_iterator imageHeight = exifData_.findKey(Exiv2::ExifKey("Exif.Photo.PixelYDimension")); + if (imageHeight != exifData_.end() && imageHeight->count() > 0) { + return imageHeight->toLong(); + } + return 0; + } + + std::string BmffImage::uuidName(Exiv2::DataBuf& uuid) { const char* uuidCano = "\x85\xC0\xB6\x87\x82\xF\x11\xE0\x81\x11\xF4\xCE\x46\x2B\x6A\x48"; @@ -447,7 +466,6 @@ namespace Exiv2 io_->seek(address, BasicIo::beg); address = boxHandler(); } - } // BmffImage::readMetadata void BmffImage::printStructure(std::ostream& out, PrintStructureOption option, int depth) From 3ed67d32298833734a92d3b9f19dce6db95fc2e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Kov=C3=A1=C5=99?= Date: Thu, 25 Feb 2021 18:53:58 +0100 Subject: [PATCH 35/79] Update README.md Add BMFF support build option --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 9875d918a0..d8b98fe563 100644 --- a/README.md +++ b/README.md @@ -127,6 +127,7 @@ option( EXIV2_ENABLE_XMP "Build with XMP metadata support" ON option( EXIV2_ENABLE_EXTERNAL_XMP "Use external version of XMP" OFF ) option( EXIV2_ENABLE_PNG "Build with png support (requires libz)" ON ) ... +option( EXIV2_ENABLE_BMFF "Build with BMFF support" OFF ) 577 rmills@rmillsmm:~/gnu/github/exiv2/exiv2 $ ``` From 5c778880376d2b3d0a1732e18ccd793251a9afb2 Mon Sep 17 00:00:00 2001 From: Robin Mills Date: Thu, 25 Feb 2021 18:10:48 +0000 Subject: [PATCH 36/79] Revised following code review by @hassec. Thank You, Christoph. --- include/exiv2/bmffimage.hpp | 7 ++----- src/bmffimage.cpp | 13 +++++++------ 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/include/exiv2/bmffimage.hpp b/include/exiv2/bmffimage.hpp index f241afe861..aed56f32a4 100644 --- a/include/exiv2/bmffimage.hpp +++ b/include/exiv2/bmffimage.hpp @@ -32,7 +32,7 @@ namespace Exiv2 { EXIV2API bool enableBMFF(bool enable = true); - class Iloc; // We'll define this in bmffimage.cpp + struct Iloc; // We'll define this in bmffimage.cpp // ***************************************************************************** // class definitions @@ -131,10 +131,7 @@ namespace Exiv2 uint64_t visits_max_; std::string indent(int i) { - std::string r; - while (i-- > 0) - r += std::string(" "); - return r; + return std::string(2*i,' '); } uint16_t unknownID_; // 0xffff diff --git a/src/bmffimage.cpp b/src/bmffimage.cpp index 954366ce4b..e35415511b 100644 --- a/src/bmffimage.cpp +++ b/src/bmffimage.cpp @@ -67,10 +67,10 @@ struct BmffBoxHeader #define TAG_ispe 0x69737065 /**< "ispe" Image spatial extents */ #define TAG_infe 0x696e6665 /**< "infe" Item Info Extention */ #define TAG_ipma 0x69706d61 /**< "ipma" Item Property Association */ -#define TAG_cmt1 0x434d5431 /**< ifd0Id */ -#define TAG_cmt2 0x434D5432 /**< exifID */ -#define TAG_cmt3 0x434D5433 /**< canonID */ -#define TAG_cmt4 0x434D5434 /**< gpsID */ +#define TAG_cmt1 0x434d5431 /**< "CMT1" ifd0Id */ +#define TAG_cmt2 0x434D5432 /**< "CMD2" exifID */ +#define TAG_cmt3 0x434D5433 /**< "CMT3" canonID */ +#define TAG_cmt4 0x434D5434 /**< "CMT4" gpsID */ // ***************************************************************************** // class member definitions @@ -88,9 +88,8 @@ namespace Exiv2 return enable; } - class Iloc + struct Iloc { - public: Iloc(uint32_t ID = 0, uint32_t start = 0, uint32_t length = 0) : ID_(ID), start_(start), length_(length){}; virtual ~Iloc(){}; @@ -215,7 +214,9 @@ namespace Exiv2 result = (long)io_->size(); box.length = result - address; } +#ifdef EXIV2_DEBUG_MESSAGES std::cerr << Internal::stringFormat(" (%lu)", result); +#endif } // read data in box and restore file position From c46e800c0aa3e49fe8b4abb369a4da87c9f97e19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Kov=C3=A1=C5=99?= Date: Thu, 25 Feb 2021 19:40:03 +0100 Subject: [PATCH 37/79] Add artist tag --- src/actions.cpp | 1 + src/tiffimage_int.cpp | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/actions.cpp b/src/actions.cpp index a6f885a16c..3ea87f15ef 100644 --- a/src/actions.cpp +++ b/src/actions.cpp @@ -350,6 +350,7 @@ namespace Action { printTag(exifData, Exiv2::whiteBalance , _("White balance") ); printTag(exifData, "Exif.Image.Copyright" , _("Copyright") ); printTag(exifData, "Exif.Photo.UserComment" , _("Exif comment") ); + printTag(exifData, "Exif.Image.Artist" , _("Artist") ); std::cout << std::endl; diff --git a/src/tiffimage_int.cpp b/src/tiffimage_int.cpp index c31ed754f9..c7af868652 100644 --- a/src/tiffimage_int.cpp +++ b/src/tiffimage_int.cpp @@ -1997,6 +1997,8 @@ namespace Exiv2 { { 0x0128, ifd0Id }, // Exif.Image.ResolutionUnit { 0x0129, ifd0Id }, // Exif.Image.PageNumber { 0x012d, ifd0Id }, // Exif.Image.TransferFunction + { 0x0132, ifd0Id }, // Exif.Image.DateTime + { 0x013b, ifd0Id }, // Exif.Image.Artist { 0x013d, ifd0Id }, // Exif.Image.Predictor { 0x013e, ifd0Id }, // Exif.Image.WhitePoint { 0x013f, ifd0Id }, // Exif.Image.PrimaryChromaticities From dcfe538a09cbe6bc6ddf6d74d5fff27ca5028c62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Kov=C3=A1=C5=99?= Date: Thu, 25 Feb 2021 20:08:46 +0100 Subject: [PATCH 38/79] Revert "Add artist tag" This reverts commit c46e800c0aa3e49fe8b4abb369a4da87c9f97e19. --- src/actions.cpp | 1 - src/tiffimage_int.cpp | 2 -- 2 files changed, 3 deletions(-) diff --git a/src/actions.cpp b/src/actions.cpp index 3ea87f15ef..a6f885a16c 100644 --- a/src/actions.cpp +++ b/src/actions.cpp @@ -350,7 +350,6 @@ namespace Action { printTag(exifData, Exiv2::whiteBalance , _("White balance") ); printTag(exifData, "Exif.Image.Copyright" , _("Copyright") ); printTag(exifData, "Exif.Photo.UserComment" , _("Exif comment") ); - printTag(exifData, "Exif.Image.Artist" , _("Artist") ); std::cout << std::endl; diff --git a/src/tiffimage_int.cpp b/src/tiffimage_int.cpp index c7af868652..c31ed754f9 100644 --- a/src/tiffimage_int.cpp +++ b/src/tiffimage_int.cpp @@ -1997,8 +1997,6 @@ namespace Exiv2 { { 0x0128, ifd0Id }, // Exif.Image.ResolutionUnit { 0x0129, ifd0Id }, // Exif.Image.PageNumber { 0x012d, ifd0Id }, // Exif.Image.TransferFunction - { 0x0132, ifd0Id }, // Exif.Image.DateTime - { 0x013b, ifd0Id }, // Exif.Image.Artist { 0x013d, ifd0Id }, // Exif.Image.Predictor { 0x013e, ifd0Id }, // Exif.Image.WhitePoint { 0x013f, ifd0Id }, // Exif.Image.PrimaryChromaticities From 44d976c2a1bfd570873f339bff3f036902fdf500 Mon Sep 17 00:00:00 2001 From: Robin Mills Date: Fri, 26 Feb 2021 10:21:12 +0000 Subject: [PATCH 39/79] Remove bmffimage::printStructure() as discussed in review with @hassec. Corpse removal and cleanup in bmpfimage.hpp --- include/exiv2/bmffimage.hpp | 45 +++++++------------------------------ src/bmffimage.cpp | 26 +++++---------------- 2 files changed, 14 insertions(+), 57 deletions(-) diff --git a/include/exiv2/bmffimage.hpp b/include/exiv2/bmffimage.hpp index aed56f32a4..8899e4bca0 100644 --- a/include/exiv2/bmffimage.hpp +++ b/include/exiv2/bmffimage.hpp @@ -83,24 +83,11 @@ namespace Exiv2 void parseTiff(uint32_t root_tag, uint32_t length); void parseTiff(uint32_t root_tag, uint32_t length,uint32_t start); //@} - + //! @name Manipulators //@{ void readMetadata() /* override */; void writeMetadata() /* override */; - - /*! - @brief Print out the structure of image file. - @throw Error if reading of the file fails or the image data is - not valid (does not look like data of the specific image type). - @warning This function is not thread safe and intended for exiv2 -pS for debugging. - */ - void printStructure(std::ostream& out, PrintStructureOption option, int depth) /* override */; - - /*! - @brief Todo: Not supported yet(?). Calling this function will throw - an instance of Error(kerInvalidSettingForImage). - */ void setComment(const std::string& comment) /* override */; //@} @@ -110,12 +97,6 @@ namespace Exiv2 int pixelWidth() const; int pixelHeight() const; //@} -#if 0 - BmffImage& operator=(const BmffImage& rhs) /* = delete*/ ; - BmffImage& operator=(const BmffImage&& rhs) /* = delete */ ; - BmffImage(const BmffImage& rhs) /* = delete */; - BmffImage(const BmffImage&& rhs) /* = delete */; -#endif private: /*! @@ -125,27 +106,17 @@ namespace Exiv2 @warning This function should only be called by readMetadata() */ long boxHandler(int depth = 0); - - uint32_t fileType; - std::set visits_; - uint64_t visits_max_; std::string indent(int i) { return std::string(2*i,' '); } - uint16_t unknownID_; // 0xffff - uint16_t exifID_; + uint32_t fileType_; + std::set visits_; + uint64_t visits_max_; + uint16_t unknownID_; // 0xffff + uint16_t exifID_; std::map ilocs_; - - /*! - @brief Provides the main implementation of writeMetadata() by - writing all buffered metadata to the provided BasicIo. - @param oIo BasicIo instance to write to (a temporary location). - - @return 4 if opening or writing to the associated BasicIo fails - */ - void doWriteMetadata(BasicIo& outIo); //@} /*! @@ -153,8 +124,8 @@ namespace Exiv2 */ std::string toAscii(long n); std::string boxName(uint32_t box); - bool superBox(uint32_t box); - bool fullBox(uint32_t box); + bool superBox(uint32_t box); + bool fullBox(uint32_t box); std::string uuidName(Exiv2::DataBuf& uuid); }; // class BmffImage diff --git a/src/bmffimage.cpp b/src/bmffimage.cpp index e35415511b..620fe3c760 100644 --- a/src/bmffimage.cpp +++ b/src/bmffimage.cpp @@ -141,7 +141,7 @@ namespace Exiv2 std::string BmffImage::mimeType() const { - switch (fileType) { + switch (fileType_) { case TAG_avif: return "image/avif"; case TAG_heic: @@ -238,9 +238,9 @@ namespace Exiv2 switch (box.type) { case TAG_ftyp: { - fileType = getLong(data.pData_, bigEndian); + fileType_ = getLong(data.pData_, bigEndian); #ifdef EXIV2_DEBUG_MESSAGES - std::cerr << "brand: " << toAscii(fileType); + std::cerr << "brand: " << toAscii(fileType_); #endif } break; @@ -439,7 +439,7 @@ namespace Exiv2 void BmffImage::setComment(const std::string& /*comment*/) { - // Todo: implement me! + // bmff files are read-only throw(Error(kerInvalidSettingForImage, "Image comment", "BMFF")); } // BmffImage::setComment @@ -469,24 +469,10 @@ namespace Exiv2 } } // BmffImage::readMetadata - void BmffImage::printStructure(std::ostream& out, PrintStructureOption option, int depth) - { - if (io_->open() != 0) - throw Error(kerDataSourceOpenFailed, io_->path(), strError()); - - // Ensure that this is the correct image type - if (!isBmffType(*io_, false)) { - if (io_->error() || io_->eof()) - throw Error(kerFailedToReadImageData); - throw Error(kerNotAnImage); - } - UNUSED(out); - UNUSED(option); - UNUSED(depth); - } // BmffImage::printStructure - void BmffImage::writeMetadata() { + // bmff files are read-only + throw(Error(kerInvalidSettingForImage, "Image comment", "BMFF")); } // BmffImage::writeMetadata // ************************************************************************* From 025004688dee949b9e3c1710cdea04aacdf5f912 Mon Sep 17 00:00:00 2001 From: clanmills Date: Sun, 28 Feb 2021 07:58:14 +0000 Subject: [PATCH 40/79] Adding test images. --- test/data/2021-02-13-1929.heic | Bin 0 -> 1474454 bytes test/data/Canon.HIF | Bin 0 -> 1253392 bytes test/data/IMG_3578.HEIC | Bin 0 -> 1122310 bytes test/data/Sony.HIF | Bin 0 -> 151552 bytes test/data/Stonehenge.heic | Bin 0 -> 18241 bytes test/data/avif.avif | Bin 0 -> 219216 bytes test/data/avif_metadata2.avif | Bin 0 -> 9784 bytes test/data/avif_with_metadata_exif_xmp.avif | Bin 0 -> 10863 bytes test/data/heic.heic | Bin 0 -> 718114 bytes 9 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 test/data/2021-02-13-1929.heic create mode 100755 test/data/Canon.HIF create mode 100644 test/data/IMG_3578.HEIC create mode 100755 test/data/Sony.HIF create mode 100644 test/data/Stonehenge.heic create mode 100644 test/data/avif.avif create mode 100644 test/data/avif_metadata2.avif create mode 100644 test/data/avif_with_metadata_exif_xmp.avif create mode 100644 test/data/heic.heic diff --git a/test/data/2021-02-13-1929.heic b/test/data/2021-02-13-1929.heic new file mode 100644 index 0000000000000000000000000000000000000000..5c1934e9ed461d7aa23cc128a2e4468ccf54cb0d GIT binary patch literal 1474454 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