From 30bf563f4d71ff284b5f42d45f77226200a2e571 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20D=C3=ADaz=20M=C3=A1s?= Date: Wed, 16 Mar 2022 17:44:25 +0100 Subject: [PATCH] Update .clang-format file & apply clang-format to whole project --- .clang-format | 23 +- app/actions.cpp | 3708 ++++++----- app/actions.hpp | 488 +- app/app_utils.cpp | 30 +- app/app_utils.hpp | 16 +- app/exiv2.cpp | 2712 ++++---- app/exiv2app.hpp | 328 +- app/getopt.cpp | 178 +- app/getopt.hpp | 143 +- app/wmain.c | 56 +- fuzz/fuzz-read-print-write.cpp | 11 +- include/exiv2/basicio.hpp | 1757 ++--- include/exiv2/bmffimage.hpp | 275 +- include/exiv2/bmpimage.hpp | 117 +- include/exiv2/config.h | 72 +- include/exiv2/convert.hpp | 109 +- include/exiv2/cr2image.hpp | 189 +- include/exiv2/crwimage.hpp | 198 +- include/exiv2/datasets.hpp | 550 +- include/exiv2/easyaccess.hpp | 143 +- include/exiv2/epsimage.hpp | 130 +- include/exiv2/error.hpp | 480 +- include/exiv2/exif.hpp | 936 +-- include/exiv2/exiv2.hpp | 6 +- include/exiv2/futils.hpp | 204 +- include/exiv2/gifimage.hpp | 141 +- include/exiv2/http.hpp | 19 +- include/exiv2/image.hpp | 1295 ++-- include/exiv2/image_types.hpp | 66 +- include/exiv2/ini.hpp | 108 +- include/exiv2/iptc.hpp | 497 +- include/exiv2/jp2image.hpp | 160 +- include/exiv2/jpgimage.hpp | 695 +- include/exiv2/metadatum.hpp | 485 +- include/exiv2/mrwimage.hpp | 151 +- include/exiv2/orfimage.hpp | 172 +- include/exiv2/pgfimage.hpp | 147 +- include/exiv2/pngimage.hpp | 144 +- include/exiv2/preview.hpp | 226 +- include/exiv2/properties.hpp | 474 +- include/exiv2/psdimage.hpp | 163 +- include/exiv2/rafimage.hpp | 153 +- include/exiv2/rw2image.hpp | 182 +- include/exiv2/slice.hpp | 1203 ++-- include/exiv2/tags.hpp | 297 +- include/exiv2/tgaimage.hpp | 141 +- include/exiv2/tiffimage.hpp | 273 +- include/exiv2/types.hpp | 952 +-- include/exiv2/value.hpp | 3319 +++++----- include/exiv2/version.hpp | 73 +- include/exiv2/webpimage.hpp | 156 +- include/exiv2/xmp_exiv2.hpp | 701 +- include/exiv2/xmpsidecar.hpp | 117 +- samples/CMakeLists.txt | 2 +- samples/Jzon.cpp | 2014 +++--- samples/Jzon.h | 868 +-- samples/addmoddel.cpp | 35 +- samples/conntest.cpp | 167 +- samples/convert-test.cpp | 16 +- samples/easyaccess-test.cpp | 109 +- samples/exifcomment.cpp | 20 +- samples/exifdata-test.cpp | 66 +- samples/exifdata.cpp | 313 +- samples/exifprint.cpp | 140 +- samples/exifvalue.cpp | 55 +- samples/exiv2json.cpp | 492 +- samples/geotag.cpp | 1418 ++-- samples/getopt-test.cpp | 145 +- samples/ini-test.cpp | 44 +- samples/iotest.cpp | 410 +- samples/iptceasy.cpp | 64 +- samples/iptcprint.cpp | 76 +- samples/iptctest.cpp | 266 +- samples/key-test.cpp | 329 +- samples/largeiptc-test.cpp | 131 +- samples/metacopy.cpp | 212 +- samples/metacopy.hpp | 100 +- samples/mmap-test.cpp | 56 +- samples/mrwthumb.cpp | 83 +- samples/path-test.cpp | 54 +- samples/prevtest.cpp | 56 +- samples/remotetest.cpp | 174 +- samples/stringto-test.cpp | 77 +- samples/taglist.cpp | 238 +- samples/tiff-test.cpp | 146 +- samples/write-test.cpp | 176 +- samples/write2-test.cpp | 139 +- samples/xmpdump.cpp | 51 +- samples/xmpparse.cpp | 66 +- samples/xmpparser-test.cpp | 98 +- samples/xmpprint.cpp | 59 +- samples/xmpsample.cpp | 326 +- src/basicio.cpp | 3173 +++++---- src/bmffimage.cpp | 1215 ++-- src/bmpimage.cpp | 176 +- src/canonmn_int.cpp | 5858 ++++++++--------- src/canonmn_int.hpp | 341 +- src/casiomn_int.cpp | 908 ++- src/casiomn_int.hpp | 66 +- src/convert.cpp | 2851 +++++---- src/cr2header_int.cpp | 105 +- src/cr2header_int.hpp | 61 +- src/cr2image.cpp | 269 +- src/crwimage.cpp | 261 +- src/crwimage_int.cpp | 2039 +++--- src/crwimage_int.hpp | 1279 ++-- src/datasets.cpp | 1192 ++-- src/doxygen.hpp.in | 4 +- src/easyaccess.cpp | 932 +-- src/enforce.hpp | 45 +- src/epsimage.cpp | 2219 +++---- src/error.cpp | 341 +- src/exif.cpp | 1373 ++-- src/fff.h | 579 +- src/fujimn_int.cpp | 538 +- src/fujimn_int.hpp | 25 +- src/futils.cpp | 632 +- src/gifimage.cpp | 147 +- src/helper_functions.cpp | 13 +- src/http.cpp | 525 +- src/i18n.h | 10 +- src/image.cpp | 1518 +++-- src/image_int.cpp | 64 +- src/image_int.hpp | 155 +- src/ini.cpp | 320 +- src/iptc.cpp | 872 ++- src/jp2image.cpp | 1603 +++-- src/jpgimage.cpp | 2311 ++++--- src/makernote_int.cpp | 2194 +++---- src/makernote_int.hpp | 1206 ++-- src/metadatum.cpp | 43 +- src/minoltamn_int.cpp | 4159 +++++------- src/minoltamn_int.hpp | 167 +- src/mrwimage.cpp | 228 +- src/nikonmn_int.cpp | 6345 +++++++++--------- src/nikonmn_int.hpp | 504 +- src/olympusmn_int.cpp | 3069 +++++---- src/olympusmn_int.hpp | 144 +- src/orfimage.cpp | 273 +- src/orfimage_int.cpp | 82 +- src/orfimage_int.hpp | 55 +- src/panasonicmn_int.cpp | 1269 ++-- src/panasonicmn_int.hpp | 83 +- src/pentaxmn_int.cpp | 2971 ++++----- src/pentaxmn_int.hpp | 136 +- src/pgfimage.cpp | 468 +- src/pngchunk_int.cpp | 969 ++- src/pngchunk_int.hpp | 224 +- src/pngimage.cpp | 1272 ++-- src/preview.cpp | 1858 +++--- src/private.h | 51 +- src/properties.cpp | 9248 +++++++++++++++------------ src/psdimage.cpp | 1354 ++-- src/rafimage.cpp | 593 +- src/rw2image.cpp | 372 +- src/rw2image_int.cpp | 16 +- src/rw2image_int.hpp | 43 +- src/safe_op.hpp | 446 +- src/samsungmn_int.cpp | 303 +- src/samsungmn_int.hpp | 33 +- src/sigmamn_int.cpp | 211 +- src/sigmamn_int.hpp | 43 +- src/sonymn_int.cpp | 2330 +++---- src/sonymn_int.hpp | 133 +- src/tags.cpp | 622 +- src/tags_int.cpp | 6075 +++++++++--------- src/tags_int.hpp | 891 ++- src/tgaimage.cpp | 206 +- src/tiffcomposite_int.cpp | 3045 ++++----- src/tiffcomposite_int.hpp | 3090 ++++----- src/tifffwd_int.hpp | 115 +- src/tiffimage.cpp | 446 +- src/tiffimage_int.cpp | 4290 ++++++------- src/tiffimage_int.hpp | 729 +-- src/tiffvisitor_int.cpp | 3017 +++++---- src/tiffvisitor_int.hpp | 1204 ++-- src/types.cpp | 1310 ++-- src/tzfile.h | 128 +- src/utils.cpp | 10 +- src/utils.hpp | 7 +- src/value.cpp | 2040 +++--- src/version.cpp | 613 +- src/webpimage.cpp | 1466 +++-- src/xmp.cpp | 1854 +++--- src/xmpsidecar.cpp | 366 +- unitTests/mainTestRunner.cpp | 11 +- unitTests/test_DateValue.cpp | 246 +- unitTests/test_Error.cpp | 18 +- unitTests/test_FileIo.cpp | 114 +- unitTests/test_ImageFactory.cpp | 572 +- unitTests/test_IptcKey.cpp | 145 +- unitTests/test_LangAltValueRead.cpp | 298 +- unitTests/test_TimeValue.cpp | 260 +- unitTests/test_XmpKey.cpp | 111 +- unitTests/test_basicio.cpp | 195 +- unitTests/test_bmpimage.cpp | 295 +- unitTests/test_cr2header_int.cpp | 70 +- unitTests/test_datasets.cpp | 243 +- unitTests/test_enforce.cpp | 35 +- unitTests/test_futils.cpp | 151 +- unitTests/test_helper_functions.cpp | 24 +- unitTests/test_image_int.cpp | 51 +- unitTests/test_pngimage.cpp | 241 +- unitTests/test_safe_op.cpp | 137 +- unitTests/test_slice.cpp | 419 +- unitTests/test_tiffheader.cpp | 69 +- unitTests/test_types.cpp | 130 +- 207 files changed, 71141 insertions(+), 75793 deletions(-) mode change 100755 => 100644 include/exiv2/ini.hpp mode change 100755 => 100644 src/ini.cpp diff --git a/.clang-format b/.clang-format index 83d40c72..775e6e1b 100644 --- a/.clang-format +++ b/.clang-format @@ -1,41 +1,20 @@ --- # Indentation for all files ColumnLimit: 120 -IndentWidth: 4 -TabWidth: 4 -UseTab: Never # C++ Options Language: Cpp -Standard: c++17 - BasedOnStyle: Google +# Useful for sorting the project inclusions and standard library inclusions separately IncludeBlocks: Preserve -AccessModifierOffset: -4 -ContinuationIndentWidth: 4 - # Constructor initializers better formatted in presence of preprocessor conditions (see image.cpp) BreakConstructorInitializers: AfterColon -AllowAllConstructorInitializersOnNextLine: true - -# break braces for most of the cases (except conditionals and loops) -BreakBeforeBraces: Custom -BraceWrapping: - AfterStruct: true - AfterClass: true - AfterFunction: true - AfterControlStatement: false - AfterEnum: true - AfterNamespace: true # Do not allow SingleLine statements (to improve coverage statistics) AllowShortFunctionsOnASingleLine: None -AllowShortBlocksOnASingleLine: false AllowShortIfStatementsOnASingleLine: false AllowShortLoopsOnASingleLine: false -Cpp11BracedListStyle: true - ... diff --git a/app/actions.cpp b/app/actions.cpp index 03cc1a4f..28470fd0 100644 --- a/app/actions.cpp +++ b/app/actions.cpp @@ -30,17 +30,17 @@ #endif #if defined(_WIN32) || defined(__CYGWIN__) -#include #include #include #include +#include #else #include #endif #if !defined(__MINGW__) && !defined(_MSC_VER) #define _fileno(a) a -#define _setmode(a,b) +#define _setmode(a, b) #endif namespace fs = std::filesystem; @@ -48,2018 +48,1892 @@ namespace fs = std::filesystem; // ***************************************************************************** // local declarations namespace { - std::mutex cs; +std::mutex cs; - //! Helper class to set the timestamp of a file to that of another file - class Timestamp { - public: - //! C'tor - Timestamp() = default; - int read(const std::string& path); - //! Read the timestamp from a broken-down time in buffer \em tm. - int read(struct tm* tm); - //! Set the timestamp of a file - int touch(const std::string& path) const; +//! Helper class to set the timestamp of a file to that of another file +class Timestamp { + public: + //! C'tor + Timestamp() = default; + int read(const std::string& path); + //! Read the timestamp from a broken-down time in buffer \em tm. + int read(struct tm* tm); + //! Set the timestamp of a file + int touch(const std::string& path) const; - private: - time_t actime_{0}; - time_t modtime_{0}; - }; + private: + time_t actime_{0}; + time_t modtime_{0}; +}; - /*! - @brief Convert a string "YYYY:MM:DD HH:MI:SS" to a struct tm type, - returns 0 if successful - */ - int str2Tm(const std::string& timeStr, struct tm* tm); +/*! + @brief Convert a string "YYYY:MM:DD HH:MI:SS" to a struct tm type, + returns 0 if successful + */ +int str2Tm(const std::string& timeStr, struct tm* tm); - //! Convert a localtime to a string "YYYY:MM:DD HH:MI:SS", "" on error - std::string time2Str(time_t time); +//! Convert a localtime to a string "YYYY:MM:DD HH:MI:SS", "" on error +std::string time2Str(time_t time); - //! Convert a tm structure to a string "YYYY:MM:DD HH:MI:SS", "" on error - std::string tm2Str(const struct tm* tm); +//! Convert a tm structure to a string "YYYY:MM:DD HH:MI:SS", "" on error +std::string tm2Str(const struct tm* tm); - /*! - @brief Copy metadata from source to target according to Params::copyXyz +/*! + @brief Copy metadata from source to target according to Params::copyXyz - @param source Source file path - @param target Target file path. An *.exv file is created if target doesn't - exist. - @param targetType Image type for the target image in case it needs to be - created. - @param preserve Indicates if existing metadata in the target file should - be kept. - @return 0 if successful, else an error code - */ - int metacopy(const std::string& source, const std::string& tgt, Exiv2::ImageType targetType, bool preserve); + @param source Source file path + @param target Target file path. An *.exv file is created if target doesn't + exist. + @param targetType Image type for the target image in case it needs to be + created. + @param preserve Indicates if existing metadata in the target file should + be kept. + @return 0 if successful, else an error code +*/ +int metacopy(const std::string& source, const std::string& tgt, Exiv2::ImageType targetType, bool preserve); - /*! - @brief Rename a file according to a timestamp value. +/*! + @brief Rename a file according to a timestamp value. - @param path The original file path. Contains the new path on exit. - @param tm Pointer to a buffer with the broken-down time to rename - the file to. - @return 0 if successful, -1 if the file was skipped, 1 on error. - */ - int renameFile(std::string& path, const struct tm* tm); + @param path The original file path. Contains the new path on exit. + @param tm Pointer to a buffer with the broken-down time to rename + the file to. + @return 0 if successful, -1 if the file was skipped, 1 on error. +*/ +int renameFile(std::string& path, const struct tm* tm); - /*! - @brief Make a file path from the current file path, destination - directory (if any) and the filename extension passed in. +/*! + @brief Make a file path from the current file path, destination + directory (if any) and the filename extension passed in. - @param path Path of the existing file - @param ext New filename extension (incl. the dot '.' if required) - @return 0 if successful, 1 if the new file exists and the user - chose not to overwrite it. - */ - std::string newFilePath(const std::string& path, const std::string& ext); + @param path Path of the existing file + @param ext New filename extension (incl. the dot '.' if required) + @return 0 if successful, 1 if the new file exists and the user + chose not to overwrite it. + */ +std::string newFilePath(const std::string& path, const std::string& ext); - /*! - @brief Check if file \em path exists and whether it should be - overwritten. Ask user if necessary. Return 1 if the file - exists and shouldn't be overwritten, else 0. - */ - int dontOverwrite(const std::string& path); +/*! + @brief Check if file \em path exists and whether it should be + overwritten. Ask user if necessary. Return 1 if the file + exists and shouldn't be overwritten, else 0. + */ +int dontOverwrite(const std::string& path); - /*! - @brief Output a text with a given minimum number of chars, honoring - multi-byte characters correctly. Replace code in the form - os << setw(width) << myString - with - os << pair( myString, width) - */ - std::ostream& operator<<(std::ostream& os, const std::pair& strAndWidth); +/*! + @brief Output a text with a given minimum number of chars, honoring + multi-byte characters correctly. Replace code in the form + os << setw(width) << myString + with + os << pair( myString, width) + */ +std::ostream& operator<<(std::ostream& os, const std::pair& strAndWidth); - //! Print image Structure information - int printStructure(std::ostream& out, Exiv2::PrintStructureOption option, const std::string &path); +//! Print image Structure information +int printStructure(std::ostream& out, Exiv2::PrintStructureOption option, const std::string& path); } // namespace // ***************************************************************************** // class member definitions namespace Action { - TaskFactory& TaskFactory::instance() - { - static TaskFactory instance_; - return instance_; +TaskFactory& TaskFactory::instance() { + static TaskFactory instance_; + return instance_; +} + +void TaskFactory::cleanup() { + registry_.clear(); +} + +TaskFactory::TaskFactory() { + registry_.emplace(adjust, std::make_unique()); + registry_.emplace(print, std::make_unique()); + registry_.emplace(rename, std::make_unique()); + registry_.emplace(erase, std::make_unique()); + registry_.emplace(extract, std::make_unique()); + registry_.emplace(insert, std::make_unique()); + registry_.emplace(modify, std::make_unique()); + registry_.emplace(fixiso, std::make_unique()); + registry_.emplace(fixcom, std::make_unique()); +} + +Task::UniquePtr TaskFactory::create(TaskType type) { + auto i = registry_.find(type); + if (i != registry_.end() && i->second) { + return i->second->clone(); + } + return nullptr; +} + +int setModeAndPrintStructure(Exiv2::PrintStructureOption option, const std::string& path, bool binary) { + int result = 0; + if (binary && option == Exiv2::kpsIccProfile) { + std::stringstream output(std::stringstream::out | std::stringstream::binary); + result = printStructure(output, option, path); + if (result == 0) { + size_t size = output.str().size(); + Exiv2::DataBuf iccProfile(size); + Exiv2::DataBuf ascii(size * 3 + 1); + ascii.write_uint8(size * 3, 0); + iccProfile.copyBytes(0, output.str().c_str(), size); + if (Exiv2::base64encode(iccProfile.c_data(), size, reinterpret_cast(ascii.data()), size * 3)) { + long chunk = 60; + std::string code = std::string("data:") + ascii.c_str(); + size_t length = code.size(); + for (size_t start = 0; start < length; start += chunk) { + size_t count = (start + chunk) < length ? chunk : length - start; + std::cout << code.substr(start, count) << std::endl; + } + } + } + } else { + _setmode(fileno(stdout), O_BINARY); + result = printStructure(std::cout, option, path); + } + + return result; +} + +int Print::run(const std::string& path) { + try { + path_ = path; + int rc = 0; + switch (Params::instance().printMode_) { + case Params::pmSummary: + rc = Params::instance().greps_.empty() ? printSummary() : printList(); + break; + case Params::pmList: + rc = printList(); + break; + case Params::pmComment: + rc = printComment(); + break; + case Params::pmPreview: + rc = printPreviewList(); + break; + case Params::pmStructure: + rc = printStructure(std::cout, Exiv2::kpsBasic, path_); + break; + case Params::pmRecursive: + rc = printStructure(std::cout, Exiv2::kpsRecursive, path_); + break; + case Params::pmXMP: + rc = setModeAndPrintStructure(Exiv2::kpsXMP, path_, binary()); + break; + case Params::pmIccProfile: + rc = setModeAndPrintStructure(Exiv2::kpsIccProfile, path_, binary()); + break; + } + return rc; + } catch (const Exiv2::Error& e) { + std::cerr << "Exiv2 exception in print action for file " << path << ":\n" << e << "\n"; + return 1; + } catch (const std::overflow_error& e) { + std::cerr << "std::overflow_error exception in print action for file " << path << ":\n" << e.what() << "\n"; + return 1; + } +} + +int Print::printSummary() { + if (!Exiv2::fileExists(path_)) { + std::cerr << path_ << ": " << _("Failed to open the file\n"); + return -1; + } + + auto image = Exiv2::ImageFactory::open(path_); + assert(image); + image->readMetadata(); + Exiv2::ExifData& exifData = image->exifData(); + align_ = 16; + + // Filename + printLabel(_("File name")); + std::cout << path_ << std::endl; + + // Filesize + printLabel(_("File size")); + std::cout << fs::file_size(path_) << " " << _("Bytes") << std::endl; + + // MIME type + printLabel(_("MIME type")); + std::cout << image->mimeType() << std::endl; + + // Image size + printLabel(_("Image size")); + std::cout << image->pixelWidth() << " x " << image->pixelHeight() << std::endl; + + if (exifData.empty()) { + std::cerr << path_ << ": " << _("No Exif data found in the file\n"); + return -3; + } + + // Thumbnail + printLabel(_("Thumbnail")); + Exiv2::ExifThumbC exifThumb(exifData); + std::string thumbExt = exifThumb.extension(); + if (thumbExt.empty()) { + std::cout << _("None"); + } else { + auto dataBuf = exifThumb.copy(); + if (dataBuf.empty()) { + std::cout << _("None"); + } else { + std::cout << exifThumb.mimeType() << ", " << dataBuf.size() << " " << _("Bytes"); + } + } + std::cout << std::endl; + + printTag(exifData, Exiv2::make, _("Camera make")); + printTag(exifData, Exiv2::model, _("Camera model")); + printTag(exifData, Exiv2::dateTimeOriginal, _("Image timestamp")); + printTag(exifData, "Exif.Canon.FileNumber", _("File number")); + printTag(exifData, Exiv2::exposureTime, _("Exposure time"), Exiv2::shutterSpeedValue); + printTag(exifData, Exiv2::fNumber, _("Aperture"), Exiv2::apertureValue); + printTag(exifData, Exiv2::exposureBiasValue, _("Exposure bias")); + printTag(exifData, Exiv2::flash, _("Flash")); + printTag(exifData, Exiv2::flashBias, _("Flash bias")); + printTag(exifData, Exiv2::focalLength, _("Focal length")); + printTag(exifData, Exiv2::subjectDistance, _("Subject distance")); + printTag(exifData, Exiv2::isoSpeed, _("ISO speed")); + printTag(exifData, Exiv2::exposureMode, _("Exposure mode")); + printTag(exifData, Exiv2::meteringMode, _("Metering mode")); + printTag(exifData, Exiv2::macroMode, _("Macro mode")); + printTag(exifData, Exiv2::imageQuality, _("Image quality")); + printTag(exifData, Exiv2::whiteBalance, _("White balance")); + printTag(exifData, "Exif.Image.Copyright", _("Copyright")); + printTag(exifData, "Exif.Photo.UserComment", _("Exif comment")); + + std::cout << std::endl; + + return 0; +} // Print::printSummary + +void Print::printLabel(const std::string& label) const { + std::cout << std::setfill(' ') << std::left; + if (Params::instance().files_.size() > 1) { + std::cout << std::setw(20) << path_ << " "; + } + std::cout << std::pair(label, align_) << ": "; +} + +int Print::printTag(const Exiv2::ExifData& exifData, const std::string& key, const std::string& label) const { + int rc = 0; + if (!label.empty()) { + printLabel(label); + } + Exiv2::ExifKey ek(key); + auto md = exifData.findKey(ek); + if (md != exifData.end()) { + md->write(std::cout, &exifData); + rc = 1; + } + if (!label.empty()) + std::cout << std::endl; + return rc; +} // Print::printTag + +int Print::printTag(const Exiv2::ExifData& exifData, EasyAccessFct easyAccessFct, const std::string& label, + EasyAccessFct easyAccessFctFallback) const { + int rc = 0; + if (!label.empty()) { + printLabel(label); + } + auto md = easyAccessFct(exifData); + if (md != exifData.end()) { + md->write(std::cout, &exifData); + rc = 1; + } else if (easyAccessFctFallback) { + md = easyAccessFctFallback(exifData); + if (md != exifData.end()) { + md->write(std::cout, &exifData); + rc = 1; + } + } + if (!label.empty()) + std::cout << std::endl; + return rc; +} // Print::printTag + +int Print::printList() { + if (!Exiv2::fileExists(path_)) { + std::cerr << path_ << ": " << _("Failed to open the file\n"); + return -1; + } + + auto image = Exiv2::ImageFactory::open(path_); + assert(image); + image->readMetadata(); + // Set defaults for metadata types and data columns + if (Params::instance().printTags_ == Exiv2::mdNone) { + Params::instance().printTags_ = Exiv2::mdExif | Exiv2::mdIptc | Exiv2::mdXmp; + } + if (Params::instance().printItems_ == 0) { + Params::instance().printItems_ = Params::prKey | Params::prType | Params::prCount | Params::prTrans; + } + return printMetadata(image.get()); +} // Print::printList + +int Print::printMetadata(const Exiv2::Image* image) { + bool ret = false; + bool noExif = false; + if (Params::instance().printTags_ & Exiv2::mdExif) { + const Exiv2::ExifData& exifData = image->exifData(); + for (auto&& md : exifData) { + ret |= printMetadatum(md, image); + } + if (exifData.empty()) + noExif = true; + } + + bool noIptc = false; + if (Params::instance().printTags_ & Exiv2::mdIptc) { + const Exiv2::IptcData& iptcData = image->iptcData(); + for (auto&& md : iptcData) { + ret |= printMetadatum(md, image); + } + if (iptcData.empty()) + noIptc = true; + } + + bool noXmp = false; + if (Params::instance().printTags_ & Exiv2::mdXmp) { + const Exiv2::XmpData& xmpData = image->xmpData(); + for (auto&& md : xmpData) { + ret |= printMetadatum(md, image); + } + if (xmpData.empty()) + noXmp = true; + } + + // With -v, inform about the absence of any (requested) type of metadata + if (Params::instance().verbose_) { + if (noExif) + std::cerr << path_ << ": " << _("No Exif data found in the file\n"); + if (noIptc) + std::cerr << path_ << ": " << _("No IPTC data found in the file\n"); + if (noXmp) + std::cerr << path_ << ": " << _("No XMP data found in the file\n"); + } + + // With -g or -K, return -3 if no matching tags were found + int rc = 0; + if ((!Params::instance().greps_.empty() || !Params::instance().keys_.empty()) && !ret) + rc = 1; + + return rc; +} // Print::printMetadata + +bool Print::grepTag(const std::string& key) { + bool result = Params::instance().greps_.empty(); + for (auto const& g : Params::instance().greps_) { + result = std::regex_search(key, g); + if (result) { + break; + } + } + return result; +} + +bool Print::keyTag(const std::string& key) { + bool result = Params::instance().keys_.empty(); + for (auto&& k : Params::instance().keys_) { + if (result) + break; + result = key == k; + } + return result; +} + +static void binaryOutput(const std::ostringstream& os) { + std::cout << os.str(); +} + +bool Print::printMetadatum(const Exiv2::Metadatum& md, const Exiv2::Image* pImage) { + if (!grepTag(md.key())) + return false; + if (!keyTag(md.key())) + return false; + + if (Params::instance().unknown_ && md.tagName().substr(0, 2) == "0x") { + return false; + } + + bool const manyFiles = Params::instance().files_.size() > 1; + if (manyFiles) { + std::cout << std::setfill(' ') << std::left << std::setw(20) << path_ << " "; + } + + bool first = true; + if (Params::instance().printItems_ & Params::prTag) { + first = false; + std::cout << "0x" << std::setw(4) << std::setfill('0') << std::right << std::hex << md.tag(); + } + if (Params::instance().printItems_ & Params::prSet) { + if (!first) + std::cout << " "; + first = false; + std::cout << "set"; + } + if (Params::instance().printItems_ & Params::prGroup) { + if (!first) + std::cout << " "; + first = false; + std::cout << std::setw(12) << std::setfill(' ') << std::left << md.groupName(); + } + if (Params::instance().printItems_ & Params::prKey) { + if (!first) + std::cout << " "; + first = false; + std::cout << std::setfill(' ') << std::left << std::setw(44) << md.key(); + } + if (Params::instance().printItems_ & Params::prName) { + if (!first) + std::cout << " "; + first = false; + std::cout << std::setw(27) << std::setfill(' ') << std::left << md.tagName(); + } + if (Params::instance().printItems_ & Params::prLabel) { + if (!first) + std::cout << " "; + first = false; + std::cout << std::setw(30) << std::setfill(' ') << std::left << md.tagLabel(); + } + if (Params::instance().printItems_ & Params::prType) { + if (!first) + std::cout << " "; + first = false; + std::cout << std::setw(9) << std::setfill(' ') << std::left; + const char* tn = md.typeName(); + if (tn) { + std::cout << tn; + } else { + std::ostringstream os; + os << "0x" << std::setw(4) << std::setfill('0') << std::hex << md.typeId(); + std::cout << os.str(); + } + } + if (Params::instance().printItems_ & Params::prCount) { + if (!first) + std::cout << " "; + first = false; + std::cout << std::dec << std::setw(3) << std::setfill(' ') << std::right << md.count(); + } + if (Params::instance().printItems_ & Params::prSize) { + if (!first) + std::cout << " "; + first = false; + std::cout << std::dec << std::setw(3) << std::setfill(' ') << std::right << md.size(); + } + if (Params::instance().printItems_ & Params::prValue && md.size() > 0) { + if (!first) + std::cout << " "; + first = false; + std::ostringstream os; + // #1114 - show negative values for SByte + if (md.typeId() == Exiv2::signedByte) { + for (size_t c = 0; c < md.value().count(); c++) { + const auto value = md.value().toInt64(c); + os << (c ? " " : "") << std::dec << (value < 128 ? value : value - 256); + } + } else { + os << std::dec << md.value(); + } + binaryOutput(os); + } + if (Params::instance().printItems_ & Params::prTrans) { + if (!first) + std::cout << " "; + first = false; + std::ostringstream os; + os << std::dec << md.print(&pImage->exifData()); + binaryOutput(os); + } + if (Params::instance().printItems_ & Params::prHex) { + if (!first) + std::cout << std::endl; + Exiv2::DataBuf buf(md.size()); + md.copy(buf.data(), pImage->byteOrder()); + Exiv2::hexdump(std::cout, buf.c_data(), buf.size()); + } + std::cout << std::endl; + return true; +} // Print::printMetadatum + +int Print::printComment() { + if (!Exiv2::fileExists(path_)) { + std::cerr << path_ << ": " << _("Failed to open the file\n"); + return -1; + } + + auto image = Exiv2::ImageFactory::open(path_); + assert(image); + image->readMetadata(); + if (Params::instance().verbose_) { + std::cout << _("JPEG comment") << ": "; + } + std::cout << image->comment() << std::endl; + return 0; +} // Print::printComment + +int Print::printPreviewList() { + if (!Exiv2::fileExists(path_)) { + std::cerr << path_ << ": " << _("Failed to open the file\n"); + return -1; + } + + auto image = Exiv2::ImageFactory::open(path_); + assert(image); + image->readMetadata(); + bool const manyFiles = Params::instance().files_.size() > 1; + int cnt = 0; + Exiv2::PreviewManager pm(*image); + Exiv2::PreviewPropertiesList list = pm.getPreviewProperties(); + for (auto&& pos : list) { + if (manyFiles) { + std::cout << std::setfill(' ') << std::left << std::setw(20) << path_ << " "; + } + std::cout << _("Preview") << " " << ++cnt << ": " << pos.mimeType_ << ", "; + if (pos.width_ != 0 && pos.height_ != 0) { + std::cout << pos.width_ << "x" << pos.height_ << " " << _("pixels") << ", "; + } + std::cout << pos.size_ << " " << _("bytes") << "\n"; + } + return 0; +} // Print::printPreviewList + +Task::UniquePtr Print::clone() const { + return std::make_unique(*this); +} + +int Rename::run(const std::string& path) { + try { + if (!Exiv2::fileExists(path)) { + std::cerr << path << ": " << _("Failed to open the file\n"); + return -1; + } + Timestamp ts; + if (Params::instance().preserve_) + ts.read(path); + + auto image = Exiv2::ImageFactory::open(path); + assert(image); + image->readMetadata(); + Exiv2::ExifData& exifData = image->exifData(); + if (exifData.empty()) { + std::cerr << path << ": " << _("No Exif data found in the file\n"); + return -3; + } + Exiv2::ExifKey key("Exif.Photo.DateTimeOriginal"); + auto md = exifData.findKey(key); + if (md == exifData.end()) { + key = Exiv2::ExifKey("Exif.Image.DateTime"); + md = exifData.findKey(key); + } + if (md == exifData.end()) { + std::cerr << _("Neither tag") << " `Exif.Photo.DateTimeOriginal' " << _("nor") << " `Exif.Image.DateTime' " + << _("found in the file") << " " << path << "\n"; + return 1; + } + std::string v = md->toString(); + if (v.length() == 0 || v[0] == ' ') { + std::cerr << _("Image file creation timestamp not set in the file") << " " << path << "\n"; + return 1; + } + struct tm tm; + if (str2Tm(v, &tm) != 0) { + std::cerr << _("Failed to parse timestamp") << " `" << v << "' " << _("in the file") << " " << path << "\n"; + return 1; + } + if (Params::instance().timestamp_ || Params::instance().timestampOnly_) { + ts.read(&tm); + } + int rc = 0; + std::string newPath = path; + if (Params::instance().timestampOnly_) { + if (Params::instance().verbose_) { + std::cout << _("Updating timestamp to") << " " << v << std::endl; + } + } else { + rc = renameFile(newPath, &tm); + if (rc == -1) + return 0; // skip + } + if (0 == rc && + (Params::instance().preserve_ || Params::instance().timestamp_ || Params::instance().timestampOnly_)) { + ts.touch(newPath); + } + return rc; + } catch (const Exiv2::Error& e) { + std::cerr << "Exiv2 exception in rename action for file " << path << ":\n" << e << "\n"; + return 1; + } +} + +Task::UniquePtr Rename::clone() const { + return std::make_unique(*this); +} + +int Erase::run(const std::string& path) { + try { + path_ = path; + + if (!Exiv2::fileExists(path_)) { + std::cerr << path_ << ": " << _("Failed to open the file\n"); + return -1; + } + Timestamp ts; + if (Params::instance().preserve_) + ts.read(path); + + auto image = Exiv2::ImageFactory::open(path_); + assert(image); + image->readMetadata(); + // Thumbnail must be before Exif + int rc = 0; + if (Params::instance().target_ & Params::ctThumb) { + rc = eraseThumbnail(image.get()); + } + if (0 == rc && Params::instance().target_ & Params::ctExif) { + rc = eraseExifData(image.get()); + } + if (0 == rc && Params::instance().target_ & Params::ctIptc) { + rc = eraseIptcData(image.get()); + } + if (0 == rc && Params::instance().target_ & Params::ctComment) { + rc = eraseComment(image.get()); + } + if (0 == rc && Params::instance().target_ & Params::ctXmp) { + rc = eraseXmpData(image.get()); + } + if (0 == rc && Params::instance().target_ & Params::ctIccProfile) { + rc = eraseIccProfile(image.get()); + } + if (0 == rc && Params::instance().target_ & Params::ctIptcRaw) { + rc = printStructure(std::cout, Exiv2::kpsIptcErase, path_); } - void TaskFactory::cleanup() - { - registry_.clear(); + if (0 == rc) { + image->writeMetadata(); + if (Params::instance().preserve_) + ts.touch(path); } - TaskFactory::TaskFactory() - { - registry_.emplace(adjust, std::make_unique()); - registry_.emplace(print, std::make_unique()); - registry_.emplace(rename, std::make_unique()); - registry_.emplace(erase, std::make_unique()); - registry_.emplace(extract, std::make_unique()); - registry_.emplace(insert, std::make_unique()); - registry_.emplace(modify, std::make_unique()); - registry_.emplace(fixiso, std::make_unique()); - registry_.emplace(fixcom, std::make_unique()); + return rc; + } catch (const Exiv2::Error& e) { + std::cerr << "Exiv2 exception in erase action for file " << path << ":\n" << e << "\n"; + return 1; + } +} + +int Erase::eraseThumbnail(Exiv2::Image* image) { + Exiv2::ExifThumb exifThumb(image->exifData()); + std::string thumbExt = exifThumb.extension(); + if (thumbExt.empty()) { + return 0; + } + exifThumb.erase(); + if (Params::instance().verbose_) { + std::cout << _("Erasing thumbnail data") << std::endl; + } + return 0; +} + +int Erase::eraseExifData(Exiv2::Image* image) { + if (Params::instance().verbose_ && image->exifData().count() > 0) { + std::cout << _("Erasing Exif data from the file") << std::endl; + } + image->clearExifData(); + return 0; +} + +int Erase::eraseIptcData(Exiv2::Image* image) { + if (Params::instance().verbose_ && image->iptcData().count() > 0) { + std::cout << _("Erasing IPTC data from the file") << std::endl; + } + image->clearIptcData(); + return 0; +} + +int Erase::eraseComment(Exiv2::Image* image) { + if (Params::instance().verbose_ && !image->comment().empty()) { + std::cout << _("Erasing JPEG comment from the file") << std::endl; + } + image->clearComment(); + return 0; +} + +int Erase::eraseXmpData(Exiv2::Image* image) { + if (Params::instance().verbose_ && image->xmpData().count() > 0) { + std::cout << _("Erasing XMP data from the file") << std::endl; + } + image->clearXmpData(); // Quick fix for bug #612 + image->clearXmpPacket(); + return 0; +} +int Erase::eraseIccProfile(Exiv2::Image* image) { + if (Params::instance().verbose_ && image->iccProfileDefined()) { + std::cout << _("Erasing ICC Profile data from the file") << std::endl; + } + image->clearIccProfile(); + return 0; +} + +Task::UniquePtr Erase::clone() const { + return std::make_unique(*this); +} + +int Extract::run(const std::string& path) { + try { + path_ = path; + int rc = 0; + + bool bStdout = (Params::instance().target_ & Params::ctStdInOut) != 0; + if (bStdout) { + _setmode(fileno(stdout), _O_BINARY); } - Task::UniquePtr TaskFactory::create(TaskType type) - { - auto i = registry_.find(type); - if (i != registry_.end() && i->second) { - return i->second->clone(); - } - return nullptr; + if (Params::instance().target_ & Params::ctThumb) { + rc = writeThumbnail(); } - - int setModeAndPrintStructure(Exiv2::PrintStructureOption option, const std::string& path,bool binary) - { - int result = 0 ; - if ( binary && option == Exiv2::kpsIccProfile ) { - std::stringstream output(std::stringstream::out|std::stringstream::binary); - result = printStructure(output, option, path); - if ( result == 0 ) { - size_t size = output.str().size(); - Exiv2::DataBuf iccProfile(size); - Exiv2::DataBuf ascii(size * 3 + 1); - ascii.write_uint8(size * 3, 0); - iccProfile.copyBytes(0,output.str().c_str(),size); - if (Exiv2::base64encode(iccProfile.c_data(), size, reinterpret_cast(ascii.data()), size * 3)) { - long chunk = 60 ; - std::string code = std::string("data:") + ascii.c_str(); - size_t length = code.size(); - for ( size_t start = 0 ; start < length ; start += chunk ) { - size_t count = (start+chunk) < length ? chunk : length - start ; - std::cout << code.substr(start,count) << std::endl; - } - } - } - } else { - _setmode(fileno(stdout),O_BINARY); - result = printStructure(std::cout, option, path); - } - - return result; + if (!rc && Params::instance().target_ & Params::ctPreview) { + rc = writePreviews(); } - - int Print::run(const std::string& path) - { - try { - path_ = path; - int rc = 0; - switch (Params::instance().printMode_) { - case Params::pmSummary: rc = Params::instance().greps_.empty() ? printSummary() : printList(); break; - case Params::pmList: rc = printList(); break; - case Params::pmComment: rc = printComment(); break; - case Params::pmPreview: rc = printPreviewList(); break; - case Params::pmStructure: rc = printStructure(std::cout,Exiv2::kpsBasic, path_) ; break; - case Params::pmRecursive: rc = printStructure(std::cout,Exiv2::kpsRecursive, path_) ; break; - case Params::pmXMP: - rc = setModeAndPrintStructure(Exiv2::kpsXMP, path_,binary()); - break; - case Params::pmIccProfile: - rc = setModeAndPrintStructure(Exiv2::kpsIccProfile, path_,binary()); - break; - } - return rc; - } - catch(const Exiv2::Error& e) { - std::cerr << "Exiv2 exception in print action for file " - << path << ":\n" << e << "\n"; - return 1; - } - catch(const std::overflow_error& e) { - std::cerr << "std::overflow_error exception in print action for file " - << path << ":\n" << e.what() << "\n"; - return 1; - } - } - - int Print::printSummary() - { - if (!Exiv2::fileExists(path_)) { - std::cerr << path_ << ": " << _("Failed to open the file\n"); - return -1; - } - - auto image = Exiv2::ImageFactory::open(path_); - assert(image); - image->readMetadata(); - Exiv2::ExifData& exifData = image->exifData(); - align_ = 16; - - // Filename - printLabel(_("File name")); - std::cout << path_ << std::endl; - - // Filesize - printLabel(_("File size")); - std::cout << fs::file_size(path_) << " " << _("Bytes") << std::endl; - - // MIME type - printLabel(_("MIME type")); - std::cout << image->mimeType() << std::endl; - - // Image size - printLabel(_("Image size")); - std::cout << image->pixelWidth() << " x " << image->pixelHeight() << std::endl; - - if (exifData.empty()) { - std::cerr << path_ << ": " - << _("No Exif data found in the file\n"); - return -3; - } - - // Thumbnail - printLabel(_("Thumbnail")); - Exiv2::ExifThumbC exifThumb(exifData); - std::string thumbExt = exifThumb.extension(); - if (thumbExt.empty()) { - std::cout << _("None"); - } - else { - auto dataBuf = exifThumb.copy(); - if (dataBuf.empty()) { - std::cout << _("None"); - } - else { - std::cout << exifThumb.mimeType() << ", " - << dataBuf.size() << " " << _("Bytes"); - } - } - std::cout << std::endl; - - printTag(exifData, Exiv2::make , _("Camera make") ); - printTag(exifData, Exiv2::model , _("Camera model") ); - printTag(exifData, Exiv2::dateTimeOriginal , _("Image timestamp") ); - printTag(exifData, "Exif.Canon.FileNumber" , _("File number") ); - printTag(exifData, Exiv2::exposureTime , _("Exposure time") , Exiv2::shutterSpeedValue ); - printTag(exifData, Exiv2::fNumber , _("Aperture") , Exiv2::apertureValue ); - printTag(exifData, Exiv2::exposureBiasValue , _("Exposure bias") ); - printTag(exifData, Exiv2::flash , _("Flash") ); - printTag(exifData, Exiv2::flashBias , _("Flash bias") ); - printTag(exifData, Exiv2::focalLength , _("Focal length") ); - printTag(exifData, Exiv2::subjectDistance , _("Subject distance") ); - printTag(exifData, Exiv2::isoSpeed , _("ISO speed") ); - printTag(exifData, Exiv2::exposureMode , _("Exposure mode") ); - printTag(exifData, Exiv2::meteringMode , _("Metering mode") ); - printTag(exifData, Exiv2::macroMode , _("Macro mode") ); - printTag(exifData, Exiv2::imageQuality , _("Image quality") ); - printTag(exifData, Exiv2::whiteBalance , _("White balance") ); - printTag(exifData, "Exif.Image.Copyright" , _("Copyright") ); - printTag(exifData, "Exif.Photo.UserComment" , _("Exif comment") ); - - std::cout << std::endl; - + if (!rc && Params::instance().target_ & Params::ctXmpSidecar) { + std::string xmpPath = bStdout ? "-" : newFilePath(path_, ".xmp"); + if (dontOverwrite(xmpPath)) return 0; - } // Print::printSummary + rc = metacopy(path_, xmpPath, Exiv2::ImageType::xmp, false); + } + if (!rc && Params::instance().target_ & Params::ctIccProfile) { + std::string iccPath = bStdout ? "-" : newFilePath(path_, ".icc"); + rc = writeIccProfile(iccPath); + } + if (!rc && !(Params::instance().target_ & Params::ctXmpSidecar) && + !(Params::instance().target_ & Params::ctThumb) && !(Params::instance().target_ & Params::ctPreview) && + !(Params::instance().target_ & Params::ctIccProfile)) { + std::string exvPath = bStdout ? "-" : newFilePath(path_, ".exv"); + if (dontOverwrite(exvPath)) + return 0; + rc = metacopy(path_, exvPath, Exiv2::ImageType::exv, false); + } + return rc; + } catch (const Exiv2::Error& e) { + std::cerr << "Exiv2 exception in extract action for file " << path << ":\n" << e << "\n"; + return 1; + } +} - void Print::printLabel(const std::string& label) const - { - std::cout << std::setfill(' ') << std::left; - if (Params::instance().files_.size() > 1) { - std::cout << std::setw(20) << path_ << " "; - } - std::cout << std::pair(label, align_) << ": "; +int Extract::writeThumbnail() const { + if (!Exiv2::fileExists(path_)) { + std::cerr << path_ << ": " << _("Failed to open the file\n"); + return -1; + } + auto image = Exiv2::ImageFactory::open(path_); + assert(image); + image->readMetadata(); + Exiv2::ExifData& exifData = image->exifData(); + if (exifData.empty()) { + std::cerr << path_ << ": " << _("No Exif data found in the file\n"); + return -3; + } + int rc = 0; + Exiv2::ExifThumb exifThumb(exifData); + std::string thumbExt = exifThumb.extension(); + if (thumbExt.empty()) { + std::cerr << path_ << ": " << _("Image does not contain an Exif thumbnail\n"); + } else { + if ((Params::instance().target_ & Params::ctStdInOut) != 0) { + Exiv2::DataBuf buf = exifThumb.copy(); + std::cout.write(buf.c_str(), buf.size()); + return 0; } - int Print::printTag(const Exiv2::ExifData& exifData, - const std::string& key, - const std::string& label) const - { - int rc = 0; - if (!label.empty()) { - printLabel(label); - } - Exiv2::ExifKey ek(key); - auto md = exifData.findKey(ek); - if (md != exifData.end()) { - md->write(std::cout, &exifData); - rc = 1; - } - if (!label.empty()) std::cout << std::endl; - return rc; - } // Print::printTag + std::string thumb = newFilePath(path_, "-thumb"); + std::string thumbPath = thumb + thumbExt; + if (dontOverwrite(thumbPath)) + return 0; + if (Params::instance().verbose_) { + Exiv2::DataBuf buf = exifThumb.copy(); + if (!buf.empty()) { + std::cout << _("Writing thumbnail") << " (" << exifThumb.mimeType() << ", " << buf.size() << " " << _("Bytes") + << ") " << _("to file") << " " << thumbPath << std::endl; + } + } + rc = static_cast(exifThumb.writeFile(thumb)); + if (rc == 0) { + std::cerr << path_ << ": " << _("Exif data doesn't contain a thumbnail\n"); + } + } + return rc; +} // Extract::writeThumbnail - int Print::printTag(const Exiv2::ExifData& exifData, - EasyAccessFct easyAccessFct, - const std::string& label, - EasyAccessFct easyAccessFctFallback) const - { - int rc = 0; - if (!label.empty()) { - printLabel(label); - } - auto md = easyAccessFct(exifData); - if (md != exifData.end()) { - md->write(std::cout, &exifData); - rc = 1; - } else if (easyAccessFctFallback) { - md = easyAccessFctFallback(exifData); - if (md != exifData.end()) { - md->write(std::cout, &exifData); - rc = 1; - } - } - if (!label.empty()) std::cout << std::endl; - return rc; - } // Print::printTag +int Extract::writePreviews() const { + if (!Exiv2::fileExists(path_)) { + std::cerr << path_ << ": " << _("Failed to open the file\n"); + return -1; + } - int Print::printList() - { - if (!Exiv2::fileExists(path_)) { - std::cerr << path_ << ": " << _("Failed to open the file\n"); - return -1; - } + auto image = Exiv2::ImageFactory::open(path_); + assert(image); + image->readMetadata(); - auto image = Exiv2::ImageFactory::open(path_); - assert(image); - image->readMetadata(); - // Set defaults for metadata types and data columns - if (Params::instance().printTags_ == Exiv2::mdNone) { - Params::instance().printTags_ = Exiv2::mdExif | Exiv2::mdIptc | Exiv2::mdXmp; - } - if (Params::instance().printItems_ == 0) { - Params::instance().printItems_ = Params::prKey | Params::prType | Params::prCount | Params::prTrans; - } - return printMetadata(image.get()); - } // Print::printList + Exiv2::PreviewManager pvMgr(*image); + Exiv2::PreviewPropertiesList pvList = pvMgr.getPreviewProperties(); - int Print::printMetadata(const Exiv2::Image* image) - { - bool ret = false; - bool noExif = false; - if (Params::instance().printTags_ & Exiv2::mdExif) { - const Exiv2::ExifData& exifData = image->exifData(); - for (auto&& md : exifData) { - ret |= printMetadatum(md, image); - } - if (exifData.empty()) noExif = true; - } + const Params::PreviewNumbers& numbers = Params::instance().previewNumbers_; + for (auto number : numbers) { + auto num = static_cast(number); + if (num == 0) { + // Write all previews + for (num = 0; num < pvList.size(); ++num) { + writePreviewFile(pvMgr.getPreviewImage(pvList[num]), num + 1); + } + break; + } + num--; + if (num >= pvList.size()) { + std::cerr << path_ << ": " << _("Image does not have preview") << " " << num + 1 << "\n"; + continue; + } + writePreviewFile(pvMgr.getPreviewImage(pvList[num]), num + 1); + } + return 0; +} // Extract::writePreviews - bool noIptc = false; - if (Params::instance().printTags_ & Exiv2::mdIptc) { - const Exiv2::IptcData& iptcData = image->iptcData(); - for (auto&& md : iptcData) { - ret |= printMetadatum(md, image); - } - if (iptcData.empty()) noIptc = true; - } +int Extract::writeIccProfile(const std::string& target) const { + int rc = 0; + if (!Exiv2::fileExists(path_)) { + std::cerr << path_ << ": " << _("Failed to open the file\n"); + rc = -1; + } - bool noXmp = false; - if (Params::instance().printTags_ & Exiv2::mdXmp) { - const Exiv2::XmpData& xmpData = image->xmpData(); - for (auto&& md : xmpData) { - ret |= printMetadatum(md, image); - } - if (xmpData.empty()) noXmp = true; - } + bool bStdout = target == "-"; - // With -v, inform about the absence of any (requested) type of metadata + if (rc == 0) { + auto image = Exiv2::ImageFactory::open(path_); + assert(image); + image->readMetadata(); + if (!image->iccProfileDefined()) { + std::cerr << _("No embedded iccProfile: ") << path_ << std::endl; + rc = -2; + } else { + if (bStdout) { // -eC- + std::cout.write(image->iccProfile().c_str(), image->iccProfile().size()); + } else { if (Params::instance().verbose_) { - if (noExif) std::cerr << path_ << ": " << _("No Exif data found in the file\n"); - if (noIptc) std::cerr << path_ << ": " << _("No IPTC data found in the file\n"); - if (noXmp) std::cerr << path_ << ": " << _("No XMP data found in the file\n"); + std::cout << _("Writing iccProfile: ") << target << std::endl; } - - // With -g or -K, return -3 if no matching tags were found - int rc = 0; - if ((!Params::instance().greps_.empty() || !Params::instance().keys_.empty()) && !ret) rc = 1; - - return rc; - } // Print::printMetadata - - bool Print::grepTag(const std::string& key) - { - bool result = Params::instance().greps_.empty(); - for (auto const& g : Params::instance().greps_) { - result = std::regex_search(key, g); - if (result) { - break; - } - } - return result; + Exiv2::FileIo iccFile(target); + iccFile.open("wb"); + iccFile.write(image->iccProfile().c_data(), image->iccProfile().size()); + iccFile.close(); + } } + } + return rc; +} // Extract::writeIccProfile - bool Print::keyTag(const std::string& key) - { - bool result=Params::instance().keys_.empty(); - for (auto&& k : Params::instance().keys_) { - if (result) - break; - result = key == k; - } - return result ; +void Extract::writePreviewFile(const Exiv2::PreviewImage& pvImg, size_t num) const { + std::string pvFile = newFilePath(path_, "-preview") + Exiv2::toString(num); + std::string pvPath = pvFile + pvImg.extension(); + if (dontOverwrite(pvPath)) + return; + if (Params::instance().verbose_) { + std::cout << _("Writing preview") << " " << num << " (" << pvImg.mimeType() << ", "; + if (pvImg.width() != 0 && pvImg.height() != 0) { + std::cout << pvImg.width() << "x" << pvImg.height() << " " << _("pixels") << ", "; } + std::cout << pvImg.size() << " " << _("bytes") << ") " << _("to file") << " " << pvPath << std::endl; + } + auto rc = pvImg.writeFile(pvFile); + if (rc == 0) { + std::cerr << path_ << ": " << _("Image does not have preview") << " " << num << "\n"; + } +} - static void binaryOutput(const std::ostringstream& os) - { - std::cout << os.str(); +Task::UniquePtr Extract::clone() const { + return std::make_unique(*this); +} + +int Insert::run(const std::string& path) try { + // -i{tgt}- reading from stdin? + bool bStdin = (Params::instance().target_ & Params::ctStdInOut) != 0; + + if (!Exiv2::fileExists(path)) { + std::cerr << path << ": " << _("Failed to open the file\n"); + return -1; + } + + int rc = 0; + Timestamp ts; + if (Params::instance().preserve_) + ts.read(path); + + if (Params::instance().target_ & Params::ctThumb) { + rc = insertThumbnail(path); + } + + if (rc == 0 && !(Params::instance().target_ & Params::ctXmpRaw) && + (Params::instance().target_ & Params::ctExif || Params::instance().target_ & Params::ctIptc || + Params::instance().target_ & Params::ctComment || Params::instance().target_ & Params::ctXmp)) { + std::string suffix = Params::instance().suffix_; + if (suffix.empty()) + suffix = ".exv"; + if (Params::instance().target_ & Params::ctXmpSidecar) + suffix = ".xmp"; + std::string exvPath = bStdin ? "-" : newFilePath(path, suffix); + rc = metacopy(exvPath, path, Exiv2::ImageType::none, true); + } + + if (0 == rc && (Params::instance().target_ & (Params::ctXmpSidecar | Params::ctXmpRaw))) { + std::string xmpPath = bStdin ? "-" : newFilePath(path, ".xmp"); + rc = insertXmpPacket(path, xmpPath); + } + + if (0 == rc && Params::instance().target_ & Params::ctIccProfile) { + std::string iccPath = bStdin ? "-" : newFilePath(path, ".icc"); + rc = insertIccProfile(path, iccPath); + } + + if (Params::instance().preserve_) + ts.touch(path); + return rc; +} catch (const Exiv2::Error& e) { + std::cerr << "Exiv2 exception in insert action for file " << path << ":\n" << e << "\n"; + return 1; +} // Insert::run + +int Insert::insertXmpPacket(const std::string& path, const std::string& xmpPath) { + int rc = 0; + bool bStdin = xmpPath == "-"; + if (bStdin) { + Exiv2::DataBuf xmpBlob; + Params::instance().getStdin(xmpBlob); + rc = insertXmpPacket(path, xmpBlob, true); + } else { + if (!Exiv2::fileExists(xmpPath)) { + std::cerr << xmpPath << ": " << _("Failed to open the file\n"); + rc = -1; } + if (rc == 0 && !Exiv2::fileExists(path)) { + std::cerr << path << ": " << _("Failed to open the file\n"); + rc = -1; + } + if (rc == 0) { + Exiv2::DataBuf xmpBlob = Exiv2::readFile(xmpPath); + rc = insertXmpPacket(path, xmpBlob); + } + } + return rc; - bool Print::printMetadatum(const Exiv2::Metadatum& md, const Exiv2::Image* pImage) - { - if (!grepTag(md.key())) - return false; - if (!keyTag(md.key())) - return false; +} // Insert::insertXmpPacket - if (Params::instance().unknown_ && md.tagName().substr(0, 2) == "0x") { - return false; - } +int Insert::insertXmpPacket(const std::string& path, const Exiv2::DataBuf& xmpBlob, bool usePacket) { + std::string xmpPacket; + for (size_t i = 0; i < xmpBlob.size(); i++) { + xmpPacket += static_cast(xmpBlob.read_uint8(i)); + } + auto image = Exiv2::ImageFactory::open(path); + assert(image); + image->readMetadata(); + image->clearXmpData(); + image->setXmpPacket(xmpPacket); + image->writeXmpFromPacket(usePacket); + image->writeMetadata(); - bool const manyFiles = Params::instance().files_.size() > 1; - if (manyFiles) { - std::cout << std::setfill(' ') << std::left << std::setw(20) << path_ << " "; - } + return 0; +} - bool first = true; - if (Params::instance().printItems_ & Params::prTag) { - first = false; - std::cout << "0x" << std::setw(4) << std::setfill('0') << std::right << std::hex << md.tag(); - } - if (Params::instance().printItems_ & Params::prSet) { - if (!first) - std::cout << " "; - first = false; - std::cout << "set"; - } - if (Params::instance().printItems_ & Params::prGroup) { - if (!first) - std::cout << " "; - first = false; - std::cout << std::setw(12) << std::setfill(' ') << std::left << md.groupName(); - } - if (Params::instance().printItems_ & Params::prKey) { - if (!first) - std::cout << " "; - first = false; - std::cout << std::setfill(' ') << std::left << std::setw(44) << md.key(); - } - if (Params::instance().printItems_ & Params::prName) { - if (!first) - std::cout << " "; - first = false; - std::cout << std::setw(27) << std::setfill(' ') << std::left << md.tagName(); - } - if (Params::instance().printItems_ & Params::prLabel) { - if (!first) - std::cout << " "; - first = false; - std::cout << std::setw(30) << std::setfill(' ') << std::left << md.tagLabel(); - } - if (Params::instance().printItems_ & Params::prType) { - if (!first) - std::cout << " "; - first = false; - std::cout << std::setw(9) << std::setfill(' ') << std::left; - const char* tn = md.typeName(); - if (tn) { - std::cout << tn; - } else { - std::ostringstream os; - os << "0x" << std::setw(4) << std::setfill('0') << std::hex << md.typeId(); - std::cout << os.str(); - } - } - if (Params::instance().printItems_ & Params::prCount) { - if (!first) - std::cout << " "; - first = false; - std::cout << std::dec << std::setw(3) << std::setfill(' ') << std::right << md.count(); - } - if (Params::instance().printItems_ & Params::prSize) { - if (!first) - std::cout << " "; - first = false; - std::cout << std::dec << std::setw(3) << std::setfill(' ') << std::right << md.size(); - } - if (Params::instance().printItems_ & Params::prValue && md.size() > 0) { - if (!first) - std::cout << " "; - first = false; - std::ostringstream os; - // #1114 - show negative values for SByte - if (md.typeId() == Exiv2::signedByte) { - for ( size_t c = 0 ; c < md.value().count() ; c++ ) { - const auto value = md.value().toInt64(c); - os << (c?" ":"") << std::dec << (value < 128 ? value : value - 256); - } - } else { - os << std::dec << md.value(); - } - binaryOutput(os); - } - if (Params::instance().printItems_ & Params::prTrans) { - if (!first) - std::cout << " "; - first = false; - std::ostringstream os; - os << std::dec << md.print(&pImage->exifData()); - binaryOutput(os) ; - } - if (Params::instance().printItems_ & Params::prHex) { - if (!first) - std::cout << std::endl; - Exiv2::DataBuf buf(md.size()); - md.copy(buf.data(), pImage->byteOrder()); - Exiv2::hexdump(std::cout, buf.c_data(), buf.size()); - } - std::cout << std::endl; - return true; - } // Print::printMetadatum +int Insert::insertIccProfile(const std::string& path, const std::string& iccPath) { + int rc = 0; + // for path "foo.XXX", do a binary copy of "foo.icc" + std::string iccProfilePath = newFilePath(path, ".icc"); + if (iccPath == "-") { + Exiv2::DataBuf iccProfile; + Params::instance().getStdin(iccProfile); + rc = insertIccProfile(path, std::move(iccProfile)); + } else { + if (!Exiv2::fileExists(iccProfilePath)) { + std::cerr << iccProfilePath << ": " << _("Failed to open the file\n"); + rc = -1; + } else { + Exiv2::DataBuf iccProfile = Exiv2::readFile(iccPath); + rc = insertIccProfile(path, std::move(iccProfile)); + } + } + return rc; +} // Insert::insertIccProfile - int Print::printComment() - { - if (!Exiv2::fileExists(path_)) { - std::cerr << path_ << ": " << _("Failed to open the file\n"); - return -1; - } +int Insert::insertIccProfile(const std::string& path, Exiv2::DataBuf&& iccProfileBlob) { + int rc = 0; + // test path exists + if (!Exiv2::fileExists(path)) { + std::cerr << path << ": " << _("Failed to open the file\n"); + rc = -1; + } - auto image = Exiv2::ImageFactory::open(path_); - assert(image); - image->readMetadata(); + // read in the metadata + if (rc == 0) { + auto image = Exiv2::ImageFactory::open(path); + assert(image); + image->readMetadata(); + // clear existing profile, assign the blob and rewrite image + image->clearIccProfile(); + if (!iccProfileBlob.empty()) { + image->setIccProfile(std::move(iccProfileBlob)); + } + image->writeMetadata(); + } + + return rc; +} // Insert::insertIccProfile + +int Insert::insertThumbnail(const std::string& path) { + std::string thumbPath = newFilePath(path, "-thumb.jpg"); + if (!Exiv2::fileExists(thumbPath)) { + std::cerr << thumbPath << ": " << _("Failed to open the file\n"); + return -1; + } + if (!Exiv2::fileExists(path)) { + std::cerr << path << ": " << _("Failed to open the file\n"); + return -1; + } + auto image = Exiv2::ImageFactory::open(path); + assert(image); + image->readMetadata(); + Exiv2::ExifThumb exifThumb(image->exifData()); + exifThumb.setJpegThumbnail(thumbPath); + image->writeMetadata(); + + return 0; +} // Insert::insertThumbnail + +Task::UniquePtr Insert::clone() const { + return std::make_unique(*this); +} + +int Modify::run(const std::string& path) { + try { + if (!Exiv2::fileExists(path)) { + std::cerr << path << ": " << _("Failed to open the file\n"); + return -1; + } + Timestamp ts; + if (Params::instance().preserve_) + ts.read(path); + + auto image = Exiv2::ImageFactory::open(path); + assert(image); + image->readMetadata(); + + int rc = applyCommands(image.get()); + + // Save both exif and iptc metadata + image->writeMetadata(); + + if (Params::instance().preserve_) + ts.touch(path); + + return rc; + } catch (const Exiv2::Error& e) { + std::cerr << "Exiv2 exception in modify action for file " << path << ":\n" << e << "\n"; + return 1; + } +} // Modify::run + +int Modify::applyCommands(Exiv2::Image* pImage) { + if (!Params::instance().jpegComment_.empty()) { + // If modify is used when extracting to stdout then ignore verbose + if (Params::instance().verbose_ && + !(Params::instance().action_ & Action::extract && Params::instance().target_ & Params::ctStdInOut)) { + std::cout << _("Setting JPEG comment") << " '" << Params::instance().jpegComment_ << "'" << std::endl; + } + pImage->setComment(Params::instance().jpegComment_); + } + + // loop through command table and apply each command + ModifyCmds& modifyCmds = Params::instance().modifyCmds_; + int rc = 0; + int ret = 0; + for (auto&& cmd : modifyCmds) { + switch (cmd.cmdId_) { + case add: + ret = addMetadatum(pImage, cmd); + if (rc == 0) + rc = ret; + break; + case set: + ret = setMetadatum(pImage, cmd); + if (rc == 0) + rc = ret; + break; + case del: + delMetadatum(pImage, cmd); + break; + case reg: + regNamespace(cmd); + break; + case invalidCmdId: + assert(invalidCmdId == cmd.cmdId_); + break; + } + } + return rc; +} // Modify::applyCommands + +int Modify::addMetadatum(Exiv2::Image* pImage, const ModifyCmd& modifyCmd) { + // If modify is used when extracting to stdout then ignore verbose + if (Params::instance().verbose_ && + !(Params::instance().action_ & Action::extract && Params::instance().target_ & Params::ctStdInOut)) { + std::cout << _("Add") << " " << modifyCmd.key_ << " \"" << modifyCmd.value_ << "\" (" + << Exiv2::TypeInfo::typeName(modifyCmd.typeId_) << ")" << std::endl; + } + Exiv2::ExifData& exifData = pImage->exifData(); + Exiv2::IptcData& iptcData = pImage->iptcData(); + Exiv2::XmpData& xmpData = pImage->xmpData(); + auto value = Exiv2::Value::create(modifyCmd.typeId_); + int rc = value->read(modifyCmd.value_); + if (0 == rc) { + if (modifyCmd.metadataId_ == exif) { + exifData.add(Exiv2::ExifKey(modifyCmd.key_), value.get()); + } + if (modifyCmd.metadataId_ == iptc) { + iptcData.add(Exiv2::IptcKey(modifyCmd.key_), value.get()); + } + if (modifyCmd.metadataId_ == xmp) { + xmpData.add(Exiv2::XmpKey(modifyCmd.key_), value.get()); + } + } else { + std::cerr << _("Warning") << ": " << modifyCmd.key_ << ": " << _("Failed to read") << " " + << Exiv2::TypeInfo::typeName(value->typeId()) << " " << _("value") << " \"" << modifyCmd.value_ << "\"\n"; + } + return rc; +} + +// This function looks rather complex because we try to avoid adding an +// empty metadatum if reading the value fails +int Modify::setMetadatum(Exiv2::Image* pImage, const ModifyCmd& modifyCmd) { + // If modify is used when extracting to stdout then ignore verbose + if (Params::instance().verbose_ && + !(Params::instance().action_ & Action::extract && Params::instance().target_ & Params::ctStdInOut)) { + std::cout << _("Set") << " " << modifyCmd.key_ << " \"" << modifyCmd.value_ << "\" (" + << Exiv2::TypeInfo::typeName(modifyCmd.typeId_) << ")" << std::endl; + } + Exiv2::ExifData& exifData = pImage->exifData(); + Exiv2::IptcData& iptcData = pImage->iptcData(); + Exiv2::XmpData& xmpData = pImage->xmpData(); + Exiv2::Metadatum* metadatum = nullptr; + if (modifyCmd.metadataId_ == exif) { + auto pos = exifData.findKey(Exiv2::ExifKey(modifyCmd.key_)); + if (pos != exifData.end()) { + metadatum = &(*pos); + } + } + if (modifyCmd.metadataId_ == iptc) { + auto pos = iptcData.findKey(Exiv2::IptcKey(modifyCmd.key_)); + if (pos != iptcData.end()) { + metadatum = &(*pos); + } + } + if (modifyCmd.metadataId_ == xmp) { + auto pos = xmpData.findKey(Exiv2::XmpKey(modifyCmd.key_)); + if (pos != xmpData.end()) { + metadatum = &(*pos); + } + } + // If a type was explicitly requested, use it; else + // use the current type of the metadatum, if any; + // or the default type + Exiv2::Value::UniquePtr value; + if (metadatum) { + value = metadatum->getValue(); + } + if (!value || (modifyCmd.explicitType_ && modifyCmd.typeId_ != value->typeId())) { + value = Exiv2::Value::create(modifyCmd.typeId_); + } + int rc = value->read(modifyCmd.value_); + if (0 == rc) { + if (metadatum) { + metadatum->setValue(value.get()); + } else { + if (modifyCmd.metadataId_ == exif) { + exifData.add(Exiv2::ExifKey(modifyCmd.key_), value.get()); + } + if (modifyCmd.metadataId_ == iptc) { + iptcData.add(Exiv2::IptcKey(modifyCmd.key_), value.get()); + } + if (modifyCmd.metadataId_ == xmp) { + xmpData.add(Exiv2::XmpKey(modifyCmd.key_), value.get()); + } + } + } else { + std::cerr << _("Warning") << ": " << modifyCmd.key_ << ": " << _("Failed to read") << " " + << Exiv2::TypeInfo::typeName(value->typeId()) << " " << _("value") << " \"" << modifyCmd.value_ << "\"\n"; + } + return rc; +} + +void Modify::delMetadatum(Exiv2::Image* pImage, const ModifyCmd& modifyCmd) { + // If modify is used when extracting to stdout then ignore verbose + if (Params::instance().verbose_ && + !(Params::instance().action_ & Action::extract && Params::instance().target_ & Params::ctStdInOut)) { + std::cout << _("Del") << " " << modifyCmd.key_ << std::endl; + } + + Exiv2::ExifData& exifData = pImage->exifData(); + Exiv2::IptcData& iptcData = pImage->iptcData(); + Exiv2::XmpData& xmpData = pImage->xmpData(); + if (modifyCmd.metadataId_ == exif) { + Exiv2::ExifData::iterator pos; + const Exiv2::ExifKey exifKey(modifyCmd.key_); + while ((pos = exifData.findKey(exifKey)) != exifData.end()) { + exifData.erase(pos); + } + } + if (modifyCmd.metadataId_ == iptc) { + Exiv2::IptcData::iterator pos; + const Exiv2::IptcKey iptcKey(modifyCmd.key_); + while ((pos = iptcData.findKey(iptcKey)) != iptcData.end()) { + iptcData.erase(pos); + } + } + if (modifyCmd.metadataId_ == xmp) { + Exiv2::XmpData::iterator pos; + const Exiv2::XmpKey xmpKey(modifyCmd.key_); + if ((pos = xmpData.findKey(xmpKey)) != xmpData.end()) { + xmpData.eraseFamily(pos); + } + } +} + +void Modify::regNamespace(const ModifyCmd& modifyCmd) { + // If modify is used when extracting to stdout then ignore verbose + if (Params::instance().verbose_ && + !(Params::instance().action_ & Action::extract && Params::instance().target_ & Params::ctStdInOut)) { + std::cout << _("Reg ") << modifyCmd.key_ << "=\"" << modifyCmd.value_ << "\"" << std::endl; + } + Exiv2::XmpProperties::registerNs(modifyCmd.value_, modifyCmd.key_); +} + +Task::UniquePtr Modify::clone() const { + return std::make_unique(*this); +} + +int Adjust::run(const std::string& path) try { + adjustment_ = Params::instance().adjustment_; + yearAdjustment_ = Params::instance().yodAdjust_[Params::yodYear].adjustment_; + monthAdjustment_ = Params::instance().yodAdjust_[Params::yodMonth].adjustment_; + dayAdjustment_ = Params::instance().yodAdjust_[Params::yodDay].adjustment_; + + if (!Exiv2::fileExists(path)) { + std::cerr << path << ": " << _("Failed to open the file\n"); + return -1; + } + Timestamp ts; + if (Params::instance().preserve_) + ts.read(path); + + auto image = Exiv2::ImageFactory::open(path); + assert(image); + image->readMetadata(); + Exiv2::ExifData& exifData = image->exifData(); + if (exifData.empty()) { + std::cerr << path << ": " << _("No Exif data found in the file\n"); + return -3; + } + int rc = adjustDateTime(exifData, "Exif.Image.DateTime", path); + rc += adjustDateTime(exifData, "Exif.Photo.DateTimeOriginal", path); + rc += adjustDateTime(exifData, "Exif.Image.DateTimeOriginal", path); + rc += adjustDateTime(exifData, "Exif.Photo.DateTimeDigitized", path); + + if (rc == 0) { + image->writeMetadata(); + if (Params::instance().preserve_) + ts.touch(path); + } + return rc ? 1 : 0; +} catch (const Exiv2::Error& e) { + std::cerr << "Exiv2 exception in adjust action for file " << path << ":\n" << e << "\n"; + return 1; +} // Adjust::run + +Task::UniquePtr Adjust::clone() const { + return std::make_unique(*this); +} + +int Adjust::adjustDateTime(Exiv2::ExifData& exifData, const std::string& key, const std::string& path) const { + Exiv2::ExifKey ek(key); + auto md = exifData.findKey(ek); + if (md == exifData.end()) { + // Key not found. That's ok, we do nothing. + return 0; + } + std::string timeStr = md->toString(); + if (timeStr.empty() || timeStr[0] == ' ') { + std::cerr << path << ": " << _("Timestamp of metadatum with key") << " `" << ek << "' " << _("not set\n"); + return 1; + } + if (Params::instance().verbose_) { + bool comma = false; + std::cout << _("Adjusting") << " `" << ek << "' " << _("by"); + if (yearAdjustment_ != 0) { + std::cout << (yearAdjustment_ < 0 ? " " : " +") << yearAdjustment_ << " "; + if (yearAdjustment_ < -1 || yearAdjustment_ > 1) { + std::cout << _("years"); + } else { + std::cout << _("year"); + } + comma = true; + } + if (monthAdjustment_ != 0) { + if (comma) + std::cout << ","; + std::cout << (monthAdjustment_ < 0 ? " " : " +") << monthAdjustment_ << " "; + if (monthAdjustment_ < -1 || monthAdjustment_ > 1) { + std::cout << _("months"); + } else { + std::cout << _("month"); + } + comma = true; + } + if (dayAdjustment_ != 0) { + if (comma) + std::cout << ","; + std::cout << (dayAdjustment_ < 0 ? " " : " +") << dayAdjustment_ << " "; + if (dayAdjustment_ < -1 || dayAdjustment_ > 1) { + std::cout << _("days"); + } else { + std::cout << _("day"); + } + comma = true; + } + if (adjustment_ != 0) { + if (comma) + std::cout << ","; + std::cout << " " << adjustment_ << _("s"); + } + } + struct tm tm; + if (str2Tm(timeStr, &tm) != 0) { + if (Params::instance().verbose_) + std::cout << std::endl; + std::cerr << path << ": " << _("Failed to parse timestamp") << " `" << timeStr << "'\n"; + return 1; + } + const long monOverflow = (tm.tm_mon + monthAdjustment_) / 12; + tm.tm_mon = (tm.tm_mon + monthAdjustment_) % 12; + tm.tm_year += yearAdjustment_ + monOverflow; + // Let's not create files with non-4-digit years, we can't read them. + if (tm.tm_year > 9999 - 1900 || tm.tm_year < 1000 - 1900) { + if (Params::instance().verbose_) + std::cout << std::endl; + std::cerr << path << ": " << _("Can't adjust timestamp by") << " " << yearAdjustment_ + monOverflow << " " + << _("years") << "\n"; + return 1; + } + time_t time = mktime(&tm); + time += adjustment_ + dayAdjustment_ * 86400; + timeStr = time2Str(time); + if (Params::instance().verbose_) { + std::cout << " " << _("to") << " " << timeStr << std::endl; + } + md->setValue(timeStr); + return 0; +} // Adjust::adjustDateTime + +int FixIso::run(const std::string& path) { + try { + if (!Exiv2::fileExists(path)) { + std::cerr << path << ": " << _("Failed to open the file\n"); + return -1; + } + Timestamp ts; + if (Params::instance().preserve_) + ts.read(path); + + auto image = Exiv2::ImageFactory::open(path); + assert(image); + image->readMetadata(); + Exiv2::ExifData& exifData = image->exifData(); + if (exifData.empty()) { + std::cerr << path << ": " << _("No Exif data found in the file\n"); + return -3; + } + auto md = Exiv2::isoSpeed(exifData); + if (md != exifData.end()) { + if (strcmp(md->key().c_str(), "Exif.Photo.ISOSpeedRatings") == 0) { if (Params::instance().verbose_) { - std::cout << _("JPEG comment") << ": "; - } - std::cout << image->comment() << std::endl; - return 0; - } // Print::printComment - - int Print::printPreviewList() - { - if (!Exiv2::fileExists(path_)) { - std::cerr << path_ << ": " << _("Failed to open the file\n"); - return -1; - } - - auto image = Exiv2::ImageFactory::open(path_); - assert(image); - image->readMetadata(); - bool const manyFiles = Params::instance().files_.size() > 1; - int cnt = 0; - Exiv2::PreviewManager pm(*image); - Exiv2::PreviewPropertiesList list = pm.getPreviewProperties(); - for (auto&& pos : list) { - if (manyFiles) { - std::cout << std::setfill(' ') << std::left << std::setw(20) - << path_ << " "; - } - std::cout << _("Preview") << " " << ++cnt << ": " << pos.mimeType_ << ", "; - if (pos.width_ != 0 && pos.height_ != 0) { - std::cout << pos.width_ << "x" << pos.height_ << " " << _("pixels") << ", "; - } - std::cout << pos.size_ << " " << _("bytes") << "\n"; + std::cout << _("Standard Exif ISO tag exists; not modified\n"); } return 0; - } // Print::printPreviewList - - Task::UniquePtr Print::clone() const - { - return std::make_unique(*this); + } + // Copy the proprietary tag to the standard place + std::ostringstream os; + md->write(os, &exifData); + if (Params::instance().verbose_) { + std::cout << _("Setting Exif ISO value to") << " " << os.str() << "\n"; + } + exifData["Exif.Photo.ISOSpeedRatings"] = os.str(); } + image->writeMetadata(); + if (Params::instance().preserve_) + ts.touch(path); - int Rename::run(const std::string& path) - { - try { - if (!Exiv2::fileExists(path)) { - std::cerr << path << ": " << _("Failed to open the file\n"); - return -1; - } - Timestamp ts; - if (Params::instance().preserve_) - ts.read(path); + return 0; + } catch (const Exiv2::Error& e) { + std::cerr << "Exiv2 exception in fixiso action for file " << path << ":\n" << e << "\n"; + return 1; + } +} // FixIso::run - auto image = Exiv2::ImageFactory::open(path); - assert(image); - image->readMetadata(); - Exiv2::ExifData& exifData = image->exifData(); - if (exifData.empty()) { - std::cerr << path - << ": " << _("No Exif data found in the file\n"); - return -3; - } - Exiv2::ExifKey key("Exif.Photo.DateTimeOriginal"); - auto md = exifData.findKey(key); - if (md == exifData.end()) { - key = Exiv2::ExifKey("Exif.Image.DateTime"); - md = exifData.findKey(key); - } - if (md == exifData.end()) { - std::cerr << _("Neither tag") << " `Exif.Photo.DateTimeOriginal' " - << _("nor") << " `Exif.Image.DateTime' " - << _("found in the file") << " " << path << "\n"; - return 1; - } - std::string v = md->toString(); - if (v.length() == 0 || v[0] == ' ') { - std::cerr << _("Image file creation timestamp not set in the file") - << " " << path << "\n"; - return 1; - } - struct tm tm; - if (str2Tm(v, &tm) != 0) { - std::cerr << _("Failed to parse timestamp") << " `" << v - << "' " << _("in the file") << " " << path << "\n"; - return 1; - } - if ( Params::instance().timestamp_ - || Params::instance().timestampOnly_) { - ts.read(&tm); - } - int rc = 0; - std::string newPath = path; - if (Params::instance().timestampOnly_) { - if (Params::instance().verbose_) { - std::cout << _("Updating timestamp to") << " " << v << std::endl; - } - } - else { - rc = renameFile(newPath, &tm); - if (rc == -1) return 0; // skip - } - if ( 0 == rc - && ( Params::instance().preserve_ - || Params::instance().timestamp_ - || Params::instance().timestampOnly_)) { - ts.touch(newPath); - } - return rc; +Task::UniquePtr FixIso::clone() const { + return std::make_unique(*this); +} + +int FixCom::run(const std::string& path) { + try { + if (!Exiv2::fileExists(path)) { + std::cerr << path << ": " << _("Failed to open the file\n"); + return -1; } - catch(const Exiv2::Error& e) - { - std::cerr << "Exiv2 exception in rename action for file " << path - << ":\n" << e << "\n"; - return 1; + Timestamp ts; + if (Params::instance().preserve_) + ts.read(path); + + auto image = Exiv2::ImageFactory::open(path); + assert(image); + image->readMetadata(); + Exiv2::ExifData& exifData = image->exifData(); + if (exifData.empty()) { + std::cerr << path << ": " << _("No Exif data found in the file\n"); + return -3; } + auto pos = exifData.findKey(Exiv2::ExifKey("Exif.Photo.UserComment")); + if (pos == exifData.end()) { + if (Params::instance().verbose_) { + std::cout << _("No Exif user comment found") << "\n"; + } + return 0; } - - Task::UniquePtr Rename::clone() const - { - return std::make_unique(*this); + Exiv2::Value::UniquePtr v = pos->getValue(); + const auto pcv = dynamic_cast(v.get()); + if (!pcv) { + if (Params::instance().verbose_) { + std::cout << _("Found Exif user comment with unexpected value type") << "\n"; + } + return 0; } - - int Erase::run(const std::string& path) - { - try { - path_ = path; - - if (!Exiv2::fileExists(path_)) { - std::cerr << path_ << ": " << _("Failed to open the file\n"); - return -1; - } - Timestamp ts; - if (Params::instance().preserve_) - ts.read(path); - - auto image = Exiv2::ImageFactory::open(path_); - assert(image); - image->readMetadata(); - // Thumbnail must be before Exif - int rc = 0; - if (Params::instance().target_ & Params::ctThumb) { - rc = eraseThumbnail(image.get()); - } - if (0 == rc && Params::instance().target_ & Params::ctExif) { - rc = eraseExifData(image.get()); - } - if (0 == rc && Params::instance().target_ & Params::ctIptc) { - rc = eraseIptcData(image.get()); - } - if (0 == rc && Params::instance().target_ & Params::ctComment) { - rc = eraseComment(image.get()); - } - if (0 == rc && Params::instance().target_ & Params::ctXmp) { - rc = eraseXmpData(image.get()); - } - if (0 == rc && Params::instance().target_ & Params::ctIccProfile) { - rc = eraseIccProfile(image.get()); - } - if (0 == rc && Params::instance().target_ & Params::ctIptcRaw) { - rc = printStructure(std::cout,Exiv2::kpsIptcErase,path_); - } - - if (0 == rc) { - image->writeMetadata(); - if (Params::instance().preserve_) ts.touch(path); - } - - return rc; + Exiv2::CommentValue::CharsetId csId = pcv->charsetId(); + if (csId != Exiv2::CommentValue::unicode) { + if (Params::instance().verbose_) { + std::cout << _("No Exif UNICODE user comment found") << "\n"; + } + return 0; } - catch(const Exiv2::Error& e) - { - std::cerr << "Exiv2 exception in erase action for file " << path - << ":\n" << e << "\n"; - return 1; + std::string comment = pcv->comment(Params::instance().charset_.c_str()); + if (Params::instance().verbose_) { + std::cout << _("Setting Exif UNICODE user comment to") << " \"" << comment << "\"\n"; } - } - - int Erase::eraseThumbnail(Exiv2::Image* image) - { - Exiv2::ExifThumb exifThumb(image->exifData()); - std::string thumbExt = exifThumb.extension(); - if (thumbExt.empty()) { - return 0; - } - exifThumb.erase(); - if (Params::instance().verbose_) { - std::cout << _("Erasing thumbnail data") << std::endl; - } - return 0; - } - - int Erase::eraseExifData(Exiv2::Image* image) - { - if (Params::instance().verbose_ && image->exifData().count() > 0) { - std::cout << _("Erasing Exif data from the file") << std::endl; - } - image->clearExifData(); - return 0; - } - - int Erase::eraseIptcData(Exiv2::Image* image) - { - if (Params::instance().verbose_ && image->iptcData().count() > 0) { - std::cout << _("Erasing IPTC data from the file") << std::endl; - } - image->clearIptcData(); - return 0; - } - - int Erase::eraseComment(Exiv2::Image* image) - { - if (Params::instance().verbose_ && !image->comment().empty()) { - std::cout << _("Erasing JPEG comment from the file") << std::endl; - } - image->clearComment(); - return 0; - } - - int Erase::eraseXmpData(Exiv2::Image* image) - { - if (Params::instance().verbose_ && image->xmpData().count() > 0) { - std::cout << _("Erasing XMP data from the file") << std::endl; - } - image->clearXmpData(); // Quick fix for bug #612 - image->clearXmpPacket(); - return 0; - } - int Erase::eraseIccProfile(Exiv2::Image* image) - { - if (Params::instance().verbose_ && image->iccProfileDefined() ) { - std::cout << _("Erasing ICC Profile data from the file") << std::endl; - } - image->clearIccProfile(); - return 0; - } - - Task::UniquePtr Erase::clone() const - { - return std::make_unique(*this); - } - - int Extract::run(const std::string& path) - { - try { - path_ = path; - int rc = 0; - - bool bStdout = (Params::instance().target_ & Params::ctStdInOut) != 0; - if (bStdout) { - _setmode(fileno(stdout), _O_BINARY); - } - - if (Params::instance().target_ & Params::ctThumb) { - rc = writeThumbnail(); - } - if (!rc && Params::instance().target_ & Params::ctPreview) { - rc = writePreviews(); - } - if (!rc && Params::instance().target_ & Params::ctXmpSidecar) { - std::string xmpPath = bStdout ? "-" : newFilePath(path_, ".xmp"); - if (dontOverwrite(xmpPath)) - return 0; - rc = metacopy(path_, xmpPath, Exiv2::ImageType::xmp, false); - } - if (!rc && Params::instance().target_ & Params::ctIccProfile) { - std::string iccPath = bStdout ? "-" : newFilePath(path_, ".icc"); - rc = writeIccProfile(iccPath); - } - if (!rc - && !(Params::instance().target_ & Params::ctXmpSidecar) - && !(Params::instance().target_ & Params::ctThumb) - && !(Params::instance().target_ & Params::ctPreview) - && !(Params::instance().target_ & Params::ctIccProfile)) { - std::string exvPath = bStdout ? "-" : newFilePath(path_, ".exv"); - if (dontOverwrite(exvPath)) - return 0; - rc = metacopy(path_, exvPath, Exiv2::ImageType::exv, false); - } - return rc; - } catch (const Exiv2::Error& e) { - std::cerr << "Exiv2 exception in extract action for file " << path << ":\n" << e << "\n"; - return 1; - } - } - - int Extract::writeThumbnail() const - { - if (!Exiv2::fileExists(path_)) { - std::cerr << path_ << ": " << _("Failed to open the file\n"); - return -1; - } - auto image = Exiv2::ImageFactory::open(path_); - assert(image); - image->readMetadata(); - Exiv2::ExifData& exifData = image->exifData(); - if (exifData.empty()) { - std::cerr << path_ << ": " << _("No Exif data found in the file\n"); - return -3; - } - int rc = 0; - Exiv2::ExifThumb exifThumb(exifData); - std::string thumbExt = exifThumb.extension(); - if (thumbExt.empty()) { - std::cerr << path_ << ": " << _("Image does not contain an Exif thumbnail\n"); - } - else { - if ( (Params::instance().target_ & Params::ctStdInOut) != 0 ) { - Exiv2::DataBuf buf = exifThumb.copy(); - std::cout.write(buf.c_str(), buf.size()); - return 0; - } - - std::string thumb = newFilePath(path_, "-thumb"); - std::string thumbPath = thumb + thumbExt; - if (dontOverwrite(thumbPath)) return 0; - if (Params::instance().verbose_) { - Exiv2::DataBuf buf = exifThumb.copy(); - if (!buf.empty()) { - std::cout << _("Writing thumbnail") << " (" << exifThumb.mimeType() << ", " - << buf.size() << " " << _("Bytes") << ") " << _("to file") << " " - << thumbPath << std::endl; - } - } - rc = static_cast(exifThumb.writeFile(thumb)); - if (rc == 0) { - std::cerr << path_ << ": " << _("Exif data doesn't contain a thumbnail\n"); - } - } - return rc; - } // Extract::writeThumbnail - - int Extract::writePreviews() const - { - if (!Exiv2::fileExists(path_)) { - std::cerr << path_ << ": " << _("Failed to open the file\n"); - return -1; - } - - auto image = Exiv2::ImageFactory::open(path_); - assert(image); - image->readMetadata(); - - Exiv2::PreviewManager pvMgr(*image); - Exiv2::PreviewPropertiesList pvList = pvMgr.getPreviewProperties(); - - const Params::PreviewNumbers& numbers = Params::instance().previewNumbers_; - for (auto number : numbers) { - auto num = static_cast(number); - if (num == 0) { - // Write all previews - for (num = 0; num < pvList.size(); ++num) { - writePreviewFile(pvMgr.getPreviewImage(pvList[num]), num + 1); - } - break; - } - num--; - if (num >= pvList.size()) { - std::cerr << path_ << ": " << _("Image does not have preview") - << " " << num + 1 << "\n"; - continue; - } - writePreviewFile(pvMgr.getPreviewImage(pvList[num]), num + 1); - } - return 0; - } // Extract::writePreviews - - int Extract::writeIccProfile(const std::string& target) const - { - int rc = 0; - if (!Exiv2::fileExists(path_)) { - std::cerr << path_ << ": " << _("Failed to open the file\n"); - rc = -1; - } - - bool bStdout = target == "-" ; - - if ( rc == 0 ) { - auto image = Exiv2::ImageFactory::open(path_); - assert(image); - image->readMetadata(); - if ( !image->iccProfileDefined() ) { - std::cerr << _("No embedded iccProfile: ") << path_ << std::endl; - rc = -2; - } else { - - if ( bStdout ) { // -eC- - std::cout.write(image->iccProfile().c_str(), image->iccProfile().size()); - } else { - if (Params::instance().verbose_) { - std::cout << _("Writing iccProfile: ") << target << std::endl; - } - Exiv2::FileIo iccFile(target); - iccFile.open("wb") ; - iccFile.write(image->iccProfile().c_data(), image->iccProfile().size()); - iccFile.close(); - } - } - } - return rc; - } // Extract::writeIccProfile - - - void Extract::writePreviewFile(const Exiv2::PreviewImage& pvImg, size_t num) const - { - std::string pvFile = newFilePath(path_, "-preview") + Exiv2::toString(num); - std::string pvPath = pvFile + pvImg.extension(); - if (dontOverwrite(pvPath)) return; - if (Params::instance().verbose_) { - std::cout << _("Writing preview") << " " << num << " (" - << pvImg.mimeType() << ", "; - if (pvImg.width() != 0 && pvImg.height() != 0) { - std::cout << pvImg.width() << "x" << pvImg.height() << " " - << _("pixels") << ", "; - } - std::cout << pvImg.size() << " " << _("bytes") << ") " - << _("to file") << " " << pvPath << std::endl; - } - auto rc = pvImg.writeFile(pvFile); - if (rc == 0) { - std::cerr << path_ << ": " << _("Image does not have preview") - << " " << num << "\n"; - } - } - - Task::UniquePtr Extract::clone() const - { - return std::make_unique(*this); - } - - int Insert::run(const std::string& path) - try { - // -i{tgt}- reading from stdin? - bool bStdin = (Params::instance().target_ & Params::ctStdInOut) != 0; - - if (!Exiv2::fileExists(path)) { - std::cerr << path - << ": " << _("Failed to open the file\n"); - return -1; - } - - int rc = 0; - Timestamp ts; - if (Params::instance().preserve_) ts.read(path); - - if (Params::instance().target_ & Params::ctThumb) { - rc = insertThumbnail(path); - } - - if ( rc == 0 && !(Params::instance().target_ & Params::ctXmpRaw) - && ( Params::instance().target_ & Params::ctExif - || Params::instance().target_ & Params::ctIptc - || Params::instance().target_ & Params::ctComment - || Params::instance().target_ & Params::ctXmp - ) - ) { - std::string suffix = Params::instance().suffix_; - if (suffix.empty()) suffix = ".exv"; - if (Params::instance().target_ & Params::ctXmpSidecar) suffix = ".xmp"; - std::string exvPath = bStdin ? "-" : newFilePath(path, suffix); - rc = metacopy(exvPath, path, Exiv2::ImageType::none, true); - } - - if (0 == rc && (Params::instance().target_ & (Params::ctXmpSidecar|Params::ctXmpRaw)) ) { - std::string xmpPath = bStdin ? "-" : newFilePath(path,".xmp"); - rc = insertXmpPacket(path,xmpPath); - } - - if (0 == rc && Params::instance().target_ & Params::ctIccProfile) { - std::string iccPath = bStdin ? "-" : newFilePath(path,".icc"); - rc = insertIccProfile(path,iccPath); - } - - if (Params::instance().preserve_) ts.touch(path); - return rc; - } - catch(const Exiv2::Error& e) - { - std::cerr << "Exiv2 exception in insert action for file " << path - << ":\n" << e << "\n"; - return 1; - } // Insert::run - - int Insert::insertXmpPacket(const std::string& path,const std::string& xmpPath) - { - int rc = 0; - bool bStdin = xmpPath == "-" ; - if ( bStdin ) { - Exiv2::DataBuf xmpBlob; - Params::instance().getStdin(xmpBlob); - rc = insertXmpPacket(path,xmpBlob,true); - } else { - if (!Exiv2::fileExists(xmpPath)) { - std::cerr << xmpPath - << ": " << _("Failed to open the file\n"); - rc = -1; - } - if (rc == 0 && !Exiv2::fileExists(path)) { - std::cerr << path - << ": " << _("Failed to open the file\n"); - rc = -1; - } - if ( rc == 0 ) { - Exiv2::DataBuf xmpBlob = Exiv2::readFile(xmpPath); - rc = insertXmpPacket(path,xmpBlob); - } - } - return rc; - - } // Insert::insertXmpPacket - - int Insert::insertXmpPacket(const std::string& path, const Exiv2::DataBuf& xmpBlob, bool usePacket) - { - std::string xmpPacket; - for ( size_t i = 0 ; i < xmpBlob.size() ; i++ ) { - xmpPacket += static_cast(xmpBlob.read_uint8(i)); - } - auto image = Exiv2::ImageFactory::open(path); - assert(image); - image->readMetadata(); - image->clearXmpData(); - image->setXmpPacket(xmpPacket); - image->writeXmpFromPacket(usePacket); - image->writeMetadata(); - - return 0; - } - - int Insert::insertIccProfile(const std::string& path,const std::string& iccPath) - { - int rc = 0; - // for path "foo.XXX", do a binary copy of "foo.icc" - std::string iccProfilePath = newFilePath(path, ".icc"); - if ( iccPath == "-" ) { - Exiv2::DataBuf iccProfile ; - Params::instance().getStdin(iccProfile); - rc = insertIccProfile(path,std::move(iccProfile)); - } else { - if (!Exiv2::fileExists(iccProfilePath)) { - std::cerr << iccProfilePath - << ": " << _("Failed to open the file\n"); - rc = -1; - } else { - Exiv2::DataBuf iccProfile = Exiv2::readFile(iccPath); - rc = insertIccProfile(path,std::move(iccProfile)); - } - } - return rc; - } // Insert::insertIccProfile - - int Insert::insertIccProfile(const std::string& path, Exiv2::DataBuf&& iccProfileBlob) - { - int rc = 0; - // test path exists - if (!Exiv2::fileExists(path)) { - std::cerr << path << ": " << _("Failed to open the file\n"); - rc=-1; - } - - // read in the metadata - if ( rc == 0 ) { - auto image = Exiv2::ImageFactory::open(path); - assert(image); - image->readMetadata(); - // clear existing profile, assign the blob and rewrite image - image->clearIccProfile(); - if (!iccProfileBlob.empty()) { - image->setIccProfile(std::move(iccProfileBlob)); - } - image->writeMetadata(); - } - - return rc; - } // Insert::insertIccProfile - - int Insert::insertThumbnail(const std::string& path) - { - std::string thumbPath = newFilePath(path, "-thumb.jpg"); - if (!Exiv2::fileExists(thumbPath)) { - std::cerr << thumbPath - << ": " << _("Failed to open the file\n"); - return -1; - } - if (!Exiv2::fileExists(path)) { - std::cerr << path - << ": " << _("Failed to open the file\n"); - return -1; - } - auto image = Exiv2::ImageFactory::open(path); - assert(image); - image->readMetadata(); - Exiv2::ExifThumb exifThumb(image->exifData()); - exifThumb.setJpegThumbnail(thumbPath); - image->writeMetadata(); - - return 0; - } // Insert::insertThumbnail - - Task::UniquePtr Insert::clone() const - { - return std::make_unique(*this); - } - - int Modify::run(const std::string& path) - { - try { - if (!Exiv2::fileExists(path)) { - std::cerr << path << ": " << _("Failed to open the file\n"); - return -1; - } - Timestamp ts; - if (Params::instance().preserve_) - ts.read(path); - - auto image = Exiv2::ImageFactory::open(path); - assert(image); - image->readMetadata(); - - int rc = applyCommands(image.get()); - - // Save both exif and iptc metadata - image->writeMetadata(); - - if (Params::instance().preserve_) ts.touch(path); - - return rc; - } - catch(const Exiv2::Error& e) - { - std::cerr << "Exiv2 exception in modify action for file " << path - << ":\n" << e << "\n"; - return 1; - } - } // Modify::run - - int Modify::applyCommands(Exiv2::Image* pImage) - { - if (!Params::instance().jpegComment_.empty()) { - // If modify is used when extracting to stdout then ignore verbose - if (Params::instance().verbose_ && !(Params::instance().action_ & Action::extract && Params::instance().target_ & Params::ctStdInOut)) { - std::cout << _("Setting JPEG comment") << " '" - << Params::instance().jpegComment_ - << "'" - << std::endl; - } - pImage->setComment(Params::instance().jpegComment_); - } - - // loop through command table and apply each command - ModifyCmds& modifyCmds = Params::instance().modifyCmds_; - int rc = 0; - int ret = 0; - for (auto&& cmd : modifyCmds) { - switch (cmd.cmdId_) { - case add: - ret = addMetadatum(pImage, cmd); - if (rc == 0) - rc = ret; - break; - case set: - ret = setMetadatum(pImage, cmd); - if (rc == 0) - rc = ret; - break; - case del: - delMetadatum(pImage, cmd); - break; - case reg: - regNamespace(cmd); - break; - case invalidCmdId: - assert(invalidCmdId == cmd.cmdId_); - break; - } - } - return rc; - } // Modify::applyCommands - - int Modify::addMetadatum(Exiv2::Image* pImage, const ModifyCmd& modifyCmd) - { - // If modify is used when extracting to stdout then ignore verbose - if (Params::instance().verbose_ && !(Params::instance().action_ & Action::extract && Params::instance().target_ & Params::ctStdInOut)) { - std::cout << _("Add") << " " << modifyCmd.key_ << " \"" - << modifyCmd.value_ << "\" (" - << Exiv2::TypeInfo::typeName(modifyCmd.typeId_) - << ")" << std::endl; - } - Exiv2::ExifData& exifData = pImage->exifData(); - Exiv2::IptcData& iptcData = pImage->iptcData(); - Exiv2::XmpData& xmpData = pImage->xmpData(); - auto value = Exiv2::Value::create(modifyCmd.typeId_); - int rc = value->read(modifyCmd.value_); - if (0 == rc) { - if (modifyCmd.metadataId_ == exif) { - exifData.add(Exiv2::ExifKey(modifyCmd.key_), value.get()); - } - if (modifyCmd.metadataId_ == iptc) { - iptcData.add(Exiv2::IptcKey(modifyCmd.key_), value.get()); - } - if (modifyCmd.metadataId_ == xmp) { - xmpData.add(Exiv2::XmpKey(modifyCmd.key_), value.get()); - } - } - else { - std::cerr << _("Warning") << ": " << modifyCmd.key_ << ": " - << _("Failed to read") << " " - << Exiv2::TypeInfo::typeName(value->typeId()) - << " " << _("value") - << " \"" << modifyCmd.value_ << "\"\n"; - } - return rc; - } - - // This function looks rather complex because we try to avoid adding an - // empty metadatum if reading the value fails - int Modify::setMetadatum(Exiv2::Image* pImage, const ModifyCmd& modifyCmd) - { - // If modify is used when extracting to stdout then ignore verbose - if (Params::instance().verbose_ && !(Params::instance().action_ & Action::extract && Params::instance().target_ & Params::ctStdInOut)) { - std::cout << _("Set") << " " << modifyCmd.key_ << " \"" - << modifyCmd.value_ << "\" (" - << Exiv2::TypeInfo::typeName(modifyCmd.typeId_) - << ")" << std::endl; - } - Exiv2::ExifData& exifData = pImage->exifData(); - Exiv2::IptcData& iptcData = pImage->iptcData(); - Exiv2::XmpData& xmpData = pImage->xmpData(); - Exiv2::Metadatum* metadatum = nullptr; - if (modifyCmd.metadataId_ == exif) { - auto pos = exifData.findKey(Exiv2::ExifKey(modifyCmd.key_)); - if (pos != exifData.end()) { - metadatum = &(*pos); - } - } - if (modifyCmd.metadataId_ == iptc) { - auto pos = iptcData.findKey(Exiv2::IptcKey(modifyCmd.key_)); - if (pos != iptcData.end()) { - metadatum = &(*pos); - } - } - if (modifyCmd.metadataId_ == xmp) { - auto pos = xmpData.findKey(Exiv2::XmpKey(modifyCmd.key_)); - if (pos != xmpData.end()) { - metadatum = &(*pos); - } - } - // If a type was explicitly requested, use it; else - // use the current type of the metadatum, if any; - // or the default type - Exiv2::Value::UniquePtr value; - if (metadatum) { - value = metadatum->getValue(); - } - if (!value || (modifyCmd.explicitType_ && modifyCmd.typeId_ != value->typeId())) { - value = Exiv2::Value::create(modifyCmd.typeId_); - } - int rc = value->read(modifyCmd.value_); - if (0 == rc) { - if (metadatum) { - metadatum->setValue(value.get()); - } - else { - if (modifyCmd.metadataId_ == exif) { - exifData.add(Exiv2::ExifKey(modifyCmd.key_), value.get()); - } - if (modifyCmd.metadataId_ == iptc) { - iptcData.add(Exiv2::IptcKey(modifyCmd.key_), value.get()); - } - if (modifyCmd.metadataId_ == xmp) { - xmpData.add(Exiv2::XmpKey(modifyCmd.key_), value.get()); - } - } - } - else { - std::cerr << _("Warning") << ": " << modifyCmd.key_ << ": " - << _("Failed to read") << " " - << Exiv2::TypeInfo::typeName(value->typeId()) - << " " << _("value") - << " \"" << modifyCmd.value_ << "\"\n"; - } - return rc; - } - - void Modify::delMetadatum(Exiv2::Image* pImage, const ModifyCmd& modifyCmd) - { - // If modify is used when extracting to stdout then ignore verbose - if (Params::instance().verbose_ && !(Params::instance().action_ & Action::extract && Params::instance().target_ & Params::ctStdInOut)) { - std::cout << _("Del") << " " << modifyCmd.key_ << std::endl; - } - - Exiv2::ExifData& exifData = pImage->exifData(); - Exiv2::IptcData& iptcData = pImage->iptcData(); - Exiv2::XmpData& xmpData = pImage->xmpData(); - if (modifyCmd.metadataId_ == exif) { - Exiv2::ExifData::iterator pos; - const Exiv2::ExifKey exifKey(modifyCmd.key_); - while((pos = exifData.findKey(exifKey)) != exifData.end()) { - exifData.erase(pos); - } - } - if (modifyCmd.metadataId_ == iptc) { - Exiv2::IptcData::iterator pos; - const Exiv2::IptcKey iptcKey(modifyCmd.key_); - while((pos = iptcData.findKey(iptcKey)) != iptcData.end()) { - iptcData.erase(pos); - } - } - if (modifyCmd.metadataId_ == xmp) { - Exiv2::XmpData::iterator pos; - const Exiv2::XmpKey xmpKey (modifyCmd.key_); - if((pos = xmpData.findKey(xmpKey)) != xmpData.end()) { - xmpData.eraseFamily(pos); - } - } - } - - void Modify::regNamespace(const ModifyCmd& modifyCmd) - { - // If modify is used when extracting to stdout then ignore verbose - if (Params::instance().verbose_ && !(Params::instance().action_ & Action::extract && Params::instance().target_ & Params::ctStdInOut)) { - std::cout << _("Reg ") << modifyCmd.key_ << "=\"" - << modifyCmd.value_ << "\"" << std::endl; - } - Exiv2::XmpProperties::registerNs(modifyCmd.value_, modifyCmd.key_); - } - - Task::UniquePtr Modify::clone() const - { - return std::make_unique(*this); - } - - int Adjust::run(const std::string& path) - try { - adjustment_ = Params::instance().adjustment_; - yearAdjustment_ = Params::instance().yodAdjust_[Params::yodYear].adjustment_; - monthAdjustment_ = Params::instance().yodAdjust_[Params::yodMonth].adjustment_; - dayAdjustment_ = Params::instance().yodAdjust_[Params::yodDay].adjustment_; - - if (!Exiv2::fileExists(path)) { - std::cerr << path << ": " << _("Failed to open the file\n"); - return -1; - } - Timestamp ts; - if (Params::instance().preserve_) - ts.read(path); - - auto image = Exiv2::ImageFactory::open(path); - assert(image); - image->readMetadata(); - Exiv2::ExifData& exifData = image->exifData(); - if (exifData.empty()) { - std::cerr << path - << ": " << _("No Exif data found in the file\n"); - return -3; - } - int rc = adjustDateTime(exifData, "Exif.Image.DateTime", path); - rc += adjustDateTime(exifData, "Exif.Photo.DateTimeOriginal", path); - rc += adjustDateTime(exifData, "Exif.Image.DateTimeOriginal", path); - rc += adjustDateTime(exifData, "Exif.Photo.DateTimeDigitized", path); - - if (rc == 0 ) { - image->writeMetadata(); - if (Params::instance().preserve_) ts.touch(path); - } - return rc?1:0; - } - catch(const Exiv2::Error& e) - { - std::cerr << "Exiv2 exception in adjust action for file " << path - << ":\n" << e << "\n"; - return 1; - } // Adjust::run - - Task::UniquePtr Adjust::clone() const - { - return std::make_unique(*this); - } - - int Adjust::adjustDateTime(Exiv2::ExifData& exifData, - const std::string& key, - const std::string& path) const - { - Exiv2::ExifKey ek(key); - auto md = exifData.findKey(ek); - if (md == exifData.end()) { - // Key not found. That's ok, we do nothing. - return 0; - } - std::string timeStr = md->toString(); - if (timeStr.empty() || timeStr[0] == ' ') { - std::cerr << path << ": " << _("Timestamp of metadatum with key") << " `" - << ek << "' " << _("not set\n"); - return 1; - } - if (Params::instance().verbose_) { - bool comma = false; - std::cout << _("Adjusting") << " `" << ek << "' " << _("by"); - if (yearAdjustment_ != 0) { - std::cout << (yearAdjustment_ < 0 ? " " : " +") << yearAdjustment_ << " "; - if (yearAdjustment_ < -1 || yearAdjustment_ > 1) { - std::cout << _("years"); - } - else { - std::cout << _("year"); - } - comma = true; - } - if (monthAdjustment_ != 0) { - if (comma) std::cout << ","; - std::cout << (monthAdjustment_ < 0 ? " " : " +") << monthAdjustment_ << " "; - if (monthAdjustment_ < -1 || monthAdjustment_ > 1) { - std::cout << _("months"); - } - else { - std::cout << _("month"); - } - comma = true; - } - if (dayAdjustment_ != 0) { - if (comma) std::cout << ","; - std::cout << (dayAdjustment_ < 0 ? " " : " +") << dayAdjustment_ << " "; - if (dayAdjustment_ < -1 || dayAdjustment_ > 1) { - std::cout << _("days"); - } - else { - std::cout << _("day"); - } - comma = true; - } - if (adjustment_ != 0) { - if (comma) std::cout << ","; - std::cout << " " << adjustment_ << _("s"); - } - } - struct tm tm; - if (str2Tm(timeStr, &tm) != 0) { - if (Params::instance().verbose_) std::cout << std::endl; - std::cerr << path << ": " << _("Failed to parse timestamp") << " `" - << timeStr << "'\n"; - return 1; - } - const long monOverflow = (tm.tm_mon + monthAdjustment_) / 12; - tm.tm_mon = (tm.tm_mon + monthAdjustment_) % 12; - tm.tm_year += yearAdjustment_ + monOverflow; - // Let's not create files with non-4-digit years, we can't read them. - if (tm.tm_year > 9999 - 1900 || tm.tm_year < 1000 - 1900) { - if (Params::instance().verbose_) std::cout << std::endl; - std::cerr << path << ": " << _("Can't adjust timestamp by") << " " - << yearAdjustment_ + monOverflow - << " " << _("years") << "\n"; - return 1; - } - time_t time = mktime(&tm); - time += adjustment_ + dayAdjustment_ * 86400; - timeStr = time2Str(time); - if (Params::instance().verbose_) { - std::cout << " " << _("to") << " " << timeStr << std::endl; - } - md->setValue(timeStr); - return 0; - } // Adjust::adjustDateTime - - int FixIso::run(const std::string& path) - { - try { - if (!Exiv2::fileExists(path)) { - std::cerr << path << ": " <<_("Failed to open the file\n"); - return -1; - } - Timestamp ts; - if (Params::instance().preserve_) - ts.read(path); - - auto image = Exiv2::ImageFactory::open(path); - assert(image); - image->readMetadata(); - Exiv2::ExifData& exifData = image->exifData(); - if (exifData.empty()) { - std::cerr << path << ": " << _("No Exif data found in the file\n"); - return -3; - } - auto md = Exiv2::isoSpeed(exifData); - if (md != exifData.end()) { - if (strcmp(md->key().c_str(), "Exif.Photo.ISOSpeedRatings") == 0) { - if (Params::instance().verbose_) { - std::cout << _("Standard Exif ISO tag exists; not modified\n"); - } - return 0; - } - // Copy the proprietary tag to the standard place - std::ostringstream os; - md->write(os, &exifData); - if (Params::instance().verbose_) { - std::cout << _("Setting Exif ISO value to") << " " << os.str() << "\n"; - } - exifData["Exif.Photo.ISOSpeedRatings"] = os.str(); - } - image->writeMetadata(); - if (Params::instance().preserve_) ts.touch(path); - - return 0; - } - catch(const Exiv2::Error& e) - { - std::cerr << "Exiv2 exception in fixiso action for file " << path - << ":\n" << e << "\n"; - return 1; - } - } // FixIso::run - - Task::UniquePtr FixIso::clone() const - { - return std::make_unique(*this); - } - - int FixCom::run(const std::string& path) - { - try { - if (!Exiv2::fileExists(path)) { - std::cerr << path << ": " <<_("Failed to open the file\n"); - return -1; - } - Timestamp ts; - if (Params::instance().preserve_) - ts.read(path); - - auto image = Exiv2::ImageFactory::open(path); - assert(image); - image->readMetadata(); - Exiv2::ExifData& exifData = image->exifData(); - if (exifData.empty()) { - std::cerr << path << ": " << _("No Exif data found in the file\n"); - return -3; - } - auto pos = exifData.findKey(Exiv2::ExifKey("Exif.Photo.UserComment")); - if (pos == exifData.end()) { - if (Params::instance().verbose_) { - std::cout << _("No Exif user comment found") << "\n"; - } - return 0; - } - Exiv2::Value::UniquePtr v = pos->getValue(); - const auto pcv = dynamic_cast(v.get()); - if (!pcv) { - if (Params::instance().verbose_) { - std::cout << _("Found Exif user comment with unexpected value type") << "\n"; - } - return 0; - } - Exiv2::CommentValue::CharsetId csId = pcv->charsetId(); - if (csId != Exiv2::CommentValue::unicode) { - if (Params::instance().verbose_) { - std::cout << _("No Exif UNICODE user comment found") << "\n"; - } - return 0; - } - std::string comment = pcv->comment(Params::instance().charset_.c_str()); - if (Params::instance().verbose_) { - std::cout << _("Setting Exif UNICODE user comment to") << " \"" << comment << "\"\n"; - } - comment = std::string("charset=\"") + Exiv2::CommentValue::CharsetInfo::name(csId) + "\" " + comment; - // Remove BOM and convert value from source charset to UCS-2, but keep byte order - pos->setValue(comment); - image->writeMetadata(); - if (Params::instance().preserve_) ts.touch(path); - - return 0; - } - catch(const Exiv2::Error& e) - { - std::cerr << "Exiv2 exception in fixcom action for file " << path - << ":\n" << e << "\n"; - return 1; - } - } // FixCom::run - - Task::UniquePtr FixCom::clone() const - { - return std::make_unique(*this); - } - -} // namespace Action + comment = std::string("charset=\"") + Exiv2::CommentValue::CharsetInfo::name(csId) + "\" " + comment; + // Remove BOM and convert value from source charset to UCS-2, but keep byte order + pos->setValue(comment); + image->writeMetadata(); + if (Params::instance().preserve_) + ts.touch(path); + + return 0; + } catch (const Exiv2::Error& e) { + std::cerr << "Exiv2 exception in fixcom action for file " << path << ":\n" << e << "\n"; + return 1; + } +} // FixCom::run + +Task::UniquePtr FixCom::clone() const { + return std::make_unique(*this); +} + +} // namespace Action // ***************************************************************************** // local definitions namespace { +//! @cond IGNORE +int Timestamp::read(const std::string& path) { + struct stat buf; + int rc = stat(path.c_str(), &buf); + if (0 == rc) { + actime_ = buf.st_atime; + modtime_ = buf.st_mtime; + } + return rc; +} - //! @cond IGNORE - int Timestamp::read(const std::string& path) - { - struct stat buf; - int rc = stat(path.c_str(), &buf); - if (0 == rc) { - actime_ = buf.st_atime; - modtime_ = buf.st_mtime; - } - return rc; - } +int Timestamp::read(struct tm* tm) { + int rc = 1; + time_t t = mktime(tm); // interpret tm according to current timezone settings + if (t != static_cast(-1)) { + rc = 0; + actime_ = t; + modtime_ = t; + } + return rc; +} - int Timestamp::read(struct tm* tm) - { - int rc = 1; - time_t t = mktime(tm); // interpret tm according to current timezone settings - if (t != static_cast(-1)) { - rc = 0; - actime_ = t; - modtime_ = t; - } - return rc; - } +int Timestamp::touch(const std::string& path) const { + if (0 == actime_) + return 1; + struct utimbuf buf; + buf.actime = actime_; + buf.modtime = modtime_; + return utime(path.c_str(), &buf); +} +//! @endcond - int Timestamp::touch(const std::string& path) const - { - if (0 == actime_) return 1; - struct utimbuf buf; - buf.actime = actime_; - buf.modtime = modtime_; - return utime(path.c_str(), &buf); - } - //! @endcond +int str2Tm(const std::string& timeStr, struct tm* tm) { + if (timeStr.length() == 0 || timeStr[0] == ' ') + return 1; + if (timeStr.length() < 19) + return 2; + if ((timeStr[4] != ':' && timeStr[4] != '-') || (timeStr[7] != ':' && timeStr[7] != '-') || timeStr[10] != ' ' || + timeStr[13] != ':' || timeStr[16] != ':') + return 3; + if (!tm) + return 4; + std::memset(tm, 0x0, sizeof(struct tm)); + tm->tm_isdst = -1; - int str2Tm(const std::string& timeStr, struct tm* tm) - { - if (timeStr.length() == 0 || timeStr[0] == ' ') return 1; - if (timeStr.length() < 19) return 2; - if ( (timeStr[4] != ':' && timeStr[4] != '-') || (timeStr[7] != ':' && timeStr[7] != '-') || timeStr[10] != ' ' - || timeStr[13] != ':' || timeStr[16] != ':') return 3; - if (!tm) - return 4; - std::memset(tm, 0x0, sizeof(struct tm)); - tm->tm_isdst = -1; + long tmp = 0; + if (!Util::strtol(timeStr.substr(0, 4).c_str(), tmp)) + return 5; + tm->tm_year = tmp - 1900; + if (!Util::strtol(timeStr.substr(5, 2).c_str(), tmp)) + return 6; + tm->tm_mon = tmp - 1; + if (!Util::strtol(timeStr.substr(8, 2).c_str(), tmp)) + return 7; + tm->tm_mday = tmp; + if (!Util::strtol(timeStr.substr(11, 2).c_str(), tmp)) + return 8; + tm->tm_hour = tmp; + if (!Util::strtol(timeStr.substr(14, 2).c_str(), tmp)) + return 9; + tm->tm_min = tmp; + if (!Util::strtol(timeStr.substr(17, 2).c_str(), tmp)) + return 10; + tm->tm_sec = tmp; - long tmp = 0; - if (!Util::strtol(timeStr.substr(0,4).c_str(), tmp)) return 5; - tm->tm_year = tmp - 1900; - if (!Util::strtol(timeStr.substr(5,2).c_str(), tmp)) return 6; - tm->tm_mon = tmp - 1; - if (!Util::strtol(timeStr.substr(8,2).c_str(), tmp)) return 7; - tm->tm_mday = tmp; - if (!Util::strtol(timeStr.substr(11,2).c_str(), tmp)) return 8; - tm->tm_hour = tmp; - if (!Util::strtol(timeStr.substr(14,2).c_str(), tmp)) return 9; - tm->tm_min = tmp; - if (!Util::strtol(timeStr.substr(17,2).c_str(), tmp)) return 10; - tm->tm_sec = tmp; + // Conversions to set remaining fields of the tm structure + if (mktime(tm) == static_cast(-1)) + return 11; - // Conversions to set remaining fields of the tm structure - if (mktime(tm) == static_cast(-1)) - return 11; + return 0; +} // str2Tm - return 0; - } // str2Tm +std::string time2Str(time_t time) { + struct tm* tm = localtime(&time); + return tm2Str(tm); +} // time2Str - std::string time2Str(time_t time) - { - struct tm* tm = localtime(&time); - return tm2Str(tm); - } // time2Str +std::string tm2Str(const struct tm* tm) { + if (!tm) + return ""; - std::string tm2Str(const struct tm* tm) - { - if (!tm) - return ""; + std::ostringstream os; + os << std::setfill('0') << tm->tm_year + 1900 << ":" << std::setw(2) << tm->tm_mon + 1 << ":" << std::setw(2) + << tm->tm_mday << " " << std::setw(2) << tm->tm_hour << ":" << std::setw(2) << tm->tm_min << ":" << std::setw(2) + << tm->tm_sec; - std::ostringstream os; - os << std::setfill('0') - << tm->tm_year + 1900 << ":" - << std::setw(2) << tm->tm_mon + 1 << ":" - << std::setw(2) << tm->tm_mday << " " - << std::setw(2) << tm->tm_hour << ":" - << std::setw(2) << tm->tm_min << ":" - << std::setw(2) << tm->tm_sec; + return os.str(); +} // tm2Str - return os.str(); - } // tm2Str - - std::string temporaryPath() - { - static int count = 0; - std::lock_guard guard(cs); +std::string temporaryPath() { + static int count = 0; + std::lock_guard guard(cs); #if defined(_MSC_VER) || defined(__MINGW__) - HANDLE process=0; - DWORD pid = ::GetProcessId(process); + HANDLE process = 0; + DWORD pid = ::GetProcessId(process); #else - pid_t pid = ::getpid(); + pid_t pid = ::getpid(); #endif - /// \todo check if we can use std::tmpnam - auto p = fs::temp_directory_path() / (Exiv2::toString(pid) + "_" + std::to_string(count)); - if (fs::exists(p)) { - fs::remove(p); - } + /// \todo check if we can use std::tmpnam + auto p = fs::temp_directory_path() / (Exiv2::toString(pid) + "_" + std::to_string(count)); + if (fs::exists(p)) { + fs::remove(p); + } - return p.string(); - } + return p.string(); +} - int metacopy(const std::string& source, - const std::string& tgt, - Exiv2::ImageType targetType, - bool preserve) - { +int metacopy(const std::string& source, const std::string& tgt, Exiv2::ImageType targetType, bool preserve) { #ifdef EXIV2_DEBUG_MESSAGES - std::cerr << "actions.cpp::metacopy" << " source = " << source << " target = " << tgt << std::endl; + std::cerr << "actions.cpp::metacopy" + << " source = " << source << " target = " << tgt << std::endl; #endif - // read the source metadata - int rc = -1 ; - if (!Exiv2::fileExists(source)) { - std::cerr << source << ": " << _("Failed to open the file\n"); - return rc; - } + // read the source metadata + int rc = -1; + if (!Exiv2::fileExists(source)) { + std::cerr << source << ": " << _("Failed to open the file\n"); + return rc; + } - bool bStdin = source == "-"; - bool bStdout = tgt == "-"; + bool bStdin = source == "-"; + bool bStdout = tgt == "-"; - Exiv2::DataBuf stdIn; - Exiv2::Image::UniquePtr sourceImage; - if ( bStdin ) { - Params::instance().getStdin(stdIn); - auto ioStdin = std::make_unique(stdIn.c_data(), stdIn.size()); - sourceImage = Exiv2::ImageFactory::open(std::move(ioStdin)); - } else { - sourceImage = Exiv2::ImageFactory::open(source); - } + Exiv2::DataBuf stdIn; + Exiv2::Image::UniquePtr sourceImage; + if (bStdin) { + Params::instance().getStdin(stdIn); + auto ioStdin = std::make_unique(stdIn.c_data(), stdIn.size()); + sourceImage = Exiv2::ImageFactory::open(std::move(ioStdin)); + } else { + sourceImage = Exiv2::ImageFactory::open(source); + } + assert(sourceImage); + sourceImage->readMetadata(); - assert(sourceImage); - sourceImage->readMetadata(); + // Apply any modification commands to the source image on-the-fly + Action::Modify::applyCommands(sourceImage.get()); - // Apply any modification commands to the source image on-the-fly - Action::Modify::applyCommands(sourceImage.get()); + // Open or create the target file + std::string target(bStdout ? temporaryPath() : tgt); - // Open or create the target file - std::string target(bStdout ? temporaryPath() : tgt); + std::unique_ptr targetImage; + if (Exiv2::fileExists(target)) { + targetImage = Exiv2::ImageFactory::open(target); + assert(targetImage); + targetImage->readMetadata(); + } else { + targetImage = Exiv2::ImageFactory::create(targetType, target); + assert(targetImage); + } - std::unique_ptr targetImage; - if (Exiv2::fileExists(target)) { - targetImage = Exiv2::ImageFactory::open(target); - assert(targetImage); - targetImage->readMetadata(); - } else { - targetImage = Exiv2::ImageFactory::create(targetType, target); - assert(targetImage); - } - - // Copy each type of metadata - if ( Params::instance().target_ & Params::ctExif - && !sourceImage->exifData().empty()) { - if (Params::instance().verbose_ && !bStdout) { - std::cout << _("Writing Exif data from") << " " << source - << " " << _("to") << " " << target << std::endl; - } - if ( preserve ) { - for (auto&& exif : sourceImage->exifData()) { - targetImage->exifData()[exif.key()] = exif.value(); - } - } else { - targetImage->setExifData(sourceImage->exifData()); - } - } - if ( Params::instance().target_ & Params::ctIptc - && !sourceImage->iptcData().empty()) { - if (Params::instance().verbose_ && !bStdout) { - std::cout << _("Writing IPTC data from") << " " << source - << " " << _("to") << " " << target << std::endl; - } - if ( preserve ) { - for (auto&& iptc : sourceImage->iptcData()) { - targetImage->iptcData()[iptc.key()] = iptc.value(); - } - } else { - targetImage->setIptcData(sourceImage->iptcData()); - } - } - if ( Params::instance().target_ & (Params::ctXmp|Params::ctXmpRaw) - && !sourceImage->xmpData().empty()) { - if (Params::instance().verbose_ && !bStdout) { - std::cout << _("Writing XMP data from") << " " << source - << " " << _("to") << " " << target << std::endl; - } - - // #1148 use Raw XMP packet if there are no XMP modification commands - int tRawSidecar = Params::ctXmpSidecar | Params::ctXmpRaw; // option -eXX - if (Params::instance().modifyCmds_.empty() && (Params::instance().target_ & tRawSidecar) == tRawSidecar) { - // std::cout << "short cut" << std::endl; - // http://www.cplusplus.com/doc/tutorial/files/ - std::ofstream os; - os.open(target.c_str()); - sourceImage->printStructure(os,Exiv2::kpsXMP); - os.close(); - rc = 0; - } else if (preserve) { - for (auto&& xmp : sourceImage->xmpData()) { - targetImage->xmpData()[xmp.key()] = xmp.value(); - } - } else { - // std::cout << "long cut" << std::endl; - targetImage->setXmpData(sourceImage->xmpData()); - } - } - if ( Params::instance().target_ & Params::ctComment - && !sourceImage->comment().empty()) { - if (Params::instance().verbose_ && !bStdout) { - std::cout << _("Writing JPEG comment from") << " " << source - << " " << _("to") << " " << tgt << std::endl; - } - targetImage->setComment(sourceImage->comment()); - } - if ( rc < 0 ) try { - targetImage->writeMetadata(); - rc=0; - } - catch (const Exiv2::Error& e) { - std::cerr << tgt << - ": " << _("Could not write metadata to file") << ": " << e << "\n"; - rc=1; - } - - // if we used a temporary target, copy it to stdout - if ( rc == 0 && bStdout ) { - FILE* f = ::fopen(target.c_str(),"rb") ; - _setmode(fileno(stdout),O_BINARY); - - if ( f ) { - char buffer[8*1024]; - size_t n = 1 ; - while ( !feof(f) && n > 0) { - n=fread(buffer,1,sizeof buffer,f); - fwrite(buffer,1,n,stdout); - } - fclose(f); - } - } - - // delete temporary target - if ( bStdout ) - fs::remove(target.c_str()); - - return rc; - } // metacopy - - // Defined outside of the function so that Exiv2::find() can see it - struct String { - const char* s_; - bool operator==(const char* s) const { - return 0 == strcmp(s_, s); - } - }; - - void replace(std::string& text, const std::string& searchText, const std::string& replaceText) - { - std::string::size_type index = 0; - while ((index = text.find(searchText, index)) != std::string::npos) - { - text.replace(index, searchText.length(), replaceText.c_str(), replaceText.length()); - index++; - } + // Copy each type of metadata + if (Params::instance().target_ & Params::ctExif && !sourceImage->exifData().empty()) { + if (Params::instance().verbose_ && !bStdout) { + std::cout << _("Writing Exif data from") << " " << source << " " << _("to") << " " << target << std::endl; } - - int renameFile(std::string& newPath, const struct tm* tm) - { - auto p = fs::path(newPath); - std::string path = newPath; - auto oldFsPath = fs::path(path); - std::string format = Params::instance().format_; - replace(format, ":basename:", p.stem().string()); - replace(format, ":dirname:", p.parent_path().filename().string()); - replace(format, ":parentname:", p.parent_path().parent_path().filename().string()); - - const size_t max = 1024; - char basename[max]; - std::memset(basename, 0x0, max); - if (strftime(basename, max, format.c_str(), tm) == 0) { - std::cerr << _("Filename format yields empty filename for the file") << " " << path << "\n"; - return 1; - } - - newPath = (p.parent_path() / (basename + p.extension().string())).string(); - p = fs::path(newPath); - - if (p.parent_path() == oldFsPath.parent_path() && p.filename() == oldFsPath.filename()) { - if (Params::instance().verbose_) { - std::cout << _("This file already has the correct name") << std::endl; - } - return -1; - } - - bool go = true; - int seq = 1; - std::string s; - Params::FileExistsPolicy fileExistsPolicy = Params::instance().fileExistsPolicy_; - while (go) { - if (Exiv2::fileExists(newPath)) { - switch (fileExistsPolicy) { - case Params::overwritePolicy: - go = false; - break; - case Params::renamePolicy: - newPath = (p.parent_path() / - (std::string(basename) + "_" + Exiv2::toString(seq++) + p.extension().string())) - .string(); - break; - case Params::askPolicy: - std::cout << Params::instance().progname() << ": " << _("File") << " `" << newPath << "' " - << _("exists. [O]verwrite, [r]ename or [s]kip?") << " "; - std::cin >> s; - switch (s.at(0)) { - case 'o': - case 'O': - go = false; - break; - case 'r': - case 'R': - fileExistsPolicy = Params::renamePolicy; - newPath = (p.parent_path() / (std::string(basename) + "_" + Exiv2::toString(seq++) + - p.extension().string())) - .string(); - break; - default: // skip - return -1; - break; - } - } - } else { - go = false; - } - } - - if (Params::instance().verbose_) { - std::cout << _("Renaming file to") << " " << newPath; - if (Params::instance().timestamp_) { - std::cout << ", " << _("updating timestamp"); - } - std::cout << std::endl; - } - - fs::rename(path, newPath); - return 0; - } - - std::string newFilePath(const std::string& path, const std::string& ext) - { - auto p = fs::path(path); - auto directory = fs::path(Params::instance().directory_); - if (directory.empty()) - directory = p.parent_path(); - if (Exiv2::fileProtocol(path) != Exiv2::pFile) - directory.clear(); // use current directory for remote files - return (directory / (p.stem().string() + ext)).string(); - } - - int dontOverwrite(const std::string& path) - { - if ( path == "-" ) return 0; - - if (!Params::instance().force_ && Exiv2::fileExists(path)) { - std::cout << Params::instance().progname() - << ": " << _("Overwrite") << " `" << path << "'? "; - std::string s; - std::cin >> s; - if (s.at(0) != 'y' && s.at(0) != 'Y') return 1; - } - return 0; - } - - std::ostream& operator<<(std::ostream& os, const std::pair& strAndWidth) - { - const std::string& str( strAndWidth.first); - size_t minChCount( strAndWidth.second); - size_t count = mbstowcs(nullptr, str.c_str(), 0); // returns 0xFFFFFFFF on error - if( count < minChCount) - { - minChCount += str.size() - count; + if (preserve) { + for (auto&& exif : sourceImage->exifData()) { + targetImage->exifData()[exif.key()] = exif.value(); } - return os << std::setw( minChCount) << str; + } else { + targetImage->setExifData(sourceImage->exifData()); + } + } + if (Params::instance().target_ & Params::ctIptc && !sourceImage->iptcData().empty()) { + if (Params::instance().verbose_ && !bStdout) { + std::cout << _("Writing IPTC data from") << " " << source << " " << _("to") << " " << target << std::endl; + } + if (preserve) { + for (auto&& iptc : sourceImage->iptcData()) { + targetImage->iptcData()[iptc.key()] = iptc.value(); + } + } else { + targetImage->setIptcData(sourceImage->iptcData()); + } + } + if (Params::instance().target_ & (Params::ctXmp | Params::ctXmpRaw) && !sourceImage->xmpData().empty()) { + if (Params::instance().verbose_ && !bStdout) { + std::cout << _("Writing XMP data from") << " " << source << " " << _("to") << " " << target << std::endl; } - int printStructure(std::ostream& out, Exiv2::PrintStructureOption option, const std::string &path) - { - if (!Exiv2::fileExists(path)) { - std::cerr << path << ": " - << _("Failed to open the file\n"); - return -1; - } - Exiv2::Image::UniquePtr image = Exiv2::ImageFactory::open(path); - assert(image.get() != 0); - image->printStructure(out,option); - return 0; + // #1148 use Raw XMP packet if there are no XMP modification commands + int tRawSidecar = Params::ctXmpSidecar | Params::ctXmpRaw; // option -eXX + if (Params::instance().modifyCmds_.empty() && (Params::instance().target_ & tRawSidecar) == tRawSidecar) { + // std::cout << "short cut" << std::endl; + // http://www.cplusplus.com/doc/tutorial/files/ + std::ofstream os; + os.open(target.c_str()); + sourceImage->printStructure(os, Exiv2::kpsXMP); + os.close(); + rc = 0; + } else if (preserve) { + for (auto&& xmp : sourceImage->xmpData()) { + targetImage->xmpData()[xmp.key()] = xmp.value(); + } + } else { + // std::cout << "long cut" << std::endl; + targetImage->setXmpData(sourceImage->xmpData()); } + } + if (Params::instance().target_ & Params::ctComment && !sourceImage->comment().empty()) { + if (Params::instance().verbose_ && !bStdout) { + std::cout << _("Writing JPEG comment from") << " " << source << " " << _("to") << " " << tgt << std::endl; + } + targetImage->setComment(sourceImage->comment()); + } + if (rc < 0) + try { + targetImage->writeMetadata(); + rc = 0; + } catch (const Exiv2::Error& e) { + std::cerr << tgt << ": " << _("Could not write metadata to file") << ": " << e << "\n"; + rc = 1; + } + + // if we used a temporary target, copy it to stdout + if (rc == 0 && bStdout) { + FILE* f = ::fopen(target.c_str(), "rb"); + _setmode(fileno(stdout), O_BINARY); + + if (f) { + char buffer[8 * 1024]; + size_t n = 1; + while (!feof(f) && n > 0) { + n = fread(buffer, 1, sizeof buffer, f); + fwrite(buffer, 1, n, stdout); + } + fclose(f); + } + } + + // delete temporary target + if (bStdout) + fs::remove(target.c_str()); + + return rc; +} // metacopy + +// Defined outside of the function so that Exiv2::find() can see it +struct String { + const char* s_; + bool operator==(const char* s) const { + return 0 == strcmp(s_, s); + } +}; + +void replace(std::string& text, const std::string& searchText, const std::string& replaceText) { + std::string::size_type index = 0; + while ((index = text.find(searchText, index)) != std::string::npos) { + text.replace(index, searchText.length(), replaceText.c_str(), replaceText.length()); + index++; + } +} + +int renameFile(std::string& newPath, const struct tm* tm) { + auto p = fs::path(newPath); + std::string path = newPath; + auto oldFsPath = fs::path(path); + std::string format = Params::instance().format_; + replace(format, ":basename:", p.stem().string()); + replace(format, ":dirname:", p.parent_path().filename().string()); + replace(format, ":parentname:", p.parent_path().parent_path().filename().string()); + + const size_t max = 1024; + char basename[max]; + std::memset(basename, 0x0, max); + if (strftime(basename, max, format.c_str(), tm) == 0) { + std::cerr << _("Filename format yields empty filename for the file") << " " << path << "\n"; + return 1; + } + + newPath = (p.parent_path() / (basename + p.extension().string())).string(); + p = fs::path(newPath); + + if (p.parent_path() == oldFsPath.parent_path() && p.filename() == oldFsPath.filename()) { + if (Params::instance().verbose_) { + std::cout << _("This file already has the correct name") << std::endl; + } + return -1; + } + + bool go = true; + int seq = 1; + std::string s; + Params::FileExistsPolicy fileExistsPolicy = Params::instance().fileExistsPolicy_; + while (go) { + if (Exiv2::fileExists(newPath)) { + switch (fileExistsPolicy) { + case Params::overwritePolicy: + go = false; + break; + case Params::renamePolicy: + newPath = (p.parent_path() / (std::string(basename) + "_" + Exiv2::toString(seq++) + p.extension().string())) + .string(); + break; + case Params::askPolicy: + std::cout << Params::instance().progname() << ": " << _("File") << " `" << newPath << "' " + << _("exists. [O]verwrite, [r]ename or [s]kip?") << " "; + std::cin >> s; + switch (s.at(0)) { + case 'o': + case 'O': + go = false; + break; + case 'r': + case 'R': + fileExistsPolicy = Params::renamePolicy; + newPath = + (p.parent_path() / (std::string(basename) + "_" + Exiv2::toString(seq++) + p.extension().string())) + .string(); + break; + default: // skip + return -1; + break; + } + } + } else { + go = false; + } + } + + if (Params::instance().verbose_) { + std::cout << _("Renaming file to") << " " << newPath; + if (Params::instance().timestamp_) { + std::cout << ", " << _("updating timestamp"); + } + std::cout << std::endl; + } + + fs::rename(path, newPath); + return 0; +} + +std::string newFilePath(const std::string& path, const std::string& ext) { + auto p = fs::path(path); + auto directory = fs::path(Params::instance().directory_); + if (directory.empty()) + directory = p.parent_path(); + if (Exiv2::fileProtocol(path) != Exiv2::pFile) + directory.clear(); // use current directory for remote files + return (directory / (p.stem().string() + ext)).string(); +} + +int dontOverwrite(const std::string& path) { + if (path == "-") + return 0; + + if (!Params::instance().force_ && Exiv2::fileExists(path)) { + std::cout << Params::instance().progname() << ": " << _("Overwrite") << " `" << path << "'? "; + std::string s; + std::cin >> s; + if (s.at(0) != 'y' && s.at(0) != 'Y') + return 1; + } + return 0; +} + +std::ostream& operator<<(std::ostream& os, const std::pair& strAndWidth) { + const std::string& str(strAndWidth.first); + size_t minChCount(strAndWidth.second); + size_t count = mbstowcs(nullptr, str.c_str(), 0); // returns 0xFFFFFFFF on error + if (count < minChCount) { + minChCount += str.size() - count; + } + return os << std::setw(minChCount) << str; +} + +int printStructure(std::ostream& out, Exiv2::PrintStructureOption option, const std::string& path) { + if (!Exiv2::fileExists(path)) { + std::cerr << path << ": " << _("Failed to open the file\n"); + return -1; + } + Exiv2::Image::UniquePtr image = Exiv2::ImageFactory::open(path); + assert(image.get() != 0); + image->printStructure(out, option); + return 0; +} } // namespace diff --git a/app/actions.hpp b/app/actions.hpp index 7e213e23..f40fb488 100644 --- a/app/actions.hpp +++ b/app/actions.hpp @@ -12,314 +12,308 @@ #define ACTIONS_HPP_ // ***************************************************************************** -#include "exiv2app.hpp" #include +#include "exiv2app.hpp" // ***************************************************************************** // class declarations namespace Exiv2 { - class ExifData; - class Image; - class Metadatum; - class PreviewImage; -} +class ExifData; +class Image; +class Metadatum; +class PreviewImage; +} // namespace Exiv2 // ***************************************************************************** // namespace extensions /// @brief Contains all action classes (task subclasses). namespace Action { - - //! Enumerates all tasks - enum TaskType { none, adjust, print, rename, erase, extract, insert, - modify, fixiso, fixcom }; +//! Enumerates all tasks +enum TaskType { none, adjust, print, rename, erase, extract, insert, modify, fixiso, fixcom }; // ***************************************************************************** // class definitions - /*! - @brief Abstract base class for all concrete actions. +/*! + @brief Abstract base class for all concrete actions. - Task provides a simple interface that actions must implement and a few - commonly used helpers. - */ - class Task { - public: - //! Shortcut for an auto pointer. - using UniquePtr = std::unique_ptr; - //! Virtual destructor. - virtual ~Task() = default; + Task provides a simple interface that actions must implement and a few + commonly used helpers. + */ +class Task { + public: + //! Shortcut for an auto pointer. + using UniquePtr = std::unique_ptr; + //! Virtual destructor. + virtual ~Task() = default; - //! Virtual copy construction. - virtual UniquePtr clone() const = 0; + //! Virtual copy construction. + virtual UniquePtr clone() const = 0; - /// @brief Application interface to perform a task. - /// @param path Path of the file to process. - /// @return 0 if successful. - virtual int run(const std::string& path) =0; + /// @brief Application interface to perform a task. + /// @param path Path of the file to process. + /// @return 0 if successful. + virtual int run(const std::string& path) = 0; - bool setBinary(bool b) - { - bool bResult = binary_; - binary_ = b; - return bResult ; - } + bool setBinary(bool b) { + bool bResult = binary_; + binary_ = b; + return bResult; + } - bool binary() { return binary_ ; } + bool binary() { + return binary_; + } - private: - //! copy binary_ from command-line params to task - bool binary_ {false} ; - }; // class Task + private: + //! copy binary_ from command-line params to task + bool binary_{false}; +}; // class Task - /*! - @brief Task factory. +/*! + @brief Task factory. - Creates an instance of the task of the requested type. The factory is - implemented as a singleton, which can be accessed only through the static - member function instance(). - */ - class TaskFactory { - public: - /*! - @brief Get access to the task factory. - Clients access the task factory exclusively through this method. (SINGLETON) - */ - static TaskFactory& instance(); + Creates an instance of the task of the requested type. The factory is + implemented as a singleton, which can be accessed only through the static + member function instance(). +*/ +class TaskFactory { + public: + /*! + @brief Get access to the task factory. + Clients access the task factory exclusively through this method. (SINGLETON) + */ + static TaskFactory& instance(); - //! Prevent copy construction: not implemented. - TaskFactory(const TaskFactory& rhs) = delete; + //! Prevent copy construction: not implemented. + TaskFactory(const TaskFactory& rhs) = delete; - //! Destructor - void cleanup(); + //! Destructor + void cleanup(); - /*! - @brief Create a task. + /*! + @brief Create a task. - @param type Identifies the type of task to create. - @return An auto pointer that owns a task of the requested type. If - the task type is not supported, the pointer is 0. - @remark The caller of the function should check the content of the - returned auto pointer and take appropriate action (e.g., throw - an exception) if it is 0. - */ - Task::UniquePtr create(TaskType type); + @param type Identifies the type of task to create. + @return An auto pointer that owns a task of the requested type. If + the task type is not supported, the pointer is 0. + @remark The caller of the function should check the content of the + returned auto pointer and take appropriate action (e.g., throw + an exception) if it is 0. + */ + Task::UniquePtr create(TaskType type); - private: - //! Prevent construction other than through instance(). - TaskFactory(); + private: + //! Prevent construction other than through instance(). + TaskFactory(); - //! List of task types and corresponding prototypes. - std::unordered_map registry_; - }; + //! List of task types and corresponding prototypes. + std::unordered_map registry_; +}; - //! %Print the Exif (or other metadata) of a file to stdout - class Print : public Task { - public: - ~Print() override = default; - int run(const std::string& path) override; - Task::UniquePtr clone() const override; +//! %Print the Exif (or other metadata) of a file to stdout +class Print : public Task { + public: + ~Print() override = default; + int run(const std::string& path) override; + Task::UniquePtr clone() const override; - //! Print the Jpeg comment - int printComment(); - //! Print list of available preview images - int printPreviewList(); - //! Print Exif summary information - int printSummary(); - //! Print Exif, IPTC and XMP metadata in user defined format - int printList(); - //! Return true if key should be printed, else false - static bool grepTag(const std::string& key); - //! Return true if key should be printed, else false - static bool keyTag(const std::string& key); - //! Print all metadata in a user defined format - int printMetadata(const Exiv2::Image* image); - //! Print a metadatum in a user defined format, return true if something was printed - bool printMetadatum(const Exiv2::Metadatum& md, const Exiv2::Image* image); - //! Print the label for a summary line - void printLabel(const std::string& label) const; - /*! - @brief Print one summary line with a label (if provided) and requested - data. A line break is printed only if a label is provided. - @return 1 if a line was written, 0 if the key was not found. - */ - int printTag(const Exiv2::ExifData& exifData, - const std::string& key, - const std::string& label ="") const; - //! Type for an Exiv2 Easy access function - using EasyAccessFct = Exiv2::ExifData::const_iterator (*)(const Exiv2::ExifData& ed); - /*! - @brief Print one summary line with a label (if provided) and requested - data. A line break is printed only if a label is provided. - @return 1 if a line was written, 0 if the information was not found. - */ - int printTag(const Exiv2::ExifData& exifData, - EasyAccessFct easyAccessFct, - const std::string& label ="", - EasyAccessFct easyAccessFctFallback =NULL) const; + //! Print the Jpeg comment + int printComment(); + //! Print list of available preview images + int printPreviewList(); + //! Print Exif summary information + int printSummary(); + //! Print Exif, IPTC and XMP metadata in user defined format + int printList(); + //! Return true if key should be printed, else false + static bool grepTag(const std::string& key); + //! Return true if key should be printed, else false + static bool keyTag(const std::string& key); + //! Print all metadata in a user defined format + int printMetadata(const Exiv2::Image* image); + //! Print a metadatum in a user defined format, return true if something was printed + bool printMetadatum(const Exiv2::Metadatum& md, const Exiv2::Image* image); + //! Print the label for a summary line + void printLabel(const std::string& label) const; + /*! + @brief Print one summary line with a label (if provided) and requested + data. A line break is printed only if a label is provided. + @return 1 if a line was written, 0 if the key was not found. + */ + int printTag(const Exiv2::ExifData& exifData, const std::string& key, const std::string& label = "") const; + //! Type for an Exiv2 Easy access function + using EasyAccessFct = Exiv2::ExifData::const_iterator (*)(const Exiv2::ExifData& ed); + /*! + @brief Print one summary line with a label (if provided) and requested + data. A line break is printed only if a label is provided. + @return 1 if a line was written, 0 if the information was not found. + */ + int printTag(const Exiv2::ExifData& exifData, EasyAccessFct easyAccessFct, const std::string& label = "", + EasyAccessFct easyAccessFctFallback = NULL) const; - private: - std::string path_; - int align_{0}; // for the alignment of the summary output - }; + private: + std::string path_; + int align_{0}; // for the alignment of the summary output +}; - /// @brief %Rename a file to its metadata creation timestamp, in the specified format. - class Rename : public Task { - public: - ~Rename() override = default; - int run(const std::string& path) override; - Task::UniquePtr clone() const override; - }; // class Rename +/// @brief %Rename a file to its metadata creation timestamp, in the specified format. +class Rename : public Task { + public: + ~Rename() override = default; + int run(const std::string& path) override; + Task::UniquePtr clone() const override; +}; // class Rename - //! %Adjust the Exif (or other metadata) timestamps - class Adjust : public Task { - public: - ~Adjust() override = default; - int run(const std::string& path) override; - Task::UniquePtr clone() const override; +//! %Adjust the Exif (or other metadata) timestamps +class Adjust : public Task { + public: + ~Adjust() override = default; + int run(const std::string& path) override; + Task::UniquePtr clone() const override; - private: - int adjustDateTime(Exiv2::ExifData& exifData, - const std::string& key, - const std::string& path) const; + private: + int adjustDateTime(Exiv2::ExifData& exifData, const std::string& key, const std::string& path) const; - long adjustment_ {0}; - long yearAdjustment_ {0}; - long monthAdjustment_ {0}; - long dayAdjustment_ {0}; + long adjustment_{0}; + long yearAdjustment_{0}; + long monthAdjustment_{0}; + long dayAdjustment_{0}; - }; // class Adjust +}; // class Adjust - /// @brief %Erase the entire exif data or only the thumbnail section. - class Erase : public Task { - public: - ~Erase() override = default; - int run(const std::string& path) override; - Task::UniquePtr clone() const override; +/// @brief %Erase the entire exif data or only the thumbnail section. +class Erase : public Task { + public: + ~Erase() override = default; + int run(const std::string& path) override; + Task::UniquePtr clone() const override; - /// @brief Delete the thumbnail image, incl IFD1 metadata from the file. - static int eraseThumbnail(Exiv2::Image* image); + /// @brief Delete the thumbnail image, incl IFD1 metadata from the file. + static int eraseThumbnail(Exiv2::Image* image); - /// @brief Erase the complete Exif data block from the file. - static int eraseExifData(Exiv2::Image* image); + /// @brief Erase the complete Exif data block from the file. + static int eraseExifData(Exiv2::Image* image); - /// @brief Erase all Iptc data from the file. - static int eraseIptcData(Exiv2::Image* image); + /// @brief Erase all Iptc data from the file. + static int eraseIptcData(Exiv2::Image* image); - /// @brief Erase Jpeg comment from the file. - static int eraseComment(Exiv2::Image* image); + /// @brief Erase Jpeg comment from the file. + static int eraseComment(Exiv2::Image* image); - /// @brief Erase XMP packet from the file. - static int eraseXmpData(Exiv2::Image* image); + /// @brief Erase XMP packet from the file. + static int eraseXmpData(Exiv2::Image* image); - /// @brief Erase ICCProfile from the file. - static int eraseIccProfile(Exiv2::Image* image); + /// @brief Erase ICCProfile from the file. + static int eraseIccProfile(Exiv2::Image* image); - private: - std::string path_; - }; + private: + std::string path_; +}; - /// @brief %Extract the entire exif data or only the thumbnail section. - class Extract : public Task { - public: - ~Extract() override = default; - int run(const std::string& path) override; - Task::UniquePtr clone() const override; +/// @brief %Extract the entire exif data or only the thumbnail section. +class Extract : public Task { + public: + ~Extract() override = default; + int run(const std::string& path) override; + Task::UniquePtr clone() const override; - /*! - @brief Write the thumbnail image to a file. The filename is composed by - removing the suffix from the image filename and appending - "-thumb" and the appropriate suffix (".jpg" or ".tif"), depending - on the format of the Exif thumbnail image. - */ - int writeThumbnail() const; + /*! + @brief Write the thumbnail image to a file. The filename is composed by + removing the suffix from the image filename and appending + "-thumb" and the appropriate suffix (".jpg" or ".tif"), depending + on the format of the Exif thumbnail image. + */ + int writeThumbnail() const; - /// @brief Write preview images to files. - int writePreviews() const; + /// @brief Write preview images to files. + int writePreviews() const; - /// @brief Write one preview image to a file. The filename is composed by removing the suffix from the image - /// filename and appending "-preview" and the appropriate suffix (".jpg" or ".tif"), depending on the - /// format of the Exif thumbnail image. - void writePreviewFile(const Exiv2::PreviewImage& pvImg, size_t num) const; + /// @brief Write one preview image to a file. The filename is composed by removing the suffix from the image + /// filename and appending "-preview" and the appropriate suffix (".jpg" or ".tif"), depending on the + /// format of the Exif thumbnail image. + void writePreviewFile(const Exiv2::PreviewImage& pvImg, size_t num) const; - /// @brief Write embedded iccProfile files. - int writeIccProfile(const std::string& target) const; + /// @brief Write embedded iccProfile files. + int writeIccProfile(const std::string& target) const; - private: - std::string path_; - }; + private: + std::string path_; +}; - /// @brief %Insert the Exif data from corresponding *.exv files. - class Insert : public Task { - public: - ~Insert() override = default; - int run(const std::string& path) override; - Task::UniquePtr clone() const override; +/// @brief %Insert the Exif data from corresponding *.exv files. +class Insert : public Task { + public: + ~Insert() override = default; + int run(const std::string& path) override; + Task::UniquePtr clone() const override; - /*! - @brief Insert a Jpeg thumbnail image from a file into file \em path. - The filename of the thumbnail is expected to be the image - filename (\em path) minus its suffix plus "-thumb.jpg". - */ - static int insertThumbnail(const std::string& path); + /*! + @brief Insert a Jpeg thumbnail image from a file into file \em path. + The filename of the thumbnail is expected to be the image + filename (\em path) minus its suffix plus "-thumb.jpg". + */ + static int insertThumbnail(const std::string& path); - /// @brief Insert an XMP packet from a xmpPath into file \em path. - static int insertXmpPacket(const std::string& path,const std::string& xmpPath) ; + /// @brief Insert an XMP packet from a xmpPath into file \em path. + static int insertXmpPacket(const std::string& path, const std::string& xmpPath); - /// @brief Insert xmp from a DataBuf into file \em path. - static int insertXmpPacket(const std::string& path, const Exiv2::DataBuf& xmpBlob, bool usePacket = false); + /// @brief Insert xmp from a DataBuf into file \em path. + static int insertXmpPacket(const std::string& path, const Exiv2::DataBuf& xmpBlob, bool usePacket = false); - /// @brief Insert an ICC profile from iccPath into file \em path. - static int insertIccProfile(const std::string& path,const std::string& iccPath) ; + /// @brief Insert an ICC profile from iccPath into file \em path. + static int insertIccProfile(const std::string& path, const std::string& iccPath); - /// @brief Insert an ICC profile from binary DataBuf into file \em path. - static int insertIccProfile(const std::string& path, Exiv2::DataBuf&& iccProfileBlob); - }; + /// @brief Insert an ICC profile from binary DataBuf into file \em path. + static int insertIccProfile(const std::string& path, Exiv2::DataBuf&& iccProfileBlob); +}; - /// @brief %Modify the Exif data according to the commands in the modification table. - class Modify : public Task { - public: - Modify() = default; - ~Modify() override = default; - int run(const std::string& path) override; - Task::UniquePtr clone() const override; - //! Apply modification commands to the \em pImage, return 0 if successful. - static int applyCommands(Exiv2::Image* pImage); +/// @brief %Modify the Exif data according to the commands in the modification table. +class Modify : public Task { + public: + Modify() = default; + ~Modify() override = default; + int run(const std::string& path) override; + Task::UniquePtr clone() const override; + //! Apply modification commands to the \em pImage, return 0 if successful. + static int applyCommands(Exiv2::Image* pImage); - private: - //! Add a metadatum to \em pImage according to \em modifyCmd - static int addMetadatum(Exiv2::Image* pImage, const ModifyCmd& modifyCmd); - //! Set a metadatum in \em pImage according to \em modifyCmd - static int setMetadatum(Exiv2::Image* pImage, const ModifyCmd& modifyCmd); - //! Delete a metadatum from \em pImage according to \em modifyCmd - static void delMetadatum(Exiv2::Image* pImage, const ModifyCmd& modifyCmd); - //! Register an XMP namespace according to \em modifyCmd - static void regNamespace(const ModifyCmd& modifyCmd); - }; + private: + //! Add a metadatum to \em pImage according to \em modifyCmd + static int addMetadatum(Exiv2::Image* pImage, const ModifyCmd& modifyCmd); + //! Set a metadatum in \em pImage according to \em modifyCmd + static int setMetadatum(Exiv2::Image* pImage, const ModifyCmd& modifyCmd); + //! Delete a metadatum from \em pImage according to \em modifyCmd + static void delMetadatum(Exiv2::Image* pImage, const ModifyCmd& modifyCmd); + //! Register an XMP namespace according to \em modifyCmd + static void regNamespace(const ModifyCmd& modifyCmd); +}; - /// @brief %Copy ISO settings from any of the Nikon makernotes to the regular Exif tag, Exif.Photo.ISOSpeedRatings. - class FixIso : public Task { - public: - ~FixIso() override = default; - int run(const std::string& path) override; - Task::UniquePtr clone() const override; +/// @brief %Copy ISO settings from any of the Nikon makernotes to the regular Exif tag, Exif.Photo.ISOSpeedRatings. +class FixIso : public Task { + public: + ~FixIso() override = default; + int run(const std::string& path) override; + Task::UniquePtr clone() const override; - private: - std::string path_; - }; + private: + std::string path_; +}; - /// @brief Fix the character encoding of Exif UNICODE user comments. - /// - /// Decodes the comment using the auto-detected or specified character encoding and writes it back in UCS-2. - class FixCom : public Task { - public: - ~FixCom() override = default; - int run(const std::string& path) override; - Task::UniquePtr clone() const override; - private: - std::string path_; - }; +/// @brief Fix the character encoding of Exif UNICODE user comments. +/// +/// Decodes the comment using the auto-detected or specified character encoding and writes it back in UCS-2. +class FixCom : public Task { + public: + ~FixCom() override = default; + int run(const std::string& path) override; + Task::UniquePtr clone() const override; -} // namespace Action + private: + std::string path_; +}; -#endif // #ifndef ACTIONS_HPP_ +} // namespace Action + +#endif // #ifndef ACTIONS_HPP_ diff --git a/app/app_utils.cpp b/app/app_utils.cpp index 8027f68c..cc28ece2 100644 --- a/app/app_utils.cpp +++ b/app/app_utils.cpp @@ -1,22 +1,20 @@ // SPDX-License-Identifier: GPL-2.0-or-later -#include #include +#include -namespace Util -{ - bool strtol(const char* nptr, long& n) - { - if (!nptr || *nptr == '\0') - return false; - char* endptr = nullptr; - long tmp = std::strtol(nptr, &endptr, 10); - if (*endptr != '\0') - return false; - if (tmp == LONG_MAX || tmp == LONG_MIN) - return false; - n = tmp; - return true; - } +namespace Util { +bool strtol(const char* nptr, long& n) { + if (!nptr || *nptr == '\0') + return false; + char* endptr = nullptr; + long tmp = std::strtol(nptr, &endptr, 10); + if (*endptr != '\0') + return false; + if (tmp == LONG_MAX || tmp == LONG_MIN) + return false; + n = tmp; + return true; +} } // namespace Util diff --git a/app/app_utils.hpp b/app/app_utils.hpp index e71c03b8..90a6a792 100644 --- a/app/app_utils.hpp +++ b/app/app_utils.hpp @@ -4,12 +4,12 @@ #define APP_UTILS_HPP_ namespace Util { - /*! - @brief Convert a C string to a long value, which is returned in n. - Returns true if the conversion is successful, else false. - n is not modified if the conversion is unsuccessful. See strtol(2). - */ - bool strtol(const char* nptr, long& n); -} // namespace Util +/*! + @brief Convert a C string to a long value, which is returned in n. + Returns true if the conversion is successful, else false. + n is not modified if the conversion is unsuccessful. See strtol(2). + */ +bool strtol(const char* nptr, long& n); +} // namespace Util -#endif // #ifndef UTILS_HPP_ +#endif // #ifndef UTILS_HPP_ diff --git a/app/exiv2.cpp b/app/exiv2.cpp index 45797784..70535e66 100644 --- a/app/exiv2.cpp +++ b/app/exiv2.cpp @@ -12,18 +12,18 @@ #include "i18n.h" // NLS support. #include "xmp_exiv2.hpp" -#include -#include -#include -#include #include #include +#include +#include +#include +#include #include #if defined(_WIN32) || defined(__CYGWIN__) -#include #include #include +#include #else #include #include @@ -33,196 +33,182 @@ // ***************************************************************************** // local declarations namespace { - const Params::YodAdjust emptyYodAdjust_[] = { - { false, "-Y", 0 }, - { false, "-O", 0 }, - { false, "-D", 0 }, - }; +const Params::YodAdjust emptyYodAdjust_[] = { + {false, "-Y", 0}, + {false, "-O", 0}, + {false, "-D", 0}, +}; - //! List of all command identifiers and corresponding strings - const CmdIdAndString cmdIdAndString[] = { - { add, "add" }, - { set, "set" }, - { del, "del" }, - { reg, "reg" }, - { invalidCmdId, "invalidCmd" }, // End of list marker - }; +//! List of all command identifiers and corresponding strings +const CmdIdAndString cmdIdAndString[] = { + {add, "add"}, {set, "set"}, {del, "del"}, {reg, "reg"}, {invalidCmdId, "invalidCmd"}, // End of list marker +}; - // Return a command Id for a command string - CmdId commandId(const std::string& cmdString); +// Return a command Id for a command string +CmdId commandId(const std::string& cmdString); - // Evaluate [-]HH[:MM[:SS]], returns true and sets time to the value - // in seconds if successful, else returns false. - bool parseTime(const std::string& ts, long& time); +// Evaluate [-]HH[:MM[:SS]], returns true and sets time to the value +// in seconds if successful, else returns false. +bool parseTime(const std::string& ts, long& time); - /*! - @brief Parse the oparg string into a bitmap of common targets. - @param optArg Option arguments - @param action Action being processed - @return A bitmap of common targets or -1 in case of a parse error - */ - int parseCommonTargets(const std::string& optArg, - const std::string& action); +/*! + @brief Parse the oparg string into a bitmap of common targets. + @param optArg Option arguments + @param action Action being processed + @return A bitmap of common targets or -1 in case of a parse error + */ +int parseCommonTargets(const std::string& optArg, const std::string& action); - /*! - @brief Parse numbers separated by commas into container - @param previewNumbers Container for the numbers - @param optArg Option arguments - @param j Starting index into optArg - @return Number of characters processed - */ - int parsePreviewNumbers(Params::PreviewNumbers& previewNumbers, - const std::string& optArg, - int j); +/*! + @brief Parse numbers separated by commas into container + @param previewNumbers Container for the numbers + @param optArg Option arguments + @param j Starting index into optArg + @return Number of characters processed + */ +int parsePreviewNumbers(Params::PreviewNumbers& previewNumbers, const std::string& optArg, int j); - /*! - @brief Parse metadata modification commands from multiple files - @param modifyCmds Reference to a structure to store the parsed commands - @param cmdFiles Container with the file names - */ - bool parseCmdFiles(ModifyCmds& modifyCmds, - const Params::CmdFiles& cmdFiles); +/*! + @brief Parse metadata modification commands from multiple files + @param modifyCmds Reference to a structure to store the parsed commands + @param cmdFiles Container with the file names + */ +bool parseCmdFiles(ModifyCmds& modifyCmds, const Params::CmdFiles& cmdFiles); - /*! - @brief Parse metadata modification commands from a container of commands - @param modifyCmds Reference to a structure to store the parsed commands - @param cmdLines Container with the commands - */ - bool parseCmdLines(ModifyCmds& modifyCmds, - const Params::CmdLines& cmdLines); +/*! + @brief Parse metadata modification commands from a container of commands + @param modifyCmds Reference to a structure to store the parsed commands + @param cmdLines Container with the commands + */ +bool parseCmdLines(ModifyCmds& modifyCmds, const Params::CmdLines& cmdLines); - /*! - @brief Parse one line of the command file - @param modifyCmd Reference to a command structure to store the parsed - command - @param line Input line - @param num Line number (used for error output) - */ - bool parseLine(ModifyCmd& modifyCmd, - const std::string& line, int num); +/*! + @brief Parse one line of the command file + @param modifyCmd Reference to a command structure to store the parsed + command + @param line Input line + @param num Line number (used for error output) + */ +bool parseLine(ModifyCmd& modifyCmd, const std::string& line, int num); - /*! - @brief Parses a string containing backslash-escapes - @param input Input string, assumed to be UTF-8 - */ - std::string parseEscapes(const std::string& input); +/*! + @brief Parses a string containing backslash-escapes + @param input Input string, assumed to be UTF-8 + */ +std::string parseEscapes(const std::string& input); } // namespace // ***************************************************************************** // Main -int main(int argc, char* const argv[]) -{ - setlocale(LC_CTYPE, ".utf8"); +int main(int argc, char* const argv[]) { + setlocale(LC_CTYPE, ".utf8"); - Exiv2::XmpParser::initialize(); - ::atexit(Exiv2::XmpParser::terminate); + Exiv2::XmpParser::initialize(); + ::atexit(Exiv2::XmpParser::terminate); #ifdef EXV_ENABLE_BMFF - Exiv2::enableBMFF(); + Exiv2::enableBMFF(); #endif #ifdef EXV_ENABLE_NLS - setlocale(LC_ALL, ""); - const std::string localeDir = EXV_LOCALEDIR[0] == '/' ? EXV_LOCALEDIR : (Exiv2::getProcessPath() + EXV_SEPARATOR_STR + EXV_LOCALEDIR); - bindtextdomain(EXV_PACKAGE_NAME, localeDir.c_str()); - textdomain(EXV_PACKAGE_NAME); + setlocale(LC_ALL, ""); + const std::string localeDir = + EXV_LOCALEDIR[0] == '/' ? EXV_LOCALEDIR : (Exiv2::getProcessPath() + EXV_SEPARATOR_STR + EXV_LOCALEDIR); + bindtextdomain(EXV_PACKAGE_NAME, localeDir.c_str()); + textdomain(EXV_PACKAGE_NAME); #endif - // Handle command line arguments - Params& params = Params::instance(); - if (params.getopt(argc, argv)) { - params.usage(); - return 1; - } - if (params.help_) { - params.help(); - return 0; - } - if (params.version_) { - Params::version(params.verbose_); - return 0; - } + // Handle command line arguments + Params& params = Params::instance(); + if (params.getopt(argc, argv)) { + params.usage(); + return 1; + } + if (params.help_) { + params.help(); + return 0; + } + if (params.version_) { + Params::version(params.verbose_); + return 0; + } - int rc = 0; + int rc = 0; - try { - // Create the required action class - Action::TaskFactory& taskFactory = Action::TaskFactory::instance(); - auto task = taskFactory.create(Action::TaskType(params.action_)); - assert(task); + try { + // Create the required action class + Action::TaskFactory& taskFactory = Action::TaskFactory::instance(); + auto task = taskFactory.create(Action::TaskType(params.action_)); + assert(task); - // Process all files - auto s = static_cast(params.files_.size()); - if (params.action_ & Action::extract && params.target_ & Params::ctStdInOut && s > 1) { - std::cerr << params.progname() << ": " << _("Only one file is allowed when extracting to stdout") << std::endl; - rc = 1; + // Process all files + auto s = static_cast(params.files_.size()); + if (params.action_ & Action::extract && params.target_ & Params::ctStdInOut && s > 1) { + std::cerr << params.progname() << ": " << _("Only one file is allowed when extracting to stdout") << std::endl; + rc = 1; + } else { + int w = s > 9 ? s > 99 ? 3 : 2 : 1; + int n = 1; + for (auto&& file : params.files_) { + // If extracting to stdout then ignore verbose + if (params.verbose_ && !(params.action_ & Action::extract && params.target_ & Params::ctStdInOut)) { + std::cout << _("File") << " " << std::setw(w) << std::right << n++ << "/" << s << ": " << file << std::endl; } - else { - int w = s > 9 ? s > 99 ? 3 : 2 : 1; - int n = 1; - for (auto&& file : params.files_) { - // If extracting to stdout then ignore verbose - if (params.verbose_ && !(params.action_ & Action::extract && params.target_ & Params::ctStdInOut)) { - std::cout << _("File") << " " << std::setw(w) << std::right << n++ << "/" << s << ": " << file - << std::endl; - } - task->setBinary(params.binary_); - int ret = task->run(file); - if (rc == 0) - rc = ret; - } + task->setBinary(params.binary_); + int ret = task->run(file); + if (rc == 0) + rc = ret; + } - taskFactory.cleanup(); - Exiv2::XmpParser::terminate(); - } - } catch (const std::exception& exc) { - std::cerr << "Uncaught exception: " << exc.what() << std::endl; - rc = 1; + taskFactory.cleanup(); + Exiv2::XmpParser::terminate(); } + } catch (const std::exception& exc) { + std::cerr << "Uncaught exception: " << exc.what() << std::endl; + rc = 1; + } - // Return a positive one byte code for better consistency across platforms - return static_cast(rc) % 256; -} // main + // Return a positive one byte code for better consistency across platforms + return static_cast(rc) % 256; +} // main // ***************************************************************************** // class Params -Params::Params() : optstring_(":hVvqfbuktTFa:Y:O:D:r:p:P:d:e:i:c:m:M:l:S:g:K:n:Q:"), - help_(false), - version_(false), - verbose_(false), - force_(false), - binary_(false), - unknown_(true), - preserve_(false), - timestamp_(false), - timestampOnly_(false), - fileExistsPolicy_(askPolicy), - adjust_(false), - printMode_(pmSummary), - printItems_(0), - printTags_(Exiv2::mdNone), - action_(0), - target_(ctExif|ctIptc|ctComment|ctXmp), - adjustment_(0), - format_("%Y%m%d_%H%M%S"), - formatSet_(false), - first_(true) -{ - yodAdjust_[yodYear] = emptyYodAdjust_[yodYear]; - yodAdjust_[yodMonth] = emptyYodAdjust_[yodMonth]; - yodAdjust_[yodDay] = emptyYodAdjust_[yodDay]; +Params::Params() : + optstring_(":hVvqfbuktTFa:Y:O:D:r:p:P:d:e:i:c:m:M:l:S:g:K:n:Q:"), + help_(false), + version_(false), + verbose_(false), + force_(false), + binary_(false), + unknown_(true), + preserve_(false), + timestamp_(false), + timestampOnly_(false), + fileExistsPolicy_(askPolicy), + adjust_(false), + printMode_(pmSummary), + printItems_(0), + printTags_(Exiv2::mdNone), + action_(0), + target_(ctExif | ctIptc | ctComment | ctXmp), + adjustment_(0), + format_("%Y%m%d_%H%M%S"), + formatSet_(false), + first_(true) { + yodAdjust_[yodYear] = emptyYodAdjust_[yodYear]; + yodAdjust_[yodMonth] = emptyYodAdjust_[yodMonth]; + yodAdjust_[yodDay] = emptyYodAdjust_[yodDay]; } -Params& Params::instance() -{ - static Params instance_; - return instance_; +Params& Params::instance() { + static Params instance_; + return instance_; } -void Params::version(bool verbose, std::ostream& os) -{ - os << EXV_PACKAGE_STRING << std::endl; - if ( Params::instance().greps_.empty() && !verbose) { +void Params::version(bool verbose, std::ostream& os) { + os << EXV_PACKAGE_STRING << std::endl; + if (Params::instance().greps_.empty() && !verbose) { os << "\n" << _("This program is free software; you can redistribute it and/or\n" "modify it under the terms of the GNU General Public License\n" @@ -238,1345 +224,1309 @@ void Params::version(bool verbose, std::ostream& os) "License along with this program; if not, write to the Free\n" "Software Foundation, Inc., 51 Franklin Street, Fifth Floor,\n" "Boston, MA 02110-1301 USA\n"); - } + } - if ( verbose ) Exiv2::dumpLibraryInfo(os,Params::instance().greps_); + if (verbose) + Exiv2::dumpLibraryInfo(os, Params::instance().greps_); } -void Params::usage(std::ostream& os) const -{ - os << _("Usage:") << " " << progname() - << " " << _("[ option [ arg ] ]+ [ action ] file ...\n\n") - << _("Image metadata manipulation tool.\n"); +void Params::usage(std::ostream& os) const { + os << _("Usage:") << " " << progname() << " " << _("[ option [ arg ] ]+ [ action ] file ...\n\n") + << _("Image metadata manipulation tool.\n"); } -void Params::help(std::ostream& os) const -{ - usage(os); - os << _("\nWhere file is one or more files, optionally containing a URL\n" - "(http, https, ftp, sftp, data or file) or wildcard\n") - << _("\nActions:\n") - << _(" pr | print Print image metadata (default is a summary). This is the default\n" - " action\n") - << _(" ad | adjust Adjust Exif timestamps by the given time. Requires\n" - " at least one of -a, -Y, -O or -D\n") - << _(" rm | delete Deletes image metadata, use -d to choose type to delete\n" - " (default is all)\n") - << _(" in | insert Insert metadata from .exv, .xmp, thumbnail or .icc file.\n" - " Use option -S to change the suffix of the input files and\n" - " -l to change the location\n") - << _(" ex | extract Extract metadata to .exv, .xmp, preview image, thumbnail,\n" - " or ICC profile. Use option -S to change the suffix of the input\n" - " files and -l to change the location\n") - << _(" mv | rename Rename files and/or set file timestamps according to the\n" - " Exif timestamps. The filename format can be set with\n" - " -r format, timestamp options are controlled with -t and -T\n") - << _(" mo | modify Apply commands to modify the Exif, IPTC and XMP metadata.\n" - " Requires option -m or -M\n") - << _(" fi | fixiso Copy ISO setting from Canon and Nikon makernotes, to the\n" - " standard Exif tag\n") - << _(" fc | fixcom Convert the Unicode Exif user comment to UCS-2. The current\n" - " character encoding can be specified with the -n option\n") - << _("\nOptions:\n") - << _(" -h Display this help and exit\n") - << _(" -V Show the program version and exit\n") - << _(" -v Be verbose during the program run\n") - << _(" -q Silence warnings and error messages (quiet)\n") - << _(" -Q lvl Set log-level to d(ebug), i(nfo), w(arning), e(rror) or m(ute)\n") - << _(" -b Obsolete, reserved for use with the test suit\n") - << _(" -u Show unknown tags (e.g., Exif.SonyMisc3c.0x022b)\n") - << _(" -g str Only output where 'str' matches in output text (grep)\n" - " Append /i to 'str' for case insensitive\n") - << _(" -K key Only output where 'key' exactly matches tag's key\n") - << _(" -n enc Character set to decode Exif Unicode user comments\n") - << _(" -k Preserve file timestamps when updating files (keep)\n") - << _(" -t Set the file timestamp from Exif metadata when renaming (overrides -k)\n") - << _(" -T Only set the file timestamp from Exif metadata ('rename' action)\n") - << _(" -f Do not prompt before overwriting existing files (force)\n") - << _(" -F Do not prompt before renaming files (Force)\n") - << _(" -a time Time adjustment in the format [+|-]HH[:MM[:SS]]. For 'adjust' action\n") - << _(" -Y yrs Year adjustment with the 'adjust' action\n") - << _(" -O mon Month adjustment with the 'adjust' action\n") - << _(" -D day Day adjustment with the 'adjust' action\n") - << _(" -p mode Print mode for the 'print' action. Possible modes are:\n") - << _(" s : A summary of the Exif metadata (the default)\n") - << _(" a : Exif, IPTC and XMP tags (shortcut for -Pkyct)\n") - << _(" e : Exif tags (shortcut for -PEkycv)\n") - << _(" t : Interpreted (translated) Exif tags (-PEkyct)\n") - << _(" v : Plain (untranslated) Exif tags values (-PExgnycv)\n") - << _(" h : Hex dump of the Exif tags (-PExgnycsh)\n") - << _(" i : IPTC tags (-PIkyct)\n") - << _(" x : XMP tags (-PXkyct)\n") - << _(" c : JPEG comment\n") - << _(" p : List available image preview, sorted by size\n") - << _(" C : Print ICC profile\n") - << _(" R : Recursive print structure of image (debug build only)\n") - << _(" S : Print structure of image (limited file types)\n") - << _(" X : Extract \"raw\" XMP\n") - << _(" -P flgs Print flags for fine control of tag lists ('print' action):\n") - << _(" E : Exif tags\n") - << _(" I : IPTC tags\n") - << _(" X : XMP tags\n") - << _(" x : Tag number (Exif and IPTC only)\n") - << _(" g : Group name (e.g. Exif.Photo.UserComment, Photo)\n") - << _(" k : Key (e.g. Exif.Photo.UserComment)\n") - << _(" l : Tag label (e.g. Exif.Photo.UserComment, 'User comment')\n") - << _(" n : Tag name (e.g. Exif.Photo.UserComment, UserComment)\n") - << _(" y : Type\n") - << _(" c : Number of components (count)\n") - << _(" s : Size in bytes (Ascii and Comment types include NULL)\n") - << _(" v : Plain data value, untranslated (vanilla)\n") - << _(" t : Interpreted (translated) human readable values\n") - << _(" h : Hex dump of the data\n") - << _(" -d tgt1 Delete target(s) for the 'delete' action. Possible targets are:\n") - << _(" a : All supported metadata (the default)\n") - << _(" e : Exif tags\n") - << _(" t : Exif thumbnail only\n") - << _(" i : IPTC tags\n") - << _(" x : XMP tags\n") - << _(" c : JPEG comment\n") - << _(" C : ICC Profile\n") - << _(" c : All IPTC data (any broken multiple IPTC blocks)\n") - << _(" - : Input from stdin\n") - << _(" -i tgt2 Insert target(s) for the 'insert' action. Possible targets are\n") - << _(" a : All supported metadata (the default)\n") - << _(" e : Exif tags\n") - << _(" t : Exif thumbnail only (JPEGs only from -thumb.jpg)\n") - << _(" i : IPTC tags\n") - << _(" x : XMP tags\n") - << _(" c : JPEG comment\n") - << _(" C : ICC Profile, from .icc\n") - << _(" X : XMP sidecar from file .xmp\n") - << _(" XX: \"raw\" metadata from .exv. XMP default, optional Exif and IPTC\n") - << _(" - : Input from stdin\n") - << _(" -e tgt3 Extract target(s) for the 'extract' action. Possible targets\n") - << _(" a : All supported metadata (the default)\n") - << _(" e : Exif tags\n") - << _(" t : Exif thumbnail only (to -thumb.jpg)\n") - << _(" i : IPTC tags\n") - << _(" x : XMP tags\n") - << _(" c : JPEG comment\n") - << _(" pN: Extract N'th preview image to -preview.\n") - << _(" C : ICC Profile, to .icc\n") - << _(" X : XMP sidecar to .xmp\n") - << _(" XX: \"raw\" metadata to .exv. XMP default, optional Exif and IPTC\n") - << _(" - : Output to stdin\n") - << _(" -r fmt Filename format for the 'rename' action. The format string\n") - << _(" follows strftime(3). The following keywords are also supported:\n") - << _(" :basename: - original filename without extension\n") - << _(" :dirname: - name of the directory holding the original file\n") - << _(" :parentname: - name of parent directory\n") - << _(" Default 'fmt' is %Y%m%d_%H%M%S\n") - << _(" -c txt JPEG comment string to set in the image.\n") - << _(" -m cmdf Applies commands in 'cmdf' file, for the modify action (see -M for format).\n") - << _(" -M cmd Command line for the modify action. The format is:\n") - << _(" ( (set | add) [[] ] |\n") - << _(" del [] |\n") - << _(" reg prefix namespace )\n") - << _(" -l dir Location (directory) for files to be inserted from or extracted to.\n") - << _(" -S suf Use suffix 'suf' for source files for insert action.\n") - << _("\nExamples:\n") - << _(" exiv2 -pe image.dng *.jp2\n" - " Print all Exif tags in image.dng and all .jp2 files\n") - << _(" exiv2 -g date/i https://clanmills.com/Stonehenge.jpg\n" - " Print all tags in file, where key contains 'date' (case insensitive)\n") - << _(" exiv2 -M\"set Xmp.dc.subject XmpBag Sky\" image.tiff\n" - " Set (or add if missing) value to tag in file\n\n"); -} // Params::help +void Params::help(std::ostream& os) const { + usage(os); + os << _("\nWhere file is one or more files, optionally containing a URL\n" + "(http, https, ftp, sftp, data or file) or wildcard\n") + << _("\nActions:\n") + << _(" pr | print Print image metadata (default is a summary). This is the default\n" + " action\n") + << _(" ad | adjust Adjust Exif timestamps by the given time. Requires\n" + " at least one of -a, -Y, -O or -D\n") + << _(" rm | delete Deletes image metadata, use -d to choose type to delete\n" + " (default is all)\n") + << _(" in | insert Insert metadata from .exv, .xmp, thumbnail or .icc file.\n" + " Use option -S to change the suffix of the input files and\n" + " -l to change the location\n") + << _(" ex | extract Extract metadata to .exv, .xmp, preview image, thumbnail,\n" + " or ICC profile. Use option -S to change the suffix of the input\n" + " files and -l to change the location\n") + << _(" mv | rename Rename files and/or set file timestamps according to the\n" + " Exif timestamps. The filename format can be set with\n" + " -r format, timestamp options are controlled with -t and -T\n") + << _(" mo | modify Apply commands to modify the Exif, IPTC and XMP metadata.\n" + " Requires option -m or -M\n") + << _(" fi | fixiso Copy ISO setting from Canon and Nikon makernotes, to the\n" + " standard Exif tag\n") + << _(" fc | fixcom Convert the Unicode Exif user comment to UCS-2. The current\n" + " character encoding can be specified with the -n option\n") + << _("\nOptions:\n") << _(" -h Display this help and exit\n") + << _(" -V Show the program version and exit\n") << _(" -v Be verbose during the program run\n") + << _(" -q Silence warnings and error messages (quiet)\n") + << _(" -Q lvl Set log-level to d(ebug), i(nfo), w(arning), e(rror) or m(ute)\n") + << _(" -b Obsolete, reserved for use with the test suit\n") + << _(" -u Show unknown tags (e.g., Exif.SonyMisc3c.0x022b)\n") + << _(" -g str Only output where 'str' matches in output text (grep)\n" + " Append /i to 'str' for case insensitive\n") + << _(" -K key Only output where 'key' exactly matches tag's key\n") + << _(" -n enc Character set to decode Exif Unicode user comments\n") + << _(" -k Preserve file timestamps when updating files (keep)\n") + << _(" -t Set the file timestamp from Exif metadata when renaming (overrides -k)\n") + << _(" -T Only set the file timestamp from Exif metadata ('rename' action)\n") + << _(" -f Do not prompt before overwriting existing files (force)\n") + << _(" -F Do not prompt before renaming files (Force)\n") + << _(" -a time Time adjustment in the format [+|-]HH[:MM[:SS]]. For 'adjust' action\n") + << _(" -Y yrs Year adjustment with the 'adjust' action\n") + << _(" -O mon Month adjustment with the 'adjust' action\n") + << _(" -D day Day adjustment with the 'adjust' action\n") + << _(" -p mode Print mode for the 'print' action. Possible modes are:\n") + << _(" s : A summary of the Exif metadata (the default)\n") + << _(" a : Exif, IPTC and XMP tags (shortcut for -Pkyct)\n") + << _(" e : Exif tags (shortcut for -PEkycv)\n") + << _(" t : Interpreted (translated) Exif tags (-PEkyct)\n") + << _(" v : Plain (untranslated) Exif tags values (-PExgnycv)\n") + << _(" h : Hex dump of the Exif tags (-PExgnycsh)\n") << _(" i : IPTC tags (-PIkyct)\n") + << _(" x : XMP tags (-PXkyct)\n") << _(" c : JPEG comment\n") + << _(" p : List available image preview, sorted by size\n") + << _(" C : Print ICC profile\n") + << _(" R : Recursive print structure of image (debug build only)\n") + << _(" S : Print structure of image (limited file types)\n") + << _(" X : Extract \"raw\" XMP\n") + << _(" -P flgs Print flags for fine control of tag lists ('print' action):\n") + << _(" E : Exif tags\n") << _(" I : IPTC tags\n") << _(" X : XMP tags\n") + << _(" x : Tag number (Exif and IPTC only)\n") + << _(" g : Group name (e.g. Exif.Photo.UserComment, Photo)\n") + << _(" k : Key (e.g. Exif.Photo.UserComment)\n") + << _(" l : Tag label (e.g. Exif.Photo.UserComment, 'User comment')\n") + << _(" n : Tag name (e.g. Exif.Photo.UserComment, UserComment)\n") << _(" y : Type\n") + << _(" c : Number of components (count)\n") + << _(" s : Size in bytes (Ascii and Comment types include NULL)\n") + << _(" v : Plain data value, untranslated (vanilla)\n") + << _(" t : Interpreted (translated) human readable values\n") + << _(" h : Hex dump of the data\n") + << _(" -d tgt1 Delete target(s) for the 'delete' action. Possible targets are:\n") + << _(" a : All supported metadata (the default)\n") << _(" e : Exif tags\n") + << _(" t : Exif thumbnail only\n") << _(" i : IPTC tags\n") + << _(" x : XMP tags\n") << _(" c : JPEG comment\n") << _(" C : ICC Profile\n") + << _(" c : All IPTC data (any broken multiple IPTC blocks)\n") + << _(" - : Input from stdin\n") + << _(" -i tgt2 Insert target(s) for the 'insert' action. Possible targets are\n") + << _(" a : All supported metadata (the default)\n") << _(" e : Exif tags\n") + << _(" t : Exif thumbnail only (JPEGs only from -thumb.jpg)\n") + << _(" i : IPTC tags\n") << _(" x : XMP tags\n") << _(" c : JPEG comment\n") + << _(" C : ICC Profile, from .icc\n") << _(" X : XMP sidecar from file .xmp\n") + << _(" XX: \"raw\" metadata from .exv. XMP default, optional Exif and IPTC\n") + << _(" - : Input from stdin\n") + << _(" -e tgt3 Extract target(s) for the 'extract' action. Possible targets\n") + << _(" a : All supported metadata (the default)\n") << _(" e : Exif tags\n") + << _(" t : Exif thumbnail only (to -thumb.jpg)\n") << _(" i : IPTC tags\n") + << _(" x : XMP tags\n") << _(" c : JPEG comment\n") + << _(" pN: Extract N'th preview image to -preview.\n") + << _(" C : ICC Profile, to .icc\n") << _(" X : XMP sidecar to .xmp\n") + << _(" XX: \"raw\" metadata to .exv. XMP default, optional Exif and IPTC\n") + << _(" - : Output to stdin\n") + << _(" -r fmt Filename format for the 'rename' action. The format string\n") + << _(" follows strftime(3). The following keywords are also supported:\n") + << _(" :basename: - original filename without extension\n") + << _(" :dirname: - name of the directory holding the original file\n") + << _(" :parentname: - name of parent directory\n") << _(" Default 'fmt' is %Y%m%d_%H%M%S\n") + << _(" -c txt JPEG comment string to set in the image.\n") + << _(" -m cmdf Applies commands in 'cmdf' file, for the modify action (see -M for format).\n") + << _(" -M cmd Command line for the modify action. The format is:\n") + << _(" ( (set | add) [[] ] |\n") << _(" del [] |\n") + << _(" reg prefix namespace )\n") + << _(" -l dir Location (directory) for files to be inserted from or extracted to.\n") + << _(" -S suf Use suffix 'suf' for source files for insert action.\n") << _("\nExamples:\n") + << _(" exiv2 -pe image.dng *.jp2\n" + " Print all Exif tags in image.dng and all .jp2 files\n") + << _(" exiv2 -g date/i https://clanmills.com/Stonehenge.jpg\n" + " Print all tags in file, where key contains 'date' (case insensitive)\n") + << _(" exiv2 -M\"set Xmp.dc.subject XmpBag Sky\" image.tiff\n" + " Set (or add if missing) value to tag in file\n\n"); +} // Params::help -int Params::option(int opt, const std::string& optArg, int optOpt) -{ - int rc = 0; - switch (opt) { - case 'h': help_ = true; break; - case 'V': version_ = true; break; - case 'v': verbose_ = true; break; - case 'q': Exiv2::LogMsg::setLevel(Exiv2::LogMsg::mute); break; - case 'Q': rc = setLogLevel(optArg); break; - case 'k': preserve_ = true; break; - case 'b': binary_ = true; break; - case 'u': unknown_ = false; break; - case 'f': force_ = true; fileExistsPolicy_ = overwritePolicy; break; - case 'F': force_ = true; fileExistsPolicy_ = renamePolicy; break; - case 'g': rc = evalGrep(optArg); break; - case 'K': rc = evalKey(optArg); printMode_ = pmList; break; - case 'n': charset_ = optArg; break; - case 'r': rc = evalRename(opt, optArg); break; - case 't': rc = evalRename(opt, optArg); break; - case 'T': rc = evalRename(opt, optArg); break; - case 'a': rc = evalAdjust(optArg); break; - case 'Y': rc = evalYodAdjust(yodYear, optArg); break; - case 'O': rc = evalYodAdjust(yodMonth, optArg); break; - case 'D': rc = evalYodAdjust(yodDay, optArg); break; - case 'p': rc = evalPrint(optArg); break; - case 'P': rc = evalPrintFlags(optArg); break; - case 'd': rc = evalDelete(optArg); break; - case 'e': rc = evalExtract(optArg); break; - case 'C': rc = evalExtract(optArg); break; - case 'i': rc = evalInsert(optArg); break; - case 'c': rc = evalModify(opt, optArg); break; - case 'm': rc = evalModify(opt, optArg); break; - case 'M': rc = evalModify(opt, optArg); break; - case 'l': directory_ = optArg; break; - case 'S': suffix_ = optArg; break; +int Params::option(int opt, const std::string& optArg, int optOpt) { + int rc = 0; + switch (opt) { + case 'h': + help_ = true; + break; + case 'V': + version_ = true; + break; + case 'v': + verbose_ = true; + break; + case 'q': + Exiv2::LogMsg::setLevel(Exiv2::LogMsg::mute); + break; + case 'Q': + rc = setLogLevel(optArg); + break; + case 'k': + preserve_ = true; + break; + case 'b': + binary_ = true; + break; + case 'u': + unknown_ = false; + break; + case 'f': + force_ = true; + fileExistsPolicy_ = overwritePolicy; + break; + case 'F': + force_ = true; + fileExistsPolicy_ = renamePolicy; + break; + case 'g': + rc = evalGrep(optArg); + break; + case 'K': + rc = evalKey(optArg); + printMode_ = pmList; + break; + case 'n': + charset_ = optArg; + break; + case 'r': + rc = evalRename(opt, optArg); + break; + case 't': + rc = evalRename(opt, optArg); + break; + case 'T': + rc = evalRename(opt, optArg); + break; + case 'a': + rc = evalAdjust(optArg); + break; + case 'Y': + rc = evalYodAdjust(yodYear, optArg); + break; + case 'O': + rc = evalYodAdjust(yodMonth, optArg); + break; + case 'D': + rc = evalYodAdjust(yodDay, optArg); + break; + case 'p': + rc = evalPrint(optArg); + break; + case 'P': + rc = evalPrintFlags(optArg); + break; + case 'd': + rc = evalDelete(optArg); + break; + case 'e': + rc = evalExtract(optArg); + break; + case 'C': + rc = evalExtract(optArg); + break; + case 'i': + rc = evalInsert(optArg); + break; + case 'c': + rc = evalModify(opt, optArg); + break; + case 'm': + rc = evalModify(opt, optArg); + break; + case 'M': + rc = evalModify(opt, optArg); + break; + case 'l': + directory_ = optArg; + break; + case 'S': + suffix_ = optArg; + break; case ':': - std::cerr << progname() << ": " << _("Option") << " -" << static_cast(optOpt) - << " " << _("requires an argument\n"); - rc = 1; - break; + std::cerr << progname() << ": " << _("Option") << " -" << static_cast(optOpt) << " " + << _("requires an argument\n"); + rc = 1; + break; case '?': - std::cerr << progname() << ": " << _("Unrecognized option") << " -" - << static_cast(optOpt) << "\n"; - rc = 1; - break; + std::cerr << progname() << ": " << _("Unrecognized option") << " -" << static_cast(optOpt) << "\n"; + rc = 1; + break; default: - std::cerr << progname() - << ": " << _("getopt returned unexpected character code") << " " - << std::hex << opt << "\n"; - rc = 1; - break; - } - return rc; -} // Params::option + std::cerr << progname() << ": " << _("getopt returned unexpected character code") << " " << std::hex << opt + << "\n"; + rc = 1; + break; + } + return rc; +} // Params::option -int Params::setLogLevel(const std::string& optArg) -{ - int rc = 0; - const char logLevel = tolower(optArg[0]); - switch (logLevel) { - case 'd': Exiv2::LogMsg::setLevel(Exiv2::LogMsg::debug); break; - case 'i': Exiv2::LogMsg::setLevel(Exiv2::LogMsg::info); break; - case 'w': Exiv2::LogMsg::setLevel(Exiv2::LogMsg::warn); break; - case 'e': Exiv2::LogMsg::setLevel(Exiv2::LogMsg::error); break; - case 'm': Exiv2::LogMsg::setLevel(Exiv2::LogMsg::mute); break; +int Params::setLogLevel(const std::string& optArg) { + int rc = 0; + const char logLevel = tolower(optArg[0]); + switch (logLevel) { + case 'd': + Exiv2::LogMsg::setLevel(Exiv2::LogMsg::debug); + break; + case 'i': + Exiv2::LogMsg::setLevel(Exiv2::LogMsg::info); + break; + case 'w': + Exiv2::LogMsg::setLevel(Exiv2::LogMsg::warn); + break; + case 'e': + Exiv2::LogMsg::setLevel(Exiv2::LogMsg::error); + break; + case 'm': + Exiv2::LogMsg::setLevel(Exiv2::LogMsg::mute); + break; default: - std::cerr << progname() << ": " << _("Option") << " -Q: " - << _("Invalid argument") << " \"" << optArg << "\"\n"; - rc = 1; - break; - } - return rc; -} // Params::setLogLevel + std::cerr << progname() << ": " << _("Option") << " -Q: " << _("Invalid argument") << " \"" << optArg << "\"\n"; + rc = 1; + break; + } + return rc; +} // Params::setLogLevel -int Params::evalGrep(const std::string& optArg) -{ - // check that string ends in "/i" - bool bIgnoreCase = optArg.size() > 2 && optArg.back() == 'i' && optArg[optArg.size() - 2] == '/'; - auto pattern = bIgnoreCase ? optArg.substr(0, optArg.size() - 2) : optArg; +int Params::evalGrep(const std::string& optArg) { + // check that string ends in "/i" + bool bIgnoreCase = optArg.size() > 2 && optArg.back() == 'i' && optArg[optArg.size() - 2] == '/'; + auto pattern = bIgnoreCase ? optArg.substr(0, optArg.size() - 2) : optArg; - try { - // use POSIX syntax, optimize for faster matching, treat all sub expressions as unnamed - auto flags = std::regex::basic | std::regex::optimize | std::regex::nosubs; - flags = bIgnoreCase ? flags | std::regex::icase : flags; - // try and emplace regex into vector - // might throw if invalid pattern - greps_.emplace_back(pattern, flags); - } catch (std::regex_error const&) { - // there was an error compiling the regexp - std::cerr << progname() << ": " << _("Option") << " -g: " << _("Invalid regexp") << " \"" << optArg << "\n"; - return 1; - } + try { + // use POSIX syntax, optimize for faster matching, treat all sub expressions as unnamed + auto flags = std::regex::basic | std::regex::optimize | std::regex::nosubs; + flags = bIgnoreCase ? flags | std::regex::icase : flags; + // try and emplace regex into vector + // might throw if invalid pattern + greps_.emplace_back(pattern, flags); + } catch (std::regex_error const&) { + // there was an error compiling the regexp + std::cerr << progname() << ": " << _("Option") << " -g: " << _("Invalid regexp") << " \"" << optArg << "\n"; + return 1; + } - return 0; + return 0; } // Params::evalGrep -int Params::evalKey( const std::string& optArg) -{ - int result=0; - keys_.push_back(optArg); - return result; -} // Params::evalKey +int Params::evalKey(const std::string& optArg) { + int result = 0; + keys_.push_back(optArg); + return result; +} // Params::evalKey -int Params::evalRename(int opt, const std::string& optArg) -{ - int rc = 0; - switch (action_) { +int Params::evalRename(int opt, const std::string& optArg) { + int rc = 0; + switch (action_) { case Action::none: - action_ = Action::rename; - switch (opt) { + action_ = Action::rename; + switch (opt) { case 'r': - format_ = optArg; - formatSet_ = true; - break; - case 't': timestamp_ = true; break; - case 'T': timestampOnly_ = true; break; - } - break; + format_ = optArg; + formatSet_ = true; + break; + case 't': + timestamp_ = true; + break; + case 'T': + timestampOnly_ = true; + break; + } + break; case Action::rename: - if (opt == 'r' && (formatSet_ || timestampOnly_)) { - std::cerr << progname() - << ": " << _("Ignoring surplus option") << " -r \"" << optArg << "\"\n"; - } - else { - format_ = optArg; - formatSet_ = true; - } - break; + if (opt == 'r' && (formatSet_ || timestampOnly_)) { + std::cerr << progname() << ": " << _("Ignoring surplus option") << " -r \"" << optArg << "\"\n"; + } else { + format_ = optArg; + formatSet_ = true; + } + break; default: - std::cerr << progname() << ": " << _("Option") << " -" << static_cast(opt) << " " - << _("is not compatible with a previous option\n"); - rc = 1; - break; - } - return rc; -} // Params::evalRename + std::cerr << progname() << ": " << _("Option") << " -" << static_cast(opt) << " " + << _("is not compatible with a previous option\n"); + rc = 1; + break; + } + return rc; +} // Params::evalRename -int Params::evalAdjust(const std::string& optArg) -{ - int rc = 0; - switch (action_) { +int Params::evalAdjust(const std::string& optArg) { + int rc = 0; + switch (action_) { case Action::none: case Action::adjust: - if (adjust_) { - std::cerr << progname() - << ": " << _("Ignoring surplus option -a") << " " << optArg << "\n"; - break; - } - action_ = Action::adjust; - adjust_ = parseTime(optArg, adjustment_); - if (!adjust_) { - std::cerr << progname() << ": " << _("Error parsing -a option argument") << " `" - << optArg << "'\n"; - rc = 1; - } + if (adjust_) { + std::cerr << progname() << ": " << _("Ignoring surplus option -a") << " " << optArg << "\n"; break; - default: - std::cerr << progname() - << ": " << _("Option -a is not compatible with a previous option\n"); + } + action_ = Action::adjust; + adjust_ = parseTime(optArg, adjustment_); + if (!adjust_) { + std::cerr << progname() << ": " << _("Error parsing -a option argument") << " `" << optArg << "'\n"; rc = 1; - break; - } - return rc; -} // Params::evalAdjust + } + break; + default: + std::cerr << progname() << ": " << _("Option -a is not compatible with a previous option\n"); + rc = 1; + break; + } + return rc; +} // Params::evalAdjust -int Params::evalYodAdjust(const Yod& yod, const std::string& optArg) -{ - int rc = 0; - switch (action_) { - case Action::none: // fall-through +int Params::evalYodAdjust(const Yod& yod, const std::string& optArg) { + int rc = 0; + switch (action_) { + case Action::none: // fall-through case Action::adjust: - if (yodAdjust_[yod].flag_) { - std::cerr << progname() - << ": " << _("Ignoring surplus option") << " " - << yodAdjust_[yod].option_ << " " << optArg << "\n"; - break; - } - action_ = Action::adjust; - yodAdjust_[yod].flag_ = true; - if (!Util::strtol(optArg.c_str(), yodAdjust_[yod].adjustment_)) { - std::cerr << progname() << ": " << _("Error parsing") << " " - << yodAdjust_[yod].option_ << " " - << _("option argument") << " `" << optArg << "'\n"; - rc = 1; - } + if (yodAdjust_[yod].flag_) { + std::cerr << progname() << ": " << _("Ignoring surplus option") << " " << yodAdjust_[yod].option_ << " " + << optArg << "\n"; break; - default: - std::cerr << progname() - << ": " << _("Option") << " " - << yodAdjust_[yod].option_ << " " - << _("is not compatible with a previous option\n"); + } + action_ = Action::adjust; + yodAdjust_[yod].flag_ = true; + if (!Util::strtol(optArg.c_str(), yodAdjust_[yod].adjustment_)) { + std::cerr << progname() << ": " << _("Error parsing") << " " << yodAdjust_[yod].option_ << " " + << _("option argument") << " `" << optArg << "'\n"; rc = 1; - break; - } - return rc; -} // Params::evalYodAdjust + } + break; + default: + std::cerr << progname() << ": " << _("Option") << " " << yodAdjust_[yod].option_ << " " + << _("is not compatible with a previous option\n"); + rc = 1; + break; + } + return rc; +} // Params::evalYodAdjust -int Params::evalPrint(const std::string& optArg) -{ - int rc = 0; - switch (action_) { - case Action::none: - switch (optArg[0]) { - case 's': - action_ = Action::print; - printMode_ = pmSummary; - break; - case 'a': - rc = evalPrintFlags("kyct"); - break; - case 'e': - rc = evalPrintFlags("Ekycv"); - break; - case 't': - rc = evalPrintFlags("Ekyct"); - break; - case 'v': - rc = evalPrintFlags("Exgnycv"); - break; - case 'h': - rc = evalPrintFlags("Exgnycsh"); - break; - case 'i': - rc = evalPrintFlags("Ikyct"); - break; - case 'x': - rc = evalPrintFlags("Xkyct"); - break; - case 'c': - action_ = Action::print; - printMode_ = pmComment; - break; - case 'p': - action_ = Action::print; - printMode_ = pmPreview; - break; - case 'C': - action_ = Action::print; - printMode_ = pmIccProfile; - break; - case 'R': - #ifdef NDEBUG - std::cerr << progname() << ": " << _("Action not available in Release mode") - << ": '" << optArg << "'\n"; - rc = 1; - #else - action_ = Action::print; - printMode_ = pmRecursive; - #endif - break; - case 'S': - action_ = Action::print; - printMode_ = pmStructure; - break; - case 'X': - action_ = Action::print; - printMode_ = pmXMP; - break; - default: - std::cerr << progname() << ": " << _("Unrecognized print mode") << " `" << optArg << "'\n"; - rc = 1; - break; - } - break; - case Action::print: - std::cerr << progname() << ": " << _("Ignoring surplus option -p") << optArg << "\n"; - break; +int Params::evalPrint(const std::string& optArg) { + int rc = 0; + switch (action_) { + case Action::none: + switch (optArg[0]) { + case 's': + action_ = Action::print; + printMode_ = pmSummary; + break; + case 'a': + rc = evalPrintFlags("kyct"); + break; + case 'e': + rc = evalPrintFlags("Ekycv"); + break; + case 't': + rc = evalPrintFlags("Ekyct"); + break; + case 'v': + rc = evalPrintFlags("Exgnycv"); + break; + case 'h': + rc = evalPrintFlags("Exgnycsh"); + break; + case 'i': + rc = evalPrintFlags("Ikyct"); + break; + case 'x': + rc = evalPrintFlags("Xkyct"); + break; + case 'c': + action_ = Action::print; + printMode_ = pmComment; + break; + case 'p': + action_ = Action::print; + printMode_ = pmPreview; + break; + case 'C': + action_ = Action::print; + printMode_ = pmIccProfile; + break; + case 'R': +#ifdef NDEBUG + std::cerr << progname() << ": " << _("Action not available in Release mode") << ": '" << optArg << "'\n"; + rc = 1; +#else + action_ = Action::print; + printMode_ = pmRecursive; +#endif + break; + case 'S': + action_ = Action::print; + printMode_ = pmStructure; + break; + case 'X': + action_ = Action::print; + printMode_ = pmXMP; + break; default: - std::cerr << progname() << ": " << _("Option -p is not compatible with a previous option\n"); - rc = 1; - break; - } - return rc; + std::cerr << progname() << ": " << _("Unrecognized print mode") << " `" << optArg << "'\n"; + rc = 1; + break; + } + break; + case Action::print: + std::cerr << progname() << ": " << _("Ignoring surplus option -p") << optArg << "\n"; + break; + default: + std::cerr << progname() << ": " << _("Option -p is not compatible with a previous option\n"); + rc = 1; + break; + } + return rc; } // Params::evalPrint -int Params::evalPrintFlags(const std::string& optArg) -{ - int rc = 0; - switch (action_) { +int Params::evalPrintFlags(const std::string& optArg) { + int rc = 0; + switch (action_) { case Action::none: - action_ = Action::print; - printMode_ = pmList; - for (auto&& i : optArg) { - switch (i) { - case 'E': - printTags_ |= Exiv2::mdExif; - break; - case 'I': - printTags_ |= Exiv2::mdIptc; - break; - case 'X': - printTags_ |= Exiv2::mdXmp; - break; - case 'x': - printItems_ |= prTag; - break; - case 'g': - printItems_ |= prGroup; - break; - case 'k': - printItems_ |= prKey; - break; - case 'l': - printItems_ |= prLabel; - break; - case 'n': - printItems_ |= prName; - break; - case 'y': - printItems_ |= prType; - break; - case 'c': - printItems_ |= prCount; - break; - case 's': - printItems_ |= prSize; - break; - case 'v': - printItems_ |= prValue; - break; - case 't': - printItems_ |= prTrans; - break; - case 'h': - printItems_ |= prHex; - break; - case 'V': - printItems_ |= prSet | prKey | prType | prValue; - break; - default: - std::cerr << progname() << ": " << _("Unrecognized print item") << " `" << i << "'\n"; - rc = 1; - break; - } + action_ = Action::print; + printMode_ = pmList; + for (auto&& i : optArg) { + switch (i) { + case 'E': + printTags_ |= Exiv2::mdExif; + break; + case 'I': + printTags_ |= Exiv2::mdIptc; + break; + case 'X': + printTags_ |= Exiv2::mdXmp; + break; + case 'x': + printItems_ |= prTag; + break; + case 'g': + printItems_ |= prGroup; + break; + case 'k': + printItems_ |= prKey; + break; + case 'l': + printItems_ |= prLabel; + break; + case 'n': + printItems_ |= prName; + break; + case 'y': + printItems_ |= prType; + break; + case 'c': + printItems_ |= prCount; + break; + case 's': + printItems_ |= prSize; + break; + case 'v': + printItems_ |= prValue; + break; + case 't': + printItems_ |= prTrans; + break; + case 'h': + printItems_ |= prHex; + break; + case 'V': + printItems_ |= prSet | prKey | prType | prValue; + break; + default: + std::cerr << progname() << ": " << _("Unrecognized print item") << " `" << i << "'\n"; + rc = 1; + break; } - break; + } + break; case Action::print: - std::cerr << progname() << ": " - << _("Ignoring surplus option -P") << optArg << "\n"; - break; + std::cerr << progname() << ": " << _("Ignoring surplus option -P") << optArg << "\n"; + break; default: - std::cerr << progname() << ": " - << _("Option -P is not compatible with a previous option\n"); - rc = 1; - break; - } - return rc; -} // Params::evalPrintFlags + std::cerr << progname() << ": " << _("Option -P is not compatible with a previous option\n"); + rc = 1; + break; + } + return rc; +} // Params::evalPrintFlags -int Params::evalDelete(const std::string& optArg) -{ - int rc = 0; - switch (action_) { +int Params::evalDelete(const std::string& optArg) { + int rc = 0; + switch (action_) { case Action::none: - action_ = Action::erase; - target_ = 0; - // fallthrough + action_ = Action::erase; + target_ = 0; + // fallthrough case Action::erase: - rc = parseCommonTargets(optArg, "erase"); - if (rc > 0) { - target_ |= rc; - rc = 0; - } - else { - rc = 1; - } - break; - default: - std::cerr << progname() << ": " - << _("Option -d is not compatible with a previous option\n"); + rc = parseCommonTargets(optArg, "erase"); + if (rc > 0) { + target_ |= rc; + rc = 0; + } else { rc = 1; - break; - } - return rc; -} // Params::evalDelete + } + break; + default: + std::cerr << progname() << ": " << _("Option -d is not compatible with a previous option\n"); + rc = 1; + break; + } + return rc; +} // Params::evalDelete -int Params::evalExtract(const std::string& optArg) -{ - int rc = 0; - switch (action_) { +int Params::evalExtract(const std::string& optArg) { + int rc = 0; + switch (action_) { case Action::none: case Action::modify: - action_ = Action::extract; - target_ = 0; - // fallthrough + action_ = Action::extract; + target_ = 0; + // fallthrough case Action::extract: - rc = parseCommonTargets(optArg, "extract"); - if (rc > 0) { - target_ |= rc; - rc = 0; - } - else { - rc = 1; - } - break; - default: - std::cerr << progname() << ": " - << _("Option -e is not compatible with a previous option\n"); + rc = parseCommonTargets(optArg, "extract"); + if (rc > 0) { + target_ |= rc; + rc = 0; + } else { rc = 1; - break; - } - return rc; -} // Params::evalExtract + } + break; + default: + std::cerr << progname() << ": " << _("Option -e is not compatible with a previous option\n"); + rc = 1; + break; + } + return rc; +} // Params::evalExtract -int Params::evalInsert(const std::string& optArg) -{ - int rc = 0; - switch (action_) { +int Params::evalInsert(const std::string& optArg) { + int rc = 0; + switch (action_) { case Action::none: case Action::modify: - action_ = Action::insert; - target_ = 0; - // fallthrough + action_ = Action::insert; + target_ = 0; + // fallthrough case Action::insert: - rc = parseCommonTargets(optArg, "insert"); - if (rc > 0) { - target_ |= rc; - rc = 0; - } - else { - rc = 1; - } - break; - default: - std::cerr << progname() << ": " - << _("Option -i is not compatible with a previous option\n"); + rc = parseCommonTargets(optArg, "insert"); + if (rc > 0) { + target_ |= rc; + rc = 0; + } else { rc = 1; - break; - } - return rc; -} // Params::evalInsert + } + break; + default: + std::cerr << progname() << ": " << _("Option -i is not compatible with a previous option\n"); + rc = 1; + break; + } + return rc; +} // Params::evalInsert -int Params::evalModify(int opt, const std::string& optArg) -{ - int rc = 0; - switch (action_) { +int Params::evalModify(int opt, const std::string& optArg) { + int rc = 0; + switch (action_) { case Action::none: - action_ = Action::modify; - // fallthrough + action_ = Action::modify; + // fallthrough case Action::modify: case Action::extract: case Action::insert: - if (opt == 'c') jpegComment_ = parseEscapes(optArg); - if (opt == 'm') cmdFiles_.push_back(optArg); // parse the files later - if (opt == 'M') cmdLines_.push_back(optArg); // parse the commands later - break; + if (opt == 'c') + jpegComment_ = parseEscapes(optArg); + if (opt == 'm') + cmdFiles_.push_back(optArg); // parse the files later + if (opt == 'M') + cmdLines_.push_back(optArg); // parse the commands later + break; default: - std::cerr << progname() << ": " << _("Option") << " -" << static_cast(opt) << " " - << _("is not compatible with a previous option\n"); + std::cerr << progname() << ": " << _("Option") << " -" << static_cast(opt) << " " + << _("is not compatible with a previous option\n"); + rc = 1; + break; + } + return rc; +} // Params::evalModify + +int Params::nonoption(const std::string& argv) { + int rc = 0; + bool action = false; + if (first_) { + // The first non-option argument must be the action + first_ = false; + if (argv == "ad" || argv == "adjust") { + if (action_ != Action::none && action_ != Action::adjust) { + std::cerr << progname() << ": " << _("Action adjust is not compatible with the given options\n"); rc = 1; - break; + } + action = true; + action_ = Action::adjust; } - return rc; -} // Params::evalModify + if (argv == "pr" || argv == "print") { + if (action_ != Action::none && action_ != Action::print) { + std::cerr << progname() << ": " << _("Action print is not compatible with the given options\n"); + rc = 1; + } + action = true; + action_ = Action::print; + } + if (argv == "rm" || argv == "delete") { + if (action_ != Action::none && action_ != Action::erase) { + std::cerr << progname() << ": " << _("Action delete is not compatible with the given options\n"); + rc = 1; + } + action = true; + action_ = Action::erase; + } + if (argv == "ex" || argv == "extract") { + if (action_ != Action::none && action_ != Action::extract && action_ != Action::modify) { + std::cerr << progname() << ": " << _("Action extract is not compatible with the given options\n"); + rc = 1; + } + action = true; + action_ = Action::extract; + } + if (argv == "in" || argv == "insert") { + if (action_ != Action::none && action_ != Action::insert && action_ != Action::modify) { + std::cerr << progname() << ": " << _("Action insert is not compatible with the given options\n"); + rc = 1; + } + action = true; + action_ = Action::insert; + } + if (argv == "mv" || argv == "rename") { + if (action_ != Action::none && action_ != Action::rename) { + std::cerr << progname() << ": " << _("Action rename is not compatible with the given options\n"); + rc = 1; + } + action = true; + action_ = Action::rename; + } + if (argv == "mo" || argv == "modify") { + if (action_ != Action::none && action_ != Action::modify) { + std::cerr << progname() << ": " << _("Action modify is not compatible with the given options\n"); + rc = 1; + } + action = true; + action_ = Action::modify; + } + if (argv == "fi" || argv == "fixiso") { + if (action_ != Action::none && action_ != Action::fixiso) { + std::cerr << progname() << ": " << _("Action fixiso is not compatible with the given options\n"); + rc = 1; + } + action = true; + action_ = Action::fixiso; + } + if (argv == "fc" || argv == "fixcom" || argv == "fixcomment") { + if (action_ != Action::none && action_ != Action::fixcom) { + std::cerr << progname() << ": " << _("Action fixcom is not compatible with the given options\n"); + rc = 1; + } + action = true; + action_ = Action::fixcom; + } + if (action_ == Action::none) { + // if everything else fails, assume print as the default action + action_ = Action::print; + } + } + if (!action) { + files_.push_back(argv); + } + return rc; +} // Params::nonoption -int Params::nonoption(const std::string& argv) -{ - int rc = 0; - bool action = false; - if (first_) { - // The first non-option argument must be the action - first_ = false; - if (argv == "ad" || argv == "adjust") { - if (action_ != Action::none && action_ != Action::adjust) { - std::cerr << progname() << ": " - << _("Action adjust is not compatible with the given options\n"); - rc = 1; - } - action = true; - action_ = Action::adjust; - } - if (argv == "pr" || argv == "print") { - if (action_ != Action::none && action_ != Action::print) { - std::cerr << progname() << ": " - << _("Action print is not compatible with the given options\n"); - rc = 1; - } - action = true; - action_ = Action::print; - } - if (argv == "rm" || argv == "delete") { - if (action_ != Action::none && action_ != Action::erase) { - std::cerr << progname() << ": " - << _("Action delete is not compatible with the given options\n"); - rc = 1; - } - action = true; - action_ = Action::erase; - } - if (argv == "ex" || argv == "extract") { - if ( action_ != Action::none - && action_ != Action::extract - && action_ != Action::modify) { - std::cerr << progname() << ": " - << _("Action extract is not compatible with the given options\n"); - rc = 1; - } - action = true; - action_ = Action::extract; - } - if (argv == "in" || argv == "insert") { - if ( action_ != Action::none - && action_ != Action::insert - && action_ != Action::modify) { - std::cerr << progname() << ": " - << _("Action insert is not compatible with the given options\n"); - rc = 1; - } - action = true; - action_ = Action::insert; - } - if (argv == "mv" || argv == "rename") { - if (action_ != Action::none && action_ != Action::rename) { - std::cerr << progname() << ": " - << _("Action rename is not compatible with the given options\n"); - rc = 1; - } - action = true; - action_ = Action::rename; - } - if (argv == "mo" || argv == "modify") { - if (action_ != Action::none && action_ != Action::modify) { - std::cerr << progname() << ": " - << _("Action modify is not compatible with the given options\n"); - rc = 1; - } - action = true; - action_ = Action::modify; - } - if (argv == "fi" || argv == "fixiso") { - if (action_ != Action::none && action_ != Action::fixiso) { - std::cerr << progname() << ": " - << _("Action fixiso is not compatible with the given options\n"); - rc = 1; - } - action = true; - action_ = Action::fixiso; - } - if (argv == "fc" || argv == "fixcom" || argv == "fixcomment") { - if (action_ != Action::none && action_ != Action::fixcom) { - std::cerr << progname() << ": " - << _("Action fixcom is not compatible with the given options\n"); - rc = 1; - } - action = true; - action_ = Action::fixcom; - } - if (action_ == Action::none) { - // if everything else fails, assume print as the default action - action_ = Action::print; - } +static int readFileToBuf(FILE* f, Exiv2::DataBuf& buf) { + const int buff_size = 4 * 1028; + std::vector bytes(buff_size); + int nBytes = 0; + bool more{true}; + while (more) { + char buff[buff_size]; + auto n = static_cast(fread(buff, 1, buff_size, f)); + more = n > 0; + if (more) { + bytes.resize(nBytes + n); + memcpy(bytes.data() + nBytes, buff, n); + nBytes += n; } - if (!action) { - files_.push_back(argv); - } - return rc; -} // Params::nonoption + } -static int readFileToBuf(FILE* f,Exiv2::DataBuf& buf) -{ - const int buff_size = 4*1028; - std::vector bytes(buff_size); - int nBytes = 0 ; - bool more {true}; - while ( more ) { - char buff[buff_size]; - auto n = static_cast(fread(buff, 1, buff_size, f)); - more = n > 0 ; - if ( more ) { - bytes.resize(nBytes+n); - memcpy(bytes.data()+nBytes,buff,n); - nBytes += n ; - } - } - - if ( nBytes ) { - buf.alloc(nBytes); - buf.copyBytes(0, bytes.data(), nBytes); - } - return nBytes; + if (nBytes) { + buf.alloc(nBytes); + buf.copyBytes(0, bytes.data(), nBytes); + } + return nBytes; } -void Params::getStdin(Exiv2::DataBuf& buf) -{ - // copy stdin to stdinBuf - if (stdinBuf.empty()) { +void Params::getStdin(Exiv2::DataBuf& buf) { + // copy stdin to stdinBuf + if (stdinBuf.empty()) { #if defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW__) || defined(_MSC_VER) - DWORD fdwMode; - _setmode(fileno(stdin),O_BINARY); - Sleep(300); - if ( !GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &fdwMode) ) { // failed: stdin has bytes! + DWORD fdwMode; + _setmode(fileno(stdin), O_BINARY); + Sleep(300); + if (!GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &fdwMode)) { // failed: stdin has bytes! #else - // http://stackoverflow.com/questions/34479795/make-c-not-wait-for-user-input/34479916#34479916 - fd_set readfds; - FD_ZERO (&readfds); - FD_SET(STDIN_FILENO, &readfds); - struct timeval timeout = {1,0}; // yes: set timeout seconds,microseconds + // http://stackoverflow.com/questions/34479795/make-c-not-wait-for-user-input/34479916#34479916 + fd_set readfds; + FD_ZERO(&readfds); + FD_SET(STDIN_FILENO, &readfds); + struct timeval timeout = {1, 0}; // yes: set timeout seconds,microseconds - // if we have something in the pipe, read it - if (select(1, &readfds, nullptr, nullptr, &timeout)) { + // if we have something in the pipe, read it + if (select(1, &readfds, nullptr, nullptr, &timeout)) { #endif #ifdef DEBUG - std::cerr << "stdin has data" << std::endl; -#endif - readFileToBuf(stdin,stdinBuf); - } -#ifdef DEBUG - // this is only used to simulate reading from stdin when debugging - // to simulate exiv2 -pX foo.jpg | exiv2 -iXX- bar.jpg - // exiv2 -pX foo.jpg > ~/temp/stdin ; exiv2 -iXX- bar.jpg - if ( stdinBuf.empty()) { - const char* path = "/Users/rmills/temp/stdin"; - FILE* f = fopen(path,"rb"); - if ( f ) { - readFileToBuf(f,stdinBuf); - fclose(f); - std::cerr << "read stdin from " << path << std::endl; - } - } -#endif -#ifdef DEBUG - std::cerr << "getStdin stdinBuf.size_ = " << stdinBuf.size() << std::endl; + std::cerr << "stdin has data" << std::endl; #endif + readFileToBuf(stdin, stdinBuf); } - - // copy stdinBuf to buf - if (!stdinBuf.empty()) { - buf.alloc(stdinBuf.size()); - buf.copyBytes(0,stdinBuf.c_data(),buf.size()); +#ifdef DEBUG + // this is only used to simulate reading from stdin when debugging + // to simulate exiv2 -pX foo.jpg | exiv2 -iXX- bar.jpg + // exiv2 -pX foo.jpg > ~/temp/stdin ; exiv2 -iXX- bar.jpg + if (stdinBuf.empty()) { + const char* path = "/Users/rmills/temp/stdin"; + FILE* f = fopen(path, "rb"); + if (f) { + readFileToBuf(f, stdinBuf); + fclose(f); + std::cerr << "read stdin from " << path << std::endl; + } } +#endif #ifdef DEBUG std::cerr << "getStdin stdinBuf.size_ = " << stdinBuf.size() << std::endl; #endif + } -} // Params::getStdin() + // copy stdinBuf to buf + if (!stdinBuf.empty()) { + buf.alloc(stdinBuf.size()); + buf.copyBytes(0, stdinBuf.c_data(), buf.size()); + } +#ifdef DEBUG + std::cerr << "getStdin stdinBuf.size_ = " << stdinBuf.size() << std::endl; +#endif -int Params::getopt(int argc, char* const Argv[]) -{ - std::vector argv(argc+1); - argv[argc] = nullptr; +} // Params::getStdin() - const std::unordered_map longs { - {"--adjust" , "-a"}, - {"--binary" , "-b"}, - {"--comment" , "-c"}, - {"--delete" , "-d"}, - {"--days" , "-D"}, - {"--extract" , "-e"}, - {"--force" , "-f"}, - {"--Force" , "-F"}, - {"--grep" , "-g"}, - {"--help" , "-h"}, - {"--insert" , "-i"}, - {"--keep" , "-k"}, - {"--key" , "-K"}, - {"--location" , "-l"}, - {"--modify" , "-m"}, - {"--Modify" , "-M"}, - {"--encode" , "-n"}, - {"--months" , "-O"}, - {"--print" , "-p"}, - {"--Print" , "-P"}, - {"--quiet" , "-q"}, - {"--log" , "-Q"}, - {"--rename" , "-r"}, - {"--suffix" , "-S"}, - {"--timestamp", "-t"}, - {"--Timestamp", "-T"}, - {"--unknown" , "-u"}, - {"--verbose" , "-v"}, - {"--Version" , "-V"}, - {"--version" , "-V"}, - {"--years" , "-Y"}, - }; +int Params::getopt(int argc, char* const Argv[]) { + std::vector argv(argc + 1); + argv[argc] = nullptr; - for ( int i = 0 ; i < argc ; i++ ) { - std::string arg(Argv[i]); - if (longs.find(arg) != longs.end() ) { - argv[i] = ::strdup(longs.at(arg).c_str()); - } else { - argv[i] = ::strdup(Argv[i]); - } - } + const std::unordered_map longs{ + {"--adjust", "-a"}, {"--binary", "-b"}, {"--comment", "-c"}, {"--delete", "-d"}, {"--days", "-D"}, + {"--extract", "-e"}, {"--force", "-f"}, {"--Force", "-F"}, {"--grep", "-g"}, {"--help", "-h"}, + {"--insert", "-i"}, {"--keep", "-k"}, {"--key", "-K"}, {"--location", "-l"}, {"--modify", "-m"}, + {"--Modify", "-M"}, {"--encode", "-n"}, {"--months", "-O"}, {"--print", "-p"}, {"--Print", "-P"}, + {"--quiet", "-q"}, {"--log", "-Q"}, {"--rename", "-r"}, {"--suffix", "-S"}, {"--timestamp", "-t"}, + {"--Timestamp", "-T"}, {"--unknown", "-u"}, {"--verbose", "-v"}, {"--Version", "-V"}, {"--version", "-V"}, + {"--years", "-Y"}, + }; - int rc = Util::Getopt::getopt(argc, argv.data(), optstring_); - // Further consistency checks - if (help_ || version_) { - goto cleanup; - } - if (action_ == Action::none) { - // This shouldn't happen since print is taken as default action - std::cerr << progname() << ": " << _("An action must be specified\n"); - rc = 1; - } - if ( action_ == Action::adjust - && !adjust_ - && !yodAdjust_[yodYear].flag_ - && !yodAdjust_[yodMonth].flag_ - && !yodAdjust_[yodDay].flag_) { - std::cerr << progname() << ": " - << _("Adjust action requires at least one -a, -Y, -O or -D option\n"); - rc = 1; - } - if ( action_ == Action::modify - && cmdFiles_.empty() && cmdLines_.empty() && jpegComment_.empty()) { - std::cerr << progname() << ": " - << _("Modify action requires at least one -c, -m or -M option\n"); - rc = 1; - } - if (files_.empty()) { - std::cerr << progname() << ": " << _("At least one file is required\n"); - rc = 1; - } - if (rc == 0 && !cmdFiles_.empty()) { - // Parse command files - if (!parseCmdFiles(modifyCmds_, cmdFiles_)) { - std::cerr << progname() << ": " << _("Error parsing -m option arguments\n"); - rc = 1; - } - } - if (rc == 0 && !cmdLines_.empty()) { - // Parse command lines - if (!parseCmdLines(modifyCmds_, cmdLines_)) { - std::cerr << progname() << ": " << _("Error parsing -M option arguments\n"); - rc = 1; - } - } - if (rc == 0 && (!cmdFiles_.empty() || !cmdLines_.empty())) { - // We'll set them again, after reading the file - Exiv2::XmpProperties::unregisterNs(); - } - if ( !directory_.empty() - && !(action_ == Action::insert || action_ == Action::extract)) { - std::cerr << progname() << ": " - << _("-l option can only be used with extract or insert actions\n"); - rc = 1; - } - if (!suffix_.empty() && !(action_ == Action::insert)) { - std::cerr << progname() << ": " - << _("-S option can only be used with insert action\n"); - rc = 1; - } - if (timestamp_ && !(action_ == Action::rename)) { - std::cerr << progname() << ": " - << _("-t option can only be used with rename action\n"); - rc = 1; - } - if (timestampOnly_ && !(action_ == Action::rename)) { - std::cerr << progname() << ": " - << _("-T option can only be used with rename action\n"); - rc = 1; + for (int i = 0; i < argc; i++) { + std::string arg(Argv[i]); + if (longs.find(arg) != longs.end()) { + argv[i] = ::strdup(longs.at(arg).c_str()); + } else { + argv[i] = ::strdup(Argv[i]); } + } - cleanup: - // cleanup the argument vector - for (int i = 0; i < argc; i++) - ::free(argv[i]); + int rc = Util::Getopt::getopt(argc, argv.data(), optstring_); + // Further consistency checks + if (help_ || version_) { + goto cleanup; + } + if (action_ == Action::none) { + // This shouldn't happen since print is taken as default action + std::cerr << progname() << ": " << _("An action must be specified\n"); + rc = 1; + } + if (action_ == Action::adjust && !adjust_ && !yodAdjust_[yodYear].flag_ && !yodAdjust_[yodMonth].flag_ && + !yodAdjust_[yodDay].flag_) { + std::cerr << progname() << ": " << _("Adjust action requires at least one -a, -Y, -O or -D option\n"); + rc = 1; + } + if (action_ == Action::modify && cmdFiles_.empty() && cmdLines_.empty() && jpegComment_.empty()) { + std::cerr << progname() << ": " << _("Modify action requires at least one -c, -m or -M option\n"); + rc = 1; + } + if (files_.empty()) { + std::cerr << progname() << ": " << _("At least one file is required\n"); + rc = 1; + } + if (rc == 0 && !cmdFiles_.empty()) { + // Parse command files + if (!parseCmdFiles(modifyCmds_, cmdFiles_)) { + std::cerr << progname() << ": " << _("Error parsing -m option arguments\n"); + rc = 1; + } + } + if (rc == 0 && !cmdLines_.empty()) { + // Parse command lines + if (!parseCmdLines(modifyCmds_, cmdLines_)) { + std::cerr << progname() << ": " << _("Error parsing -M option arguments\n"); + rc = 1; + } + } + if (rc == 0 && (!cmdFiles_.empty() || !cmdLines_.empty())) { + // We'll set them again, after reading the file + Exiv2::XmpProperties::unregisterNs(); + } + if (!directory_.empty() && !(action_ == Action::insert || action_ == Action::extract)) { + std::cerr << progname() << ": " << _("-l option can only be used with extract or insert actions\n"); + rc = 1; + } + if (!suffix_.empty() && !(action_ == Action::insert)) { + std::cerr << progname() << ": " << _("-S option can only be used with insert action\n"); + rc = 1; + } + if (timestamp_ && !(action_ == Action::rename)) { + std::cerr << progname() << ": " << _("-t option can only be used with rename action\n"); + rc = 1; + } + if (timestampOnly_ && !(action_ == Action::rename)) { + std::cerr << progname() << ": " << _("-T option can only be used with rename action\n"); + rc = 1; + } - return rc; +cleanup: + // cleanup the argument vector + for (int i = 0; i < argc; i++) + ::free(argv[i]); + + return rc; } // ***************************************************************************** // local implementations namespace { +bool parseTime(const std::string& ts, long& time) { + std::string hstr, mstr, sstr; + auto cts = new char[ts.length() + 1]; + strcpy(cts, ts.c_str()); + char* tmp = ::strtok(cts, ":"); + if (tmp) + hstr = tmp; + tmp = ::strtok(nullptr, ":"); + if (tmp) + mstr = tmp; + tmp = ::strtok(nullptr, ":"); + if (tmp) + sstr = tmp; + delete[] cts; - bool parseTime(const std::string& ts, long& time) - { - std::string hstr, mstr, sstr; - auto cts = new char[ts.length() + 1]; - strcpy(cts, ts.c_str()); - char *tmp = ::strtok(cts, ":"); - if (tmp) hstr = tmp; - tmp = ::strtok(nullptr, ":"); - if (tmp) mstr = tmp; - tmp = ::strtok(nullptr, ":"); - if (tmp) sstr = tmp; - delete[] cts; + int sign = 1; + long hh(0), mm(0), ss(0); + // [-]HH part + if (!Util::strtol(hstr.c_str(), hh)) + return false; + if (hh < 0) { + sign = -1; + hh *= -1; + } + // check for the -0 special case + if (hh == 0 && hstr.find('-') != std::string::npos) + sign = -1; + // MM part, if there is one + if (!mstr.empty()) { + if (!Util::strtol(mstr.c_str(), mm)) + return false; + if (mm > 59) + return false; + if (mm < 0) + return false; + } + // SS part, if there is one + if (!sstr.empty()) { + if (!Util::strtol(sstr.c_str(), ss)) + return false; + if (ss > 59) + return false; + if (ss < 0) + return false; + } - int sign = 1; - long hh(0), mm(0), ss(0); - // [-]HH part - if (!Util::strtol(hstr.c_str(), hh)) return false; - if (hh < 0) { - sign = -1; - hh *= -1; - } - // check for the -0 special case - if (hh == 0 && hstr.find('-') != std::string::npos) sign = -1; - // MM part, if there is one - if (!mstr.empty()) { - if (!Util::strtol(mstr.c_str(), mm)) return false; - if (mm > 59) return false; - if (mm < 0) return false; - } - // SS part, if there is one - if (!sstr.empty()) { - if (!Util::strtol(sstr.c_str(), ss)) return false; - if (ss > 59) return false; - if (ss < 0) return false; + time = sign * (hh * 3600 + mm * 60 + ss); + return true; +} // parseTime + +void printUnrecognizedArgument(const char argc, const std::string& action) { + std::cerr << Params::instance().progname() << ": " << _("Unrecognized ") << action << " " << _("target") << " `" + << argc << "'\n"; +} + +int parseCommonTargets(const std::string& optArg, const std::string& action) { + int rc = 0; + int target = 0; + int all = Params::ctExif | Params::ctIptc | Params::ctComment | Params::ctXmp; + int extra = Params::ctXmpSidecar | Params::ctExif | Params::ctIptc | Params::ctXmp; + for (size_t i = 0; rc == 0 && i < optArg.size(); ++i) { + switch (optArg[i]) { + case 'e': + target |= Params::ctExif; + break; + case 'i': + target |= Params::ctIptc; + break; + case 'x': + target |= Params::ctXmp; + break; + case 'c': + target |= Params::ctComment; + break; + case 't': + target |= Params::ctThumb; + break; + case 'C': + target |= Params::ctIccProfile; + break; + case 'I': + target |= Params::ctIptcRaw; + break; + case '-': + target |= Params::ctStdInOut; + break; + case 'a': + target |= all; + break; + case 'X': + target |= extra; // -eX + if (i > 0) { // -eXX or -iXX + target |= Params::ctXmpRaw; + target &= ~extra; // turn off those bits } + break; - time = sign * (hh * 3600 + mm * 60 + ss); - return true; - } // parseTime - - void printUnrecognizedArgument(const char argc, const std::string& action) - { - std::cerr << Params::instance().progname() << ": " << _("Unrecognized ") - << action << " " << _("target") << " `" << argc << "'\n"; + case 'p': { + if (strcmp(action.c_str(), "extract") == 0) { + i += static_cast( + parsePreviewNumbers(Params::instance().previewNumbers_, optArg, static_cast(i) + 1)); + target |= Params::ctPreview; + break; + } + printUnrecognizedArgument(optArg[i], action); + rc = -1; + break; + } + default: + printUnrecognizedArgument(optArg[i], action); + rc = -1; + break; } + } + return rc ? rc : target; +} - int parseCommonTargets(const std::string& optArg, const std::string& action) - { - int rc = 0; - int target = 0; - int all = Params::ctExif | Params::ctIptc | Params::ctComment | Params::ctXmp; - int extra = Params::ctXmpSidecar | Params::ctExif | Params::ctIptc | Params::ctXmp; - for (size_t i = 0; rc == 0 && i < optArg.size(); ++i) { - switch (optArg[i]) { - case 'e': - target |= Params::ctExif; - break; - case 'i': - target |= Params::ctIptc; - break; - case 'x': - target |= Params::ctXmp; - break; - case 'c': - target |= Params::ctComment; - break; - case 't': - target |= Params::ctThumb; - break; - case 'C': - target |= Params::ctIccProfile; - break; - case 'I': - target |= Params::ctIptcRaw; - break; - case '-': - target |= Params::ctStdInOut; - break; - case 'a': - target |= all; - break; - case 'X': - target |= extra; // -eX - if (i > 0) { // -eXX or -iXX - target |= Params::ctXmpRaw; - target &= ~extra; // turn off those bits - } - break; - - case 'p': { - if (strcmp(action.c_str(), "extract") == 0) { - i += static_cast( - parsePreviewNumbers(Params::instance().previewNumbers_, optArg, static_cast(i) + 1)); - target |= Params::ctPreview; - break; - } - printUnrecognizedArgument(optArg[i], action); - rc = -1; - break; - } - default: - printUnrecognizedArgument(optArg[i], action); - rc = -1; - break; - } - } - return rc ? rc : target; +int parsePreviewNumbers(Params::PreviewNumbers& previewNumbers, const std::string& optArg, int j) { + size_t k = j; + for (size_t i = j; i < optArg.size(); ++i) { + std::ostringstream os; + for (k = i; k < optArg.size() && isdigit(optArg[k]); ++k) { + os << optArg[k]; } - - int parsePreviewNumbers(Params::PreviewNumbers& previewNumbers, - const std::string& optArg, - int j) - { - size_t k = j; - for (size_t i = j; i < optArg.size(); ++i) { - std::ostringstream os; - for (k = i; k < optArg.size() && isdigit(optArg[k]); ++k) { - os << optArg[k]; - } - if (k > i) { - bool ok = false; - auto num = Exiv2::stringTo(os.str(), ok); - if (ok && num >= 0) { - previewNumbers.insert(num); - } - else { - std::cerr << Params::instance().progname() << ": " - << _("Invalid preview number") << ": " << num << "\n"; - } - i = k; - } - if (!(k < optArg.size() && optArg[i] == ',')) break; - } - auto ret = static_cast(k - j); - if (ret == 0) { - previewNumbers.insert(0); - } + if (k > i) { + bool ok = false; + auto num = Exiv2::stringTo(os.str(), ok); + if (ok && num >= 0) { + previewNumbers.insert(num); + } else { + std::cerr << Params::instance().progname() << ": " << _("Invalid preview number") << ": " << num << "\n"; + } + i = k; + } + if (!(k < optArg.size() && optArg[i] == ',')) + break; + } + auto ret = static_cast(k - j); + if (ret == 0) { + previewNumbers.insert(0); + } #ifdef DEBUG - std::cout << "\nThe set now contains: "; - for (auto&& number : previewNumbers) { - std::cout << number << ", "; - } - std::cout << std::endl; + std::cout << "\nThe set now contains: "; + for (auto&& number : previewNumbers) { + std::cout << number << ", "; + } + std::cout << std::endl; #endif - return static_cast(k - j); - } // parsePreviewNumbers + return static_cast(k - j); +} // parsePreviewNumbers - bool parseCmdFiles(ModifyCmds& modifyCmds, - const Params::CmdFiles& cmdFiles) - { - for (auto&& filename : cmdFiles) { - try { - std::ifstream file(filename.c_str()); - bool bStdin = filename == "-"; - if (!file && !bStdin) { - std::cerr << filename << ": " << _("Failed to open command file for reading\n"); - return false; - } - int num = 0; - std::string line; - while (bStdin?std::getline(std::cin, line):std::getline(file, line)) { - ModifyCmd modifyCmd; - if (parseLine(modifyCmd, line, ++num)) { - modifyCmds.push_back(modifyCmd); - } - } - } - catch (const Exiv2::Error& error) { - std::cerr << filename << ", " << _("line") << " " << error << "\n"; - return false; - } +bool parseCmdFiles(ModifyCmds& modifyCmds, const Params::CmdFiles& cmdFiles) { + for (auto&& filename : cmdFiles) { + try { + std::ifstream file(filename.c_str()); + bool bStdin = filename == "-"; + if (!file && !bStdin) { + std::cerr << filename << ": " << _("Failed to open command file for reading\n"); + return false; + } + int num = 0; + std::string line; + while (bStdin ? std::getline(std::cin, line) : std::getline(file, line)) { + ModifyCmd modifyCmd; + if (parseLine(modifyCmd, line, ++num)) { + modifyCmds.push_back(modifyCmd); } - return true; - } // parseCmdFile + } + } catch (const Exiv2::Error& error) { + std::cerr << filename << ", " << _("line") << " " << error << "\n"; + return false; + } + } + return true; +} // parseCmdFile - bool parseCmdLines(ModifyCmds& modifyCmds, - const Params::CmdLines& cmdLines) - { - try { - int num = 0; - for (auto&& line : cmdLines) { - ModifyCmd modifyCmd; - if (parseLine(modifyCmd, line, ++num)) { - modifyCmds.push_back(modifyCmd); - } - } - return true; - } - catch (const Exiv2::Error& error) { - std::cerr << _("-M option") << " " << error << "\n"; - return false; - } - } // parseCmdLines +bool parseCmdLines(ModifyCmds& modifyCmds, const Params::CmdLines& cmdLines) { + try { + int num = 0; + for (auto&& line : cmdLines) { + ModifyCmd modifyCmd; + if (parseLine(modifyCmd, line, ++num)) { + modifyCmds.push_back(modifyCmd); + } + } + return true; + } catch (const Exiv2::Error& error) { + std::cerr << _("-M option") << " " << error << "\n"; + return false; + } +} // parseCmdLines #if defined(_MSC_VER) || defined(__MINGW__) - static std::string formatArg(const char* arg) - { - std::string result = ""; - char b = ' ' ; - char e = '\\'; std::string E = std::string("\\"); - char q = '\''; std::string Q = std::string("'" ); - bool qt = false; - char* a = (char*) arg; - while ( *a ) { - if ( *a == b || *a == e || *a == q ) qt = true; - if ( *a == q ) result += E; - if ( *a == e ) result += E; - result += std::string(a,1); - a++ ; - } - if (qt) result = Q + result + Q; +static std::string formatArg(const char* arg) { + std::string result = ""; + char b = ' '; + char e = '\\'; + std::string E = std::string("\\"); + char q = '\''; + std::string Q = std::string("'"); + bool qt = false; + char* a = (char*)arg; + while (*a) { + if (*a == b || *a == e || *a == q) + qt = true; + if (*a == q) + result += E; + if (*a == e) + result += E; + result += std::string(a, 1); + a++; + } + if (qt) + result = Q + result + Q; - return result; - } + return result; +} #endif - bool parseLine(ModifyCmd& modifyCmd, const std::string& line, int num) - { - const std::string delim = " \t"; +bool parseLine(ModifyCmd& modifyCmd, const std::string& line, int num) { + const std::string delim = " \t"; - // Skip empty lines and comments - std::string::size_type cmdStart = line.find_first_not_of(delim); - if (cmdStart == std::string::npos || line[cmdStart] == '#') - return false; + // Skip empty lines and comments + std::string::size_type cmdStart = line.find_first_not_of(delim); + if (cmdStart == std::string::npos || line[cmdStart] == '#') + return false; - // Get command and key - std::string::size_type cmdEnd = line.find_first_of(delim, cmdStart+1); - std::string::size_type keyStart = line.find_first_not_of(delim, cmdEnd+1); - std::string::size_type keyEnd = line.find_first_of(delim, keyStart+1); - if (cmdEnd == std::string::npos || keyStart == std::string::npos) { - std::string cmdLine ; + // Get command and key + std::string::size_type cmdEnd = line.find_first_of(delim, cmdStart + 1); + std::string::size_type keyStart = line.find_first_not_of(delim, cmdEnd + 1); + std::string::size_type keyEnd = line.find_first_of(delim, keyStart + 1); + if (cmdEnd == std::string::npos || keyStart == std::string::npos) { + std::string cmdLine; #if defined(_MSC_VER) || defined(__MINGW__) - for ( int i = 1 ; i < __argc ; i++ ) { - cmdLine += std::string(" ") + formatArg(__argv[i]) ; - } + for (int i = 1; i < __argc; i++) { + cmdLine += std::string(" ") + formatArg(__argv[i]); + } #endif - throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, Exiv2::toString(num) - + ": " + _("Invalid command line:") + cmdLine); - } + throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, + Exiv2::toString(num) + ": " + _("Invalid command line:") + cmdLine); + } - std::string cmd(line.substr(cmdStart, cmdEnd-cmdStart)); - CmdId cmdId = commandId(cmd); - if (cmdId == invalidCmdId) { - throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, Exiv2::toString(num) - + ": " + _("Invalid command") + " `" + cmd + "'"); - } + std::string cmd(line.substr(cmdStart, cmdEnd - cmdStart)); + CmdId cmdId = commandId(cmd); + if (cmdId == invalidCmdId) { + throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, + Exiv2::toString(num) + ": " + _("Invalid command") + " `" + cmd + "'"); + } - Exiv2::TypeId defaultType = Exiv2::invalidTypeId; - std::string key(line.substr(keyStart, keyEnd-keyStart)); - MetadataId metadataId = invalidMetadataId; - if (cmdId != reg) { - try { - Exiv2::IptcKey iptcKey(key); - metadataId = iptc; - defaultType = Exiv2::IptcDataSets::dataSetType(iptcKey.tag(), - iptcKey.record()); - } - catch (const Exiv2::Error&) {} - if (metadataId == invalidMetadataId) { - try { - Exiv2::ExifKey exifKey(key); - metadataId = exif; - defaultType = exifKey.defaultTypeId(); - } - catch (const Exiv2::Error&) {} - } - if (metadataId == invalidMetadataId) { - try { - Exiv2::XmpKey xmpKey(key); - metadataId = xmp; - defaultType = Exiv2::XmpProperties::propertyType(xmpKey); - } - catch (const Exiv2::Error&) {} - } - if (metadataId == invalidMetadataId) { - throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, Exiv2::toString(num) - + ": " + _("Invalid key") + " `" + key + "'"); - } - } - std::string value; - Exiv2::TypeId type = defaultType; - bool explicitType = false; - if (cmdId != del) { - // Get type and value - std::string::size_type typeStart = std::string::npos; - if (keyEnd != std::string::npos) typeStart = line.find_first_not_of(delim, keyEnd+1); - std::string::size_type typeEnd = std::string::npos; - if (typeStart != std::string::npos) typeEnd = line.find_first_of(delim, typeStart+1); - std::string::size_type valStart = typeStart; - std::string::size_type valEnd = std::string::npos; - if (valStart != std::string::npos) valEnd = line.find_last_not_of(delim); + Exiv2::TypeId defaultType = Exiv2::invalidTypeId; + std::string key(line.substr(keyStart, keyEnd - keyStart)); + MetadataId metadataId = invalidMetadataId; + if (cmdId != reg) { + try { + Exiv2::IptcKey iptcKey(key); + metadataId = iptc; + defaultType = Exiv2::IptcDataSets::dataSetType(iptcKey.tag(), iptcKey.record()); + } catch (const Exiv2::Error&) { + } + if (metadataId == invalidMetadataId) { + try { + Exiv2::ExifKey exifKey(key); + metadataId = exif; + defaultType = exifKey.defaultTypeId(); + } catch (const Exiv2::Error&) { + } + } + if (metadataId == invalidMetadataId) { + try { + Exiv2::XmpKey xmpKey(key); + metadataId = xmp; + defaultType = Exiv2::XmpProperties::propertyType(xmpKey); + } catch (const Exiv2::Error&) { + } + } + if (metadataId == invalidMetadataId) { + throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, + Exiv2::toString(num) + ": " + _("Invalid key") + " `" + key + "'"); + } + } + std::string value; + Exiv2::TypeId type = defaultType; + bool explicitType = false; + if (cmdId != del) { + // Get type and value + std::string::size_type typeStart = std::string::npos; + if (keyEnd != std::string::npos) + typeStart = line.find_first_not_of(delim, keyEnd + 1); + std::string::size_type typeEnd = std::string::npos; + if (typeStart != std::string::npos) + typeEnd = line.find_first_of(delim, typeStart + 1); + std::string::size_type valStart = typeStart; + std::string::size_type valEnd = std::string::npos; + if (valStart != std::string::npos) + valEnd = line.find_last_not_of(delim); - if ( cmdId == reg - && ( keyEnd == std::string::npos - || valStart == std::string::npos)) { - throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, Exiv2::toString(num) - + ": " + _("Invalid command line") + " " ); - } - - if ( cmdId != reg - && typeStart != std::string::npos - && typeEnd != std::string::npos) { - std::string typeStr(line.substr(typeStart, typeEnd-typeStart)); - Exiv2::TypeId tmpType = Exiv2::TypeInfo::typeId(typeStr); - if (tmpType != Exiv2::invalidTypeId) { - valStart = line.find_first_not_of(delim, typeEnd+1); - if (valStart == std::string::npos) { - throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, Exiv2::toString(num) - + ": " + _("Invalid command line") + " " ); - } - type = tmpType; - explicitType = true; - } - } - - if (valStart != std::string::npos) { - value = parseEscapes(line.substr(valStart, valEnd+1-valStart)); - std::string::size_type last = value.length()-1; - if ( (value.at(0) == '"' && value.at(last) == '"') - || (value.at(0) == '\'' && value.at(last) == '\'')) { - value = value.substr(1, value.length()-2); - } - } - } - - modifyCmd.cmdId_ = cmdId; - modifyCmd.key_ = key; - modifyCmd.metadataId_ = metadataId; - modifyCmd.typeId_ = type; - modifyCmd.explicitType_ = explicitType; - modifyCmd.value_ = value; - - if (cmdId == reg) { - if (value.empty()) { - throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, - Exiv2::toString(num) + ": " + _("Empty value for key") + + " `" + key + "'"); - } - - // Registration needs to be done immediately as the new namespaces are - // looked up during parsing of subsequent lines (to validate XMP keys). - Exiv2::XmpProperties::registerNs(modifyCmd.value_, modifyCmd.key_); - } - - return true; - } // parseLine - - CmdId commandId(const std::string& cmdString) - { - int i = 0; - for (; cmdIdAndString[i].cmdId_ != invalidCmdId - && cmdIdAndString[i].cmdString_ != cmdString; ++i) {} - return cmdIdAndString[i].cmdId_; + if (cmdId == reg && (keyEnd == std::string::npos || valStart == std::string::npos)) { + throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, + Exiv2::toString(num) + ": " + _("Invalid command line") + " "); } - std::string parseEscapes(const std::string& input) - { - std::string result; - for (size_t i = 0; i < input.length(); ++i) { - char ch = input[i]; - if (ch != '\\') { - result.push_back(ch); - continue; - } - size_t escapeStart = i; - if (!(input.length() - 1 > i)) { - result.push_back(ch); - continue; - } + if (cmdId != reg && typeStart != std::string::npos && typeEnd != std::string::npos) { + std::string typeStr(line.substr(typeStart, typeEnd - typeStart)); + Exiv2::TypeId tmpType = Exiv2::TypeInfo::typeId(typeStr); + if (tmpType != Exiv2::invalidTypeId) { + valStart = line.find_first_not_of(delim, typeEnd + 1); + if (valStart == std::string::npos) { + throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, + Exiv2::toString(num) + ": " + _("Invalid command line") + " "); + } + type = tmpType; + explicitType = true; + } + } + + if (valStart != std::string::npos) { + value = parseEscapes(line.substr(valStart, valEnd + 1 - valStart)); + std::string::size_type last = value.length() - 1; + if ((value.at(0) == '"' && value.at(last) == '"') || (value.at(0) == '\'' && value.at(last) == '\'')) { + value = value.substr(1, value.length() - 2); + } + } + } + + modifyCmd.cmdId_ = cmdId; + modifyCmd.key_ = key; + modifyCmd.metadataId_ = metadataId; + modifyCmd.typeId_ = type; + modifyCmd.explicitType_ = explicitType; + modifyCmd.value_ = value; + + if (cmdId == reg) { + if (value.empty()) { + throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, + Exiv2::toString(num) + ": " + _("Empty value for key") + +" `" + key + "'"); + } + + // Registration needs to be done immediately as the new namespaces are + // looked up during parsing of subsequent lines (to validate XMP keys). + Exiv2::XmpProperties::registerNs(modifyCmd.value_, modifyCmd.key_); + } + + return true; +} // parseLine + +CmdId commandId(const std::string& cmdString) { + int i = 0; + for (; cmdIdAndString[i].cmdId_ != invalidCmdId && cmdIdAndString[i].cmdString_ != cmdString; ++i) { + } + return cmdIdAndString[i].cmdId_; +} + +std::string parseEscapes(const std::string& input) { + std::string result; + for (size_t i = 0; i < input.length(); ++i) { + char ch = input[i]; + if (ch != '\\') { + result.push_back(ch); + continue; + } + size_t escapeStart = i; + if (!(input.length() - 1 > i)) { + result.push_back(ch); + continue; + } + ++i; + ch = input[i]; + switch (ch) { + case '\\': // Escaping of backslash + result.push_back('\\'); + break; + case 'r': // Escaping of carriage return + result.push_back('\r'); + break; + case 'n': // Escaping of newline + result.push_back('\n'); + break; + case 't': // Escaping of tab + result.push_back('\t'); + break; + case 'u': // Escaping of unicode + if (input.length() >= 4 && input.length() - 4 > i) { + int acc = 0; + for (int j = 0; j < 4; ++j) { ++i; - ch = input[i]; - switch (ch) { - case '\\': // Escaping of backslash - result.push_back('\\'); - break; - case 'r': // Escaping of carriage return - result.push_back('\r'); - break; - case 'n': // Escaping of newline - result.push_back('\n'); - break; - case 't': // Escaping of tab - result.push_back('\t'); - break; - case 'u': // Escaping of unicode - if (input.length() >= 4 && input.length() - 4 > i) { - int acc = 0; - for (int j = 0; j < 4; ++j) { - ++i; - acc <<= 4; - if (input[i] >= '0' && input[i] <= '9') { - acc |= input[i] - '0'; - } - else if (input[i] >= 'a' && input[i] <= 'f') { - acc |= input[i] - 'a' + 10; - } - else if (input[i] >= 'A' && input[i] <= 'F') { - acc |= input[i] - 'A' + 10; - } - else { - acc = -1; - break; - } - } - if (acc == -1) { - result.push_back('\\'); - i = escapeStart; - break; - } - - std::string ucs2toUtf8; - ucs2toUtf8.push_back(static_cast((acc & 0xff00) >> 8)); - ucs2toUtf8.push_back(static_cast(acc & 0x00ff)); - - if (Exiv2::convertStringCharset (ucs2toUtf8, "UCS-2BE", "UTF-8")) { - result.append (ucs2toUtf8); - } - } - else { - result.push_back('\\'); - result.push_back(ch); - } - break; - default: - result.push_back('\\'); - result.push_back(ch); + acc <<= 4; + if (input[i] >= '0' && input[i] <= '9') { + acc |= input[i] - '0'; + } else if (input[i] >= 'a' && input[i] <= 'f') { + acc |= input[i] - 'a' + 10; + } else if (input[i] >= 'A' && input[i] <= 'F') { + acc |= input[i] - 'A' + 10; + } else { + acc = -1; + break; } + } + if (acc == -1) { + result.push_back('\\'); + i = escapeStart; + break; + } + + std::string ucs2toUtf8; + ucs2toUtf8.push_back(static_cast((acc & 0xff00) >> 8)); + ucs2toUtf8.push_back(static_cast(acc & 0x00ff)); + + if (Exiv2::convertStringCharset(ucs2toUtf8, "UCS-2BE", "UTF-8")) { + result.append(ucs2toUtf8); + } + } else { + result.push_back('\\'); + result.push_back(ch); } - return result; + break; + default: + result.push_back('\\'); + result.push_back(ch); } + } + return result; +} } // namespace diff --git a/app/exiv2app.hpp b/app/exiv2app.hpp index 5998df8a..26209e44 100644 --- a/app/exiv2app.hpp +++ b/app/exiv2app.hpp @@ -12,13 +12,13 @@ // included header files #include -#include "types.hpp" #include "getopt.hpp" +#include "types.hpp" // + standard includes -#include #include #include +#include // ***************************************************************************** // class definitions @@ -29,32 +29,28 @@ enum CmdId { invalidCmdId, add, set, del, reg }; // enum MetadataId { invalidMetadataId, iptc, exif, xmp }; //! Metadata identifiers // mdNone=0, mdExif=1, mdIptc=2, mdComment=4, mdXmp=8 -enum MetadataId { invalidMetadataId = Exiv2::mdNone - , iptc = Exiv2::mdIptc - , exif = Exiv2::mdExif - , xmp = Exiv2::mdXmp - } ; +enum MetadataId { invalidMetadataId = Exiv2::mdNone, iptc = Exiv2::mdIptc, exif = Exiv2::mdExif, xmp = Exiv2::mdXmp }; //! Structure for one parsed modification command struct ModifyCmd { - //! C'tor - ModifyCmd() : - cmdId_(invalidCmdId), metadataId_(invalidMetadataId), - typeId_(Exiv2::invalidTypeId), explicitType_(false) {} - CmdId cmdId_; //!< Command identifier - std::string key_; //!< Exiv2 key string - MetadataId metadataId_; //!< Metadata identifier - Exiv2::TypeId typeId_; //!< Exiv2 type identifier - //! Flag to indicate if the type was explicitly specified (true) - bool explicitType_; - std::string value_; //!< Data + //! C'tor + ModifyCmd() : + cmdId_(invalidCmdId), metadataId_(invalidMetadataId), typeId_(Exiv2::invalidTypeId), explicitType_(false) { + } + CmdId cmdId_; //!< Command identifier + std::string key_; //!< Exiv2 key string + MetadataId metadataId_; //!< Metadata identifier + Exiv2::TypeId typeId_; //!< Exiv2 type identifier + //! Flag to indicate if the type was explicitly specified (true) + bool explicitType_; + std::string value_; //!< Data }; //! Container for modification commands using ModifyCmds = std::vector; //! Structure to link command identifiers to strings struct CmdIdAndString { - CmdId cmdId_; //!< Commands identifier - std::string cmdString_; //!< Command string + CmdId cmdId_; //!< Commands identifier + std::string cmdString_; //!< Command string }; /*! @@ -93,180 +89,170 @@ struct CmdIdAndString { */ class Params : public Util::Getopt { -private: - std::string optstring_; + private: + std::string optstring_; -public: - //! Container for command files - using CmdFiles = std::vector; - //! Container for commands from the command line - using CmdLines = std::vector; - //! Container to store filenames. - using Files = std::vector; - //! Container for preview image numbers - using PreviewNumbers = std::set; - //! Container for keys - using Keys = std::vector; + public: + //! Container for command files + using CmdFiles = std::vector; + //! Container for commands from the command line + using CmdLines = std::vector; + //! Container to store filenames. + using Files = std::vector; + //! Container for preview image numbers + using PreviewNumbers = std::set; + //! Container for keys + using Keys = std::vector; - /*! - @brief Controls all access to the global Params instance. - @return Reference to the global Params instance. - */ - static Params& instance(); + /*! + @brief Controls all access to the global Params instance. + @return Reference to the global Params instance. + */ + static Params& instance(); - //! Prevent copy-construction: not implemented. - Params(const Params& rhs) = delete; + //! Prevent copy-construction: not implemented. + Params(const Params& rhs) = delete; - //! Enumerates print modes - enum PrintMode { - pmSummary, - pmList, - pmComment, - pmPreview, - pmStructure, - pmXMP, - pmIccProfile, - pmRecursive - }; + //! Enumerates print modes + enum PrintMode { pmSummary, pmList, pmComment, pmPreview, pmStructure, pmXMP, pmIccProfile, pmRecursive }; - //! Individual items to print, bitmap - enum PrintItem { - prTag = 1, - prGroup = 2, - prKey = 4, - prName = 8, - prLabel = 16, - prType = 32, - prCount = 64, - prSize = 128, - prValue = 256, - prTrans = 512, - prHex = 1024, - prSet = 2048 - }; + //! Individual items to print, bitmap + enum PrintItem { + prTag = 1, + prGroup = 2, + prKey = 4, + prName = 8, + prLabel = 16, + prType = 32, + prCount = 64, + prSize = 128, + prValue = 256, + prTrans = 512, + prHex = 1024, + prSet = 2048 + }; - //! Enumerates common targets, bitmap - enum CommonTarget { - ctExif = 1, - ctIptc = 2, - ctComment = 4, - ctThumb = 8, - ctXmp = 16, - ctXmpSidecar = 32, - ctPreview = 64, - ctIccProfile = 128, - ctXmpRaw = 256, - ctStdInOut = 512, - ctIptcRaw =1024 - }; + //! Enumerates common targets, bitmap + enum CommonTarget { + ctExif = 1, + ctIptc = 2, + ctComment = 4, + ctThumb = 8, + ctXmp = 16, + ctXmpSidecar = 32, + ctPreview = 64, + ctIccProfile = 128, + ctXmpRaw = 256, + ctStdInOut = 512, + ctIptcRaw = 1024 + }; - //! Enumerates the policies to handle existing files in rename action - enum FileExistsPolicy { overwritePolicy, renamePolicy, askPolicy }; + //! Enumerates the policies to handle existing files in rename action + enum FileExistsPolicy { overwritePolicy, renamePolicy, askPolicy }; - //! Enumerates year, month and day adjustments. - enum Yod { yodYear, yodMonth, yodDay }; + //! Enumerates year, month and day adjustments. + enum Yod { yodYear, yodMonth, yodDay }; - //! Structure for year, month and day adjustment command line arguments. - struct YodAdjust { - bool flag_; //!< Adjustment flag. - const char* option_; //!< Adjustment option string. - long adjustment_; //!< Adjustment value. - }; + //! Structure for year, month and day adjustment command line arguments. + struct YodAdjust { + bool flag_; //!< Adjustment flag. + const char* option_; //!< Adjustment option string. + long adjustment_; //!< Adjustment value. + }; - bool help_; //!< Help option flag. - bool version_; //!< Version option flag. - bool verbose_; //!< Verbose (talkative) option flag. - bool force_; //!< Force overwrites flag. - bool binary_; //!< Suppress long binary values. - bool unknown_; //!< Suppress unknown tags. - bool preserve_; //!< Preserve timestamps flag. - bool timestamp_; //!< Rename also sets the file timestamp. - bool timestampOnly_; //!< Rename only sets the file timestamp. - FileExistsPolicy fileExistsPolicy_; //!< What to do if file to rename exists. - bool adjust_; //!< Adjustment flag. - PrintMode printMode_; //!< Print mode. - unsigned long printItems_; //!< Print items. - unsigned long printTags_; //!< Print tags (bitmap of MetadataId flags). - //! %Action (integer rather than TaskType to avoid dependency). - int action_; - int target_; //!< What common target to process. + bool help_; //!< Help option flag. + bool version_; //!< Version option flag. + bool verbose_; //!< Verbose (talkative) option flag. + bool force_; //!< Force overwrites flag. + bool binary_; //!< Suppress long binary values. + bool unknown_; //!< Suppress unknown tags. + bool preserve_; //!< Preserve timestamps flag. + bool timestamp_; //!< Rename also sets the file timestamp. + bool timestampOnly_; //!< Rename only sets the file timestamp. + FileExistsPolicy fileExistsPolicy_; //!< What to do if file to rename exists. + bool adjust_; //!< Adjustment flag. + PrintMode printMode_; //!< Print mode. + unsigned long printItems_; //!< Print items. + unsigned long printTags_; //!< Print tags (bitmap of MetadataId flags). + //! %Action (integer rather than TaskType to avoid dependency). + int action_; + int target_; //!< What common target to process. - long adjustment_; //!< Adjustment in seconds. - YodAdjust yodAdjust_[3]; //!< Year, month and day adjustment info. - std::string format_; //!< Filename format (-r option arg). - bool formatSet_; //!< Whether the format is set with -r - CmdFiles cmdFiles_; //!< Names of the modification command files - CmdLines cmdLines_; //!< Commands from the command line - ModifyCmds modifyCmds_; //!< Parsed modification commands - std::string jpegComment_; //!< Jpeg comment to set in the image - std::string directory_; //!< Location for files to extract/insert - std::string suffix_; //!< File extension of the file to insert - Files files_; //!< List of non-option arguments. - PreviewNumbers previewNumbers_; //!< List of preview numbers - std::vector greps_; //!< List of keys to 'grep' from the metadata - Keys keys_; //!< List of keys to match from the metadata - std::string charset_; //!< Charset to use for UNICODE Exif user comment + long adjustment_; //!< Adjustment in seconds. + YodAdjust yodAdjust_[3]; //!< Year, month and day adjustment info. + std::string format_; //!< Filename format (-r option arg). + bool formatSet_; //!< Whether the format is set with -r + CmdFiles cmdFiles_; //!< Names of the modification command files + CmdLines cmdLines_; //!< Commands from the command line + ModifyCmds modifyCmds_; //!< Parsed modification commands + std::string jpegComment_; //!< Jpeg comment to set in the image + std::string directory_; //!< Location for files to extract/insert + std::string suffix_; //!< File extension of the file to insert + Files files_; //!< List of non-option arguments. + PreviewNumbers previewNumbers_; //!< List of preview numbers + std::vector greps_; //!< List of keys to 'grep' from the metadata + Keys keys_; //!< List of keys to match from the metadata + std::string charset_; //!< Charset to use for UNICODE Exif user comment - Exiv2::DataBuf stdinBuf; //!< DataBuf with the binary bytes from stdin + Exiv2::DataBuf stdinBuf; //!< DataBuf with the binary bytes from stdin -private: - bool first_; + private: + bool first_; - Params(); + Params(); -private: + private: + //! @name Helpers + //@{ + int setLogLevel(const std::string& optarg); + int evalGrep(const std::string& optarg); + int evalKey(const std::string& optarg); + int evalRename(int opt, const std::string& optarg); + int evalAdjust(const std::string& optarg); + int evalYodAdjust(const Yod& yod, const std::string& optarg); + int evalPrint(const std::string& optarg); + int evalPrintFlags(const std::string& optarg); + int evalDelete(const std::string& optarg); + int evalExtract(const std::string& optarg); + int evalInsert(const std::string& optarg); + int evalModify(int opt, const std::string& optarg); + //@} - //! @name Helpers - //@{ - int setLogLevel(const std::string& optarg); - int evalGrep( const std::string& optarg); - int evalKey( const std::string& optarg); - int evalRename(int opt, const std::string& optarg); - int evalAdjust(const std::string& optarg); - int evalYodAdjust(const Yod& yod, const std::string& optarg); - int evalPrint(const std::string& optarg); - int evalPrintFlags(const std::string& optarg); - int evalDelete(const std::string& optarg); - int evalExtract(const std::string& optarg); - int evalInsert(const std::string& optarg); - int evalModify(int opt, const std::string& optarg); - //@} + public: + /*! + @brief Call Getopt::getopt() with optstring, to initiate command line + argument parsing, perform consistency checks after all command line + arguments are parsed. -public: - /*! - @brief Call Getopt::getopt() with optstring, to initiate command line - argument parsing, perform consistency checks after all command line - arguments are parsed. + @param argc Argument count as passed to main() on program invocation. + @param argv Argument array as passed to main() on program invocation. - @param argc Argument count as passed to main() on program invocation. - @param argv Argument array as passed to main() on program invocation. + @return 0 if successful, >0 in case of errors. + */ + int getopt(int argc, char* const argv[]); - @return 0 if successful, >0 in case of errors. - */ - int getopt(int argc, char* const argv[]); + //! Handle options and their arguments. + int option(int opt, const std::string& optarg, int optopt) override; - //! Handle options and their arguments. - int option(int opt, const std::string& optarg, int optopt) override; + //! Handle non-option parameters. + int nonoption(const std::string& argv) override; - //! Handle non-option parameters. - int nonoption(const std::string& argv) override; + //! Print a minimal usage note to an output stream. + void usage(std::ostream& os = std::cout) const; - //! Print a minimal usage note to an output stream. - void usage(std::ostream& os =std::cout) const; + //! Print further usage explanations to an output stream. + void help(std::ostream& os = std::cout) const; - //! Print further usage explanations to an output stream. - void help(std::ostream& os =std::cout) const; + //! Print version information to an output stream. + static void version(bool verbose = false, std::ostream& os = std::cout); - //! Print version information to an output stream. - static void version(bool verbose = false, std::ostream& os = std::cout); + //! getStdin binary data read from stdin to DataBuf + /* + stdin can be used by multiple images in the exiv2 command line: + For example: $ cat foo.icc | exiv2 -iC- a.jpg b.jpg c.jpg will modify the ICC profile in several images. + */ + void getStdin(Exiv2::DataBuf& buf); - //! getStdin binary data read from stdin to DataBuf - /* - stdin can be used by multiple images in the exiv2 command line: - For example: $ cat foo.icc | exiv2 -iC- a.jpg b.jpg c.jpg will modify the ICC profile in several images. - */ - void getStdin(Exiv2::DataBuf& buf); +}; // class Params -}; // class Params - -#endif // #ifndef EXIV2APP_HPP_ +#endif // #ifndef EXIV2APP_HPP_ diff --git a/app/getopt.cpp b/app/getopt.cpp index c6fcd2c3..d8a57c26 100644 --- a/app/getopt.cpp +++ b/app/getopt.cpp @@ -10,107 +10,101 @@ namespace fs = std::filesystem; namespace Util { +// https://raw.githubusercontent.com/skeeto/getopt/master/getopt.h +int optind = 0; +int opterr = 1; +int optopt; +int optpos = 1; +const char* optarg; - // https://raw.githubusercontent.com/skeeto/getopt/master/getopt.h - int optind = 0; - int opterr = 1; - int optopt; - int optpos = 1; - const char* optarg; +/* A minimal POSIX getopt() implementation in ANSI C + * + * This is free and unencumbered software released into the public domain. + * + * This implementation supports the convention of resetting the option + * parser by assigning optind to 0. This resets the internal state + * appropriately. + * + * Ref: http://pubs.opengroup.org/onlinepubs/9699919799/functions/getopt.html + */ - /* A minimal POSIX getopt() implementation in ANSI C - * - * This is free and unencumbered software released into the public domain. - * - * This implementation supports the convention of resetting the option - * parser by assigning optind to 0. This resets the internal state - * appropriately. - * - * Ref: http://pubs.opengroup.org/onlinepubs/9699919799/functions/getopt.html - */ +int getopt(int argc, char* const argv[], const char* optstring) { + const char* arg; + (void)argc; - int getopt(int argc, char * const argv[], const char *optstring) - { - const char *arg; - (void)argc; + /* Reset? */ + if (optind == 0) { + optind = 1; + optpos = 1; + } - /* Reset? */ - if (optind == 0) { - optind = 1; - optpos = 1; - } - - arg = argv[optind]; - if (arg && strcmp(arg, "--") == 0) { - optind++; - return -1; - } - if (!arg || arg[0] != '-' || !isalnum(arg[1])) { - return -1; - } - const char *opt = strchr(optstring, arg[optpos]); - optopt = arg[optpos]; - if (!opt) { - if (opterr && *optstring != ':') - fprintf(stderr, "%s: illegal option: %c\n", argv[0], optopt); - return '?'; - } - if (opt[1] == ':') { - if (arg[optpos + 1]) { - optarg = const_cast(arg) + optpos + 1; - optind++; - optpos = 1; - return optopt; - } - if (argv[optind + 1]) { - optarg = argv[optind + 1]; - optind += 2; - optpos = 1; - return optopt; - } - if (opterr && *optstring != ':') - fprintf(stderr, "%s: option requires an argument: %c\n", argv[0], optopt); - return *optstring == ':' ? ':' : '?'; - } - if (!arg[++optpos]) { - optind++; - optpos = 1; - } - return optopt; + arg = argv[optind]; + if (arg && strcmp(arg, "--") == 0) { + optind++; + return -1; + } + if (!arg || arg[0] != '-' || !isalnum(arg[1])) { + return -1; + } + const char* opt = strchr(optstring, arg[optpos]); + optopt = arg[optpos]; + if (!opt) { + if (opterr && *optstring != ':') + fprintf(stderr, "%s: illegal option: %c\n", argv[0], optopt); + return '?'; + } + if (opt[1] == ':') { + if (arg[optpos + 1]) { + optarg = const_cast(arg) + optpos + 1; + optind++; + optpos = 1; + return optopt; } + if (argv[optind + 1]) { + optarg = argv[optind + 1]; + optind += 2; + optpos = 1; + return optopt; + } + if (opterr && *optstring != ':') + fprintf(stderr, "%s: option requires an argument: %c\n", argv[0], optopt); + return *optstring == ':' ? ':' : '?'; + } + if (!arg[++optpos]) { + optind++; + optpos = 1; + } + return optopt; +} // ***************************************************************************** // class Getopt - Getopt::Getopt() - : errcnt_(0) - { +Getopt::Getopt() : errcnt_(0) { +} + +int Getopt::getopt(int argc, char* const argv[], const std::string& optstring) { + progname_ = fs::path(argv[0]).filename().string(); + Util::optind = 0; // reset the Util::Getopt scanner + + for (; !errcnt_;) { + int c = Util::getopt(argc, argv, optstring.c_str()); + if (c == -1) { + break; } - - int Getopt::getopt(int argc, char* const argv[], const std::string& optstring) - { - progname_ = fs::path(argv[0]).filename().string(); - Util::optind = 0; // reset the Util::Getopt scanner - - for (;!errcnt_;) { - int c = Util::getopt(argc, argv, optstring.c_str()); - if (c == -1) { - break; - } - errcnt_ += option(c, Util::optarg ? Util::optarg : "", Util::optopt); - if (c == '?' ) { - break; - } - } - for (int i = Util::optind; i < argc; i++) { - errcnt_ += nonoption(argv[i]); - } - - return errcnt_; + errcnt_ += option(c, Util::optarg ? Util::optarg : "", Util::optopt); + if (c == '?') { + break; } + } + for (int i = Util::optind; i < argc; i++) { + errcnt_ += nonoption(argv[i]); + } - int Getopt::nonoption(const std::string& /*argv*/) - { - return 0; - } + return errcnt_; +} -} // namespace Util +int Getopt::nonoption(const std::string& /*argv*/) { + return 0; +} + +} // namespace Util diff --git a/app/getopt.hpp b/app/getopt.hpp index e9a83976..2b553a5d 100644 --- a/app/getopt.hpp +++ b/app/getopt.hpp @@ -6,96 +6,99 @@ #include namespace Util { +extern int optind; +extern int opterr; +extern int optopt; +extern int optpos; +extern const char* optarg; - extern int optind ; - extern int opterr ; - extern int optopt ; - extern int optpos ; - extern const char* optarg; +int getopt(int argc, char* const argv[], const char* optstring); - int getopt(int argc, char * const argv[], const char *optstring); +// ********************************************************************* +// class definitions - // ********************************************************************* - // class definitions +/*! + @brief Parse the command line options of a program. - /*! - @brief Parse the command line options of a program. + A wrapper around the POSIX %getopt(3) function. Parses the command line + options and passes each option to virtual option(). A derived class + implements this method to handle options as needed. Similarly, + remaining non-option parameters are passed to the virtual nonoption() + method. + */ +class Getopt { + public: + //! Default constructor. + Getopt(); - A wrapper around the POSIX %getopt(3) function. Parses the command line - options and passes each option to virtual option(). A derived class - implements this method to handle options as needed. Similarly, - remaining non-option parameters are passed to the virtual nonoption() - method. - */ - class Getopt { - public: - //! Default constructor. - Getopt(); + //! Destructor. + virtual ~Getopt() = default; - //! Destructor. - virtual ~Getopt() = default; + /*! + @brief Parse command line arguments. - /*! - @brief Parse command line arguments. + Parses the command line arguments. Calls option() with the + character value of the option and its argument (if any) for each + recognized option and with ':' or '?' for unrecognized options. + See the manual pages for %getopt(3) for details. In addition, + nonoption() is invoked for each remaining non-option parameter on + the command line. - Parses the command line arguments. Calls option() with the - character value of the option and its argument (if any) for each - recognized option and with ':' or '?' for unrecognized options. - See the manual pages for %getopt(3) for details. In addition, - nonoption() is invoked for each remaining non-option parameter on - the command line. + @param argc Argument count as passed to main() on program invocation. + @param argv Argument array as passed to main() on program invocation. + @param optstring String containing the legitimate option characters. - @param argc Argument count as passed to main() on program invocation. - @param argv Argument array as passed to main() on program invocation. - @param optstring String containing the legitimate option characters. + @return Number of errors (the sum of the return values from option() + and nonoption()). + */ + int getopt(int argc, char* const argv[], const std::string& optstring); - @return Number of errors (the sum of the return values from option() - and nonoption()). - */ - int getopt(int argc, char* const argv[], const std::string& optstring); + /*! + @brief Callback used by getopt() to pass on each option and its + argument (if any). - /*! - @brief Callback used by getopt() to pass on each option and its - argument (if any). + Implement this method in a derived class to handle the options as + needed. See the manual pages for %getopt(3) for further details, in + particular, the semantics of optarg and optopt. - Implement this method in a derived class to handle the options as - needed. See the manual pages for %getopt(3) for further details, in - particular, the semantics of optarg and optopt. + @param opt Value of the option character as returned by %getopt(3). + @param optarg The corresponding option argument. + @param optopt The actual option character in case of an unrecognized + option or a missing option argument (opt is '?' or ':'). - @param opt Value of the option character as returned by %getopt(3). - @param optarg The corresponding option argument. - @param optopt The actual option character in case of an unrecognized - option or a missing option argument (opt is '?' or ':'). + @return 0 if successful, 1 in case of an error. + */ + virtual int option(int opt, const std::string& optarg, int optopt) = 0; - @return 0 if successful, 1 in case of an error. - */ - virtual int option(int opt, const std::string& optarg, int optopt) = 0; + /*! + @brief Callback used by getopt() to pass on each non-option parameter + found on the command line. - /*! - @brief Callback used by getopt() to pass on each non-option parameter - found on the command line. + Implement this method in a derived class to handle the non-option + parameters as needed. The default implementation ignores all non-option + parameters. - Implement this method in a derived class to handle the non-option - parameters as needed. The default implementation ignores all non-option - parameters. + @param argv The non-option parameter from the command line. - @param argv The non-option parameter from the command line. + @return 0 if successful, 1 in case of an error. + */ + virtual int nonoption(const std::string& argv); - @return 0 if successful, 1 in case of an error. - */ - virtual int nonoption(const std::string& argv); + //! Program name (argv[0]) + const std::string& progname() const { + return progname_; + } - //! Program name (argv[0]) - const std::string& progname() const { return progname_; } + //! Total number of errors returned by calls to option() + int errcnt() const { + return errcnt_; + } - //! Total number of errors returned by calls to option() - int errcnt() const { return errcnt_; } + private: + std::string progname_; + int errcnt_; +}; - private: - std::string progname_; - int errcnt_; - }; - -}; // namespace Util +}; // namespace Util #endif diff --git a/app/wmain.c b/app/wmain.c index 3ef6bd5e..89f406d0 100644 --- a/app/wmain.c +++ b/app/wmain.c @@ -4,39 +4,37 @@ extern int __cdecl main(); -int wmain(int argc, wchar_t* argv[]) -{ - char** args; - int nbytes = (int)(sizeof(char*) * (argc + 1)); - HANDLE heap = GetProcessHeap(); +int wmain(int argc, wchar_t* argv[]) { + char** args; + int nbytes = (int)(sizeof(char*) * (argc + 1)); + HANDLE heap = GetProcessHeap(); - for (int i = 0; i < argc; ++i) - nbytes += WideCharToMultiByte(CP_UTF8, 0, argv[i], -1, NULL, 0, NULL, NULL); + for (int i = 0; i < argc; ++i) + nbytes += WideCharToMultiByte(CP_UTF8, 0, argv[i], -1, NULL, 0, NULL, NULL); - args = HeapAlloc(heap, 0, nbytes); - args[0] = (char*)(args + argc + 1); - - for (int i = 0; i < argc; ++i) - args[i+1] = args[i] + WideCharToMultiByte(CP_UTF8, 0, argv[i], -1, args[i], nbytes, NULL, NULL); - - args[argc] = NULL; + args = HeapAlloc(heap, 0, nbytes); + args[0] = (char*)(args + argc + 1); - argc = main(argc, args); - HeapFree(heap, 0, args); - return argc; + for (int i = 0; i < argc; ++i) + args[i + 1] = args[i] + WideCharToMultiByte(CP_UTF8, 0, argv[i], -1, args[i], nbytes, NULL, NULL); + + args[argc] = NULL; + + argc = main(argc, args); + HeapFree(heap, 0, args); + return argc; } -int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow) -{ - (void) hInstance; - (void) hPrevInstance; - (void) lpCmdLine; - (void) nCmdShow; +int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow) { + (void)hInstance; + (void)hPrevInstance; + (void)lpCmdLine; + (void)nCmdShow; - int argc; - wchar_t** argv; - argv = CommandLineToArgvW(GetCommandLineW(), &argc); - argc = wmain(argc, argv); - LocalFree(argv); - return argc; + int argc; + wchar_t** argv; + argv = CommandLineToArgvW(GetCommandLineW(), &argc); + argc = wmain(argc, argv); + LocalFree(argv); + return argc; } diff --git a/fuzz/fuzz-read-print-write.cpp b/fuzz/fuzz-read-print-write.cpp index dd4ba6ed..53c52095 100644 --- a/fuzz/fuzz-read-print-write.cpp +++ b/fuzz/fuzz-read-print-write.cpp @@ -1,10 +1,10 @@ #include -#include -#include #include +#include +#include -extern "C" int LLVMFuzzerTestOneInput(const uint8_t * data, size_t size) { +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { // Invalid files generate a lot of warnings, so switch off logging. Exiv2::LogMsg::setLevel(Exiv2::LogMsg::mute); @@ -16,8 +16,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t * data, size_t size) { try { Exiv2::DataBuf data_copy(data, size); - Exiv2::Image::UniquePtr image = - Exiv2::ImageFactory::open(data_copy.c_data(), size); + Exiv2::Image::UniquePtr image = Exiv2::ImageFactory::open(data_copy.c_data(), size); assert(image.get() != 0); image->readMetadata(); @@ -43,7 +42,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t * data, size_t size) { image->writeMetadata(); - } catch(...) { + } catch (...) { // Exiv2 throws an exception if the metadata is invalid. } diff --git a/include/exiv2/basicio.hpp b/include/exiv2/basicio.hpp index ce6bc33d..42480d51 100644 --- a/include/exiv2/basicio.hpp +++ b/include/exiv2/basicio.hpp @@ -22,977 +22,980 @@ // ***************************************************************************** // namespace extensions namespace Exiv2 { - // ***************************************************************************** // class definitions - /*! - @brief An interface for simple binary IO. +/*! + @brief An interface for simple binary IO. - Designed to have semantics and names similar to those of C style FILE* - operations. Subclasses should all behave the same so that they can be - interchanged. - */ - class EXIV2API BasicIo { - public: - //! BasicIo auto_ptr type - using UniquePtr = std::unique_ptr; + Designed to have semantics and names similar to those of C style FILE* + operations. Subclasses should all behave the same so that they can be + interchanged. + */ +class EXIV2API BasicIo { + public: + //! BasicIo auto_ptr type + using UniquePtr = std::unique_ptr; - //! Seek starting positions - enum Position { beg, cur, end }; + //! Seek starting positions + enum Position { beg, cur, end }; - //! @name Creators - //@{ - //! Destructor - virtual ~BasicIo() = default; - //@} + //! @name Creators + //@{ + //! Destructor + virtual ~BasicIo() = default; + //@} - //! @name Manipulators - //@{ - /*! - @brief Open the IO source using the default access mode. The - default mode should allow for reading and writing. + //! @name Manipulators + //@{ + /*! + @brief Open the IO source using the default access mode. The + default mode should allow for reading and writing. - This method can also be used to "reopen" an IO source which will - flush any unwritten data and reset the IO position to the start. - Subclasses may provide custom methods to allow for - opening IO sources differently. + This method can also be used to "reopen" an IO source which will + flush any unwritten data and reset the IO position to the start. + Subclasses may provide custom methods to allow for + opening IO sources differently. - @return 0 if successful;
- Nonzero if failure. - */ - virtual int open() = 0; + @return 0 if successful;
+ Nonzero if failure. + */ + virtual int open() = 0; - /*! - @brief Close the IO source. After closing a BasicIo instance can not - be read or written. Closing flushes any unwritten data. It is - safe to call close on a closed instance. - @return 0 if successful;
- Nonzero if failure. - */ - virtual int close() = 0; - /*! - @brief Write data to the IO source. Current IO position is advanced - by the number of bytes written. - @param data Pointer to data. Data must be at least \em wcount - bytes long - @param wcount Number of bytes to be written. - @return Number of bytes written to IO source successfully;
- 0 if failure; - */ - virtual size_t write(const byte* data, size_t wcount) = 0; - /*! - @brief Write data that is read from another BasicIo instance to - the IO source. Current IO position is advanced by the number - of bytes written. - @param src Reference to another BasicIo instance. Reading start - at the source's current IO position - @return Number of bytes written to IO source successfully;
- 0 if failure; - */ - virtual size_t write(BasicIo& src) = 0; - /*! - @brief Write one byte to the IO source. Current IO position is - advanced by one byte. - @param data The single byte to be written. - @return The value of the byte written if successful;
- EOF if failure; - */ - virtual int putb(byte data) = 0; - /*! - @brief Read data from the IO source. Reading starts at the current - IO position and the position is advanced by the number of bytes - read. - @param rcount Maximum number of bytes to read. Fewer bytes may be - read if \em rcount bytes are not available. - @return DataBuf instance containing the bytes read. Use the - DataBuf::size_ member to find the number of bytes read. - DataBuf::size_ will be 0 on failure. - */ - virtual DataBuf read(size_t rcount) = 0; - /*! - @brief Read data from the IO source. Reading starts at the current - IO position and the position is advanced by the number of bytes - read. - @param buf Pointer to a block of memory into which the read data - is stored. The memory block must be at least \em rcount bytes - long. - @param rcount Maximum number of bytes to read. Fewer bytes may be - read if \em rcount bytes are not available. - @return Number of bytes read from IO source successfully;
- 0 if failure; - */ - virtual size_t read(byte* buf, size_t rcount) = 0; - /*! - @brief Safe version of `read()` that checks for errors and throws - an exception if the read was unsuccessful. - @param buf Pointer to a block of memory into which the read data - is stored. The memory block must be at least \em rcount bytes - long. - @param rcount Maximum number of bytes to read. Fewer bytes may be - read if \em rcount bytes are not available. - @param err Error code to use if an exception is thrown. - */ - void readOrThrow(byte* buf, size_t rcount, ErrorCode err); - /*! - @brief Read one byte from the IO source. Current IO position is - advanced by one byte. - @return The byte read from the IO source if successful;
- EOF if failure; - */ - virtual int getb() = 0; - /*! - @brief Remove all data from this object's IO source and then transfer - data from the \em src BasicIo object into this object. + /*! + @brief Close the IO source. After closing a BasicIo instance can not + be read or written. Closing flushes any unwritten data. It is + safe to call close on a closed instance. + @return 0 if successful;
+ Nonzero if failure. + */ + virtual int close() = 0; + /*! + @brief Write data to the IO source. Current IO position is advanced + by the number of bytes written. + @param data Pointer to data. Data must be at least \em wcount + bytes long + @param wcount Number of bytes to be written. + @return Number of bytes written to IO source successfully;
+ 0 if failure; + */ + virtual size_t write(const byte *data, size_t wcount) = 0; + /*! + @brief Write data that is read from another BasicIo instance to + the IO source. Current IO position is advanced by the number + of bytes written. + @param src Reference to another BasicIo instance. Reading start + at the source's current IO position + @return Number of bytes written to IO source successfully;
+ 0 if failure; + */ + virtual size_t write(BasicIo &src) = 0; + /*! + @brief Write one byte to the IO source. Current IO position is + advanced by one byte. + @param data The single byte to be written. + @return The value of the byte written if successful;
+ EOF if failure; + */ + virtual int putb(byte data) = 0; + /*! + @brief Read data from the IO source. Reading starts at the current + IO position and the position is advanced by the number of bytes + read. + @param rcount Maximum number of bytes to read. Fewer bytes may be + read if \em rcount bytes are not available. + @return DataBuf instance containing the bytes read. Use the + DataBuf::size_ member to find the number of bytes read. + DataBuf::size_ will be 0 on failure. + */ + virtual DataBuf read(size_t rcount) = 0; + /*! + @brief Read data from the IO source. Reading starts at the current + IO position and the position is advanced by the number of bytes + read. + @param buf Pointer to a block of memory into which the read data + is stored. The memory block must be at least \em rcount bytes + long. + @param rcount Maximum number of bytes to read. Fewer bytes may be + read if \em rcount bytes are not available. + @return Number of bytes read from IO source successfully;
+ 0 if failure; + */ + virtual size_t read(byte *buf, size_t rcount) = 0; + /*! + @brief Safe version of `read()` that checks for errors and throws + an exception if the read was unsuccessful. + @param buf Pointer to a block of memory into which the read data + is stored. The memory block must be at least \em rcount bytes + long. + @param rcount Maximum number of bytes to read. Fewer bytes may be + read if \em rcount bytes are not available. + @param err Error code to use if an exception is thrown. + */ + void readOrThrow(byte *buf, size_t rcount, ErrorCode err); + /*! + @brief Read one byte from the IO source. Current IO position is + advanced by one byte. + @return The byte read from the IO source if successful;
+ EOF if failure; + */ + virtual int getb() = 0; + /*! + @brief Remove all data from this object's IO source and then transfer + data from the \em src BasicIo object into this object. - The source object is invalidated by this operation and should not be - used after this method returns. This method exists primarily to - be used with the BasicIo::temporary() method. + The source object is invalidated by this operation and should not be + used after this method returns. This method exists primarily to + be used with the BasicIo::temporary() method. - @param src Reference to another BasicIo instance. The entire contents - of src are transferred to this object. The \em src object is - invalidated by the method. - @throw Error In case of failure - */ - virtual void transfer(BasicIo& src) = 0; - /*! - @brief Move the current IO position. - @param offset Number of bytes to move the position relative - to the starting position specified by \em pos - @param pos Position from which the seek should start - @return 0 if successful;
- Nonzero if failure; - */ - virtual int seek(int64_t offset, Position pos) = 0; + @param src Reference to another BasicIo instance. The entire contents + of src are transferred to this object. The \em src object is + invalidated by the method. + @throw Error In case of failure + */ + virtual void transfer(BasicIo &src) = 0; + /*! + @brief Move the current IO position. + @param offset Number of bytes to move the position relative + to the starting position specified by \em pos + @param pos Position from which the seek should start + @return 0 if successful;
+ Nonzero if failure; + */ + virtual int seek(int64_t offset, Position pos) = 0; - /*! - @brief Safe version of `seek()` that checks for errors and throws - an exception if the seek was unsuccessful. - @param offset Number of bytes to move the position relative - to the starting position specified by \em pos - @param pos Position from which the seek should start - @param err Error code to use if an exception is thrown. - */ - void seekOrThrow(int64_t offset, Position pos, ErrorCode err); + /*! + @brief Safe version of `seek()` that checks for errors and throws + an exception if the seek was unsuccessful. + @param offset Number of bytes to move the position relative + to the starting position specified by \em pos + @param pos Position from which the seek should start + @param err Error code to use if an exception is thrown. + */ + void seekOrThrow(int64_t offset, Position pos, ErrorCode err); - /*! - @brief Direct access to the IO data. For files, this is done by - mapping the file into the process's address space; for memory - blocks, this allows direct access to the memory block. - @param isWriteable Set to true if the mapped area should be writeable - (default is false). - @return A pointer to the mapped area. - @throw Error In case of failure. - */ - virtual byte* mmap(bool isWriteable =false) =0; - /*! - @brief Remove a mapping established with mmap(). If the mapped area - is writeable, this ensures that changes are written back. - @return 0 if successful;
- Nonzero if failure; - */ - virtual int munmap() =0; + /*! + @brief Direct access to the IO data. For files, this is done by + mapping the file into the process's address space; for memory + blocks, this allows direct access to the memory block. + @param isWriteable Set to true if the mapped area should be writeable + (default is false). + @return A pointer to the mapped area. + @throw Error In case of failure. + */ + virtual byte *mmap(bool isWriteable = false) = 0; + /*! + @brief Remove a mapping established with mmap(). If the mapped area + is writeable, this ensures that changes are written back. + @return 0 if successful;
+ Nonzero if failure; + */ + virtual int munmap() = 0; - //@} + //@} - //! @name Accessors - //@{ - /*! - @brief Get the current IO position. - @return Offset from the start of IO if successful;
- -1 if failure; - */ - virtual long tell() const = 0; - /*! - @brief Get the current size of the IO source in bytes. - @return Size of the IO source in bytes;
- -1 if failure; - */ - virtual size_t size() const = 0; - //!Returns true if the IO source is open, otherwise false. - virtual bool isopen() const = 0; - //!Returns 0 if the IO source is in a valid state, otherwise nonzero. - virtual int error() const = 0; - //!Returns true if the IO position has reached the end, otherwise false. - virtual bool eof() const = 0; - /*! - @brief Return the path to the IO resource. Often used to form - comprehensive error messages where only a BasicIo instance is - available. - */ - virtual const std::string& path() const noexcept =0; + //! @name Accessors + //@{ + /*! + @brief Get the current IO position. + @return Offset from the start of IO if successful;
+ -1 if failure; + */ + virtual long tell() const = 0; + /*! + @brief Get the current size of the IO source in bytes. + @return Size of the IO source in bytes;
+ -1 if failure; + */ + virtual size_t size() const = 0; + //! Returns true if the IO source is open, otherwise false. + virtual bool isopen() const = 0; + //! Returns 0 if the IO source is in a valid state, otherwise nonzero. + virtual int error() const = 0; + //! Returns true if the IO position has reached the end, otherwise false. + virtual bool eof() const = 0; + /*! + @brief Return the path to the IO resource. Often used to form + comprehensive error messages where only a BasicIo instance is + available. + */ + virtual const std::string &path() const noexcept = 0; - /*! - @brief Mark all the bNone blocks to bKnow. This avoids allocating memory - for parts of the file that contain image-date (non-metadata/pixel data) + /*! + @brief Mark all the bNone blocks to bKnow. This avoids allocating memory + for parts of the file that contain image-date (non-metadata/pixel data) - @note This method should be only called after the concerned data (metadata) - are all downloaded from the remote file to memory. - */ - virtual void populateFakeData() = 0; + @note This method should be only called after the concerned data (metadata) + are all downloaded from the remote file to memory. + */ + virtual void populateFakeData() = 0; - /*! - @brief this is allocated and populated by mmap() - */ - byte* bigBlock_{}; + /*! + @brief this is allocated and populated by mmap() + */ + byte *bigBlock_{}; - //@} - }; // class BasicIo + //@} +}; // class BasicIo - /*! - @brief Utility class that closes a BasicIo instance upon destruction. - Meant to be used as a stack variable in functions that need to - ensure BasicIo instances get closed. Useful when functions return - errors from many locations. - */ - class EXIV2API IoCloser { - public: - //! @name Creators - //@{ - //! Constructor, takes a BasicIo reference - explicit IoCloser(BasicIo& bio) : bio_(bio) {} - //! Destructor, closes the BasicIo reference - virtual ~IoCloser() { close(); } - //@} +/*! + @brief Utility class that closes a BasicIo instance upon destruction. + Meant to be used as a stack variable in functions that need to + ensure BasicIo instances get closed. Useful when functions return + errors from many locations. + */ +class EXIV2API IoCloser { + public: + //! @name Creators + //@{ + //! Constructor, takes a BasicIo reference + explicit IoCloser(BasicIo &bio) : bio_(bio) { + } + //! Destructor, closes the BasicIo reference + virtual ~IoCloser() { + close(); + } + //@} - //! @name Manipulators - //@{ - //! Close the BasicIo if it is open - void close() { if (bio_.isopen()) bio_.close(); } - //@} + //! @name Manipulators + //@{ + //! Close the BasicIo if it is open + void close() { + if (bio_.isopen()) + bio_.close(); + } + //@} - // DATA - //! The BasicIo reference - BasicIo& bio_; + // DATA + //! The BasicIo reference + BasicIo &bio_; - // Not implemented - //! Copy constructor - IoCloser(const IoCloser&) = delete; - //! Assignment operator - IoCloser& operator=(const IoCloser&) = delete; - }; // class IoCloser + // Not implemented + //! Copy constructor + IoCloser(const IoCloser &) = delete; + //! Assignment operator + IoCloser &operator=(const IoCloser &) = delete; +}; // class IoCloser - /*! - @brief Provides binary file IO by implementing the BasicIo - interface. - */ - class EXIV2API FileIo : public BasicIo { - public: - //! @name Creators - //@{ - /*! - @brief Constructor that accepts the file path on which IO will be - performed. The constructor does not open the file, and - therefore never fails. - @param path The full path of a file - */ - explicit FileIo(const std::string& path); +/*! + @brief Provides binary file IO by implementing the BasicIo + interface. + */ +class EXIV2API FileIo : public BasicIo { + public: + //! @name Creators + //@{ + /*! + @brief Constructor that accepts the file path on which IO will be + performed. The constructor does not open the file, and + therefore never fails. + @param path The full path of a file + */ + explicit FileIo(const std::string &path); - //! Destructor. Flushes and closes an open file. - ~FileIo() override; - //@} + //! Destructor. Flushes and closes an open file. + ~FileIo() override; + //@} - //! @name Manipulators - //@{ - /*! - @brief Open the file using the specified mode. + //! @name Manipulators + //@{ + /*! + @brief Open the file using the specified mode. - This method can also be used to "reopen" a file which will flush any - unwritten data and reset the IO position to the start. Although - files can be opened in binary or text mode, this class has - only been tested carefully in binary mode. + This method can also be used to "reopen" a file which will flush any + unwritten data and reset the IO position to the start. Although + files can be opened in binary or text mode, this class has + only been tested carefully in binary mode. - @param mode Specified that type of access allowed on the file. - Valid values match those of the C fopen command exactly. - @return 0 if successful;
- Nonzero if failure. - */ - int open(const std::string& mode); - /*! - @brief Open the file using the default access mode of "rb". - This method can also be used to "reopen" a file which will flush - any unwritten data and reset the IO position to the start. - @return 0 if successful;
- Nonzero if failure. - */ - int open() override; - /*! - @brief Flush and unwritten data and close the file . It is - safe to call close on an already closed instance. - @return 0 if successful;
- Nonzero if failure; - */ - int close() override; - /*! - @brief Write data to the file. The file position is advanced - by the number of bytes written. - @param data Pointer to data. Data must be at least \em wcount - bytes long - @param wcount Number of bytes to be written. - @return Number of bytes written to the file successfully;
- 0 if failure; - */ - size_t write(const byte* data, size_t wcount) override; - /*! - @brief Write data that is read from another BasicIo instance to - the file. The file position is advanced by the number - of bytes written. - @param src Reference to another BasicIo instance. Reading start - at the source's current IO position - @return Number of bytes written to the file successfully;
- 0 if failure; - */ - size_t write(BasicIo& src) override; - /*! - @brief Write one byte to the file. The file position is - advanced by one byte. - @param data The single byte to be written. - @return The value of the byte written if successful;
- EOF if failure; - */ - int putb(byte data) override; - /*! - @brief Read data from the file. Reading starts at the current - file position and the position is advanced by the number of - bytes read. - @param rcount Maximum number of bytes to read. Fewer bytes may be - read if \em rcount bytes are not available. - @return DataBuf instance containing the bytes read. Use the - DataBuf::size_ member to find the number of bytes read. - DataBuf::size_ will be 0 on failure. - */ - DataBuf read(size_t rcount) override; - /*! - @brief Read data from the file. Reading starts at the current - file position and the position is advanced by the number of - bytes read. - @param buf Pointer to a block of memory into which the read data - is stored. The memory block must be at least \em rcount bytes - long. - @param rcount Maximum number of bytes to read. Fewer bytes may be - read if \em rcount bytes are not available. - @return Number of bytes read from the file successfully;
- 0 if failure; - */ - size_t read(byte* buf, size_t rcount) override; - /*! - @brief Read one byte from the file. The file position is - advanced by one byte. - @return The byte read from the file if successful;
- EOF if failure; - */ - int getb() override; - /*! - @brief Remove the contents of the file and then transfer data from - the \em src BasicIo object into the empty file. + @param mode Specified that type of access allowed on the file. + Valid values match those of the C fopen command exactly. + @return 0 if successful;
+ Nonzero if failure. + */ + int open(const std::string &mode); + /*! + @brief Open the file using the default access mode of "rb". + This method can also be used to "reopen" a file which will flush + any unwritten data and reset the IO position to the start. + @return 0 if successful;
+ Nonzero if failure. + */ + int open() override; + /*! + @brief Flush and unwritten data and close the file . It is + safe to call close on an already closed instance. + @return 0 if successful;
+ Nonzero if failure; + */ + int close() override; + /*! + @brief Write data to the file. The file position is advanced + by the number of bytes written. + @param data Pointer to data. Data must be at least \em wcount + bytes long + @param wcount Number of bytes to be written. + @return Number of bytes written to the file successfully;
+ 0 if failure; + */ + size_t write(const byte *data, size_t wcount) override; + /*! + @brief Write data that is read from another BasicIo instance to + the file. The file position is advanced by the number + of bytes written. + @param src Reference to another BasicIo instance. Reading start + at the source's current IO position + @return Number of bytes written to the file successfully;
+ 0 if failure; + */ + size_t write(BasicIo &src) override; + /*! + @brief Write one byte to the file. The file position is + advanced by one byte. + @param data The single byte to be written. + @return The value of the byte written if successful;
+ EOF if failure; + */ + int putb(byte data) override; + /*! + @brief Read data from the file. Reading starts at the current + file position and the position is advanced by the number of + bytes read. + @param rcount Maximum number of bytes to read. Fewer bytes may be + read if \em rcount bytes are not available. + @return DataBuf instance containing the bytes read. Use the + DataBuf::size_ member to find the number of bytes read. + DataBuf::size_ will be 0 on failure. + */ + DataBuf read(size_t rcount) override; + /*! + @brief Read data from the file. Reading starts at the current + file position and the position is advanced by the number of + bytes read. + @param buf Pointer to a block of memory into which the read data + is stored. The memory block must be at least \em rcount bytes + long. + @param rcount Maximum number of bytes to read. Fewer bytes may be + read if \em rcount bytes are not available. + @return Number of bytes read from the file successfully;
+ 0 if failure; + */ + size_t read(byte *buf, size_t rcount) override; + /*! + @brief Read one byte from the file. The file position is + advanced by one byte. + @return The byte read from the file if successful;
+ EOF if failure; + */ + int getb() override; + /*! + @brief Remove the contents of the file and then transfer data from + the \em src BasicIo object into the empty file. - This method is optimized to simply rename the source file if the - source object is another FileIo instance. The source BasicIo object - is invalidated by this operation and should not be used after this - method returns. This method exists primarily to be used with - the BasicIo::temporary() method. + This method is optimized to simply rename the source file if the + source object is another FileIo instance. The source BasicIo object + is invalidated by this operation and should not be used after this + method returns. This method exists primarily to be used with + the BasicIo::temporary() method. - @note If the caller doesn't have permissions to write to the file, - an exception is raised and \em src is deleted. + @note If the caller doesn't have permissions to write to the file, + an exception is raised and \em src is deleted. - @param src Reference to another BasicIo instance. The entire contents - of src are transferred to this object. The \em src object is - invalidated by the method. - @throw Error In case of failure - */ - void transfer(BasicIo& src) override; + @param src Reference to another BasicIo instance. The entire contents + of src are transferred to this object. The \em src object is + invalidated by the method. + @throw Error In case of failure + */ + void transfer(BasicIo &src) override; - int seek(int64_t offset, Position pos) override; + int seek(int64_t offset, Position pos) override; - /*! - @brief Map the file into the process's address space. The file must be - open before mmap() is called. If the mapped area is writeable, - changes may not be written back to the underlying file until - munmap() is called. The pointer is valid only as long as the - FileIo object exists. - @param isWriteable Set to true if the mapped area should be writeable - (default is false). - @return A pointer to the mapped area. - @throw Error In case of failure. - */ - byte* mmap(bool isWriteable = false) override; - /*! - @brief Remove a mapping established with mmap(). If the mapped area is - writeable, this ensures that changes are written back to the - underlying file. - @return 0 if successful;
- Nonzero if failure; - */ - int munmap() override; - /*! - @brief close the file source and set a new path. - */ - virtual void setPath(const std::string& path); + /*! + @brief Map the file into the process's address space. The file must be + open before mmap() is called. If the mapped area is writeable, + changes may not be written back to the underlying file until + munmap() is called. The pointer is valid only as long as the + FileIo object exists. + @param isWriteable Set to true if the mapped area should be writeable + (default is false). + @return A pointer to the mapped area. + @throw Error In case of failure. + */ + byte *mmap(bool isWriteable = false) override; + /*! + @brief Remove a mapping established with mmap(). If the mapped area is + writeable, this ensures that changes are written back to the + underlying file. + @return 0 if successful;
+ Nonzero if failure; + */ + int munmap() override; + /*! + @brief close the file source and set a new path. + */ + virtual void setPath(const std::string &path); - //@} - //! @name Accessors - //@{ - /*! - @brief Get the current file position. - @return Offset from the start of the file if successful;
- -1 if failure; - */ - long tell() const override; - /*! - @brief Flush any buffered writes and get the current file size - in bytes. - @return Size of the file in bytes;
- -1 if failure; - */ - size_t size() const override; - //! Returns true if the file is open, otherwise false. - bool isopen() const override; - //! Returns 0 if the file is in a valid state, otherwise nonzero. - int error() const override; - //! Returns true if the file position has reached the end, otherwise false. - bool eof() const override; - //! Returns the path of the file - const std::string& path() const noexcept override; + //@} + //! @name Accessors + //@{ + /*! + @brief Get the current file position. + @return Offset from the start of the file if successful;
+ -1 if failure; + */ + long tell() const override; + /*! + @brief Flush any buffered writes and get the current file size + in bytes. + @return Size of the file in bytes;
+ -1 if failure; + */ + size_t size() const override; + //! Returns true if the file is open, otherwise false. + bool isopen() const override; + //! Returns 0 if the file is in a valid state, otherwise nonzero. + int error() const override; + //! Returns true if the file position has reached the end, otherwise false. + bool eof() const override; + //! Returns the path of the file + const std::string &path() const noexcept override; - /*! - @brief Mark all the bNone blocks to bKnow. This avoids allocating memory - for parts of the file that contain image-date (non-metadata/pixel data) + /*! + @brief Mark all the bNone blocks to bKnow. This avoids allocating memory + for parts of the file that contain image-date (non-metadata/pixel data) - @note This method should be only called after the concerned data (metadata) - are all downloaded from the remote file to memory. - */ - void populateFakeData() override; - //@} + @note This method should be only called after the concerned data (metadata) + are all downloaded from the remote file to memory. + */ + void populateFakeData() override; + //@} - // NOT IMPLEMENTED - //! Copy constructor - FileIo(FileIo& rhs) = delete; - //! Assignment operator - FileIo& operator=(const FileIo& rhs) = delete; + // NOT IMPLEMENTED + //! Copy constructor + FileIo(FileIo &rhs) = delete; + //! Assignment operator + FileIo &operator=(const FileIo &rhs) = delete; - private: - // Pimpl idiom - class Impl; - std::unique_ptr p_; + private: + // Pimpl idiom + class Impl; + std::unique_ptr p_; - }; // class FileIo +}; // class FileIo - /*! - @brief Provides binary IO on blocks of memory by implementing the BasicIo - interface. A copy-on-write implementation ensures that the data passed - in is only copied when necessary, i.e., as soon as data is written to - the MemIo. The original data is only used for reading. If writes are - performed, the changed data can be retrieved using the read methods - (since the data used in construction is never modified). +/*! + @brief Provides binary IO on blocks of memory by implementing the BasicIo + interface. A copy-on-write implementation ensures that the data passed + in is only copied when necessary, i.e., as soon as data is written to + the MemIo. The original data is only used for reading. If writes are + performed, the changed data can be retrieved using the read methods + (since the data used in construction is never modified). - @note If read only usage of this class is common, it might be worth - creating a specialized readonly class or changing this one to - have a readonly mode. - */ - class EXIV2API MemIo : public BasicIo { - public: - //! @name Creators - //@{ - //! Default constructor that results in an empty object - MemIo(); - /*! - @brief Constructor that accepts a block of memory. A copy-on-write - algorithm allows read operations directly from the original data - and will create a copy of the buffer on the first write operation. - @param data Pointer to data. Data must be at least \em size bytes long - @param size Number of bytes to copy. - */ - MemIo(const byte* data, size_t size); - //! Destructor. Releases all managed memory - ~MemIo() override; - //@} + @note If read only usage of this class is common, it might be worth + creating a specialized readonly class or changing this one to + have a readonly mode. + */ +class EXIV2API MemIo : public BasicIo { + public: + //! @name Creators + //@{ + //! Default constructor that results in an empty object + MemIo(); + /*! + @brief Constructor that accepts a block of memory. A copy-on-write + algorithm allows read operations directly from the original data + and will create a copy of the buffer on the first write operation. + @param data Pointer to data. Data must be at least \em size bytes long + @param size Number of bytes to copy. + */ + MemIo(const byte *data, size_t size); + //! Destructor. Releases all managed memory + ~MemIo() override; + //@} - //! @name Manipulators - //@{ - /*! - @brief Memory IO is always open for reading and writing. This method - therefore only resets the IO position to the start. + //! @name Manipulators + //@{ + /*! + @brief Memory IO is always open for reading and writing. This method + therefore only resets the IO position to the start. - @return 0 - */ - int open() override; - /*! - @brief Does nothing on MemIo objects. - @return 0 - */ - int close() override; - /*! - @brief Write data to the memory block. If needed, the size of the - internal memory block is expanded. The IO position is advanced - by the number of bytes written. - @param data Pointer to data. Data must be at least \em wcount - bytes long - @param wcount Number of bytes to be written. - @return Number of bytes written to the memory block successfully;
- 0 if failure; - */ - size_t write(const byte* data, size_t wcount) override; - /*! - @brief Write data that is read from another BasicIo instance to - the memory block. If needed, the size of the internal memory - block is expanded. The IO position is advanced by the number - of bytes written. - @param src Reference to another BasicIo instance. Reading start - at the source's current IO position - @return Number of bytes written to the memory block successfully;
- 0 if failure; - */ - size_t write(BasicIo& src) override; - /*! - @brief Write one byte to the memory block. The IO position is - advanced by one byte. - @param data The single byte to be written. - @return The value of the byte written if successful;
- EOF if failure; - */ - int putb(byte data) override; - /*! - @brief Read data from the memory block. Reading starts at the current - IO position and the position is advanced by the number of - bytes read. - @param rcount Maximum number of bytes to read. Fewer bytes may be - read if \em rcount bytes are not available. - @return DataBuf instance containing the bytes read. Use the - DataBuf::size_ member to find the number of bytes read. - DataBuf::size_ will be 0 on failure. - */ - DataBuf read(size_t rcount) override; - /*! - @brief Read data from the memory block. Reading starts at the current - IO position and the position is advanced by the number of - bytes read. - @param buf Pointer to a block of memory into which the read data - is stored. The memory block must be at least \em rcount bytes - long. - @param rcount Maximum number of bytes to read. Fewer bytes may be - read if \em rcount bytes are not available. - @return Number of bytes read from the memory block successfully;
- 0 if failure; - */ - size_t read(byte* buf, size_t rcount) override; - /*! - @brief Read one byte from the memory block. The IO position is - advanced by one byte. - @return The byte read from the memory block if successful;
- EOF if failure; - */ - int getb() override; - /*! - @brief Clear the memory block and then transfer data from - the \em src BasicIo object into a new block of memory. + @return 0 + */ + int open() override; + /*! + @brief Does nothing on MemIo objects. + @return 0 + */ + int close() override; + /*! + @brief Write data to the memory block. If needed, the size of the + internal memory block is expanded. The IO position is advanced + by the number of bytes written. + @param data Pointer to data. Data must be at least \em wcount + bytes long + @param wcount Number of bytes to be written. + @return Number of bytes written to the memory block successfully;
+ 0 if failure; + */ + size_t write(const byte *data, size_t wcount) override; + /*! + @brief Write data that is read from another BasicIo instance to + the memory block. If needed, the size of the internal memory + block is expanded. The IO position is advanced by the number + of bytes written. + @param src Reference to another BasicIo instance. Reading start + at the source's current IO position + @return Number of bytes written to the memory block successfully;
+ 0 if failure; + */ + size_t write(BasicIo &src) override; + /*! + @brief Write one byte to the memory block. The IO position is + advanced by one byte. + @param data The single byte to be written. + @return The value of the byte written if successful;
+ EOF if failure; + */ + int putb(byte data) override; + /*! + @brief Read data from the memory block. Reading starts at the current + IO position and the position is advanced by the number of + bytes read. + @param rcount Maximum number of bytes to read. Fewer bytes may be + read if \em rcount bytes are not available. + @return DataBuf instance containing the bytes read. Use the + DataBuf::size_ member to find the number of bytes read. + DataBuf::size_ will be 0 on failure. + */ + DataBuf read(size_t rcount) override; + /*! + @brief Read data from the memory block. Reading starts at the current + IO position and the position is advanced by the number of + bytes read. + @param buf Pointer to a block of memory into which the read data + is stored. The memory block must be at least \em rcount bytes + long. + @param rcount Maximum number of bytes to read. Fewer bytes may be + read if \em rcount bytes are not available. + @return Number of bytes read from the memory block successfully;
+ 0 if failure; + */ + size_t read(byte *buf, size_t rcount) override; + /*! + @brief Read one byte from the memory block. The IO position is + advanced by one byte. + @return The byte read from the memory block if successful;
+ EOF if failure; + */ + int getb() override; + /*! + @brief Clear the memory block and then transfer data from + the \em src BasicIo object into a new block of memory. - This method is optimized to simply swap memory block if the source - object is another MemIo instance. The source BasicIo instance - is invalidated by this operation and should not be used after this - method returns. This method exists primarily to be used with - the BasicIo::temporary() method. + This method is optimized to simply swap memory block if the source + object is another MemIo instance. The source BasicIo instance + is invalidated by this operation and should not be used after this + method returns. This method exists primarily to be used with + the BasicIo::temporary() method. - @param src Reference to another BasicIo instance. The entire contents - of src are transferred to this object. The \em src object is - invalidated by the method. - @throw Error In case of failure - */ - void transfer(BasicIo& src) override; + @param src Reference to another BasicIo instance. The entire contents + of src are transferred to this object. The \em src object is + invalidated by the method. + @throw Error In case of failure + */ + void transfer(BasicIo &src) override; - int seek(int64_t offset, Position pos) override; + int seek(int64_t offset, Position pos) override; - /*! - @brief Allow direct access to the underlying data buffer. The buffer - is not protected against write access in any way, the argument - is ignored. - @note The application must ensure that the memory pointed to by the - returned pointer remains valid and allocated as long as the - MemIo object exists. - */ - byte* mmap(bool /*isWriteable*/ = false) override; - int munmap() override; - //@} + /*! + @brief Allow direct access to the underlying data buffer. The buffer + is not protected against write access in any way, the argument + is ignored. + @note The application must ensure that the memory pointed to by the + returned pointer remains valid and allocated as long as the + MemIo object exists. + */ + byte *mmap(bool /*isWriteable*/ = false) override; + int munmap() override; + //@} - //! @name Accessors - //@{ - /*! - @brief Get the current IO position. - @return Offset from the start of the memory block - */ - long tell() const override; - /*! - @brief Get the current memory buffer size in bytes. - @return Size of the in memory data in bytes;
- -1 if failure; - */ - size_t size() const override; - //!Always returns true - bool isopen() const override; - //!Always returns 0 - int error() const override; - //!Returns true if the IO position has reached the end, otherwise false. - bool eof() const override; - //! Returns a dummy path, indicating that memory access is used - const std::string& path() const noexcept override; + //! @name Accessors + //@{ + /*! + @brief Get the current IO position. + @return Offset from the start of the memory block + */ + long tell() const override; + /*! + @brief Get the current memory buffer size in bytes. + @return Size of the in memory data in bytes;
+ -1 if failure; + */ + size_t size() const override; + //! Always returns true + bool isopen() const override; + //! Always returns 0 + int error() const override; + //! Returns true if the IO position has reached the end, otherwise false. + bool eof() const override; + //! Returns a dummy path, indicating that memory access is used + const std::string &path() const noexcept override; - /*! - @brief Mark all the bNone blocks to bKnow. This avoids allocating memory - for parts of the file that contain image-date (non-metadata/pixel data) + /*! + @brief Mark all the bNone blocks to bKnow. This avoids allocating memory + for parts of the file that contain image-date (non-metadata/pixel data) - @note This method should be only called after the concerned data (metadata) - are all downloaded from the remote file to memory. - */ - void populateFakeData() override; + @note This method should be only called after the concerned data (metadata) + are all downloaded from the remote file to memory. + */ + void populateFakeData() override; - //@} + //@} - // NOT IMPLEMENTED - //! Copy constructor - MemIo(MemIo& rhs) = delete; - //! Assignment operator - MemIo& operator=(const MemIo& rhs) = delete; + // NOT IMPLEMENTED + //! Copy constructor + MemIo(MemIo &rhs) = delete; + //! Assignment operator + MemIo &operator=(const MemIo &rhs) = delete; - private: - // Pimpl idiom - class Impl; - std::unique_ptr p_; + private: + // Pimpl idiom + class Impl; + std::unique_ptr p_; - }; // class MemIo +}; // class MemIo - /*! - @brief Provides binary IO for the data from stdin and data uri path. - */ +/*! + @brief Provides binary IO for the data from stdin and data uri path. + */ #if EXV_XPATH_MEMIO - class EXIV2API XPathIo : public MemIo { - public: - //! @name Creators - //@{ - //! Default constructor - XPathIo(const std::string& path); - //@} - private: - /*! - @brief Read data from stdin and write the data to memory. - @throw Error if it can't convert stdin to binary. - */ - void ReadStdin(); - /*! - @brief Read the data from data uri path and write the data to memory. - @param path The data uri. - @throw Error if no base64 data in path. - */ - void ReadDataUri(const std::string& path); - }; // class XPathIo +class EXIV2API XPathIo : public MemIo { + public: + //! @name Creators + //@{ + //! Default constructor + XPathIo(const std::string &path); + //@} + private: + /*! + @brief Read data from stdin and write the data to memory. + @throw Error if it can't convert stdin to binary. + */ + void ReadStdin(); + /*! + @brief Read the data from data uri path and write the data to memory. + @param path The data uri. + @throw Error if no base64 data in path. + */ + void ReadDataUri(const std::string &path); +}; // class XPathIo #else - class EXIV2API XPathIo : public FileIo { - public: - /*! - @brief The extension of the temporary file which is created when getting input data - to read metadata. This file will be deleted in destructor. - */ - static constexpr std::string_view TEMP_FILE_EXT = ".exiv2_temp"; - /*! - @brief The extension of the generated file which is created when getting input data - to add or modify the metadata. - */ - static constexpr std::string_view GEN_FILE_EXT = ".exiv2"; +class EXIV2API XPathIo : public FileIo { + public: + /*! + @brief The extension of the temporary file which is created when getting input data + to read metadata. This file will be deleted in destructor. + */ + static constexpr std::string_view TEMP_FILE_EXT = ".exiv2_temp"; + /*! + @brief The extension of the generated file which is created when getting input data + to add or modify the metadata. + */ + static constexpr std::string_view GEN_FILE_EXT = ".exiv2"; - //! @name Creators - //@{ - //! Default constructor that reads data from stdin/data uri path and writes them to the temp file. - explicit XPathIo(const std::string& orgPath); + //! @name Creators + //@{ + //! Default constructor that reads data from stdin/data uri path and writes them to the temp file. + explicit XPathIo(const std::string &orgPath); - //! Destructor. Releases all managed memory and removes the temp file. - ~XPathIo() override; - //@} + //! Destructor. Releases all managed memory and removes the temp file. + ~XPathIo() override; + //@} - //! @name Manipulators - //@{ - /*! - @brief Change the name of the temp file and make it untemporary before - calling the method of superclass FileIo::transfer. - */ - void transfer(BasicIo& src) override; + //! @name Manipulators + //@{ + /*! + @brief Change the name of the temp file and make it untemporary before + calling the method of superclass FileIo::transfer. + */ + void transfer(BasicIo &src) override; - //@} + //@} - //! @name Static methods - //@{ - /*! - @brief Read the data from stdin/data uri path and write them to the file. - @param orgPath It equals "-" if the input data's from stdin. Otherwise, it's data uri path. - @return the name of the new file. - @throw Error if it fails. - */ - static std::string writeDataToFile(const std::string& orgPath); - //@} + //! @name Static methods + //@{ + /*! + @brief Read the data from stdin/data uri path and write them to the file. + @param orgPath It equals "-" if the input data's from stdin. Otherwise, it's data uri path. + @return the name of the new file. + @throw Error if it fails. + */ + static std::string writeDataToFile(const std::string &orgPath); + //@} - private: - // True if the file is a temporary file and it should be deleted in destructor. - bool isTemp_; - std::string tempFilePath_; - }; // class XPathIo + private: + // True if the file is a temporary file and it should be deleted in destructor. + bool isTemp_; + std::string tempFilePath_; +}; // class XPathIo #endif +/*! + @brief Provides remote binary file IO by implementing the BasicIo interface. This is an + abstract class. The logics for remote access are implemented in HttpIo, CurlIo, SshIo which + are the derived classes of RemoteIo. +*/ +class EXIV2API RemoteIo : public BasicIo { + public: + //! Destructor. Releases all managed memory. + RemoteIo(); + ~RemoteIo() override; + //@} - /*! - @brief Provides remote binary file IO by implementing the BasicIo interface. This is an - abstract class. The logics for remote access are implemented in HttpIo, CurlIo, SshIo which - are the derived classes of RemoteIo. - */ - class EXIV2API RemoteIo : public BasicIo { - public: - //! Destructor. Releases all managed memory. - RemoteIo(); - ~RemoteIo() override; - //@} + //! @name Manipulators + //@{ + /*! + @brief Connect to the remote server, get the size of the remote file and + allocate the array of blocksMap. - //! @name Manipulators - //@{ - /*! - @brief Connect to the remote server, get the size of the remote file and - allocate the array of blocksMap. + If the blocksMap is already allocated (this method has been called before), + it just reset IO position to the start and does not flush the old data. + @return 0 if successful;
+ Nonzero if failure. + */ + int open() override; - If the blocksMap is already allocated (this method has been called before), - it just reset IO position to the start and does not flush the old data. - @return 0 if successful;
- Nonzero if failure. - */ - int open() override; + /*! + @brief Reset the IO position to the start. It does not release the data. + @return 0 if successful;
+ Nonzero if failure. + */ + int close() override; + /*! + @brief Not support this method. + @return 0 means failure + */ + size_t write(const byte *data, size_t wcount) override; + /*! + @brief Write data that is read from another BasicIo instance to the remote file. - /*! - @brief Reset the IO position to the start. It does not release the data. - @return 0 if successful;
- Nonzero if failure. - */ - int close() override; - /*! - @brief Not support this method. - @return 0 means failure - */ - size_t write(const byte* data, size_t wcount) override; - /*! - @brief Write data that is read from another BasicIo instance to the remote file. + The write access is done in an efficient way. It only sends the range of different + bytes between the current data and BasicIo instance to the remote machine. - The write access is done in an efficient way. It only sends the range of different - bytes between the current data and BasicIo instance to the remote machine. + @param src Reference to another BasicIo instance. Reading start + at the source's current IO position + @return The size of BasicIo instance;
+ 0 if failure; + @throw Error In case of failure - @param src Reference to another BasicIo instance. Reading start - at the source's current IO position - @return The size of BasicIo instance;
- 0 if failure; - @throw Error In case of failure + @note The write access is only supported by http, https, ssh. + */ + size_t write(BasicIo &src) override; - @note The write access is only supported by http, https, ssh. - */ - size_t write(BasicIo& src) override; + /*! + @brief Not support + @return 0 means failure + */ + int putb(byte data) override; + /*! + @brief Read data from the memory blocks. Reading starts at the current + IO position and the position is advanced by the number of + bytes read. + If the memory blocks are not populated (False), it will connect to server + and populate the data to memory blocks. + @param rcount Maximum number of bytes to read. Fewer bytes may be + read if \em rcount bytes are not available. + @return DataBuf instance containing the bytes read. Use the + DataBuf::size_ member to find the number of bytes read. + DataBuf::size_ will be 0 on failure. + */ + DataBuf read(size_t rcount) override; + /*! + @brief Read data from the memory blocks. Reading starts at the current + IO position and the position is advanced by the number of + bytes read. + If the memory blocks are not populated (!= bMemory), it will connect to server + and populate the data to memory blocks. + @param buf Pointer to a block of memory into which the read data + is stored. The memory block must be at least \em rcount bytes + long. + @param rcount Maximum number of bytes to read. Fewer bytes may be + read if \em rcount bytes are not available. + @return Number of bytes read from the memory block successfully;
+ 0 if failure; + */ + size_t read(byte *buf, size_t rcount) override; + /*! + @brief Read one byte from the memory blocks. The IO position is + advanced by one byte. + If the memory block is not populated (!= bMemory), it will connect to server + and populate the data to the memory block. + @return The byte read from the memory block if successful;
+ EOF if failure; + */ + int getb() override; + /*! + @brief Remove the contents of the file and then transfer data from + the \em src BasicIo object into the empty file. - /*! - @brief Not support - @return 0 means failure - */ - int putb(byte data) override; - /*! - @brief Read data from the memory blocks. Reading starts at the current - IO position and the position is advanced by the number of - bytes read. - If the memory blocks are not populated (False), it will connect to server - and populate the data to memory blocks. - @param rcount Maximum number of bytes to read. Fewer bytes may be - read if \em rcount bytes are not available. - @return DataBuf instance containing the bytes read. Use the - DataBuf::size_ member to find the number of bytes read. - DataBuf::size_ will be 0 on failure. - */ - DataBuf read(size_t rcount) override; - /*! - @brief Read data from the memory blocks. Reading starts at the current - IO position and the position is advanced by the number of - bytes read. - If the memory blocks are not populated (!= bMemory), it will connect to server - and populate the data to memory blocks. - @param buf Pointer to a block of memory into which the read data - is stored. The memory block must be at least \em rcount bytes - long. - @param rcount Maximum number of bytes to read. Fewer bytes may be - read if \em rcount bytes are not available. - @return Number of bytes read from the memory block successfully;
- 0 if failure; - */ - size_t read(byte* buf, size_t rcount) override; - /*! - @brief Read one byte from the memory blocks. The IO position is - advanced by one byte. - If the memory block is not populated (!= bMemory), it will connect to server - and populate the data to the memory block. - @return The byte read from the memory block if successful;
- EOF if failure; - */ - int getb() override; - /*! - @brief Remove the contents of the file and then transfer data from - the \em src BasicIo object into the empty file. + The write access is done in an efficient way. It only sends the range of different + bytes between the current data and BasicIo instance to the remote machine. - The write access is done in an efficient way. It only sends the range of different - bytes between the current data and BasicIo instance to the remote machine. + @param src Reference to another BasicIo instance. The entire contents + of src are transferred to this object. The \em src object is + invalidated by the method. + @throw Error In case of failure - @param src Reference to another BasicIo instance. The entire contents - of src are transferred to this object. The \em src object is - invalidated by the method. - @throw Error In case of failure + @note The write access is only supported by http, https, ssh. + */ + void transfer(BasicIo &src) override; - @note The write access is only supported by http, https, ssh. - */ - void transfer(BasicIo& src) override; + int seek(int64_t offset, Position pos) override; - int seek(int64_t offset, Position pos) override; + /*! + @brief Not support + @return NULL + */ + byte *mmap(bool /*isWriteable*/ = false) override; + /*! + @brief Not support + @return 0 + */ + int munmap() override; + //@} + //! @name Accessors + //@{ + /*! + @brief Get the current IO position. + @return Offset from the start of the memory block + */ + long tell() const override; + /*! + @brief Get the current memory buffer size in bytes. + @return Size of the in memory data in bytes;
+ -1 if failure; + */ + size_t size() const override; + //! Returns true if the memory area is allocated. + bool isopen() const override; + //! Always returns 0 + int error() const override; + //! Returns true if the IO position has reached the end, otherwise false. + bool eof() const override; + //! Returns the URL of the file. + const std::string &path() const noexcept override; - /*! - @brief Not support - @return NULL - */ - byte* mmap(bool /*isWriteable*/ = false) override; - /*! - @brief Not support - @return 0 - */ - int munmap() override; - //@} - //! @name Accessors - //@{ - /*! - @brief Get the current IO position. - @return Offset from the start of the memory block - */ - long tell() const override; - /*! - @brief Get the current memory buffer size in bytes. - @return Size of the in memory data in bytes;
- -1 if failure; - */ - size_t size() const override; - //!Returns true if the memory area is allocated. - bool isopen() const override; - //!Always returns 0 - int error() const override; - //!Returns true if the IO position has reached the end, otherwise false. - bool eof() const override; - //!Returns the URL of the file. - const std::string& path() const noexcept override; + /*! + @brief Mark all the bNone blocks to bKnow. This avoids allocating memory + for parts of the file that contain image-date (non-metadata/pixel data) - /*! - @brief Mark all the bNone blocks to bKnow. This avoids allocating memory - for parts of the file that contain image-date (non-metadata/pixel data) + @note This method should be only called after the concerned data (metadata) + are all downloaded from the remote file to memory. + */ + void populateFakeData() override; - @note This method should be only called after the concerned data (metadata) - are all downloaded from the remote file to memory. - */ - void populateFakeData() override; + //@} - //@} + protected: + // Pimpl idiom + class Impl; + //! Pointer to implementation + std::unique_ptr p_; +}; // class RemoteIo - protected: +/*! + @brief Provides the http read/write access for the RemoteIo. +*/ +class EXIV2API HttpIo : public RemoteIo { + public: + //! @name Creators + //@{ + /*! + @brief Constructor that accepts the http URL on which IO will be + performed. The constructor does not open the file, and + therefore never fails. + @param url The full path of url + @param blockSize the size of the memory block. The file content is + divided into the memory blocks. These blocks are populated + on demand from the server, so it avoids copying the complete file. + */ + explicit HttpIo(const std::string &url, size_t blockSize = 1024); - // Pimpl idiom - class Impl; - //! Pointer to implementation - std::unique_ptr p_; - }; // class RemoteIo + // NOT IMPLEMENTED + //! Copy constructor + HttpIo(HttpIo &rhs) = delete; + //! Assignment operator + HttpIo &operator=(const HttpIo &rhs) = delete; - /*! - @brief Provides the http read/write access for the RemoteIo. - */ - class EXIV2API HttpIo : public RemoteIo { - public: - //! @name Creators - //@{ - /*! - @brief Constructor that accepts the http URL on which IO will be - performed. The constructor does not open the file, and - therefore never fails. - @param url The full path of url - @param blockSize the size of the memory block. The file content is - divided into the memory blocks. These blocks are populated - on demand from the server, so it avoids copying the complete file. - */ - explicit HttpIo(const std::string& url, size_t blockSize = 1024); - - // NOT IMPLEMENTED - //! Copy constructor - HttpIo(HttpIo& rhs) = delete; - //! Assignment operator - HttpIo& operator=(const HttpIo& rhs) = delete; - - private: - // Pimpl idiom - class HttpImpl; - }; + private: + // Pimpl idiom + class HttpImpl; +}; #ifdef EXV_USE_CURL - /*! - @brief Provides the http, https read/write access and ftp read access for the RemoteIo. - This class is based on libcurl. - */ - class EXIV2API CurlIo : public RemoteIo { - public: - //! @name Creators - //@{ - /*! - @brief Constructor that accepts the URL on which IO will be - performed. - @param url The full path of url - @param blockSize the size of the memory block. The file content is - divided into the memory blocks. These blocks are populated - on demand from the server, so it avoids copying the complete file. - @throw Error if it is unable to init curl pointer. - */ - explicit CurlIo(const std::string& url, size_t blockSize = 0); +/*! + @brief Provides the http, https read/write access and ftp read access for the RemoteIo. + This class is based on libcurl. +*/ +class EXIV2API CurlIo : public RemoteIo { + public: + //! @name Creators + //@{ + /*! + @brief Constructor that accepts the URL on which IO will be + performed. + @param url The full path of url + @param blockSize the size of the memory block. The file content is + divided into the memory blocks. These blocks are populated + on demand from the server, so it avoids copying the complete file. + @throw Error if it is unable to init curl pointer. + */ + explicit CurlIo(const std::string &url, size_t blockSize = 0); - /*! - @brief Write access is only available for some protocols. This method - will call RemoteIo::write(const byte* data, long wcount) if the write - access is available for the protocol. Otherwise, it throws the Error. - */ - size_t write(const byte* data, size_t wcount) override; - /*! - @brief Write access is only available for some protocols. This method - will call RemoteIo::write(BasicIo& src) if the write access is available - for the protocol. Otherwise, it throws the Error. - */ - size_t write(BasicIo& src) override; + /*! + @brief Write access is only available for some protocols. This method + will call RemoteIo::write(const byte* data, long wcount) if the write + access is available for the protocol. Otherwise, it throws the Error. + */ + size_t write(const byte *data, size_t wcount) override; + /*! + @brief Write access is only available for some protocols. This method + will call RemoteIo::write(BasicIo& src) if the write access is available + for the protocol. Otherwise, it throws the Error. + */ + size_t write(BasicIo &src) override; - // NOT IMPLEMENTED - //! Copy constructor - CurlIo(CurlIo& rhs) = delete; - //! Assignment operator - CurlIo& operator=(const CurlIo& rhs) = delete; + // NOT IMPLEMENTED + //! Copy constructor + CurlIo(CurlIo &rhs) = delete; + //! Assignment operator + CurlIo &operator=(const CurlIo &rhs) = delete; - protected: - // Pimpl idiom - class CurlImpl; - }; + protected: + // Pimpl idiom + class CurlImpl; +}; #endif // ***************************************************************************** // template, inline and free functions - /*! - @brief Read file \em path into a DataBuf, which is returned. - @return Buffer containing the file. - @throw Error In case of failure. - */ - EXIV2API DataBuf readFile(const std::string& path); - /*! - @brief Write DataBuf \em buf to file \em path. - @return Return the number of bytes written. - @throw Error In case of failure. - */ - EXIV2API size_t writeFile(const DataBuf& buf, const std::string& path); +/*! + @brief Read file \em path into a DataBuf, which is returned. + @return Buffer containing the file. + @throw Error In case of failure. + */ +EXIV2API DataBuf readFile(const std::string &path); +/*! + @brief Write DataBuf \em buf to file \em path. + @return Return the number of bytes written. + @throw Error In case of failure. + */ +EXIV2API size_t writeFile(const DataBuf &buf, const std::string &path); #ifdef EXV_USE_CURL - /*! - @brief The callback function is called by libcurl to write the data - */ - EXIV2API size_t curlWriter(char* data, size_t size, size_t nmemb, std::string* writerData); +/*! + @brief The callback function is called by libcurl to write the data +*/ +EXIV2API size_t curlWriter(char *data, size_t size, size_t nmemb, std::string *writerData); #endif -} // namespace Exiv2 -#endif // #ifndef BASICIO_HPP_ +} // namespace Exiv2 +#endif // #ifndef BASICIO_HPP_ diff --git a/include/exiv2/bmffimage.hpp b/include/exiv2/bmffimage.hpp index c83fed23..f0ad35f0 100644 --- a/include/exiv2/bmffimage.hpp +++ b/include/exiv2/bmffimage.hpp @@ -12,168 +12,155 @@ // ***************************************************************************** // namespace extensions -namespace Exiv2 -{ - EXIV2API bool enableBMFF(bool enable = true); +namespace Exiv2 { +EXIV2API bool enableBMFF(bool enable = true); } #ifdef EXV_ENABLE_BMFF -namespace Exiv2 -{ - struct Iloc - { - explicit Iloc(uint32_t ID = 0, uint32_t start = 0, uint32_t length = 0) - : ID_(ID), start_(start), length_(length){}; - virtual ~Iloc() = default; +namespace Exiv2 { +struct Iloc { + explicit Iloc(uint32_t ID = 0, uint32_t start = 0, uint32_t length = 0) : ID_(ID), start_(start), length_(length){}; + virtual ~Iloc() = default; - uint32_t ID_; - uint32_t start_; - uint32_t length_; + uint32_t ID_; + uint32_t start_; + uint32_t length_; - std::string toString() const; - }; // class Iloc + std::string toString() const; +}; // class Iloc - // ***************************************************************************** - // class definitions +// ***************************************************************************** +// class definitions - /*! - @brief Class to access BMFF images. - */ - class EXIV2API BmffImage : public Image - { - public: - //! @name Creators - //@{ - /*! - @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. - @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). - */ - BmffImage(BasicIo::UniquePtr io, bool create); - //@} +/*! + @brief Class to access BMFF images. + */ +class EXIV2API BmffImage : public Image { + public: + //! @name Creators + //@{ + /*! + @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. + @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). + */ + BmffImage(BasicIo::UniquePtr io, bool create); + //@} - //@{ - /*! - @brief parse embedded tiff file (Exif metadata) - @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()) - @ - */ - void parseTiff(uint32_t root_tag, uint64_t length); - void parseTiff(uint32_t root_tag, uint64_t length,uint64_t start); - //@} + //@{ + /*! + @brief parse embedded tiff file (Exif metadata) + @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()) + @ + */ + void parseTiff(uint32_t root_tag, uint64_t length); + void parseTiff(uint32_t root_tag, uint64_t length, uint64_t start); + //@} - //@{ - /*! - @brief parse embedded xmp/xml - @param length xmp block length - @param start offset in file - @ - */ - void parseXmp(uint64_t length,uint64_t start); - //@} + //@{ + /*! + @brief parse embedded xmp/xml + @param length xmp block length + @param start offset in file + @ + */ + void parseXmp(uint64_t length, uint64_t start); + //@} - //@{ - /*! - @brief Parse a Canon PRVW or THMB box and add an entry to the set - of native previews. - @param data Buffer containing the box - @param out Logging stream - @param bTrace Controls logging - @param width_offset Index of image width field in data - @param height_offset Index of image height field in data - @param size_offset Index of image size field in data - @param relative_position Location of the start of image data in the file, - relative to the current file position indicator. - */ - void parseCr3Preview(DataBuf &data, - std::ostream &out, - bool bTrace, - uint8_t version, - size_t width_offset, - size_t height_offset, - size_t size_offset, - size_t relative_position); - //@} + //@{ + /*! + @brief Parse a Canon PRVW or THMB box and add an entry to the set + of native previews. + @param data Buffer containing the box + @param out Logging stream + @param bTrace Controls logging + @param width_offset Index of image width field in data + @param height_offset Index of image height field in data + @param size_offset Index of image size field in data + @param relative_position Location of the start of image data in the file, + relative to the current file position indicator. + */ + void parseCr3Preview(DataBuf& data, std::ostream& out, bool bTrace, uint8_t version, size_t width_offset, + size_t height_offset, size_t size_offset, size_t relative_position); + //@} - //! @name Manipulators - //@{ - void readMetadata() override /* override */; - void writeMetadata() override /* override */; - void setComment(std::string_view comment) override /* override */; - void printStructure(std::ostream& out, Exiv2::PrintStructureOption option, int depth) override; - //@} + //! @name Manipulators + //@{ + void readMetadata() override /* override */; + void writeMetadata() override /* override */; + void setComment(std::string_view comment) override /* override */; + void printStructure(std::ostream& out, Exiv2::PrintStructureOption option, int depth) override; + //@} - //! @name Accessors - //@{ - std::string mimeType() const override /* override */; - uint32_t pixelWidth() const override; - uint32_t pixelHeight() const override; - //@} + //! @name Accessors + //@{ + std::string mimeType() const override /* override */; + uint32_t pixelWidth() const override; + uint32_t pixelHeight() const override; + //@} - Exiv2::ByteOrder endian_{Exiv2::bigEndian}; + Exiv2::ByteOrder endian_{Exiv2::bigEndian}; - private: - void openOrThrow(); - /*! - @brief recursiveBoxHandler - @throw Error if we visit a box more than once - @param pbox_end The end location of the parent box. Boxes are - nested, so we must not read beyond this. - @return address of next box - @warning This function should only be called by readMetadata() - */ - long boxHandler(std::ostream& out, Exiv2::PrintStructureOption option, - const long pbox_end, int depth); - std::string indent(int i) - { - return std::string(2*i,' '); - } + private: + void openOrThrow(); + /*! + @brief recursiveBoxHandler + @throw Error if we visit a box more than once + @param pbox_end The end location of the parent box. Boxes are + nested, so we must not read beyond this. + @return address of next box + @warning This function should only be called by readMetadata() + */ + long boxHandler(std::ostream& out, Exiv2::PrintStructureOption option, const long pbox_end, int depth); + std::string indent(int i) { + return std::string(2 * i, ' '); + } - uint32_t fileType_{0}; - std::set visits_; - uint64_t visits_max_{0}; - uint16_t unknownID_{0xffff}; - uint16_t exifID_{0xffff}; - uint16_t xmpID_{0}; - std::map ilocs_; - bool bReadMetadata_{false}; - //@} + uint32_t fileType_{0}; + std::set visits_; + uint64_t visits_max_{0}; + uint16_t unknownID_{0xffff}; + uint16_t exifID_{0xffff}; + uint16_t xmpID_{0}; + std::map ilocs_; + bool bReadMetadata_{false}; + //@} - /*! - @brief box utilities - */ - static std::string toAscii(long n); - std::string boxName(uint32_t box); - static bool superBox(uint32_t box); - static bool fullBox(uint32_t box); - static std::string uuidName(Exiv2::DataBuf& uuid); + /*! + @brief box utilities + */ + static std::string toAscii(long n); + std::string boxName(uint32_t box); + static bool superBox(uint32_t box); + static bool fullBox(uint32_t box); + static 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. - /*! - @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::UniquePtr newBmffInstance(BasicIo::UniquePtr io, bool create); +// These could be static private functions on Image subclasses but then +// ImageFactory needs to be made a friend. +/*! + @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::UniquePtr newBmffInstance(BasicIo::UniquePtr io, bool create); - //! Check if the file iIo is a BMFF image. - EXIV2API bool isBmffType(BasicIo& iIo, bool advance); +//! Check if the file iIo is a BMFF image. +EXIV2API bool isBmffType(BasicIo& iIo, bool advance); } // namespace Exiv2 -#endif // EXV_ENABLE_BMFF +#endif // EXV_ENABLE_BMFF diff --git a/include/exiv2/bmpimage.hpp b/include/exiv2/bmpimage.hpp index fc2887d0..eb535227 100644 --- a/include/exiv2/bmpimage.hpp +++ b/include/exiv2/bmpimage.hpp @@ -17,79 +17,78 @@ // ***************************************************************************** // namespace extensions namespace Exiv2 { - // ***************************************************************************** // class definitions - /*! - @brief Class to access Windows bitmaps. This is just a stub - we only - read width and height. - */ - class EXIV2API BmpImage : public Image { - public: - //! @name NOT Implemented - //@{ - //! Copy constructor - BmpImage(const BmpImage& rhs) = delete; - //! Assignment operator - BmpImage& operator=(const BmpImage& rhs) = delete; - //@} +/*! + @brief Class to access Windows bitmaps. This is just a stub - we only + read width and height. + */ +class EXIV2API BmpImage : public Image { + public: + //! @name NOT Implemented + //@{ + //! Copy constructor + BmpImage(const BmpImage& rhs) = delete; + //! Assignment operator + BmpImage& operator=(const BmpImage& rhs) = delete; + //@} - //! @name Creators - //@{ - /*! - @brief Constructor to open a Windows bitmap 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. - */ - explicit BmpImage(BasicIo::UniquePtr io); - //@} + //! @name Creators + //@{ + /*! + @brief Constructor to open a Windows bitmap 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. + */ + explicit BmpImage(BasicIo::UniquePtr io); + //@} - //! @name Manipulators - //@{ - void readMetadata() override; + //! @name Manipulators + //@{ + void readMetadata() override; - /// @throws Error(ErrorCode::kerWritingImageFormatUnsupported). - void writeMetadata() override; + /// @throws Error(ErrorCode::kerWritingImageFormatUnsupported). + void writeMetadata() override; - /// @throws Error(ErrorCode::kerInvalidSettingForImage) - void setExifData(const ExifData& exifData) override; + /// @throws Error(ErrorCode::kerInvalidSettingForImage) + void setExifData(const ExifData& exifData) override; - /// @throws Error(ErrorCode::kerInvalidSettingForImage) - void setIptcData(const IptcData& iptcData) override; + /// @throws Error(ErrorCode::kerInvalidSettingForImage) + void setIptcData(const IptcData& iptcData) override; - /// @throws Error(ErrorCode::kerInvalidSettingForImage) - void setComment(std::string_view comment) override; - //@} + /// @throws Error(ErrorCode::kerInvalidSettingForImage) + void setComment(std::string_view comment) override; + //@} - //! @name Accessors - //@{ - std::string mimeType() const override; - //@} - }; // class BmpImage + //! @name Accessors + //@{ + std::string mimeType() const override; + //@} +}; // class BmpImage // ***************************************************************************** // 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 BmpImage 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::UniquePtr newBmpInstance(BasicIo::UniquePtr io, bool create); +// These could be static private functions on Image subclasses but then +// ImageFactory needs to be made a friend. +/*! + @brief Create a new BmpImage 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::UniquePtr newBmpInstance(BasicIo::UniquePtr io, bool create); - //! Check if the file iIo is a Windows Bitmap image. - EXIV2API bool isBmpType(BasicIo& iIo, bool advance); +//! Check if the file iIo is a Windows Bitmap image. +EXIV2API bool isBmpType(BasicIo& iIo, bool advance); -} // namespace Exiv2 +} // namespace Exiv2 -#endif // #ifndef BMPIMAGE_HPP_ +#endif // #ifndef BMPIMAGE_HPP_ diff --git a/include/exiv2/config.h b/include/exiv2/config.h index 0a777129..1fd45a46 100644 --- a/include/exiv2/config.h +++ b/include/exiv2/config.h @@ -4,12 +4,12 @@ #define _CONFIG_H_ ///// Start of Visual Studio Support ///// -#ifdef _MSC_VER +#ifdef _MSC_VER -#pragma warning(disable : 4996) // Disable warnings about 'deprecated' standard functions -#pragma warning(disable : 4251) // Disable warnings from std templates about exporting interfaces +#pragma warning(disable : 4996) // Disable warnings about 'deprecated' standard functions +#pragma warning(disable : 4251) // Disable warnings from std templates about exporting interfaces -#endif // _MSC_VER +#endif // _MSC_VER ///// End of Visual Studio Support ///// #include "exv_conf.h" @@ -17,32 +17,32 @@ ///// Start of platform macros ///////// #if defined(__MINGW32__) || defined(__MINGW64__) -# ifndef __MING__ -# define __MING__ 1 -# endif -# ifndef __MINGW__ -# define __MINGW__ 1 -# endif +#ifndef __MING__ +#define __MING__ 1 +#endif +#ifndef __MINGW__ +#define __MINGW__ 1 +#endif #endif #ifndef __CYGWIN__ -# if defined(__CYGWIN32__) || defined(__CYGWIN64__) -# define __CYGWIN__ 1 -# endif +#if defined(__CYGWIN32__) || defined(__CYGWIN64__) +#define __CYGWIN__ 1 +#endif #endif #ifndef __LITTLE_ENDIAN__ -# if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) -# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ -# define __LITTLE_ENDIAN__ 1 -# endif -# endif +#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#define __LITTLE_ENDIAN__ 1 +#endif +#endif #endif #ifndef __LITTLE_ENDIAN__ -# if defined(_MSC_VER) || defined(__CYGWIN__) || defined(__MINGW__) -# define __LITTLE_ENDIAN__ 1 -# endif +#if defined(_MSC_VER) || defined(__CYGWIN__) || defined(__MINGW__) +#define __LITTLE_ENDIAN__ 1 +#endif #endif /* @@ -50,26 +50,26 @@ you must -library=stdcxx4 along with these inclusions below */ #if defined(OS_SOLARIS) -# include -# include -# include -# if defined(__cplusplus) -# include -# include -# endif +#include +#include +#include +#if defined(__cplusplus) +#include +#include +#endif #endif ///// End of platform macros ///////// ///// Path separator macros ///// #ifndef EXV_SEPARATOR_STR -# if defined(WIN32) && !defined(__CYGWIN__) -# define EXV_SEPARATOR_STR "\\" -# define EXV_SEPARATOR_CHR '\\' -# else -# define EXV_SEPARATOR_STR "/" -# define EXV_SEPARATOR_CHR '/' -# endif +#if defined(WIN32) && !defined(__CYGWIN__) +#define EXV_SEPARATOR_STR "\\" +#define EXV_SEPARATOR_CHR '\\' +#else +#define EXV_SEPARATOR_STR "/" +#define EXV_SEPARATOR_CHR '/' +#endif #endif ////////////////////////////////////// -#endif // _CONFIG_H_ +#endif // _CONFIG_H_ diff --git a/include/exiv2/convert.hpp b/include/exiv2/convert.hpp index cd9fab34..9cade0e8 100644 --- a/include/exiv2/convert.hpp +++ b/include/exiv2/convert.hpp @@ -24,75 +24,74 @@ // ***************************************************************************** // namespace extensions namespace Exiv2 { - // ***************************************************************************** // class declarations - class ExifData; - class IptcData; - class XmpData; +class ExifData; +class IptcData; +class XmpData; // ***************************************************************************** // free functions, template and inline definitions - //! Convert (copy) Exif tags to XMP properties. - EXIV2API void copyExifToXmp(const ExifData& exifData, XmpData& xmpData); - //! Convert (move) Exif tags to XMP properties, remove converted Exif tags. - EXIV2API void moveExifToXmp(ExifData& exifData, XmpData& xmpData); +//! Convert (copy) Exif tags to XMP properties. +EXIV2API void copyExifToXmp(const ExifData& exifData, XmpData& xmpData); +//! Convert (move) Exif tags to XMP properties, remove converted Exif tags. +EXIV2API void moveExifToXmp(ExifData& exifData, XmpData& xmpData); - //! Convert (copy) XMP properties to Exif tags. - EXIV2API void copyXmpToExif(const XmpData& xmpData, ExifData& exifData); - //! Convert (move) XMP properties to Exif tags, remove converted XMP properties. - EXIV2API void moveXmpToExif(XmpData& xmpData, ExifData& exifData); +//! Convert (copy) XMP properties to Exif tags. +EXIV2API void copyXmpToExif(const XmpData& xmpData, ExifData& exifData); +//! Convert (move) XMP properties to Exif tags, remove converted XMP properties. +EXIV2API void moveXmpToExif(XmpData& xmpData, ExifData& exifData); - //! Detect which metadata are newer and perform a copy in appropriate direction. - EXIV2API void syncExifWithXmp(ExifData& exifData, XmpData& xmpData); +//! Detect which metadata are newer and perform a copy in appropriate direction. +EXIV2API void syncExifWithXmp(ExifData& exifData, XmpData& xmpData); - //! Convert (copy) IPTC datasets to XMP properties. - EXIV2API void copyIptcToXmp(const IptcData& iptcData, XmpData& xmpData, const char* iptcCharset = nullptr); - //! Convert (move) IPTC datasets to XMP properties, remove converted IPTC datasets. - EXIV2API void moveIptcToXmp(IptcData& iptcData, XmpData& xmpData, const char* iptcCharset = nullptr); +//! Convert (copy) IPTC datasets to XMP properties. +EXIV2API void copyIptcToXmp(const IptcData& iptcData, XmpData& xmpData, const char* iptcCharset = nullptr); +//! Convert (move) IPTC datasets to XMP properties, remove converted IPTC datasets. +EXIV2API void moveIptcToXmp(IptcData& iptcData, XmpData& xmpData, const char* iptcCharset = nullptr); - //! Convert (copy) XMP properties to IPTC datasets. - EXIV2API void copyXmpToIptc(const XmpData& xmpData, IptcData& iptcData); - //! Convert (move) XMP properties to IPTC tags, remove converted XMP properties. - EXIV2API void moveXmpToIptc(XmpData& xmpData, IptcData& iptcData); +//! Convert (copy) XMP properties to IPTC datasets. +EXIV2API void copyXmpToIptc(const XmpData& xmpData, IptcData& iptcData); +//! Convert (move) XMP properties to IPTC tags, remove converted XMP properties. +EXIV2API void moveXmpToIptc(XmpData& xmpData, IptcData& iptcData); - /*! - @brief Convert character encoding of \em str from \em from to \em to. - If the function succeeds, \em str contains the result string. +/*! + @brief Convert character encoding of \em str from \em from to \em to. + If the function succeeds, \em str contains the result string. - This function uses the iconv library, if the %Exiv2 library was compiled - with iconv support. Otherwise, on Windows, it uses Windows functions to - support a limited number of conversions and fails with a warning if an - unsupported conversion is attempted. If the function is called but %Exiv2 - was not compiled with iconv support and can't use Windows functions, it - fails with a warning. + This function uses the iconv library, if the %Exiv2 library was compiled + with iconv support. Otherwise, on Windows, it uses Windows functions to + support a limited number of conversions and fails with a warning if an + unsupported conversion is attempted. If the function is called but %Exiv2 + was not compiled with iconv support and can't use Windows functions, it + fails with a warning. - The conversions supported on Windows without iconv are: + The conversions supported on Windows without iconv are: - - - - - - - - - - -
fromto
UTF-8 UCS-2BE
UTF-8 UCS-2LE
UCS-2BE UTF-8
UCS-2BE UCS-2LE
UCS-2LE UTF-8
UCS-2LE UCS-2BE
ISO-8859-1UTF-8
ASCII UTF-8
+ + + + + + + + + + +
fromto
UTF-8 UCS-2BE
UTF-8 UCS-2LE
UCS-2BE UTF-8
UCS-2BE UCS-2LE
UCS-2LE UTF-8
UCS-2LE UCS-2BE
ISO-8859-1UTF-8
ASCII UTF-8
- @param str The string to convert. It is updated to the converted string, - which may have a different size. If the function call fails, - the string is not modified. - @param from Charset in which the input string is encoded as a name - understood by \c iconv_open(3). - @param to Charset to convert the string to as a name - understood by \c iconv_open(3). - @return Return \c true if the conversion was successful, else \c false. - */ - EXIV2API bool convertStringCharset(std::string& str, const char* from, const char* to); + @param str The string to convert. It is updated to the converted string, + which may have a different size. If the function call fails, + the string is not modified. + @param from Charset in which the input string is encoded as a name + understood by \c iconv_open(3). + @param to Charset to convert the string to as a name + understood by \c iconv_open(3). + @return Return \c true if the conversion was successful, else \c false. + */ +EXIV2API bool convertStringCharset(std::string& str, const char* from, const char* to); -} // namespace Exiv2 +} // namespace Exiv2 -#endif // #ifndef CONVERT_HPP_ +#endif // #ifndef CONVERT_HPP_ diff --git a/include/exiv2/cr2image.hpp b/include/exiv2/cr2image.hpp index 40aa6c74..efd948e2 100644 --- a/include/exiv2/cr2image.hpp +++ b/include/exiv2/cr2image.hpp @@ -17,120 +17,107 @@ // ***************************************************************************** // namespace extensions namespace Exiv2 { - // ***************************************************************************** // class definitions - /*! - @brief Class to access raw Canon CR2 images. Exif metadata - is supported directly, IPTC is read from the Exif data, if present. - */ - class EXIV2API Cr2Image : public Image { - public: - //! @name Creators - //@{ - /*! - @brief Constructor that can either open an existing CR2 image or create - a new image from scratch. If a new image is to be created, any - existing data is overwritten. 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). - */ - Cr2Image(BasicIo::UniquePtr io, bool create); - //@} +/*! + @brief Class to access raw Canon CR2 images. Exif metadata + is supported directly, IPTC is read from the Exif data, if present. + */ +class EXIV2API Cr2Image : public Image { + public: + //! @name Creators + //@{ + /*! + @brief Constructor that can either open an existing CR2 image or create + a new image from scratch. If a new image is to be created, any + existing data is overwritten. 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). + */ + Cr2Image(BasicIo::UniquePtr 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 Not supported. CR2 format does not contain a comment. - Calling this function will throw an Error(ErrorCode::kerInvalidSettingForImage). - */ - void setComment(std::string_view comment) override; - //@} + //! @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 Not supported. CR2 format does not contain a comment. + Calling this function will throw an Error(ErrorCode::kerInvalidSettingForImage). + */ + void setComment(std::string_view comment) override; + //@} - //! @name Accessors - //@{ - std::string mimeType() const override; - uint32_t pixelWidth() const override; - uint32_t pixelHeight() const override; - //@} + //! @name Accessors + //@{ + std::string mimeType() const override; + uint32_t pixelWidth() const override; + uint32_t pixelHeight() const override; + //@} - //! @name NOT implemented - //@{ - //! Copy constructor - Cr2Image(const Cr2Image& rhs) = delete; - //! Assignment operator - Cr2Image& operator=(const Cr2Image& rhs) = delete; - //@} + //! @name NOT implemented + //@{ + //! Copy constructor + Cr2Image(const Cr2Image& rhs) = delete; + //! Assignment operator + Cr2Image& operator=(const Cr2Image& rhs) = delete; + //@} - }; // class Cr2Image +}; // class Cr2Image - /*! - @brief Stateless parser class for data in CR2 format. Images use this - class to decode and encode CR2 data. - See class TiffParser for details. - */ - class EXIV2API Cr2Parser { - public: - /*! - @brief Decode metadata from a buffer \em pData of length \em size - with data in CR2 format to the provided metadata containers. - See TiffParser::decode(). - */ - static ByteOrder decode( - ExifData& exifData, - IptcData& iptcData, - XmpData& xmpData, - const byte* pData, - size_t size - ); - /*! - @brief Encode metadata from the provided metadata to CR2 format. - See TiffParser::encode(). - */ - static WriteMethod encode(BasicIo& io, - const byte* pData, - size_t size, - ByteOrder byteOrder, - const ExifData& exifData, - const IptcData& iptcData, - const XmpData& xmpData - ); +/*! + @brief Stateless parser class for data in CR2 format. Images use this + class to decode and encode CR2 data. + See class TiffParser for details. + */ +class EXIV2API Cr2Parser { + public: + /*! + @brief Decode metadata from a buffer \em pData of length \em size + with data in CR2 format to the provided metadata containers. + See TiffParser::decode(). + */ + static ByteOrder decode(ExifData& exifData, IptcData& iptcData, XmpData& xmpData, const byte* pData, size_t size); + /*! + @brief Encode metadata from the provided metadata to CR2 format. + See TiffParser::encode(). + */ + static WriteMethod encode(BasicIo& io, const byte* pData, size_t size, ByteOrder byteOrder, const ExifData& exifData, + const IptcData& iptcData, const XmpData& xmpData); - }; // class Cr2Parser +}; // class Cr2Parser // ***************************************************************************** // 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 Cr2Image 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::UniquePtr newCr2Instance(BasicIo::UniquePtr io, bool create); +// These could be static private functions on Image subclasses but then +// ImageFactory needs to be made a friend. +/*! + @brief Create a new Cr2Image 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::UniquePtr newCr2Instance(BasicIo::UniquePtr io, bool create); - //! Check if the file iIo is a CR2 image. - EXIV2API bool isCr2Type(BasicIo& iIo, bool advance); +//! Check if the file iIo is a CR2 image. +EXIV2API bool isCr2Type(BasicIo& iIo, bool advance); -} // namespace Exiv2 +} // namespace Exiv2 -#endif // #ifndef CR2IMAGE_HPP_ +#endif // #ifndef CR2IMAGE_HPP_ diff --git a/include/exiv2/crwimage.hpp b/include/exiv2/crwimage.hpp index eb8fab1b..7ce322a0 100644 --- a/include/exiv2/crwimage.hpp +++ b/include/exiv2/crwimage.hpp @@ -3,7 +3,8 @@ /*! @brief Class CrwImage to access Canon CRW images.
References:
- The Canon RAW (CRW) File Format by Phil Harvey + The Canon RAW (CRW) File Format by + Phil Harvey @author Andreas Huggel (ahu) ahuggel@gmx.net @date 28-Aug-05, ahu: created @@ -20,127 +21,122 @@ // ***************************************************************************** // namespace extensions namespace Exiv2 { - // ***************************************************************************** // class declarations - class ExifData; - class IptcData; +class ExifData; +class IptcData; // ***************************************************************************** // class definitions - /*! - @brief Class to access raw Canon CRW images. Only Exif metadata and a - comment are supported. CRW format does not contain IPTC metadata. - */ - class EXIV2API CrwImage : public Image { - public: - //! @name Creators - //@{ - /*! - @brief Constructor that can either open an existing CRW image or create - a new image from scratch. If a new image is to be created, any - existing data is overwritten. 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). - */ - CrwImage(BasicIo::UniquePtr io, bool create); - //@} +/*! + @brief Class to access raw Canon CRW images. Only Exif metadata and a + comment are supported. CRW format does not contain IPTC metadata. + */ +class EXIV2API CrwImage : public Image { + public: + //! @name Creators + //@{ + /*! + @brief Constructor that can either open an existing CRW image or create + a new image from scratch. If a new image is to be created, any + existing data is overwritten. 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). + */ + CrwImage(BasicIo::UniquePtr io, bool create); + //@} - //! @name Manipulators - //@{ - void readMetadata() override; - void writeMetadata() override; - /*! - @brief Not supported. CRW format does not contain IPTC metadata. - Calling this function will throw an Error(ErrorCode::kerInvalidSettingForImage). - */ - void setIptcData(const IptcData& iptcData) override; - //@} + //! @name Manipulators + //@{ + void readMetadata() override; + void writeMetadata() override; + /*! + @brief Not supported. CRW format does not contain IPTC metadata. + Calling this function will throw an Error(ErrorCode::kerInvalidSettingForImage). + */ + void setIptcData(const IptcData& iptcData) override; + //@} - //! @name Accessors - //@{ - std::string mimeType() const override; - uint32_t pixelWidth() const override; - uint32_t pixelHeight() const override; - //@} + //! @name Accessors + //@{ + std::string mimeType() const override; + uint32_t pixelWidth() const override; + uint32_t pixelHeight() const override; + //@} - //! @name NOT Implemented - //@{ - //! Copy constructor - CrwImage(const CrwImage& rhs) = delete; - //! Assignment operator - CrwImage& operator=(const CrwImage& rhs) = delete; - //@} + //! @name NOT Implemented + //@{ + //! Copy constructor + CrwImage(const CrwImage& rhs) = delete; + //! Assignment operator + CrwImage& operator=(const CrwImage& rhs) = delete; + //@} - }; // class CrwImage +}; // class CrwImage - /*! - Stateless parser class for Canon CRW images (Ciff format). - */ - class EXIV2API CrwParser { - public: - /*! - @brief Decode metadata from a Canon CRW image in data buffer \em pData - of length \em size into \em crwImage. +/*! + Stateless parser class for Canon CRW images (Ciff format). +*/ +class EXIV2API CrwParser { + public: + /*! + @brief Decode metadata from a Canon CRW image in data buffer \em pData + of length \em size into \em crwImage. - This is the entry point to access image data in Ciff format. The - parser uses classes CiffHeader, CiffEntry, CiffDirectory. + This is the entry point to access image data in Ciff format. The + parser uses classes CiffHeader, CiffEntry, CiffDirectory. - @param pCrwImage Pointer to the %Exiv2 CRW image to hold the metadata - read from the buffer. - @param pData Pointer to the data buffer. Must point to the data of - a CRW image; no checks are performed. - @param size Length of the data buffer. + @param pCrwImage Pointer to the %Exiv2 CRW image to hold the metadata + read from the buffer. + @param pData Pointer to the data buffer. Must point to the data of + a CRW image; no checks are performed. + @param size Length of the data buffer. - @throw Error If the data buffer cannot be parsed. - */ - static void decode(CrwImage* pCrwImage, const byte* pData, size_t size); - /*! - @brief Encode metadata from the CRW image into a data buffer (the - binary CRW image). + @throw Error If the data buffer cannot be parsed. + */ + static void decode(CrwImage* pCrwImage, const byte* pData, size_t size); + /*! + @brief Encode metadata from the CRW image into a data buffer (the + binary CRW image). - @param blob Data buffer for the binary image (target). - @param pData Pointer to the binary image data buffer. Must - point to data in CRW format; no checks are - performed. - @param size Length of the data buffer. - @param pCrwImage Pointer to the %Exiv2 CRW image with the metadata to - encode. + @param blob Data buffer for the binary image (target). + @param pData Pointer to the binary image data buffer. Must + point to data in CRW format; no checks are + performed. + @param size Length of the data buffer. + @param pCrwImage Pointer to the %Exiv2 CRW image with the metadata to + encode. - @throw Error If the metadata from the CRW image cannot be encoded. - */ - static void encode(Blob& blob, - const byte* pData, - size_t size, - const CrwImage* pCrwImage - ); + @throw Error If the metadata from the CRW image cannot be encoded. + */ + static void encode(Blob& blob, const byte* pData, size_t size, const CrwImage* pCrwImage); - }; // class CrwParser +}; // class CrwParser // ***************************************************************************** // 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 CrwImage 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::UniquePtr newCrwInstance(BasicIo::UniquePtr io, bool create); +// These could be static private functions on Image subclasses but then +// ImageFactory needs to be made a friend. +/*! + @brief Create a new CrwImage 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::UniquePtr newCrwInstance(BasicIo::UniquePtr io, bool create); - //! Check if the file iIo is a CRW image. - EXIV2API bool isCrwType(BasicIo& iIo, bool advance); +//! Check if the file iIo is a CRW image. +EXIV2API bool isCrwType(BasicIo& iIo, bool advance); -} // namespace Exiv2 +} // namespace Exiv2 -#endif // #ifndef CRWIMAGE_HPP_ +#endif // #ifndef CRWIMAGE_HPP_ diff --git a/include/exiv2/datasets.hpp b/include/exiv2/datasets.hpp index 7dd4a37a..e76e20a8 100644 --- a/include/exiv2/datasets.hpp +++ b/include/exiv2/datasets.hpp @@ -16,320 +16,318 @@ // ***************************************************************************** // namespace extensions namespace Exiv2 { - // ***************************************************************************** // class definitions - //! Details of an IPTC record. - struct EXIV2API RecordInfo { - uint16_t recordId_; //!< Record id - const char* name_; //!< Record name (one word) - const char* desc_; //!< Record description - }; +//! Details of an IPTC record. +struct EXIV2API RecordInfo { + uint16_t recordId_; //!< Record id + const char* name_; //!< Record name (one word) + const char* desc_; //!< Record description +}; - //! Details of an IPTC dataset. - struct EXIV2API DataSet { - uint16_t number_; //!< Dataset number - const char* name_; //!< Dataset name - const char* title_; //!< Dataset title or label - const char* desc_; //!< Dataset description - bool mandatory_; //!< True if dataset is mandatory - bool repeatable_; //!< True if dataset is repeatable - uint32_t minbytes_; //!< Minimum number of bytes - uint32_t maxbytes_; //!< Maximum number of bytes - TypeId type_; //!< Exiv2 default type - uint16_t recordId_; //!< Record id - const char* photoshop_; //!< Photoshop string - }; // struct DataSet +//! Details of an IPTC dataset. +struct EXIV2API DataSet { + uint16_t number_; //!< Dataset number + const char* name_; //!< Dataset name + const char* title_; //!< Dataset title or label + const char* desc_; //!< Dataset description + bool mandatory_; //!< True if dataset is mandatory + bool repeatable_; //!< True if dataset is repeatable + uint32_t minbytes_; //!< Minimum number of bytes + uint32_t maxbytes_; //!< Maximum number of bytes + TypeId type_; //!< Exiv2 default type + uint16_t recordId_; //!< Record id + const char* photoshop_; //!< Photoshop string +}; // struct DataSet - //! IPTC dataset reference, implemented as a static class. - class EXIV2API IptcDataSets { - public: - /*! - @name Record identifiers - @brief Record identifiers to logically group dataSets. There are other - possible record types, but they are not standardized by the IPTC - IIM4 standard (and not commonly used in images). - */ - //@{ - static constexpr uint16_t invalidRecord = 0; - static constexpr uint16_t envelope = 1; - static constexpr uint16_t application2 = 2; - //@} +//! IPTC dataset reference, implemented as a static class. +class EXIV2API IptcDataSets { + public: + /*! + @name Record identifiers + @brief Record identifiers to logically group dataSets. There are other + possible record types, but they are not standardized by the IPTC + IIM4 standard (and not commonly used in images). + */ + //@{ + static constexpr uint16_t invalidRecord = 0; + static constexpr uint16_t envelope = 1; + static constexpr uint16_t application2 = 2; + //@} - //! @name Dataset identifiers - //@{ - static constexpr uint16_t ModelVersion = 0; - static constexpr uint16_t Destination = 5; - static constexpr uint16_t FileFormat = 20; - static constexpr uint16_t FileVersion = 22; - static constexpr uint16_t ServiceId = 30; - static constexpr uint16_t EnvelopeNumber = 40; - static constexpr uint16_t ProductId = 50; - static constexpr uint16_t EnvelopePriority = 60; - static constexpr uint16_t DateSent = 70; - static constexpr uint16_t TimeSent = 80; - static constexpr uint16_t CharacterSet = 90; - static constexpr uint16_t UNO = 100; - static constexpr uint16_t ARMId = 120; - static constexpr uint16_t ARMVersion = 122; + //! @name Dataset identifiers + //@{ + static constexpr uint16_t ModelVersion = 0; + static constexpr uint16_t Destination = 5; + static constexpr uint16_t FileFormat = 20; + static constexpr uint16_t FileVersion = 22; + static constexpr uint16_t ServiceId = 30; + static constexpr uint16_t EnvelopeNumber = 40; + static constexpr uint16_t ProductId = 50; + static constexpr uint16_t EnvelopePriority = 60; + static constexpr uint16_t DateSent = 70; + static constexpr uint16_t TimeSent = 80; + static constexpr uint16_t CharacterSet = 90; + static constexpr uint16_t UNO = 100; + static constexpr uint16_t ARMId = 120; + static constexpr uint16_t ARMVersion = 122; - static constexpr uint16_t RecordVersion = 0; - static constexpr uint16_t ObjectType = 3; - static constexpr uint16_t ObjectAttribute = 4; - static constexpr uint16_t ObjectName = 5; - static constexpr uint16_t EditStatus = 7; - static constexpr uint16_t EditorialUpdate = 8; - static constexpr uint16_t Urgency = 10; - static constexpr uint16_t Subject = 12; - static constexpr uint16_t Category = 15; - static constexpr uint16_t SuppCategory = 20; - static constexpr uint16_t FixtureId = 22; - static constexpr uint16_t Keywords = 25; - static constexpr uint16_t LocationCode = 26; - static constexpr uint16_t LocationName = 27; - static constexpr uint16_t ReleaseDate = 30; - static constexpr uint16_t ReleaseTime = 35; - static constexpr uint16_t ExpirationDate = 37; - static constexpr uint16_t ExpirationTime = 38; - static constexpr uint16_t SpecialInstructions = 40; - static constexpr uint16_t ActionAdvised = 42; - static constexpr uint16_t ReferenceService = 45; - static constexpr uint16_t ReferenceDate = 47; - static constexpr uint16_t ReferenceNumber = 50; - static constexpr uint16_t DateCreated = 55; - static constexpr uint16_t TimeCreated = 60; - static constexpr uint16_t DigitizationDate = 62; - static constexpr uint16_t DigitizationTime = 63; - static constexpr uint16_t Program = 65; - static constexpr uint16_t ProgramVersion = 70; - static constexpr uint16_t ObjectCycle = 75; - static constexpr uint16_t Byline = 80; - static constexpr uint16_t BylineTitle = 85; - static constexpr uint16_t City = 90; - static constexpr uint16_t SubLocation = 92; - static constexpr uint16_t ProvinceState = 95; - static constexpr uint16_t CountryCode = 100; - static constexpr uint16_t CountryName = 101; - static constexpr uint16_t TransmissionReference = 103; - static constexpr uint16_t Headline = 105; - static constexpr uint16_t Credit = 110; - static constexpr uint16_t Source = 115; - static constexpr uint16_t Copyright = 116; - static constexpr uint16_t Contact = 118; - static constexpr uint16_t Caption = 120; - static constexpr uint16_t Writer = 122; - static constexpr uint16_t RasterizedCaption = 125; - static constexpr uint16_t ImageType = 130; - static constexpr uint16_t ImageOrientation = 131; - static constexpr uint16_t Language = 135; - static constexpr uint16_t AudioType = 150; - static constexpr uint16_t AudioRate = 151; - static constexpr uint16_t AudioResolution = 152; - static constexpr uint16_t AudioDuration = 153; - static constexpr uint16_t AudioOutcue = 154; - static constexpr uint16_t PreviewFormat = 200; - static constexpr uint16_t PreviewVersion = 201; - static constexpr uint16_t Preview = 202; - //@} + static constexpr uint16_t RecordVersion = 0; + static constexpr uint16_t ObjectType = 3; + static constexpr uint16_t ObjectAttribute = 4; + static constexpr uint16_t ObjectName = 5; + static constexpr uint16_t EditStatus = 7; + static constexpr uint16_t EditorialUpdate = 8; + static constexpr uint16_t Urgency = 10; + static constexpr uint16_t Subject = 12; + static constexpr uint16_t Category = 15; + static constexpr uint16_t SuppCategory = 20; + static constexpr uint16_t FixtureId = 22; + static constexpr uint16_t Keywords = 25; + static constexpr uint16_t LocationCode = 26; + static constexpr uint16_t LocationName = 27; + static constexpr uint16_t ReleaseDate = 30; + static constexpr uint16_t ReleaseTime = 35; + static constexpr uint16_t ExpirationDate = 37; + static constexpr uint16_t ExpirationTime = 38; + static constexpr uint16_t SpecialInstructions = 40; + static constexpr uint16_t ActionAdvised = 42; + static constexpr uint16_t ReferenceService = 45; + static constexpr uint16_t ReferenceDate = 47; + static constexpr uint16_t ReferenceNumber = 50; + static constexpr uint16_t DateCreated = 55; + static constexpr uint16_t TimeCreated = 60; + static constexpr uint16_t DigitizationDate = 62; + static constexpr uint16_t DigitizationTime = 63; + static constexpr uint16_t Program = 65; + static constexpr uint16_t ProgramVersion = 70; + static constexpr uint16_t ObjectCycle = 75; + static constexpr uint16_t Byline = 80; + static constexpr uint16_t BylineTitle = 85; + static constexpr uint16_t City = 90; + static constexpr uint16_t SubLocation = 92; + static constexpr uint16_t ProvinceState = 95; + static constexpr uint16_t CountryCode = 100; + static constexpr uint16_t CountryName = 101; + static constexpr uint16_t TransmissionReference = 103; + static constexpr uint16_t Headline = 105; + static constexpr uint16_t Credit = 110; + static constexpr uint16_t Source = 115; + static constexpr uint16_t Copyright = 116; + static constexpr uint16_t Contact = 118; + static constexpr uint16_t Caption = 120; + static constexpr uint16_t Writer = 122; + static constexpr uint16_t RasterizedCaption = 125; + static constexpr uint16_t ImageType = 130; + static constexpr uint16_t ImageOrientation = 131; + static constexpr uint16_t Language = 135; + static constexpr uint16_t AudioType = 150; + static constexpr uint16_t AudioRate = 151; + static constexpr uint16_t AudioResolution = 152; + static constexpr uint16_t AudioDuration = 153; + static constexpr uint16_t AudioOutcue = 154; + static constexpr uint16_t PreviewFormat = 200; + static constexpr uint16_t PreviewVersion = 201; + static constexpr uint16_t Preview = 202; + //@} - //! Prevent construction: not implemented. - IptcDataSets() = delete; - //! Prevent copy-construction: not implemented. - IptcDataSets(const IptcDataSets& rhs) = delete; - //! Prevent assignment: not implemented. - IptcDataSets& operator=(const IptcDataSets& rhs) = delete; + //! Prevent construction: not implemented. + IptcDataSets() = delete; + //! Prevent copy-construction: not implemented. + IptcDataSets(const IptcDataSets& rhs) = delete; + //! Prevent assignment: not implemented. + IptcDataSets& operator=(const IptcDataSets& rhs) = delete; - /*! - @brief Return the name of the dataset. - @param number The dataset number - @param recordId The IPTC record Id - @return The name of the dataset or a string containing the hexadecimal - value of the dataset in the form "0x01ff", if this is an unknown - dataset. - */ - static std::string dataSetName(uint16_t number, uint16_t recordId); + /*! + @brief Return the name of the dataset. + @param number The dataset number + @param recordId The IPTC record Id + @return The name of the dataset or a string containing the hexadecimal + value of the dataset in the form "0x01ff", if this is an unknown + dataset. + */ + static std::string dataSetName(uint16_t number, uint16_t recordId); - /*! - @brief Return the title (label) of the dataset. - @param number The dataset number - @param recordId The IPTC record Id - @return The title (label) of the dataset - */ - static const char* dataSetTitle(uint16_t number, uint16_t recordId); + /*! + @brief Return the title (label) of the dataset. + @param number The dataset number + @param recordId The IPTC record Id + @return The title (label) of the dataset + */ + static const char* dataSetTitle(uint16_t number, uint16_t recordId); - /*! - @brief Return the description of the dataset. - @param number The dataset number - @param recordId The IPTC record Id - @return The description of the dataset - */ - static const char* dataSetDesc(uint16_t number, uint16_t recordId); + /*! + @brief Return the description of the dataset. + @param number The dataset number + @param recordId The IPTC record Id + @return The description of the dataset + */ + static const char* dataSetDesc(uint16_t number, uint16_t recordId); - /*! - @brief Return the Photoshop name of a given dataset. - @param number The dataset number - @param recordId The IPTC record Id - @return The name used by Photoshop for a dataset or an empty - string if Photoshop does not use the dataset. - */ - static const char* dataSetPsName(uint16_t number, uint16_t recordId); + /*! + @brief Return the Photoshop name of a given dataset. + @param number The dataset number + @param recordId The IPTC record Id + @return The name used by Photoshop for a dataset or an empty + string if Photoshop does not use the dataset. + */ + static const char* dataSetPsName(uint16_t number, uint16_t recordId); - /*! - @brief Check if a given dataset is repeatable - @param number The dataset number - @param recordId The IPTC record Id - @return true if the given dataset is repeatable otherwise false - */ - static bool dataSetRepeatable(uint16_t number, uint16_t recordId); + /*! + @brief Check if a given dataset is repeatable + @param number The dataset number + @param recordId The IPTC record Id + @return true if the given dataset is repeatable otherwise false + */ + static bool dataSetRepeatable(uint16_t number, uint16_t recordId); - /*! - @brief Return the dataSet number for dataset name and record id + /*! + @brief Return the dataSet number for dataset name and record id - @param dataSetName dataSet name - @param recordId recordId + @param dataSetName dataSet name + @param recordId recordId - @return dataSet number + @return dataSet number - @throw Error if the \em dataSetName or \em recordId are invalid - */ - static uint16_t dataSet(const std::string& dataSetName, uint16_t recordId); + @throw Error if the \em dataSetName or \em recordId are invalid + */ + static uint16_t dataSet(const std::string& dataSetName, uint16_t recordId); - //! Return the type for dataSet number and Record id - static TypeId dataSetType(uint16_t number, uint16_t recordId); + //! Return the type for dataSet number and Record id + static TypeId dataSetType(uint16_t number, uint16_t recordId); - /*! - @brief Return the name of the Record - @param recordId The record id - @return The name of the record or a string containing the hexadecimal - value of the record in the form "0x01ff", if this is an - unknown record. - */ - static std::string recordName(uint16_t recordId); + /*! + @brief Return the name of the Record + @param recordId The record id + @return The name of the record or a string containing the hexadecimal + value of the record in the form "0x01ff", if this is an + unknown record. + */ + static std::string recordName(uint16_t recordId); - /*! - @brief Return the description of a record - @param recordId Record Id number - @return the description of the Record - */ - static const char* recordDesc(uint16_t recordId); + /*! + @brief Return the description of a record + @param recordId Record Id number + @return the description of the Record + */ + static const char* recordDesc(uint16_t recordId); - /*! - @brief Return the Id number of a record - @param recordName Name of a record type - @return the Id number of a Record - @throw Error if the record is not known; - */ - static uint16_t recordId(const std::string& recordName); + /*! + @brief Return the Id number of a record + @param recordName Name of a record type + @return the Id number of a Record + @throw Error if the record is not known; + */ + static uint16_t recordId(const std::string& recordName); - //! Return read-only list of built-in Envelope Record datasets - static const DataSet* envelopeRecordList(); + //! Return read-only list of built-in Envelope Record datasets + static const DataSet* envelopeRecordList(); - //! Return read-only list of built-in Application2 Record datasets - static const DataSet* application2RecordList(); + //! Return read-only list of built-in Application2 Record datasets + static const DataSet* application2RecordList(); - //! Print a list of all dataSets to output stream - static void dataSetList(std::ostream& os); + //! Print a list of all dataSets to output stream + static void dataSetList(std::ostream& os); - private: - static int dataSetIdx(uint16_t number, uint16_t recordId); - static int dataSetIdx(const std::string& dataSetName, uint16_t recordId); + private: + static int dataSetIdx(uint16_t number, uint16_t recordId); + static int dataSetIdx(const std::string& dataSetName, uint16_t recordId); - static const DataSet* const records_[]; + static const DataSet* const records_[]; - }; // class IptcDataSets +}; // class IptcDataSets - /*! - @brief Concrete keys for IPTC metadata. - */ - class EXIV2API IptcKey : public Key { - public: - //! Shortcut for an %IptcKey auto pointer. - using UniquePtr = std::unique_ptr; +/*! + @brief Concrete keys for IPTC metadata. + */ +class EXIV2API IptcKey : public Key { + public: + //! Shortcut for an %IptcKey auto pointer. + using UniquePtr = std::unique_ptr; - //! @name Creators - //@{ - /*! - @brief Constructor to create an IPTC key from a key string. + //! @name Creators + //@{ + /*! + @brief Constructor to create an IPTC key from a key string. - @param key The key string. - @throw Error if the first part of the key is not 'Iptc' or - the remaining parts of the key cannot be parsed and - converted to a record name and a dataset name. - */ - explicit IptcKey(std::string key); - /*! - @brief Constructor to create an IPTC key from dataset and record ids. - @param tag Dataset id - @param record Record id - */ - IptcKey(uint16_t tag, uint16_t record); - //! Copy constructor - IptcKey(const IptcKey& rhs); - IptcKey& operator=(const IptcKey& rhs) = delete; - //! Destructor - ~IptcKey() override = default; - //@} + @param key The key string. + @throw Error if the first part of the key is not 'Iptc' or + the remaining parts of the key cannot be parsed and + converted to a record name and a dataset name. + */ + explicit IptcKey(std::string key); + /*! + @brief Constructor to create an IPTC key from dataset and record ids. + @param tag Dataset id + @param record Record id + */ + IptcKey(uint16_t tag, uint16_t record); + //! Copy constructor + IptcKey(const IptcKey& rhs); + IptcKey& operator=(const IptcKey& rhs) = delete; + //! Destructor + ~IptcKey() override = default; + //@} + //! @name Accessors + //@{ + std::string key() const override; + const char* familyName() const override; + /*! + @brief Return the name of the group (the second part of the key). + For IPTC keys, the group name is the record name. + */ + std::string groupName() const override; + std::string tagName() const override; + std::string tagLabel() const override; + uint16_t tag() const override; + UniquePtr clone() const; + //! Return the name of the record + std::string recordName() const; + //! Return the record id + uint16_t record() const; + //@} - //! @name Accessors - //@{ - std::string key() const override; - const char* familyName() const override; - /*! - @brief Return the name of the group (the second part of the key). - For IPTC keys, the group name is the record name. - */ - std::string groupName() const override; - std::string tagName() const override; - std::string tagLabel() const override; - uint16_t tag() const override; - UniquePtr clone() const; - //! Return the name of the record - std::string recordName() const; - //! Return the record id - uint16_t record() const; - //@} + protected: + //! @name Manipulators + //@{ + /*! + @brief Set the key corresponding to the dataset and record id. + The key is of the form 'Iptc.recordName.dataSetName'. + */ + void makeKey(); + /*! + @brief Parse and convert the key string into dataset and record id. + Updates data members if the string can be decomposed, or throws + \em Error. - protected: - //! @name Manipulators - //@{ - /*! - @brief Set the key corresponding to the dataset and record id. - The key is of the form 'Iptc.recordName.dataSetName'. - */ - void makeKey(); - /*! - @brief Parse and convert the key string into dataset and record id. - Updates data members if the string can be decomposed, or throws - \em Error. + @throw Error if the key cannot be decomposed. + */ + void decomposeKey(); + //@} - @throw Error if the key cannot be decomposed. - */ - void decomposeKey(); - //@} + private: + //! Internal virtual copy constructor. + IptcKey* clone_() const override; - private: - //! Internal virtual copy constructor. - IptcKey* clone_() const override; + uint16_t tag_; //!< Tag value + uint16_t record_; //!< Record value + std::string key_; //!< Key - uint16_t tag_; //!< Tag value - uint16_t record_; //!< Record value - std::string key_; //!< Key +}; // class IptcKey - }; // class IptcKey +/*! + @brief typedef for string:string map + */ +using Dictionary = std::map; - /*! - @brief typedef for string:string map - */ - using Dictionary = std::map; +// ***************************************************************************** +// free functions - // ***************************************************************************** - // free functions +//! Output operator for dataSet +EXIV2API std::ostream& operator<<(std::ostream& os, const DataSet& dataSet); - //! Output operator for dataSet - EXIV2API std::ostream& operator<<(std::ostream& os, const DataSet& dataSet); +} // namespace Exiv2 -} // namespace Exiv2 - -#endif // #ifndef DATASETS_HPP_ +#endif // #ifndef DATASETS_HPP_ diff --git a/include/exiv2/easyaccess.hpp b/include/exiv2/easyaccess.hpp index efda3168..0a30c525 100644 --- a/include/exiv2/easyaccess.hpp +++ b/include/exiv2/easyaccess.hpp @@ -15,80 +15,79 @@ #include "exif.hpp" namespace Exiv2 { - // ***************************************************************************** // class declarations - class ExifData; +class ExifData; - //! Return the orientation of the image - EXIV2API ExifData::const_iterator orientation(const ExifData& ed); - //! Return the ISO speed used to shoot the image - EXIV2API ExifData::const_iterator isoSpeed(const ExifData& ed); - //! Return the date and time when the original image data was generated - EXIV2API ExifData::const_iterator dateTimeOriginal(const ExifData& ed); - //! Return the flash bias value - EXIV2API ExifData::const_iterator flashBias(const ExifData& ed); - //! Return the exposure mode setting - EXIV2API ExifData::const_iterator exposureMode(const ExifData& ed); - //! Return the scene mode setting - EXIV2API ExifData::const_iterator sceneMode(const ExifData& ed); - //! Return the macro mode setting - EXIV2API ExifData::const_iterator macroMode(const ExifData& ed); - //! Return the image quality setting - EXIV2API ExifData::const_iterator imageQuality(const ExifData& ed); - //! Return the white balance setting - EXIV2API ExifData::const_iterator whiteBalance(const ExifData& ed); - //! Return the name of the lens used - EXIV2API ExifData::const_iterator lensName(const ExifData& ed); - //! Return the saturation level - EXIV2API ExifData::const_iterator saturation(const ExifData& ed); - //! Return the sharpness level - EXIV2API ExifData::const_iterator sharpness(const ExifData& ed); - //! Return the contrast level - EXIV2API ExifData::const_iterator contrast(const ExifData& ed); - //! Return the scene capture type - EXIV2API ExifData::const_iterator sceneCaptureType(const ExifData& ed); - //! Return the metering mode setting - EXIV2API ExifData::const_iterator meteringMode(const ExifData& ed); - //! Return the camera make - EXIV2API ExifData::const_iterator make(const ExifData& ed); - //! Return the camera model - EXIV2API ExifData::const_iterator model(const ExifData& ed); - //! Return the exposure time - EXIV2API ExifData::const_iterator exposureTime(const ExifData& ed); - //! Return the F number - EXIV2API ExifData::const_iterator fNumber(const ExifData& ed); - //! Return the shutter speed value - EXIV2API ExifData::const_iterator shutterSpeedValue(const ExifData& ed); - //! Return the aperture value - EXIV2API ExifData::const_iterator apertureValue(const ExifData& ed); - //! Return the brightness value - EXIV2API ExifData::const_iterator brightnessValue(const ExifData& ed); - //! Return the exposure bias value - EXIV2API ExifData::const_iterator exposureBiasValue(const ExifData& ed); - //! Return the max aperture value - EXIV2API ExifData::const_iterator maxApertureValue(const ExifData& ed); - //! Return the subject distance - EXIV2API ExifData::const_iterator subjectDistance(const ExifData& ed); - //! Return the kind of light source - EXIV2API ExifData::const_iterator lightSource(const ExifData& ed); - //! Return the status of flash - EXIV2API ExifData::const_iterator flash(const ExifData& ed); - //! Return the camera serial number - EXIV2API ExifData::const_iterator serialNumber(const ExifData& ed); - //! Return the focal length setting - EXIV2API ExifData::const_iterator focalLength(const ExifData& ed); - //! Return the subject location and area - EXIV2API ExifData::const_iterator subjectArea(const ExifData& ed); - //! Return the flash energy - EXIV2API ExifData::const_iterator flashEnergy(const ExifData& ed); - //! Return the exposure index - EXIV2API ExifData::const_iterator exposureIndex(const ExifData& ed); - //! Return the image sensor type - EXIV2API ExifData::const_iterator sensingMethod(const ExifData& ed); - //! Return the AF point - EXIV2API ExifData::const_iterator afPoint(const ExifData& ed); +//! Return the orientation of the image +EXIV2API ExifData::const_iterator orientation(const ExifData& ed); +//! Return the ISO speed used to shoot the image +EXIV2API ExifData::const_iterator isoSpeed(const ExifData& ed); +//! Return the date and time when the original image data was generated +EXIV2API ExifData::const_iterator dateTimeOriginal(const ExifData& ed); +//! Return the flash bias value +EXIV2API ExifData::const_iterator flashBias(const ExifData& ed); +//! Return the exposure mode setting +EXIV2API ExifData::const_iterator exposureMode(const ExifData& ed); +//! Return the scene mode setting +EXIV2API ExifData::const_iterator sceneMode(const ExifData& ed); +//! Return the macro mode setting +EXIV2API ExifData::const_iterator macroMode(const ExifData& ed); +//! Return the image quality setting +EXIV2API ExifData::const_iterator imageQuality(const ExifData& ed); +//! Return the white balance setting +EXIV2API ExifData::const_iterator whiteBalance(const ExifData& ed); +//! Return the name of the lens used +EXIV2API ExifData::const_iterator lensName(const ExifData& ed); +//! Return the saturation level +EXIV2API ExifData::const_iterator saturation(const ExifData& ed); +//! Return the sharpness level +EXIV2API ExifData::const_iterator sharpness(const ExifData& ed); +//! Return the contrast level +EXIV2API ExifData::const_iterator contrast(const ExifData& ed); +//! Return the scene capture type +EXIV2API ExifData::const_iterator sceneCaptureType(const ExifData& ed); +//! Return the metering mode setting +EXIV2API ExifData::const_iterator meteringMode(const ExifData& ed); +//! Return the camera make +EXIV2API ExifData::const_iterator make(const ExifData& ed); +//! Return the camera model +EXIV2API ExifData::const_iterator model(const ExifData& ed); +//! Return the exposure time +EXIV2API ExifData::const_iterator exposureTime(const ExifData& ed); +//! Return the F number +EXIV2API ExifData::const_iterator fNumber(const ExifData& ed); +//! Return the shutter speed value +EXIV2API ExifData::const_iterator shutterSpeedValue(const ExifData& ed); +//! Return the aperture value +EXIV2API ExifData::const_iterator apertureValue(const ExifData& ed); +//! Return the brightness value +EXIV2API ExifData::const_iterator brightnessValue(const ExifData& ed); +//! Return the exposure bias value +EXIV2API ExifData::const_iterator exposureBiasValue(const ExifData& ed); +//! Return the max aperture value +EXIV2API ExifData::const_iterator maxApertureValue(const ExifData& ed); +//! Return the subject distance +EXIV2API ExifData::const_iterator subjectDistance(const ExifData& ed); +//! Return the kind of light source +EXIV2API ExifData::const_iterator lightSource(const ExifData& ed); +//! Return the status of flash +EXIV2API ExifData::const_iterator flash(const ExifData& ed); +//! Return the camera serial number +EXIV2API ExifData::const_iterator serialNumber(const ExifData& ed); +//! Return the focal length setting +EXIV2API ExifData::const_iterator focalLength(const ExifData& ed); +//! Return the subject location and area +EXIV2API ExifData::const_iterator subjectArea(const ExifData& ed); +//! Return the flash energy +EXIV2API ExifData::const_iterator flashEnergy(const ExifData& ed); +//! Return the exposure index +EXIV2API ExifData::const_iterator exposureIndex(const ExifData& ed); +//! Return the image sensor type +EXIV2API ExifData::const_iterator sensingMethod(const ExifData& ed); +//! Return the AF point +EXIV2API ExifData::const_iterator afPoint(const ExifData& ed); -} // namespace Exiv2 +} // namespace Exiv2 -#endif // EASYACCESS_HPP_ +#endif // EASYACCESS_HPP_ diff --git a/include/exiv2/epsimage.hpp b/include/exiv2/epsimage.hpp index 71177ca1..83573ed2 100644 --- a/include/exiv2/epsimage.hpp +++ b/include/exiv2/epsimage.hpp @@ -4,10 +4,14 @@ @file epsimage.hpp @brief EPS image.
References: -
[1] Adobe PostScript Language Document Structuring Conventions Specification, Version 3.0, September 1992 -
[2] Adobe Encapsulated PostScript File Format Specification, Version 3.0, May 1992 -
[3] Adobe XMP Specification Part 3: Storage in Files, July 2010 -
[4] Re: Thumbnail data format in ai file, Dec 2003 +
[1] Adobe PostScript + Language Document Structuring Conventions Specification, Version 3.0, September 1992
[2] Adobe Encapsulated PostScript File Format + Specification, Version 3.0, May 1992
[3] Adobe XMP Specification + Part 3: Storage in Files, July 2010
[4] Re: Thumbnail data format in ai + file, Dec 2003 @author Michael Ulbrich (mul) mul@rentapacs.de @author Volker Grabsch (vog) @@ -25,77 +29,75 @@ // ***************************************************************************** // namespace extensions -namespace Exiv2 -{ - +namespace Exiv2 { // ***************************************************************************** // class definitions - /*! - @brief Class to access EPS images. - */ - class EXIV2API EpsImage : public Image { - public: - //! @name Creators - //@{ - /*! - @brief Constructor to open a EPS image. Since the - constructor can't 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). - */ - EpsImage(BasicIo::UniquePtr io, bool create); - //@} +/*! + @brief Class to access EPS images. + */ +class EXIV2API EpsImage : public Image { + public: + //! @name Creators + //@{ + /*! + @brief Constructor to open a EPS image. Since the + constructor can't 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). + */ + EpsImage(BasicIo::UniquePtr io, bool create); + //@} - //! @name Manipulators - //@{ - void readMetadata() override; - void writeMetadata() override; - /*! - @brief Not supported. - Calling this function will throw an instance of Error(ErrorCode::kerInvalidSettingForImage). - */ - void setComment(std::string_view comment) override; - //@} + //! @name Manipulators + //@{ + void readMetadata() override; + void writeMetadata() override; + /*! + @brief Not supported. + Calling this function will throw an instance of Error(ErrorCode::kerInvalidSettingForImage). + */ + void setComment(std::string_view comment) override; + //@} - //! @name Accessors - //@{ - std::string mimeType() const override; - //@} + //! @name Accessors + //@{ + std::string mimeType() const override; + //@} - //! @name NOT Implemented - //@{ - //! Copy constructor - EpsImage(const EpsImage& rhs) = delete; - //! Assignment operator - EpsImage& operator=(const EpsImage& rhs) = delete; - //@} + //! @name NOT Implemented + //@{ + //! Copy constructor + EpsImage(const EpsImage& rhs) = delete; + //! Assignment operator + EpsImage& operator=(const EpsImage& rhs) = delete; + //@} - }; // class EpsImage +}; // class EpsImage // ***************************************************************************** // 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 EpsImage 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::UniquePtr newEpsInstance(BasicIo::UniquePtr io, bool create); +// These could be static private functions on Image subclasses but then +// ImageFactory needs to be made a friend. +/*! + @brief Create a new EpsImage 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::UniquePtr newEpsInstance(BasicIo::UniquePtr io, bool create); - //! Check if the file iIo is a EPS image. - EXIV2API bool isEpsType(BasicIo& iIo, bool advance); +//! Check if the file iIo is a EPS image. +EXIV2API bool isEpsType(BasicIo& iIo, bool advance); -} // namespace Exiv2 +} // namespace Exiv2 -#endif // #ifndef EPSIMAGE_HPP_ +#endif // #ifndef EPSIMAGE_HPP_ diff --git a/include/exiv2/error.hpp b/include/exiv2/error.hpp index affc3423..dbad03d7 100644 --- a/include/exiv2/error.hpp +++ b/include/exiv2/error.hpp @@ -16,136 +16,127 @@ #include "config.h" -#include // for exception -#include // for operator<<, ostream, ostringstream, bas... -#include // for basic_string, string +#include // for exception +#include // for operator<<, ostream, ostringstream, bas... +#include // for basic_string, string // ***************************************************************************** // namespace extensions -namespace Exiv2 -{ - // ***************************************************************************** - // class definitions +namespace Exiv2 { +// ***************************************************************************** +// class definitions - /*! - @brief Class for a log message, used by the library. Applications can set - the log level and provide a customer log message handler (callback - function). +/*! + @brief Class for a log message, used by the library. Applications can set + the log level and provide a customer log message handler (callback + function). - This class is meant to be used as a temporary object with the - related macro-magic like this: + This class is meant to be used as a temporary object with the + related macro-magic like this: - - EXV_WARNING << "Warning! Something looks fishy.\n"; - + + EXV_WARNING << "Warning! Something looks fishy.\n"; + - which translates to + which translates to - - if (LogMsg::warn >= LogMsg::level() && LogMsg::handler()) - LogMsg(LogMsg::warn).os() << "Warning! Something looks fishy.\n"; - + + if (LogMsg::warn >= LogMsg::level() && LogMsg::handler()) + LogMsg(LogMsg::warn).os() << "Warning! Something looks fishy.\n"; + - The macros EXV_DEBUG, EXV_INFO, EXV_WARNING and EXV_ERROR are - shorthands and ensure efficient use of the logging facility: If a - log message doesn't need to be generated because of the log level - setting, the temp object is not even created. + The macros EXV_DEBUG, EXV_INFO, EXV_WARNING and EXV_ERROR are + shorthands and ensure efficient use of the logging facility: If a + log message doesn't need to be generated because of the log level + setting, the temp object is not even created. - Caveat: The entire log message is not processed in this case. So don't - make that call any logic that always needs to be executed. - */ - class EXIV2API LogMsg - { - public: - //! Prevent copy-construction: not implemented. - LogMsg(const LogMsg&) = delete; - //! Prevent assignment: not implemented. - LogMsg& operator=(const LogMsg&) = delete; - /*! - @brief Defined log levels. To suppress all log messages, either set the - log level to \c mute or set the log message handler to 0. - */ - enum Level - { - debug = 0, - info = 1, - warn = 2, - error = 3, - mute = 4 - }; - /*! - @brief Type for a log message handler function. The function receives - the log level and message and can process it in an application - specific way. The default handler sends the log message to - standard error. - */ - using Handler = void (*)(int, const char*); + Caveat: The entire log message is not processed in this case. So don't + make that call any logic that always needs to be executed. + */ +class EXIV2API LogMsg { + public: + //! Prevent copy-construction: not implemented. + LogMsg(const LogMsg&) = delete; + //! Prevent assignment: not implemented. + LogMsg& operator=(const LogMsg&) = delete; + /*! + @brief Defined log levels. To suppress all log messages, either set the + log level to \c mute or set the log message handler to 0. + */ + enum Level { debug = 0, info = 1, warn = 2, error = 3, mute = 4 }; + /*! + @brief Type for a log message handler function. The function receives + the log level and message and can process it in an application + specific way. The default handler sends the log message to + standard error. + */ + using Handler = void (*)(int, const char*); - //! @name Creators - //@{ - //! Constructor, takes the log message type as an argument - explicit LogMsg(Level msgType); + //! @name Creators + //@{ + //! Constructor, takes the log message type as an argument + explicit LogMsg(Level msgType); - //! Destructor, passes the log message to the message handler depending on the log level - ~LogMsg(); - //@} + //! Destructor, passes the log message to the message handler depending on the log level + ~LogMsg(); + //@} - //! @name Manipulators - //@{ - //! Return a reference to the ostringstream which holds the log message - std::ostringstream& os(); - //@} + //! @name Manipulators + //@{ + //! Return a reference to the ostringstream which holds the log message + std::ostringstream& os(); + //@} - /*! - @brief Set the log level. Only log messages with a level greater or - equal \em level are sent to the log message handler. Default - log level is \c warn. To suppress all log messages, set the log - level to \c mute (or set the log message handler to 0). - */ - static void setLevel(Level level); - /*! - @brief Set the log message handler. The default handler writes log - messages to standard error. To suppress all log messages, set - the log message handler to 0 (or set the log level to \c mute). - */ - static void setHandler(Handler handler); - //! Return the current log level - static Level level(); - //! Return the current log message handler - static Handler handler(); - //! The default log handler. Sends the log message to standard error. - static void defaultHandler(int level, const char* s); + /*! + @brief Set the log level. Only log messages with a level greater or + equal \em level are sent to the log message handler. Default + log level is \c warn. To suppress all log messages, set the log + level to \c mute (or set the log message handler to 0). + */ + static void setLevel(Level level); + /*! + @brief Set the log message handler. The default handler writes log + messages to standard error. To suppress all log messages, set + the log message handler to 0 (or set the log level to \c mute). + */ + static void setHandler(Handler handler); + //! Return the current log level + static Level level(); + //! Return the current log message handler + static Handler handler(); + //! The default log handler. Sends the log message to standard error. + static void defaultHandler(int level, const char* s); - private: - // DATA - // The output level. Only messages with type >= level_ will be written - static Level level_; - // The log handler in use - static Handler handler_; - // The type of this log message - const Level msgType_; - // Holds the log message until it is passed to the message handler - std::ostringstream os_; + private: + // DATA + // The output level. Only messages with type >= level_ will be written + static Level level_; + // The log handler in use + static Handler handler_; + // The type of this log message + const Level msgType_; + // Holds the log message until it is passed to the message handler + std::ostringstream os_; - }; // class LogMsg +}; // class LogMsg // Macros for simple access //! Shorthand to create a temp debug log message object and return its ostringstream -#define EXV_DEBUG \ - if (LogMsg::debug >= LogMsg::level() && LogMsg::handler()) \ - LogMsg(LogMsg::debug).os() +#define EXV_DEBUG \ + if (LogMsg::debug >= LogMsg::level() && LogMsg::handler()) \ + LogMsg(LogMsg::debug).os() //! Shorthand for a temp info log message object and return its ostringstream -#define EXV_INFO \ - if (LogMsg::info >= LogMsg::level() && LogMsg::handler()) \ - LogMsg(LogMsg::info).os() +#define EXV_INFO \ + if (LogMsg::info >= LogMsg::level() && LogMsg::handler()) \ + LogMsg(LogMsg::info).os() //! Shorthand for a temp warning log message object and return its ostringstream -#define EXV_WARNING \ - if (LogMsg::warn >= LogMsg::level() && LogMsg::handler()) \ - LogMsg(LogMsg::warn).os() +#define EXV_WARNING \ + if (LogMsg::warn >= LogMsg::level() && LogMsg::handler()) \ + LogMsg(LogMsg::warn).os() //! Shorthand for a temp error log message object and return its ostringstream -#define EXV_ERROR \ - if (LogMsg::error >= LogMsg::level() && LogMsg::handler()) \ - LogMsg(LogMsg::error).os() +#define EXV_ERROR \ + if (LogMsg::error >= LogMsg::level() && LogMsg::handler()) \ + LogMsg(LogMsg::error).os() #ifdef _MSC_VER // Disable MSVC warnings "non - DLL-interface classkey 'identifier' used as base @@ -153,157 +144,150 @@ namespace Exiv2 #pragma warning(disable : 4275) #endif - //! Generalised toString function - template - std::basic_string toBasicString(const T& arg) - { - std::basic_ostringstream os; - os << arg; - return os.str(); - } +//! Generalised toString function +template +std::basic_string toBasicString(const T& arg) { + std::basic_ostringstream os; + os << arg; + return os.str(); +} - //! Complete list of all Exiv2 error codes - enum class ErrorCode - { - kerSuccess = 0, - kerGeneralError, - kerErrorMessage, - kerCallFailed, - kerNotAnImage, - kerInvalidDataset, - kerInvalidRecord, - kerInvalidKey, - kerInvalidTag, - kerValueNotSet, - kerDataSourceOpenFailed, - kerFileOpenFailed, - kerFileContainsUnknownImageType, - kerMemoryContainsUnknownImageType, - kerUnsupportedImageType, - kerFailedToReadImageData, - kerNotAJpeg, - kerFailedToMapFileForReadWrite, - kerFileRenameFailed, - kerTransferFailed, - kerMemoryTransferFailed, - kerInputDataReadFailed, - kerImageWriteFailed, - kerNoImageInInputData, - kerInvalidIfdId, - kerValueTooLarge, - kerDataAreaValueTooLarge, - kerOffsetOutOfRange, - kerUnsupportedDataAreaOffsetType, - kerInvalidCharset, - kerUnsupportedDateFormat, - kerUnsupportedTimeFormat, - kerWritingImageFormatUnsupported, - kerInvalidSettingForImage, - kerNotACrwImage, - kerFunctionNotSupported, - kerNoNamespaceInfoForXmpPrefix, - kerNoPrefixForNamespace, - kerTooLargeJpegSegment, - kerUnhandledXmpdatum, - kerUnhandledXmpNode, - kerXMPToolkitError, - kerDecodeLangAltPropertyFailed, - kerDecodeLangAltQualifierFailed, - kerEncodeLangAltPropertyFailed, - kerPropertyNameIdentificationFailed, - kerSchemaNamespaceNotRegistered, - kerNoNamespaceForPrefix, - kerAliasesNotSupported, - kerInvalidXmpText, - kerTooManyTiffDirectoryEntries, - kerMultipleTiffArrayElementTagsInDirectory, - kerWrongTiffArrayElementTagType, - kerInvalidKeyXmpValue, - kerInvalidIccProfile, - kerInvalidXMP, - kerTiffDirectoryTooLarge, - kerInvalidTypeValue, - kerInvalidLangAltValue, - kerInvalidMalloc, - kerCorruptedMetadata, - kerArithmeticOverflow, - kerMallocFailed, +//! Complete list of all Exiv2 error codes +enum class ErrorCode { + kerSuccess = 0, + kerGeneralError, + kerErrorMessage, + kerCallFailed, + kerNotAnImage, + kerInvalidDataset, + kerInvalidRecord, + kerInvalidKey, + kerInvalidTag, + kerValueNotSet, + kerDataSourceOpenFailed, + kerFileOpenFailed, + kerFileContainsUnknownImageType, + kerMemoryContainsUnknownImageType, + kerUnsupportedImageType, + kerFailedToReadImageData, + kerNotAJpeg, + kerFailedToMapFileForReadWrite, + kerFileRenameFailed, + kerTransferFailed, + kerMemoryTransferFailed, + kerInputDataReadFailed, + kerImageWriteFailed, + kerNoImageInInputData, + kerInvalidIfdId, + kerValueTooLarge, + kerDataAreaValueTooLarge, + kerOffsetOutOfRange, + kerUnsupportedDataAreaOffsetType, + kerInvalidCharset, + kerUnsupportedDateFormat, + kerUnsupportedTimeFormat, + kerWritingImageFormatUnsupported, + kerInvalidSettingForImage, + kerNotACrwImage, + kerFunctionNotSupported, + kerNoNamespaceInfoForXmpPrefix, + kerNoPrefixForNamespace, + kerTooLargeJpegSegment, + kerUnhandledXmpdatum, + kerUnhandledXmpNode, + kerXMPToolkitError, + kerDecodeLangAltPropertyFailed, + kerDecodeLangAltQualifierFailed, + kerEncodeLangAltPropertyFailed, + kerPropertyNameIdentificationFailed, + kerSchemaNamespaceNotRegistered, + kerNoNamespaceForPrefix, + kerAliasesNotSupported, + kerInvalidXmpText, + kerTooManyTiffDirectoryEntries, + kerMultipleTiffArrayElementTagsInDirectory, + kerWrongTiffArrayElementTagType, + kerInvalidKeyXmpValue, + kerInvalidIccProfile, + kerInvalidXMP, + kerTiffDirectoryTooLarge, + kerInvalidTypeValue, + kerInvalidLangAltValue, + kerInvalidMalloc, + kerCorruptedMetadata, + kerArithmeticOverflow, + kerMallocFailed, - kerErrorCount, - }; + kerErrorCount, +}; - /*! - @brief Simple error class used for exceptions. An output operator is - provided to print errors to a stream. - */ - class EXIV2API Error : public std::exception - { - public: - //! @name Creators - //@{ - //! Constructor taking only an error code - explicit Error(ErrorCode code); +/*! + @brief Simple error class used for exceptions. An output operator is + provided to print errors to a stream. + */ +class EXIV2API Error : public std::exception { + public: + //! @name Creators + //@{ + //! Constructor taking only an error code + explicit Error(ErrorCode code); - //! Constructor taking an error code and one argument - template - Error(ErrorCode code, const A& arg1) : code_(code), arg1_(toBasicString(arg1)) - { - setMsg(1); - } + //! Constructor taking an error code and one argument + template + Error(ErrorCode code, const A& arg1) : code_(code), arg1_(toBasicString(arg1)) { + setMsg(1); + } - //! Constructor taking an error code and two arguments - template - Error(ErrorCode code, const A& arg1, const B& arg2) - : code_(code), arg1_(toBasicString(arg1)), arg2_(toBasicString(arg2)) - { - setMsg(2); - } + //! Constructor taking an error code and two arguments + template + Error(ErrorCode code, const A& arg1, const B& arg2) : + code_(code), arg1_(toBasicString(arg1)), arg2_(toBasicString(arg2)) { + setMsg(2); + } - //! Constructor taking an error code and three arguments - template - Error(ErrorCode code, const A& arg1, const B& arg2, const C& arg3) - : code_(code), - arg1_(toBasicString(arg1)), - arg2_(toBasicString(arg2)), - arg3_(toBasicString(arg3)) - { - setMsg(3); - } + //! Constructor taking an error code and three arguments + template + Error(ErrorCode code, const A& arg1, const B& arg2, const C& arg3) : + code_(code), + arg1_(toBasicString(arg1)), + arg2_(toBasicString(arg2)), + arg3_(toBasicString(arg3)) { + setMsg(3); + } - //! Virtual destructor. (Needed because of throw()) - virtual ~Error() noexcept; - //@} + //! Virtual destructor. (Needed because of throw()) + virtual ~Error() noexcept; + //@} - //! @name Accessors - //@{ - ErrorCode code() const noexcept; - /*! - @brief Return the error message as a C-string. The pointer returned by what() - is valid only as long as the BasicError object exists. - */ - const char* what() const noexcept override; - //@} + //! @name Accessors + //@{ + ErrorCode code() const noexcept; + /*! + @brief Return the error message as a C-string. The pointer returned by what() + is valid only as long as the BasicError object exists. + */ + const char* what() const noexcept override; + //@} - private: - //! @name Manipulators - //@{ - //! Assemble the error message from the arguments - void setMsg(int count); - //@} + private: + //! @name Manipulators + //@{ + //! Assemble the error message from the arguments + void setMsg(int count); + //@} - // DATA - const ErrorCode code_; //!< Error code - const std::string arg1_; //!< First argument - const std::string arg2_; //!< Second argument - const std::string arg3_; //!< Third argument - std::string msg_; //!< Complete error message - }; // class BasicError + // DATA + const ErrorCode code_; //!< Error code + const std::string arg1_; //!< First argument + const std::string arg2_; //!< Second argument + const std::string arg3_; //!< Third argument + std::string msg_; //!< Complete error message +}; // class BasicError - //! %Error output operator - inline std::ostream& operator<<(std::ostream& os, const Error& error) - { - return os << error.what(); - } +//! %Error output operator +inline std::ostream& operator<<(std::ostream& os, const Error& error) { + return os << error.what(); +} #ifdef _MSC_VER #pragma warning(default : 4275) diff --git a/include/exiv2/exif.hpp b/include/exiv2/exif.hpp index 526b2fdc..9c212d34 100644 --- a/include/exiv2/exif.hpp +++ b/include/exiv2/exif.hpp @@ -27,533 +27,535 @@ The libexiv2 API consists of the objects of this namespace. */ namespace Exiv2 { - // ***************************************************************************** // class declarations - class ExifData; +class ExifData; // ***************************************************************************** // class definitions - /*! - @brief An Exif metadatum, consisting of an ExifKey and a Value and - methods to manipulate these. - */ - class EXIV2API Exifdatum : public Metadatum { - template friend Exifdatum& setValue(Exifdatum&, const T&); - public: - //! @name Creators - //@{ - /*! - @brief Constructor for new tags created by an application. The - %Exifdatum is created from a \em key / value pair. %Exifdatum copies - (clones) the \em key and value if one is provided. Alternatively, - a program can create an 'empty' %Exifdatum with only a key - and set the value using setValue(). +/*! + @brief An Exif metadatum, consisting of an ExifKey and a Value and + methods to manipulate these. + */ +class EXIV2API Exifdatum : public Metadatum { + template + friend Exifdatum& setValue(Exifdatum&, const T&); - @param key %ExifKey. - @param pValue Pointer to an %Exifdatum value. - @throw Error if the key cannot be parsed and converted. - */ - explicit Exifdatum(const ExifKey& key, const Value* pValue = nullptr); - //! Copy constructor - Exifdatum(const Exifdatum& rhs); - //! Destructor - ~Exifdatum() override = default; - //@} + public: + //! @name Creators + //@{ + /*! + @brief Constructor for new tags created by an application. The + %Exifdatum is created from a \em key / value pair. %Exifdatum copies + (clones) the \em key and value if one is provided. Alternatively, + a program can create an 'empty' %Exifdatum with only a key + and set the value using setValue(). - //! @name Manipulators - //@{ - //! Assignment operator - Exifdatum& operator=(const Exifdatum& rhs); - /*! - @brief Assign \em value to the %Exifdatum. The type of the new Value - is set to UShortValue. - */ - Exifdatum& operator=(const uint16_t& value); - /*! - @brief Assign \em value to the %Exifdatum. The type of the new Value - is set to ULongValue. - */ - Exifdatum& operator=(const uint32_t& value); - /*! - @brief Assign \em value to the %Exifdatum. The type of the new Value - is set to URationalValue. - */ - Exifdatum& operator=(const URational& value); - /*! - @brief Assign \em value to the %Exifdatum. The type of the new Value - is set to ShortValue. - */ - Exifdatum& operator=(const int16_t& value); - /*! - @brief Assign \em value to the %Exifdatum. The type of the new Value - is set to LongValue. - */ - Exifdatum& operator=(const int32_t& value); - /*! - @brief Assign \em value to the %Exifdatum. The type of the new Value - is set to RationalValue. - */ - Exifdatum& operator=(const Rational& value); - /*! - @brief Assign \em value to the %Exifdatum. - Calls setValue(const std::string&). - */ - Exifdatum& operator=(const std::string& value); - /*! - @brief Assign \em value to the %Exifdatum. - Calls setValue(const Value*). - */ - Exifdatum& operator=(const Value& value); - void setValue(const Value* pValue) override; - /*! - @brief Set the value to the string \em value. Uses Value::read(const - std::string&). If the %Exifdatum does not have a Value yet, - then a %Value of the correct type for this %Exifdatum is - created. An AsciiValue is created for unknown tags. Return - 0 if the value was read successfully. - */ - int setValue(const std::string& value) override; - /*! - @brief Set the data area by copying (cloning) the buffer pointed to - by \em buf. + @param key %ExifKey. + @param pValue Pointer to an %Exifdatum value. + @throw Error if the key cannot be parsed and converted. + */ + explicit Exifdatum(const ExifKey& key, const Value* pValue = nullptr); + //! Copy constructor + Exifdatum(const Exifdatum& rhs); + //! Destructor + ~Exifdatum() override = default; + //@} - Values may have a data area, which can contain additional - information besides the actual value. This method is used to set such - a data area. + //! @name Manipulators + //@{ + //! Assignment operator + Exifdatum& operator=(const Exifdatum& rhs); + /*! + @brief Assign \em value to the %Exifdatum. The type of the new Value + is set to UShortValue. + */ + Exifdatum& operator=(const uint16_t& value); + /*! + @brief Assign \em value to the %Exifdatum. The type of the new Value + is set to ULongValue. + */ + Exifdatum& operator=(const uint32_t& value); + /*! + @brief Assign \em value to the %Exifdatum. The type of the new Value + is set to URationalValue. + */ + Exifdatum& operator=(const URational& value); + /*! + @brief Assign \em value to the %Exifdatum. The type of the new Value + is set to ShortValue. + */ + Exifdatum& operator=(const int16_t& value); + /*! + @brief Assign \em value to the %Exifdatum. The type of the new Value + is set to LongValue. + */ + Exifdatum& operator=(const int32_t& value); + /*! + @brief Assign \em value to the %Exifdatum. The type of the new Value + is set to RationalValue. + */ + Exifdatum& operator=(const Rational& value); + /*! + @brief Assign \em value to the %Exifdatum. + Calls setValue(const std::string&). + */ + Exifdatum& operator=(const std::string& value); + /*! + @brief Assign \em value to the %Exifdatum. + Calls setValue(const Value*). + */ + Exifdatum& operator=(const Value& value); + void setValue(const Value* pValue) override; + /*! + @brief Set the value to the string \em value. Uses Value::read(const + std::string&). If the %Exifdatum does not have a Value yet, + then a %Value of the correct type for this %Exifdatum is + created. An AsciiValue is created for unknown tags. Return + 0 if the value was read successfully. + */ + int setValue(const std::string& value) override; + /*! + @brief Set the data area by copying (cloning) the buffer pointed to + by \em buf. - @param buf Pointer to the source data area - @param len Size of the data area - @return Return -1 if the %Exifdatum does not have a value yet or the - value has no data area, else 0. - */ - int setDataArea(const byte* buf, size_t len); - //@} + Values may have a data area, which can contain additional + information besides the actual value. This method is used to set such + a data area. - //! @name Accessors - //@{ - //! Return the key of the %Exifdatum. - std::string key() const override; - const char* familyName() const override; - std::string groupName() const override; - std::string tagName() const override; - std::string tagLabel() const override; - uint16_t tag() const override; - //! Return the IFD id as an integer. (Do not use, this is meant for library internal use.) - int ifdId() const; - //! Return the name of the IFD - const char* ifdName() const; - //! Return the index (unique id of this key within the original IFD) - int idx() const; - /*! - @brief Write value to a data buffer and return the number - of bytes written. + @param buf Pointer to the source data area + @param len Size of the data area + @return Return -1 if the %Exifdatum does not have a value yet or the + value has no data area, else 0. + */ + int setDataArea(const byte* buf, size_t len); + //@} - The user must ensure that the buffer has enough memory. Otherwise - the call results in undefined behaviour. + //! @name Accessors + //@{ + //! Return the key of the %Exifdatum. + std::string key() const override; + const char* familyName() const override; + std::string groupName() const override; + std::string tagName() const override; + std::string tagLabel() const override; + uint16_t tag() const override; + //! Return the IFD id as an integer. (Do not use, this is meant for library internal use.) + int ifdId() const; + //! Return the name of the IFD + const char* ifdName() const; + //! Return the index (unique id of this key within the original IFD) + int idx() const; + /*! + @brief Write value to a data buffer and return the number + of bytes written. - @param buf Data buffer to write to. - @param byteOrder Applicable byte order (little or big endian). - @return Number of characters written. - */ - size_t copy(byte* buf, ByteOrder byteOrder) const override; - std::ostream& write(std::ostream& os, const ExifData* pMetadata = nullptr) const override; - //! Return the type id of the value - TypeId typeId() const override; - //! Return the name of the type - const char* typeName() const override; - //! Return the size in bytes of one component of this type - size_t typeSize() const override; - //! Return the number of components in the value - size_t count() const override; - //! Return the size of the value in bytes - size_t size() const override; - //! Return the value as a string. - std::string toString() const override; - std::string toString(size_t n) const override; - int64_t toInt64(size_t n = 0) const override; - float toFloat(size_t n = 0) const override; - Rational toRational(size_t n = 0) const override; - Value::UniquePtr getValue() const override; - const Value& value() const override; - //! Return the size of the data area. - size_t sizeDataArea() const; - /*! - @brief Return a copy of the data area of the value. The caller owns - this copy and %DataBuf ensures that it will be deleted. + The user must ensure that the buffer has enough memory. Otherwise + the call results in undefined behaviour. - Values may have a data area, which can contain additional - information besides the actual value. This method is used to access - such a data area. + @param buf Data buffer to write to. + @param byteOrder Applicable byte order (little or big endian). + @return Number of characters written. + */ + size_t copy(byte* buf, ByteOrder byteOrder) const override; + std::ostream& write(std::ostream& os, const ExifData* pMetadata = nullptr) const override; + //! Return the type id of the value + TypeId typeId() const override; + //! Return the name of the type + const char* typeName() const override; + //! Return the size in bytes of one component of this type + size_t typeSize() const override; + //! Return the number of components in the value + size_t count() const override; + //! Return the size of the value in bytes + size_t size() const override; + //! Return the value as a string. + std::string toString() const override; + std::string toString(size_t n) const override; + int64_t toInt64(size_t n = 0) const override; + float toFloat(size_t n = 0) const override; + Rational toRational(size_t n = 0) const override; + Value::UniquePtr getValue() const override; + const Value& value() const override; + //! Return the size of the data area. + size_t sizeDataArea() const; + /*! + @brief Return a copy of the data area of the value. The caller owns + this copy and %DataBuf ensures that it will be deleted. - @return A %DataBuf containing a copy of the data area or an empty - %DataBuf if the value does not have a data area assigned or the - value is not set. - */ - DataBuf dataArea() const; - //@} + Values may have a data area, which can contain additional + information besides the actual value. This method is used to access + such a data area. - private: - // DATA - ExifKey::UniquePtr key_; //!< Key - Value::UniquePtr value_; //!< Value + @return A %DataBuf containing a copy of the data area or an empty + %DataBuf if the value does not have a data area assigned or the + value is not set. + */ + DataBuf dataArea() const; + //@} - }; // class Exifdatum + private: + // DATA + ExifKey::UniquePtr key_; //!< Key + Value::UniquePtr value_; //!< Value - /*! - @brief Access to a Exif %thumbnail image. This class provides higher level - accessors to the thumbnail image that is optionally embedded in IFD1 - of the Exif data. These methods do not write to the Exif metadata. - Manipulators are provided in subclass ExifThumb. +}; // class Exifdatum - @note Various other preview and thumbnail images may be contained in an - image, depending on its format and the camera make and model. This - class only provides access to the Exif thumbnail as specified in the - Exif standard. - */ - class EXIV2API ExifThumbC { - public: - //! @name Creators - //@{ - //! Constructor. - explicit ExifThumbC(const ExifData& exifData); - //@} +/*! + @brief Access to a Exif %thumbnail image. This class provides higher level + accessors to the thumbnail image that is optionally embedded in IFD1 + of the Exif data. These methods do not write to the Exif metadata. + Manipulators are provided in subclass ExifThumb. - //! @name Accessors - //@{ - /*! - @brief Return the thumbnail image in a %DataBuf. The caller owns the - data buffer and %DataBuf ensures that it will be deleted. - */ - DataBuf copy() const; - /*! - @brief Write the thumbnail image to a file. + @note Various other preview and thumbnail images may be contained in an + image, depending on its format and the camera make and model. This + class only provides access to the Exif thumbnail as specified in the + Exif standard. + */ +class EXIV2API ExifThumbC { + public: + //! @name Creators + //@{ + //! Constructor. + explicit ExifThumbC(const ExifData& exifData); + //@} - A filename extension is appended to \em path according to the image - type of the thumbnail, so \em path should not include an extension. - The function will overwrite an existing file of the same name. + //! @name Accessors + //@{ + /*! + @brief Return the thumbnail image in a %DataBuf. The caller owns the + data buffer and %DataBuf ensures that it will be deleted. + */ + DataBuf copy() const; + /*! + @brief Write the thumbnail image to a file. - @param path File name of the thumbnail without extension. - @return The number of bytes written. - */ - size_t writeFile(const std::string& path) const; - /*! - @brief Return the MIME type of the thumbnail, either \c "image/tiff" - or \c "image/jpeg". - */ - const char* mimeType() const; - /*! - @brief Return the file extension for the format of the thumbnail - (".tif" or ".jpg"). - */ - const char* extension() const; - //@} + A filename extension is appended to \em path according to the image + type of the thumbnail, so \em path should not include an extension. + The function will overwrite an existing file of the same name. - private: - // DATA - const ExifData& exifData_; //!< Const reference to the Exif metadata. + @param path File name of the thumbnail without extension. + @return The number of bytes written. + */ + size_t writeFile(const std::string& path) const; + /*! + @brief Return the MIME type of the thumbnail, either \c "image/tiff" + or \c "image/jpeg". + */ + const char* mimeType() const; + /*! + @brief Return the file extension for the format of the thumbnail + (".tif" or ".jpg"). + */ + const char* extension() const; + //@} - }; // class ExifThumb + private: + // DATA + const ExifData& exifData_; //!< Const reference to the Exif metadata. - /*! - @brief Access and modify an Exif %thumbnail image. This class implements - manipulators to set and erase the thumbnail image that is optionally - embedded in IFD1 of the Exif data. Accessors are provided by the - base class, ExifThumbC. +}; // class ExifThumb - @note Various other preview and thumbnail images may be contained in an - image, depending on its format and the camera make and model. This - class only provides access to the Exif thumbnail as specified in the - Exif standard. - */ - class EXIV2API ExifThumb : public ExifThumbC { - public: - //! @name Creators - //@{ - //! Constructor. - explicit ExifThumb(ExifData& exifData); - //@} +/*! + @brief Access and modify an Exif %thumbnail image. This class implements + manipulators to set and erase the thumbnail image that is optionally + embedded in IFD1 of the Exif data. Accessors are provided by the + base class, ExifThumbC. - //! @name Manipulators - //@{ - /*! - @brief Set the Exif thumbnail to the JPEG image \em path. Set - XResolution, YResolution and ResolutionUnit to \em xres, - \em yres and \em unit, respectively. + @note Various other preview and thumbnail images may be contained in an + image, depending on its format and the camera make and model. This + class only provides access to the Exif thumbnail as specified in the + Exif standard. + */ +class EXIV2API ExifThumb : public ExifThumbC { + public: + //! @name Creators + //@{ + //! Constructor. + explicit ExifThumb(ExifData& exifData); + //@} - This results in the minimal thumbnail tags being set for a JPEG - thumbnail, as mandated by the Exif standard. + //! @name Manipulators + //@{ + /*! + @brief Set the Exif thumbnail to the JPEG image \em path. Set + XResolution, YResolution and ResolutionUnit to \em xres, + \em yres and \em unit, respectively. - @throw Error if reading the file fails. + This results in the minimal thumbnail tags being set for a JPEG + thumbnail, as mandated by the Exif standard. - @note No checks on the file format or size are performed. - @note Additional existing Exif thumbnail tags are not modified. - @note The JPEG image inserted as thumbnail image should not - itself contain Exif data (or other metadata), as existing - applications may have problems with that. (The preview - application that comes with OS X for one.) - David Harvey. - */ - void setJpegThumbnail(const std::string& path, URational xres, URational yres, uint16_t unit); - /*! - @brief Set the Exif thumbnail to the JPEG image pointed to by \em buf, - and size \em size. Set XResolution, YResolution and - ResolutionUnit to \em xres, \em yres and \em unit, respectively. + @throw Error if reading the file fails. - This results in the minimal thumbnail tags being set for a JPEG - thumbnail, as mandated by the Exif standard. + @note No checks on the file format or size are performed. + @note Additional existing Exif thumbnail tags are not modified. + @note The JPEG image inserted as thumbnail image should not + itself contain Exif data (or other metadata), as existing + applications may have problems with that. (The preview + application that comes with OS X for one.) - David Harvey. + */ + void setJpegThumbnail(const std::string& path, URational xres, URational yres, uint16_t unit); + /*! + @brief Set the Exif thumbnail to the JPEG image pointed to by \em buf, + and size \em size. Set XResolution, YResolution and + ResolutionUnit to \em xres, \em yres and \em unit, respectively. - @throw Error if reading the file fails. + This results in the minimal thumbnail tags being set for a JPEG + thumbnail, as mandated by the Exif standard. - @note No checks on the image format or size are performed. - @note Additional existing Exif thumbnail tags are not modified. - @note The JPEG image inserted as thumbnail image should not - itself contain Exif data (or other metadata), as existing - applications may have problems with that. (The preview - application that comes with OS X for one.) - David Harvey. - */ - void setJpegThumbnail(const byte* buf, size_t size, URational xres, URational yres, uint16_t unit); - /*! - @brief Set the Exif thumbnail to the JPEG image \em path. + @throw Error if reading the file fails. - This sets only the Compression, JPEGInterchangeFormat and - JPEGInterchangeFormatLength tags, which is not all the thumbnail - Exif information mandatory according to the Exif standard. (But it's - enough to work with the thumbnail.) + @note No checks on the image format or size are performed. + @note Additional existing Exif thumbnail tags are not modified. + @note The JPEG image inserted as thumbnail image should not + itself contain Exif data (or other metadata), as existing + applications may have problems with that. (The preview + application that comes with OS X for one.) - David Harvey. + */ + void setJpegThumbnail(const byte* buf, size_t size, URational xres, URational yres, uint16_t unit); + /*! + @brief Set the Exif thumbnail to the JPEG image \em path. - @throw Error if reading the file fails. + This sets only the Compression, JPEGInterchangeFormat and + JPEGInterchangeFormatLength tags, which is not all the thumbnail + Exif information mandatory according to the Exif standard. (But it's + enough to work with the thumbnail.) - @note No checks on the file format or size are performed. - @note Additional existing Exif thumbnail tags are not modified. - */ - void setJpegThumbnail(const std::string& path); - /*! - @brief Set the Exif thumbnail to the JPEG image pointed to by \em buf, - and size \em size. + @throw Error if reading the file fails. - This sets only the Compression, JPEGInterchangeFormat and - JPEGInterchangeFormatLength tags, which is not all the thumbnail - Exif information mandatory according to the Exif standard. (But it's - enough to work with the thumbnail.) + @note No checks on the file format or size are performed. + @note Additional existing Exif thumbnail tags are not modified. + */ + void setJpegThumbnail(const std::string& path); + /*! + @brief Set the Exif thumbnail to the JPEG image pointed to by \em buf, + and size \em size. - @note No checks on the image format or size are performed. - @note Additional existing Exif thumbnail tags are not modified. - */ - void setJpegThumbnail(const byte* buf, size_t size); - /*! - @brief Delete the thumbnail from the Exif data. Removes all - Exif.%Thumbnail.*, i.e., Exif IFD1 tags. - */ - void erase(); - //@} + This sets only the Compression, JPEGInterchangeFormat and + JPEGInterchangeFormatLength tags, which is not all the thumbnail + Exif information mandatory according to the Exif standard. (But it's + enough to work with the thumbnail.) - private: - // DATA - ExifData& exifData_; //!< Reference to the related Exif metadata. + @note No checks on the image format or size are performed. + @note Additional existing Exif thumbnail tags are not modified. + */ + void setJpegThumbnail(const byte* buf, size_t size); + /*! + @brief Delete the thumbnail from the Exif data. Removes all + Exif.%Thumbnail.*, i.e., Exif IFD1 tags. + */ + void erase(); + //@} - }; // class ExifThumb + private: + // DATA + ExifData& exifData_; //!< Reference to the related Exif metadata. - //! Container type to hold all metadata - using ExifMetadata = std::list; +}; // class ExifThumb - /*! - @brief A container for Exif data. This is a top-level class of the %Exiv2 - library. The container holds Exifdatum objects. +//! Container type to hold all metadata +using ExifMetadata = std::list; - Provide high-level access to the Exif data of an image: - - read Exif information from JPEG files - - access metadata through keys and standard C++ iterators - - add, modify and delete metadata - - write Exif data to JPEG files - - extract Exif metadata to files, insert from these files - - extract and delete Exif thumbnail (JPEG and TIFF thumbnails) - */ - class EXIV2API ExifData { - public: - //! ExifMetadata iterator type - using iterator = ExifMetadata::iterator; - //! ExifMetadata const iterator type - using const_iterator = ExifMetadata::const_iterator; +/*! + @brief A container for Exif data. This is a top-level class of the %Exiv2 + library. The container holds Exifdatum objects. - //! @name Manipulators - //@{ - /*! - @brief Returns a reference to the %Exifdatum that is associated with a - particular \em key. If %ExifData does not already contain such - an %Exifdatum, operator[] adds object \em Exifdatum(key). + Provide high-level access to the Exif data of an image: + - read Exif information from JPEG files + - access metadata through keys and standard C++ iterators + - add, modify and delete metadata + - write Exif data to JPEG files + - extract Exif metadata to files, insert from these files + - extract and delete Exif thumbnail (JPEG and TIFF thumbnails) +*/ +class EXIV2API ExifData { + public: + //! ExifMetadata iterator type + using iterator = ExifMetadata::iterator; + //! ExifMetadata const iterator type + using const_iterator = ExifMetadata::const_iterator; - @note Since operator[] might insert a new element, it can't be a const - member function. - */ - Exifdatum& operator[](const std::string& key); - /*! - @brief Add an Exifdatum from the supplied key and value pair. This - method copies (clones) key and value. No duplicate checks are - performed, i.e., it is possible to add multiple metadata with - the same key. - */ - void add(const ExifKey& key, const Value* pValue); - /*! - @brief Add a copy of the \em exifdatum to the Exif metadata. No - duplicate checks are performed, i.e., it is possible to add - multiple metadata with the same key. + //! @name Manipulators + //@{ + /*! + @brief Returns a reference to the %Exifdatum that is associated with a + particular \em key. If %ExifData does not already contain such + an %Exifdatum, operator[] adds object \em Exifdatum(key). - @throw Error if the makernote cannot be created - */ - void add(const Exifdatum& exifdatum); - /*! - @brief Delete the Exifdatum at iterator position \em pos, return the - position of the next exifdatum. Note that iterators into - the metadata, including \em pos, are potentially invalidated - by this call. - */ - iterator erase(iterator pos); - /*! - @brief Remove all elements of the range \em beg, \em end, return the - position of the next element. Note that iterators into - the metadata are potentially invalidated by this call. - */ - iterator erase(iterator beg, iterator end); - /*! - @brief Delete all Exifdatum instances resulting in an empty container. - Note that this also removes thumbnails. - */ - void clear(); - //! Sort metadata by key - void sortByKey(); - //! Sort metadata by tag - void sortByTag(); - //! Begin of the metadata - iterator begin() { return exifMetadata_.begin(); } - //! End of the metadata - iterator end() { return exifMetadata_.end(); } - /*! - @brief Find the first Exifdatum with the given \em key, return an - iterator to it. - */ - iterator findKey(const ExifKey& key); - //@} + @note Since operator[] might insert a new element, it can't be a const + member function. + */ + Exifdatum& operator[](const std::string& key); + /*! + @brief Add an Exifdatum from the supplied key and value pair. This + method copies (clones) key and value. No duplicate checks are + performed, i.e., it is possible to add multiple metadata with + the same key. + */ + void add(const ExifKey& key, const Value* pValue); + /*! + @brief Add a copy of the \em exifdatum to the Exif metadata. No + duplicate checks are performed, i.e., it is possible to add + multiple metadata with the same key. - //! @name Accessors - //@{ - //! Begin of the metadata - const_iterator begin() const { return exifMetadata_.begin(); } - //! End of the metadata - const_iterator end() const { return exifMetadata_.end(); } - /*! - @brief Find the first Exifdatum with the given \em key, return a const - iterator to it. - */ - const_iterator findKey(const ExifKey& key) const; - //! Return true if there is no Exif metadata - bool empty() const { return exifMetadata_.empty(); } - //! Get the number of metadata entries - size_t count() const { return exifMetadata_.size(); } - //@} + @throw Error if the makernote cannot be created + */ + void add(const Exifdatum& exifdatum); + /*! + @brief Delete the Exifdatum at iterator position \em pos, return the + position of the next exifdatum. Note that iterators into + the metadata, including \em pos, are potentially invalidated + by this call. + */ + iterator erase(iterator pos); + /*! + @brief Remove all elements of the range \em beg, \em end, return the + position of the next element. Note that iterators into + the metadata are potentially invalidated by this call. + */ + iterator erase(iterator beg, iterator end); + /*! + @brief Delete all Exifdatum instances resulting in an empty container. + Note that this also removes thumbnails. + */ + void clear(); + //! Sort metadata by key + void sortByKey(); + //! Sort metadata by tag + void sortByTag(); + //! Begin of the metadata + iterator begin() { + return exifMetadata_.begin(); + } + //! End of the metadata + iterator end() { + return exifMetadata_.end(); + } + /*! + @brief Find the first Exifdatum with the given \em key, return an + iterator to it. + */ + iterator findKey(const ExifKey& key); + //@} - private: - // DATA - ExifMetadata exifMetadata_; - }; // class ExifData + //! @name Accessors + //@{ + //! Begin of the metadata + const_iterator begin() const { + return exifMetadata_.begin(); + } + //! End of the metadata + const_iterator end() const { + return exifMetadata_.end(); + } + /*! + @brief Find the first Exifdatum with the given \em key, return a const + iterator to it. + */ + const_iterator findKey(const ExifKey& key) const; + //! Return true if there is no Exif metadata + bool empty() const { + return exifMetadata_.empty(); + } + //! Get the number of metadata entries + size_t count() const { + return exifMetadata_.size(); + } + //@} - /*! - @brief Stateless parser class for Exif data. Images use this class to - decode and encode binary Exif data. + private: + // DATA + ExifMetadata exifMetadata_; +}; // class ExifData - @note Encode is lossy and is not the inverse of decode. - */ - class EXIV2API ExifParser { - public: - /*! - @brief Decode metadata from a buffer \em pData of length \em size - with binary Exif data to the provided metadata container. +/*! + @brief Stateless parser class for Exif data. Images use this class to + decode and encode binary Exif data. - The buffer must start with a TIFF header. Return byte order - in which the data is encoded. + @note Encode is lossy and is not the inverse of decode. + */ +class EXIV2API ExifParser { + public: + /*! + @brief Decode metadata from a buffer \em pData of length \em size + with binary Exif data to the provided metadata container. - @param exifData Exif metadata container. - @param pData Pointer to the data buffer. Must point to data in - binary Exif format; no checks are performed. - @param size Length of the data buffer - @return Byte order in which the data is encoded. - */ - static ByteOrder decode(ExifData& exifData, const byte* pData, size_t size); - /*! - @brief Encode Exif metadata from the provided metadata to binary Exif - format. + The buffer must start with a TIFF header. Return byte order + in which the data is encoded. - The original binary Exif data in the memory block \em pData, \em size - is parsed and updated in-place if possible ("non-intrusive" - writing). If that is not possible (e.g., if new tags were added), the - entire Exif structure is re-written to the \em blob ("intrusive" - writing). The return value indicates which write method was used. If - it is \c wmNonIntrusive, the original memory \em pData, \em size - contains the result and \em blob is empty. If the return value is - \c wmIntrusive, a new Exif structure was created and returned in - \em blob. The memory block \em pData, \em size may be partly updated in - this case and should not be used anymore. + @param exifData Exif metadata container. + @param pData Pointer to the data buffer. Must point to data in + binary Exif format; no checks are performed. + @param size Length of the data buffer + @return Byte order in which the data is encoded. + */ + static ByteOrder decode(ExifData& exifData, const byte* pData, size_t size); + /*! + @brief Encode Exif metadata from the provided metadata to binary Exif + format. - Encode is a lossy operation. It attempts to fit the Exif data into a - binary block suitable as the payload of a JPEG APP1 Exif segment, - which can be at most 65527 bytes large. Encode omits IFD0 tags that - are "not recorded" in compressed images according to the Exif 2.2 - specification. It also doesn't write tags in groups which do not occur - in JPEG images. If the resulting binary block is larger than allowed, - it further deletes specific large preview tags, unknown tags larger - than 4kB and known tags larger than 40kB. The operation succeeds even - if the end result is still larger than the allowed size. Application - should therefore always check the size of the \em blob. + The original binary Exif data in the memory block \em pData, \em size + is parsed and updated in-place if possible ("non-intrusive" + writing). If that is not possible (e.g., if new tags were added), the + entire Exif structure is re-written to the \em blob ("intrusive" + writing). The return value indicates which write method was used. If + it is \c wmNonIntrusive, the original memory \em pData, \em size + contains the result and \em blob is empty. If the return value is + \c wmIntrusive, a new Exif structure was created and returned in + \em blob. The memory block \em pData, \em size may be partly updated in + this case and should not be used anymore. - @param blob Container for the binary Exif data if "intrusive" - writing is necessary. Empty otherwise. - @param pData Pointer to the binary Exif data buffer. Must - point to data in Exif format; no checks are - performed. Will be modified if "non-intrusive" - writing is possible. - @param size Length of the data buffer. - @param byteOrder Byte order to use. - @param exifData Exif metadata container. + Encode is a lossy operation. It attempts to fit the Exif data into a + binary block suitable as the payload of a JPEG APP1 Exif segment, + which can be at most 65527 bytes large. Encode omits IFD0 tags that + are "not recorded" in compressed images according to the Exif 2.2 + specification. It also doesn't write tags in groups which do not occur + in JPEG images. If the resulting binary block is larger than allowed, + it further deletes specific large preview tags, unknown tags larger + than 4kB and known tags larger than 40kB. The operation succeeds even + if the end result is still larger than the allowed size. Application + should therefore always check the size of the \em blob. - @return Write method used. - */ - static WriteMethod encode( - Blob& blob, - const byte* pData, - size_t size, - ByteOrder byteOrder, - const ExifData& exifData - ); - /*! - @brief Encode metadata from the provided metadata to Exif format. + @param blob Container for the binary Exif data if "intrusive" + writing is necessary. Empty otherwise. + @param pData Pointer to the binary Exif data buffer. Must + point to data in Exif format; no checks are + performed. Will be modified if "non-intrusive" + writing is possible. + @param size Length of the data buffer. + @param byteOrder Byte order to use. + @param exifData Exif metadata container. - Encode Exif metadata from the \em ExifData container to binary Exif - format in the \em blob, encoded in \em byteOrder. + @return Write method used. + */ + static WriteMethod encode(Blob& blob, const byte* pData, size_t size, ByteOrder byteOrder, const ExifData& exifData); + /*! + @brief Encode metadata from the provided metadata to Exif format. - This simpler encode method uses "intrusive" writing, i.e., it builds - the binary representation of the metadata from scratch. It does not - attempt "non-intrusive", i.e., in-place updating. It's better to use - the other encode() method, if the metadata is already available in - binary format, in order to allow for "non-intrusive" updating of the - existing binary representation. + Encode Exif metadata from the \em ExifData container to binary Exif + format in the \em blob, encoded in \em byteOrder. - This is just an inline wrapper for - ExifParser::encode(blob, 0, 0, byteOrder, exifData). + This simpler encode method uses "intrusive" writing, i.e., it builds + the binary representation of the metadata from scratch. It does not + attempt "non-intrusive", i.e., in-place updating. It's better to use + the other encode() method, if the metadata is already available in + binary format, in order to allow for "non-intrusive" updating of the + existing binary representation. - @param blob Container for the binary Exif data. - @param byteOrder Byte order to use. - @param exifData Exif metadata container. - */ - static void encode( - Blob& blob, - ByteOrder byteOrder, - const ExifData& exifData - ) - { - encode(blob, nullptr, 0, byteOrder, exifData); - } + This is just an inline wrapper for + ExifParser::encode(blob, 0, 0, byteOrder, exifData). - }; // class ExifParser + @param blob Container for the binary Exif data. + @param byteOrder Byte order to use. + @param exifData Exif metadata container. + */ + static void encode(Blob& blob, ByteOrder byteOrder, const ExifData& exifData) { + encode(blob, nullptr, 0, byteOrder, exifData); + } -} // namespace Exiv2 +}; // class ExifParser -#endif // #ifndef EXIF_HPP_ +} // namespace Exiv2 + +#endif // #ifndef EXIF_HPP_ diff --git a/include/exiv2/exiv2.hpp b/include/exiv2/exiv2.hpp index 583af9bf..66d74d5d 100644 --- a/include/exiv2/exiv2.hpp +++ b/include/exiv2/exiv2.hpp @@ -5,14 +5,14 @@ // ***************************************************************************** // included header files -#include "exiv2/config.h" -#include "exiv2/datasets.hpp" #include "exiv2/basicio.hpp" #include "exiv2/bmffimage.hpp" #include "exiv2/bmpimage.hpp" +#include "exiv2/config.h" #include "exiv2/convert.hpp" #include "exiv2/cr2image.hpp" #include "exiv2/crwimage.hpp" +#include "exiv2/datasets.hpp" #include "exiv2/easyaccess.hpp" #include "exiv2/epsimage.hpp" #include "exiv2/error.hpp" @@ -49,4 +49,4 @@ #include "exiv2/xmp_exiv2.hpp" #include "exiv2/xmpsidecar.hpp" -#endif//ifndef EXIV2_HPP_ +#endif // ifndef EXIV2_HPP_ diff --git a/include/exiv2/futils.hpp b/include/exiv2/futils.hpp index 1f2b32e7..d454846e 100644 --- a/include/exiv2/futils.hpp +++ b/include/exiv2/futils.hpp @@ -3,138 +3,122 @@ #ifndef FUTILS_HPP_ #define FUTILS_HPP_ -#include "exiv2lib_export.h" #include "config.h" +#include "exiv2lib_export.h" #include // namespace extensions -namespace Exiv2 -{ - //! the name of environmental variables. - enum EnVar - { - envHTTPPOST = 0, - envTIMEOUT = 1 - }; - //! the collection of protocols. - enum Protocol - { - pFile = 0, - pHttp, - pFtp, - pHttps, - pSftp, - pFileUri, - pDataUri, - pStdin - }; - // ********************************************************************* - // free functions - /*! - @brief Return the value of environmental variable. - @param[in] var The name of environmental variable. Must be a member of the enumeration @ref EnVar. - @return the value of environmental variable. If it's empty, the default value is returned. - @throws std::out_of_range when an unexpected EnVar is given as input. - */ - EXIV2API std::string getEnv(int env_var); +namespace Exiv2 { +//! the name of environmental variables. +enum EnVar { envHTTPPOST = 0, envTIMEOUT = 1 }; +//! the collection of protocols. +enum Protocol { pFile = 0, pHttp, pFtp, pHttps, pSftp, pFileUri, pDataUri, pStdin }; +// ********************************************************************* +// free functions +/*! + @brief Return the value of environmental variable. + @param[in] var The name of environmental variable. Must be a member of the enumeration @ref EnVar. + @return the value of environmental variable. If it's empty, the default value is returned. + @throws std::out_of_range when an unexpected EnVar is given as input. + */ +EXIV2API std::string getEnv(int env_var); - /*! - @brief Encode the input url. - @param str The url needs encoding. - @return the url-encoded version of str. - @note Source: http://www.geekhideout.com/urlcode.shtml - @todo This function can probably be hidden into the implementation details - */ - EXIV2API std::string urlencode(std::string_view str); +/*! + @brief Encode the input url. + @param str The url needs encoding. + @return the url-encoded version of str. + @note Source: http://www.geekhideout.com/urlcode.shtml + @todo This function can probably be hidden into the implementation details + */ +EXIV2API std::string urlencode(std::string_view str); - /*! - @brief Like urlencode(char* str) but accept the input url in the std::string and modify it. - @todo This function can probably be hidden into the implementation details - */ - EXIV2API void urldecode(std::string& str); +/*! + @brief Like urlencode(char* str) but accept the input url in the std::string and modify it. + @todo This function can probably be hidden into the implementation details + */ +EXIV2API void urldecode(std::string& str); - /*! - @brief Encode in base64 the data in data_buf and put the resulting string in result. - @param data_buf The data need to encode - @param dataLength Size in bytes of the in buffer - @param result The container for the result, NULL if it fails - @param resultSize Size in bytes of the out string, it should be at least - ((dataLength + 2) / 3) * 4 + 1 - @return 1 indicate success +/*! + @brief Encode in base64 the data in data_buf and put the resulting string in result. + @param data_buf The data need to encode + @param dataLength Size in bytes of the in buffer + @param result The container for the result, NULL if it fails + @param resultSize Size in bytes of the out string, it should be at least + ((dataLength + 2) / 3) * 4 + 1 + @return 1 indicate success - @note Source: http://en.wikibooks.org/wiki/Algorithm_Implementation/Miscellaneous/Base64 - */ - EXIV2API int base64encode(const void* data_buf, size_t dataLength, char* result, size_t resultSize); + @note Source: http://en.wikibooks.org/wiki/Algorithm_Implementation/Miscellaneous/Base64 + */ +EXIV2API int base64encode(const void* data_buf, size_t dataLength, char* result, size_t resultSize); - /*! - @brief Decode base64 data and put the resulting string in out. - @param in The data need to decode. - @param out The container for the result, it should be large enough to contain the result. - @param out_size The size of out in bytes. - @return the size of the resulting string. If it fails, return -1. +/*! + @brief Decode base64 data and put the resulting string in out. + @param in The data need to decode. + @param out The container for the result, it should be large enough to contain the result. + @param out_size The size of out in bytes. + @return the size of the resulting string. If it fails, return -1. - @note Source: https://github.com/davidgaleano/libwebsockets/blob/master/lib/base64-decode.c - */ - EXIV2API size_t base64decode(const char* in, char* out, size_t out_size); + @note Source: https://github.com/davidgaleano/libwebsockets/blob/master/lib/base64-decode.c + */ +EXIV2API size_t base64decode(const char* in, char* out, size_t out_size); - /*! - @brief Return the protocol of the path. - @param path The path of file to extract the protocol. - @return the protocol of the path. - */ - EXIV2API Protocol fileProtocol(const std::string& path); +/*! + @brief Return the protocol of the path. + @param path The path of file to extract the protocol. + @return the protocol of the path. + */ +EXIV2API Protocol fileProtocol(const std::string& path); - /*! - @brief Test if a file exists. +/*! + @brief Test if a file exists. - @param path Name of file to verify. - @param ct Flag to check if path is a regular file. - @return true if path exists and, if ct is set, - is a regular file, else false. + @param path Name of file to verify. + @param ct Flag to check if path is a regular file. + @return true if path exists and, if ct is set, + is a regular file, else false. - @note The function calls stat() test for path - and its type, see stat(2). errno is left unchanged - in case of an error. - */ - EXIV2API bool fileExists(const std::string& path); + @note The function calls stat() test for path + and its type, see stat(2). errno is left unchanged + in case of an error. + */ +EXIV2API bool fileExists(const std::string& path); - /*! - @brief Return a system error message and the error code (errno). - See %strerror(3). - */ - EXIV2API std::string strError(); +/*! + @brief Return a system error message and the error code (errno). + See %strerror(3). + */ +EXIV2API std::string strError(); - //! @brief Return the path of the current process. - EXIV2API std::string getProcessPath(); +//! @brief Return the path of the current process. +EXIV2API std::string getProcessPath(); - /*! - @brief A container for URL components. It also provides the method to parse a - URL to get the protocol, host, path, port, querystring, username, password. +/*! + @brief A container for URL components. It also provides the method to parse a + URL to get the protocol, host, path, port, querystring, username, password. - Source: http://stackoverflow.com/questions/2616011/easy-way-to-parse-a-url-in-c-cross-platform + Source: http://stackoverflow.com/questions/2616011/easy-way-to-parse-a-url-in-c-cross-platform - @todo This class can probably be hidden from the API - */ - class Uri - { - public: - // DATA - std::string QueryString; //!< URL query string - std::string Path; //!< URL file path - std::string Protocol; //!< URL protocol - std::string Host; //!< URL host - std::string Port; //!< URL port - std::string Username; //!< URL username - std::string Password; //!< URL password + @todo This class can probably be hidden from the API + */ +class Uri { + public: + // DATA + std::string QueryString; //!< URL query string + std::string Path; //!< URL file path + std::string Protocol; //!< URL protocol + std::string Host; //!< URL host + std::string Port; //!< URL port + std::string Username; //!< URL username + std::string Password; //!< URL password - /// @brief Parse the input URL to the protocol, host, path, username, password - static Uri EXIV2API Parse(const std::string& uri); + /// @brief Parse the input URL to the protocol, host, path, username, password + static Uri EXIV2API Parse(const std::string& uri); - /// @brief Decode the url components. - static void EXIV2API Decode(Uri& uri); - }; + /// @brief Decode the url components. + static void EXIV2API Decode(Uri& uri); +}; } // namespace Exiv2 -#endif // #ifndef FUTILS_HPP_ +#endif // #ifndef FUTILS_HPP_ diff --git a/include/exiv2/gifimage.hpp b/include/exiv2/gifimage.hpp index caf9f318..2b805753 100644 --- a/include/exiv2/gifimage.hpp +++ b/include/exiv2/gifimage.hpp @@ -12,88 +12,87 @@ // ***************************************************************************** // namespace extensions namespace Exiv2 { - // ***************************************************************************** // class definitions - /*! - @brief Class to access raw GIF images. Exif/IPTC metadata are supported - directly. - */ - class EXIV2API GifImage : public Image { - public: - //! @name NOT Implemented - //@{ - //! Copy constructor - GifImage(const GifImage& rhs) = delete; - //! Assignment operator - GifImage& operator=(const GifImage& rhs) = delete; - //@} +/*! + @brief Class to access raw GIF images. Exif/IPTC metadata are supported + directly. + */ +class EXIV2API GifImage : public Image { + public: + //! @name NOT Implemented + //@{ + //! Copy constructor + GifImage(const GifImage& rhs) = delete; + //! Assignment operator + GifImage& operator=(const GifImage& rhs) = delete; + //@} - //! @name Creators - //@{ - /*! - @brief Constructor to open a GIF 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. - */ - explicit GifImage(BasicIo::UniquePtr io); - //@} + //! @name Creators + //@{ + /*! + @brief Constructor to open a GIF 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. + */ + explicit GifImage(BasicIo::UniquePtr io); + //@} - //! @name Manipulators - //@{ - void readMetadata() override; - /*! - @brief Todo: Write metadata back to the image. This method is not - yet(?) implemented. Calling it will throw an Error(ErrorCode::kerWritingImageFormatUnsupported). - */ - void writeMetadata() override; - /*! - @brief Todo: Not supported yet(?). Calling this function will throw - an instance of Error(ErrorCode::kerInvalidSettingForImage). - */ - void setExifData(const ExifData& exifData) override; - /*! - @brief Todo: Not supported yet(?). Calling this function will throw - an instance of Error(ErrorCode::kerInvalidSettingForImage). - */ - void setIptcData(const IptcData& iptcData) override; - /*! - @brief Not supported. Calling this function will throw an instance - of Error(ErrorCode::kerInvalidSettingForImage). - */ - void setComment(std::string_view comment) override; - //@} + //! @name Manipulators + //@{ + void readMetadata() override; + /*! + @brief Todo: Write metadata back to the image. This method is not + yet(?) implemented. Calling it will throw an Error(ErrorCode::kerWritingImageFormatUnsupported). + */ + void writeMetadata() override; + /*! + @brief Todo: Not supported yet(?). Calling this function will throw + an instance of Error(ErrorCode::kerInvalidSettingForImage). + */ + void setExifData(const ExifData& exifData) override; + /*! + @brief Todo: Not supported yet(?). Calling this function will throw + an instance of Error(ErrorCode::kerInvalidSettingForImage). + */ + void setIptcData(const IptcData& iptcData) override; + /*! + @brief Not supported. Calling this function will throw an instance + of Error(ErrorCode::kerInvalidSettingForImage). + */ + void setComment(std::string_view comment) override; + //@} - //! @name Accessors - //@{ - std::string mimeType() const override; - //@} + //! @name Accessors + //@{ + std::string mimeType() const override; + //@} - }; // class GifImage +}; // class GifImage // ***************************************************************************** // 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 GifImage 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::UniquePtr newGifInstance(BasicIo::UniquePtr io, bool create); +// These could be static private functions on Image subclasses but then +// ImageFactory needs to be made a friend. +/*! + @brief Create a new GifImage 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::UniquePtr newGifInstance(BasicIo::UniquePtr io, bool create); - //! Check if the file iIo is a GIF image. - EXIV2API bool isGifType(BasicIo& iIo, bool advance); +//! Check if the file iIo is a GIF image. +EXIV2API bool isGifType(BasicIo& iIo, bool advance); -} // namespace Exiv2 +} // namespace Exiv2 -#endif // #ifndef GIFIMAGE_HPP_ +#endif // #ifndef GIFIMAGE_HPP_ diff --git a/include/exiv2/http.hpp b/include/exiv2/http.hpp index 800378bc..0c5fa784 100644 --- a/include/exiv2/http.hpp +++ b/include/exiv2/http.hpp @@ -7,16 +7,15 @@ #include "datasets.hpp" - namespace Exiv2 { - /*! - @brief execute an HTTP request - @param request - a Dictionary of headers to send to server - @param response - a Dictionary of response headers (dictionary is filled by the response) - @param errors - a String with an error - @return Server response 200 = OK, 404 = Not Found etc... - */ - EXIV2API int http(Exiv2::Dictionary& request,Exiv2::Dictionary& response,std::string& errors); -} +/*! + @brief execute an HTTP request + @param request - a Dictionary of headers to send to server + @param response - a Dictionary of response headers (dictionary is filled by the response) + @param errors - a String with an error + @return Server response 200 = OK, 404 = Not Found etc... +*/ +EXIV2API int http(Exiv2::Dictionary& request, Exiv2::Dictionary& response, std::string& errors); +} // namespace Exiv2 #endif diff --git a/include/exiv2/image.hpp b/include/exiv2/image.hpp index d991e556..4887b988 100644 --- a/include/exiv2/image.hpp +++ b/include/exiv2/image.hpp @@ -9,664 +9,667 @@ // included header files #include "basicio.hpp" #include "exif.hpp" -#include "iptc.hpp" #include "image_types.hpp" +#include "iptc.hpp" #include "xmp_exiv2.hpp" // ***************************************************************************** // namespace extensions namespace Exiv2 { - // ***************************************************************************** // class definitions - //! Native preview information. This is meant to be used only by the PreviewManager. - struct NativePreview { - size_t position_; //!< Position - size_t size_; //!< Size - size_t width_; //!< Width - size_t height_; //!< Height - std::string filter_; //!< Filter - std::string mimeType_; //!< MIME type - }; - - //! List of native previews. This is meant to be used only by the PreviewManager. - using NativePreviewList = std::vector; - - /*! - @brief Options for printStructure - */ - enum PrintStructureOption { kpsNone, kpsBasic, kpsXMP, kpsRecursive, kpsIccProfile, kpsIptcErase }; - - /*! - @brief Abstract base class defining the interface for an image. This is - the top-level interface to the Exiv2 library. - - Image has containers to store image metadata and subclasses implement - read and save metadata from and to specific image formats.
- Most client apps will obtain an Image instance by calling a static - ImageFactory method. The Image class can then be used to to read, write, - and save metadata. - */ - class EXIV2API Image { - public: - //! Image auto_ptr type - using UniquePtr = std::unique_ptr; - - //! @name Creators - //@{ - /*! - @brief Constructor taking the image type, a bitmap of the supported - metadata types and an auto-pointer that owns an IO instance. - See subclass constructor doc. - */ - Image(ImageType type, uint16_t supportedMetadata, BasicIo::UniquePtr io); - //! Virtual Destructor - virtual ~Image() = default; - //@} - - //! @name Manipulators - //@{ - /*! - @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. - @warning You may need to put the stream into binary mode (see src/actions.cpp) - */ - virtual void printStructure(std::ostream& out, PrintStructureOption option =kpsNone, int depth=0); - /*! - @brief Read all metadata supported by a specific image format from the - image. Before this method is called, the image metadata will be - cleared. - - This method returns success even if no metadata is found in the - image. Callers must therefore check the size of individual metadata - types before accessing the data. - - @throw Error if opening or reading of the file fails or the image - data is not valid (does not look like data of the specific image - type). - */ - virtual void readMetadata() =0; - /*! - @brief Write metadata back to the image. - - All existing metadata sections in the image are either created, - replaced, or erased. If values for a given metadata type have been - assigned, a section for that metadata type will either be created or - replaced. If no values have been assigned to a given metadata type, - any exists section for that metadata type will be removed from the - image. - - @throw Error if the operation fails - */ - virtual void writeMetadata() =0; - /*! - @brief Assign new Exif data. The new Exif data is not written - to the image until the writeMetadata() method is called. - @param exifData An ExifData instance holding Exif data to be copied - */ - virtual void setExifData(const ExifData& exifData); - /*! - @brief Erase any buffered Exif data. Exif data is not removed from - the actual image until the writeMetadata() method is called. - */ - virtual void clearExifData(); - /*! - @brief Assign new IPTC data. The new IPTC data is not written - to the image until the writeMetadata() method is called. - @param iptcData An IptcData instance holding IPTC data to be copied - */ - virtual void setIptcData(const IptcData& iptcData); - /*! - @brief Erase any buffered IPTC data. IPTC data is not removed from - the actual image until the writeMetadata() method is called. - */ - virtual void clearIptcData(); - /*! - @brief Assign a raw XMP packet. The new XMP packet is not written - to the image until the writeMetadata() method is called. - - Subsequent calls to writeMetadata() write the XMP packet from - the buffered raw XMP packet rather than from buffered parsed XMP - data. In order to write from parsed XMP data again, use - either writeXmpFromPacket(false) or setXmpData(). - - @param xmpPacket A string containing the raw XMP packet. - */ - virtual void setXmpPacket(const std::string& xmpPacket); - /*! - @brief Erase the buffered XMP packet. XMP data is not removed from - the actual image until the writeMetadata() method is called. - - This has the same effect as clearXmpData() but operates on the - buffered raw XMP packet only, not the parsed XMP data. - - Subsequent calls to writeMetadata() write the XMP packet from - the buffered raw XMP packet rather than from buffered parsed XMP - data. In order to write from parsed XMP data again, use - either writeXmpFromPacket(false) or setXmpData(). - */ - virtual void clearXmpPacket(); - /*! - @brief Assign new XMP data. The new XMP data is not written - to the image until the writeMetadata() method is called. - - Subsequent calls to writeMetadata() encode the XMP data to - a raw XMP packet and write the newly encoded packet to the image. - In the process, the buffered raw XMP packet is updated. - In order to write directly from the raw XMP packet, use - writeXmpFromPacket(true) or setXmpPacket(). - - @param xmpData An XmpData instance holding XMP data to be copied - */ - virtual void setXmpData(const XmpData& xmpData); - /*! - @brief Erase any buffered XMP data. XMP data is not removed from - the actual image until the writeMetadata() method is called. - - This has the same effect as clearXmpPacket() but operates on the - buffered parsed XMP data. - - Subsequent calls to writeMetadata() encode the XMP data to - a raw XMP packet and write the newly encoded packet to the image. - In the process, the buffered raw XMP packet is updated. - In order to write directly from the raw XMP packet, use - writeXmpFromPacket(true) or setXmpPacket(). - */ - virtual void clearXmpData(); - - /// @brief Set the image comment. The comment is written to the image when writeMetadata() is called. - virtual void setComment(std::string_view comment); - - /*! - @brief Erase any buffered comment. Comment is not removed - from the actual image until the writeMetadata() method is called. - */ - virtual void clearComment(); - /*! - @brief Set the image iccProfile. The new profile is not written - to the image until the writeMetadata() method is called. - @param iccProfile DataBuf containing profile (binary) - @param bTestValid - tests that iccProfile contains credible data - */ - virtual void setIccProfile(DataBuf&& iccProfile,bool bTestValid=true); - /*! - @brief Erase iccProfile. the profile is not removed from - the actual image until the writeMetadata() method is called. - */ - virtual void clearIccProfile(); - /*! - @brief Returns the status of the ICC profile in the image instance - */ - virtual bool iccProfileDefined() - { - return iccProfile_.size() != 0; - } - - /*! - @brief return iccProfile - */ - virtual const DataBuf& iccProfile() const { return iccProfile_; } - - /*! - @brief Copy all existing metadata from source Image. The data is - copied into internal buffers and is not written to the image - until the writeMetadata() method is called. - @param image Metadata source. All metadata types are copied. - */ - virtual void setMetadata(const Image& image); - /*! - @brief Erase all buffered metadata. Metadata is not removed - from the actual image until the writeMetadata() method is called. - */ - virtual void clearMetadata(); - /*! - @brief Returns an ExifData instance containing currently buffered - Exif data. - - The contained Exif data may have been read from the image by - a previous call to readMetadata() or added directly. The Exif - data in the returned instance will be written to the image when - writeMetadata() is called. - - @return modifiable ExifData instance containing Exif values - */ - virtual ExifData& exifData(); - /*! - @brief Returns an IptcData instance containing currently buffered - IPTC data. - - The contained IPTC data may have been read from the image by - a previous call to readMetadata() or added directly. The IPTC - data in the returned instance will be written to the image when - writeMetadata() is called. - - @return modifiable IptcData instance containing IPTC values - */ - virtual IptcData& iptcData(); - /*! - @brief Returns an XmpData instance containing currently buffered - XMP data. - - The contained XMP data may have been read from the image by - a previous call to readMetadata() or added directly. The XMP - data in the returned instance will be written to the image when - writeMetadata() is called. - - @return modifiable XmpData instance containing XMP values - */ - virtual XmpData& xmpData(); - /*! - @brief Return a modifiable reference to the raw XMP packet. - */ - virtual std::string& xmpPacket(); - /*! - @brief Determine the source when writing XMP. - - Depending on the setting of this flag, writeMetadata() writes - XMP from the buffered raw XMP packet or from parsed XMP data. - The default is to write from parsed XMP data. The switch is also - set by all functions to set and clear the buffered raw XMP packet - and parsed XMP data, so using this function should usually not be - necessary. - - If %Exiv2 was compiled without XMP support, the default for this - flag is true and it will never be changed in order to preserve - access to the raw XMP packet. - */ - void writeXmpFromPacket(bool flag); - /*! - @brief Set the byte order to encode the Exif metadata in. - - The setting is only used when new Exif metadata is created and may - not be applicable at all for some image formats. If the target image - already contains Exif metadata, the byte order of the existing data - is used. If byte order is not set when writeMetadata() is called, - little-endian byte order (II) is used by default. - */ - void setByteOrder(ByteOrder byteOrder); - - /*! - @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). - */ - void printTiffStructure(BasicIo& io,std::ostream& out, PrintStructureOption option,int depth,size_t offset=0); - - /*! - @brief Print out the structure of a TIFF IFD - */ - void printIFDStructure(BasicIo& io, std::ostream& out, Exiv2::PrintStructureOption option, size_t start, bool bSwap, char c, int depth); - - /*! - @brief is the host platform bigEndian - */ - static bool isBigEndianPlatform(); - - /*! - @brief is the host platform littleEndian - */ - static bool isLittleEndianPlatform(); - - static bool isStringType(uint16_t type); - static bool isShortType(uint16_t type); - static bool isLongType(uint16_t type); - static bool isLongLongType(uint16_t type); - static bool isRationalType(uint16_t type); - static bool is2ByteType(uint16_t type); - static bool is4ByteType(uint16_t type); - static bool is8ByteType(uint16_t type); - static bool isPrintXMP(uint16_t type, Exiv2::PrintStructureOption option); - static bool isPrintICC(uint16_t type, Exiv2::PrintStructureOption option); - - static uint64_t byteSwap(uint64_t value, bool bSwap); - static uint32_t byteSwap(uint32_t value, bool bSwap); - static uint16_t byteSwap(uint16_t value, bool bSwap); - static uint16_t byteSwap2(const DataBuf& buf,size_t offset,bool bSwap) ; - static uint32_t byteSwap4(const DataBuf& buf,size_t offset,bool bSwap) ; - static uint64_t byteSwap8(const DataBuf& buf,size_t offset,bool bSwap) ; - - //@} - - //! @name Accessors - //@{ - /*! - @brief Return the byte order in which the Exif metadata of the image is - encoded. Initially, it is not set (\em invalidByteOrder). - */ - ByteOrder byteOrder() const; - - /*! @brief Check if the Image instance is valid. Use after object construction. - @return true if the Image is in a valid state. - */ - bool good() const; - /*! - @brief Return the MIME type of the image. - - @note For each supported image format, the library knows only one MIME - type. This may not be the most specific MIME type for that format. In - particular, several RAW formats are variants of the TIFF format with - the same magic as TIFF itself. Class TiffImage handles most of them - and thus they all have MIME type "image/tiff", although a more - specific MIME type may exist (e.g., "image/x-nikon-nef"). - */ - virtual std::string mimeType() const =0; - /*! - @brief Return the pixel width of the image. - */ - virtual uint32_t pixelWidth() const; - /*! - @brief Return the pixel height of the image. - */ - virtual uint32_t pixelHeight() const; - /*! - @brief Returns an ExifData instance containing currently buffered - Exif data. - - The Exif data may have been read from the image by - a previous call to readMetadata() or added directly. The Exif - data in the returned instance will be written to the image when - writeMetadata() is called. - - @return read only ExifData instance containing Exif values - */ - virtual const ExifData& exifData() const; - /*! - @brief Returns an IptcData instance containing currently buffered - IPTC data. - - The contained IPTC data may have been read from the image by - a previous call to readMetadata() or added directly. The IPTC - data in the returned instance will be written to the image when - writeMetadata() is called. - - @return modifiable IptcData instance containing IPTC values - */ - virtual const IptcData& iptcData() const; - /*! - @brief Returns an XmpData instance containing currently buffered - XMP data. - - The contained XMP data may have been read from the image by - a previous call to readMetadata() or added directly. The XMP - data in the returned instance will be written to the image when - writeMetadata() is called. - - @return modifiable XmpData instance containing XMP values - */ - virtual const XmpData& xmpData() const; - /*! - @brief Return a copy of the image comment. May be an empty string. - */ - virtual std::string comment() const; - /*! - @brief Return the raw XMP packet as a string. - */ - virtual const std::string& xmpPacket() const; - /*! - @brief Return a reference to the BasicIo instance being used for Io. - - This refence is particularly useful to reading the results of - operations on a MemIo instance. For example after metadata has - been modified and the writeMetadata() method has been called, - this method can be used to get access to the modified image. - - @return BasicIo instance that can be used to read or write image - data directly. - @note If the returned BasicIo is used to write to the image, the - Image class will not see those changes until the readMetadata() - method is called. - */ - virtual BasicIo& io() const; - /*! - @brief Returns the access mode, i.e., the metadata functions, which - this image supports for the metadata type \em metadataId. - @param metadataId The metadata identifier. - @return Access mode for the requested image type and metadata identifier. - */ - AccessMode checkMode(MetadataId metadataId) const; - /*! - @brief Check if image supports a particular type of metadata. - This method is deprecated. Use checkMode() instead. - */ - bool supportsMetadata(MetadataId metadataId) const; - //! Return the flag indicating the source when writing XMP metadata. - bool writeXmpFromPacket() const; - //! Return list of native previews. This is meant to be used only by the PreviewManager. - const NativePreviewList& nativePreviews() const; - //@} - - //! set type support for this image format - void setTypeSupported(ImageType imageType, uint16_t supportedMetadata) - { - imageType_ = imageType; - supportedMetadata_ = supportedMetadata; - } - - //! set type support for this image format - ImageType imageType() const { return imageType_; } - - //! @name NOT implemented - //@{ - //! Copy constructor - Image(const Image& rhs) = delete; - //! Assignment operator - Image& operator=(const Image& rhs) = delete; - //@} - - protected: - // DATA - BasicIo::UniquePtr io_; //!< Image data IO pointer - ExifData exifData_; //!< Exif data container - IptcData iptcData_; //!< IPTC data container - XmpData xmpData_; //!< XMP data container - DataBuf iccProfile_; //!< ICC buffer (binary data) - std::string comment_; //!< User comment - std::string xmpPacket_; //!< XMP packet - uint32_t pixelWidth_; //!< image pixel width - uint32_t pixelHeight_; //!< image pixel height - NativePreviewList nativePreviews_; //!< list of native previews - - //! Return tag name for given tag id. - const std::string& tagName(uint16_t tag); - - //! Return tag type for given tag id. - static const char* typeName(uint16_t tag); - - private: - // DATA - ImageType imageType_; //!< Image type - uint16_t supportedMetadata_; //!< Bitmap with all supported metadata types - bool writeXmpFromPacket_;//!< Determines the source when writing XMP - ByteOrder byteOrder_; //!< Byte order - - std::map tags_; //!< Map of tags - bool init_; //!< Flag marking if map of tags needs to be initialized - - }; // class Image - - //! Type for function pointer that creates new Image instances - using NewInstanceFct = Image::UniquePtr (*)(BasicIo::UniquePtr io, bool create); - //! Type for function pointer that checks image types - using IsThisTypeFct = bool (*)(BasicIo& iIo, bool advance); - - /*! - @brief Returns an Image instance of the specified type. - - The factory is implemented as a static class. - */ - class EXIV2API ImageFactory { - friend bool Image::good() const; - public: - /*! - @brief Create the appropriate class type implemented BasicIo based on the protocol of the input. - - "-" path implies the data from stdin and it is handled by StdinIo. - Http path can be handled by either HttpIo or CurlIo. Https, ftp paths - are handled by CurlIo. Ssh, sftp paths are handled by SshIo. Others are handled by FileIo. - - @param path %Image file. - @param useCurl Indicate whether the libcurl is used or not. - If it's true, http is handled by CurlIo. Otherwise it is handled by HttpIo. - @return An auto-pointer that owns an BasicIo instance. - @throw Error If the file is not found or it is unable to connect to the server to - read the remote file. - */ - static BasicIo::UniquePtr createIo(const std::string& path, bool useCurl = true); - - /*! - @brief Create an Image subclass of the appropriate type by reading - the specified file. %Image type is derived from the file - contents. - @param path %Image file. The contents of the file are tested to - determine the image type. File extension is ignored. - @param useCurl Indicate whether the libcurl is used or not. - If it's true, http is handled by CurlIo. Otherwise it is handled by HttpIo. - @return An auto-pointer that owns an Image instance whose type - matches that of the file. - @throw Error If opening the file fails or it contains data of an - unknown image type. - */ - static Image::UniquePtr open(const std::string& path, bool useCurl = true); - - /*! - @brief Create an Image subclass of the appropriate type by reading - the provided memory. %Image type is derived from the memory - contents. - @param data Pointer to a data buffer containing an image. The contents - of the memory are tested to determine the image type. - @param size Number of bytes pointed to by \em data. - @return An auto-pointer that owns an Image instance whose type - matches that of the data buffer. - @throw Error If the memory contains data of an unknown image type. - */ - static Image::UniquePtr open(const byte* data, size_t size); - /*! - @brief Create an Image subclass of the appropriate type by reading - the provided BasicIo instance. %Image type is derived from the - data provided by \em io. The passed in \em io instance is - (re)opened by this method. - @param io An auto-pointer that owns a BasicIo instance that provides - image data. The contents of the image data are tested to determine - the type. - @note This method 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. - @return An auto-pointer that owns an Image instance whose type - matches that of the \em io data. If no image type could be - determined, the pointer is 0. - @throw Error If opening the BasicIo fails - */ - static Image::UniquePtr open(BasicIo::UniquePtr io); - /*! - @brief Create an Image subclass of the requested type by creating a - new image file. If the file already exists, it will be overwritten. - @param type Type of the image to be created. - @param path %Image file to create. File extension is ignored. - @return An auto-pointer that owns an Image instance of the requested - type. - @throw Error If the image type is not supported. - */ - static Image::UniquePtr create(ImageType type, const std::string& path); - /*! - @brief Create an Image subclass of the requested type by creating a - new image in memory. - @param type Type of the image to be created. - @return An auto-pointer that owns an Image instance of the requested - type. - @throw Error If the image type is not supported - */ - static Image::UniquePtr create(ImageType type); - - /*! - @brief Create an Image subclass of the requested type by writing a - new image to a BasicIo instance. If the BasicIo instance already - contains data, it will be overwritten. - @param type Type of the image to be created. - @param io An auto-pointer that owns a BasicIo instance that will - be written to when creating a new image. - @note This method 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. - @return An auto-pointer that owns an Image instance of the requested - type. If the image type is not supported, the pointer is 0. - */ - - static Image::UniquePtr create(ImageType type, BasicIo::UniquePtr io); - /*! - @brief Returns the image type of the provided file. - @param path %Image file. The contents of the file are tested to - determine the image type. File extension is ignored. - @return %Image type or Image::none if the type is not recognized. - */ - static ImageType getType(const std::string& path); - /*! - @brief Returns the image type of the provided data buffer. - @param data Pointer to a data buffer containing an image. The contents - of the memory are tested to determine the image type. - @param size Number of bytes pointed to by \em data. - @return %Image type or Image::none if the type is not recognized. - */ - static ImageType getType(const byte* data, size_t size); - /*! - @brief Returns the image type of data provided by a BasicIo instance. - The passed in \em io instance is (re)opened by this method. - @param io A BasicIo instance that provides image data. The contents - of the image data are tested to determine the type. - @return %Image type or Image::none if the type is not recognized. - */ - static ImageType getType(BasicIo& io); - /*! - @brief Returns the access mode or supported metadata functions for an - image type and a metadata type. - @param type The image type. - @param metadataId The metadata identifier. - @return Access mode for the requested image type and metadata identifier. - @throw Error(kerUnsupportedImageType) if the image type is not supported. - */ - static AccessMode checkMode(ImageType type, MetadataId metadataId); - /*! - @brief Determine if the content of \em io is an image of \em type. - - The \em advance flag determines if the read position in the - stream is moved (see below). This applies only if the type - matches and the function returns true. If the type does not - match, the stream position is not changed. However, if - reading from the stream fails, the stream position is - undefined. Consult the stream state to obtain more - information in this case. - - @param type Type of the image. - @param io BasicIo instance to read from. - @param advance Flag indicating whether the position of the io - should be advanced by the number of characters read to - analyse the data (true) or left at its original - position (false). This applies only if the type matches. - @return true if the data matches the type of this class;
- false if the data does not match - */ - static bool checkType(ImageType type, BasicIo& io, bool advance); - - //! @name Creators - //@{ - //! Prevent construction: not implemented. - ImageFactory() = delete; - //! Prevent copy construction: not implemented. - ImageFactory(const ImageFactory& rhs) = delete; - //@} - - }; // class ImageFactory +//! Native preview information. This is meant to be used only by the PreviewManager. +struct NativePreview { + size_t position_; //!< Position + size_t size_; //!< Size + size_t width_; //!< Width + size_t height_; //!< Height + std::string filter_; //!< Filter + std::string mimeType_; //!< MIME type +}; + +//! List of native previews. This is meant to be used only by the PreviewManager. +using NativePreviewList = std::vector; + +/*! + @brief Options for printStructure + */ +enum PrintStructureOption { kpsNone, kpsBasic, kpsXMP, kpsRecursive, kpsIccProfile, kpsIptcErase }; + +/*! + @brief Abstract base class defining the interface for an image. This is + the top-level interface to the Exiv2 library. + + Image has containers to store image metadata and subclasses implement + read and save metadata from and to specific image formats.
+ Most client apps will obtain an Image instance by calling a static + ImageFactory method. The Image class can then be used to to read, write, + and save metadata. + */ +class EXIV2API Image { + public: + //! Image auto_ptr type + using UniquePtr = std::unique_ptr; + + //! @name Creators + //@{ + /*! + @brief Constructor taking the image type, a bitmap of the supported + metadata types and an auto-pointer that owns an IO instance. + See subclass constructor doc. + */ + Image(ImageType type, uint16_t supportedMetadata, BasicIo::UniquePtr io); + //! Virtual Destructor + virtual ~Image() = default; + //@} + + //! @name Manipulators + //@{ + /*! + @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. + @warning You may need to put the stream into binary mode (see src/actions.cpp) + */ + virtual void printStructure(std::ostream& out, PrintStructureOption option = kpsNone, int depth = 0); + /*! + @brief Read all metadata supported by a specific image format from the + image. Before this method is called, the image metadata will be + cleared. + + This method returns success even if no metadata is found in the + image. Callers must therefore check the size of individual metadata + types before accessing the data. + + @throw Error if opening or reading of the file fails or the image + data is not valid (does not look like data of the specific image + type). + */ + virtual void readMetadata() = 0; + /*! + @brief Write metadata back to the image. + + All existing metadata sections in the image are either created, + replaced, or erased. If values for a given metadata type have been + assigned, a section for that metadata type will either be created or + replaced. If no values have been assigned to a given metadata type, + any exists section for that metadata type will be removed from the + image. + + @throw Error if the operation fails + */ + virtual void writeMetadata() = 0; + /*! + @brief Assign new Exif data. The new Exif data is not written + to the image until the writeMetadata() method is called. + @param exifData An ExifData instance holding Exif data to be copied + */ + virtual void setExifData(const ExifData& exifData); + /*! + @brief Erase any buffered Exif data. Exif data is not removed from + the actual image until the writeMetadata() method is called. + */ + virtual void clearExifData(); + /*! + @brief Assign new IPTC data. The new IPTC data is not written + to the image until the writeMetadata() method is called. + @param iptcData An IptcData instance holding IPTC data to be copied + */ + virtual void setIptcData(const IptcData& iptcData); + /*! + @brief Erase any buffered IPTC data. IPTC data is not removed from + the actual image until the writeMetadata() method is called. + */ + virtual void clearIptcData(); + /*! + @brief Assign a raw XMP packet. The new XMP packet is not written + to the image until the writeMetadata() method is called. + + Subsequent calls to writeMetadata() write the XMP packet from + the buffered raw XMP packet rather than from buffered parsed XMP + data. In order to write from parsed XMP data again, use + either writeXmpFromPacket(false) or setXmpData(). + + @param xmpPacket A string containing the raw XMP packet. + */ + virtual void setXmpPacket(const std::string& xmpPacket); + /*! + @brief Erase the buffered XMP packet. XMP data is not removed from + the actual image until the writeMetadata() method is called. + + This has the same effect as clearXmpData() but operates on the + buffered raw XMP packet only, not the parsed XMP data. + + Subsequent calls to writeMetadata() write the XMP packet from + the buffered raw XMP packet rather than from buffered parsed XMP + data. In order to write from parsed XMP data again, use + either writeXmpFromPacket(false) or setXmpData(). + */ + virtual void clearXmpPacket(); + /*! + @brief Assign new XMP data. The new XMP data is not written + to the image until the writeMetadata() method is called. + + Subsequent calls to writeMetadata() encode the XMP data to + a raw XMP packet and write the newly encoded packet to the image. + In the process, the buffered raw XMP packet is updated. + In order to write directly from the raw XMP packet, use + writeXmpFromPacket(true) or setXmpPacket(). + + @param xmpData An XmpData instance holding XMP data to be copied + */ + virtual void setXmpData(const XmpData& xmpData); + /*! + @brief Erase any buffered XMP data. XMP data is not removed from + the actual image until the writeMetadata() method is called. + + This has the same effect as clearXmpPacket() but operates on the + buffered parsed XMP data. + + Subsequent calls to writeMetadata() encode the XMP data to + a raw XMP packet and write the newly encoded packet to the image. + In the process, the buffered raw XMP packet is updated. + In order to write directly from the raw XMP packet, use + writeXmpFromPacket(true) or setXmpPacket(). + */ + virtual void clearXmpData(); + + /// @brief Set the image comment. The comment is written to the image when writeMetadata() is called. + virtual void setComment(std::string_view comment); + + /*! + @brief Erase any buffered comment. Comment is not removed + from the actual image until the writeMetadata() method is called. + */ + virtual void clearComment(); + /*! + @brief Set the image iccProfile. The new profile is not written + to the image until the writeMetadata() method is called. + @param iccProfile DataBuf containing profile (binary) + @param bTestValid - tests that iccProfile contains credible data + */ + virtual void setIccProfile(DataBuf&& iccProfile, bool bTestValid = true); + /*! + @brief Erase iccProfile. the profile is not removed from + the actual image until the writeMetadata() method is called. + */ + virtual void clearIccProfile(); + /*! + @brief Returns the status of the ICC profile in the image instance + */ + virtual bool iccProfileDefined() { + return iccProfile_.size() != 0; + } + + /*! + @brief return iccProfile + */ + virtual const DataBuf& iccProfile() const { + return iccProfile_; + } + + /*! + @brief Copy all existing metadata from source Image. The data is + copied into internal buffers and is not written to the image + until the writeMetadata() method is called. + @param image Metadata source. All metadata types are copied. + */ + virtual void setMetadata(const Image& image); + /*! + @brief Erase all buffered metadata. Metadata is not removed + from the actual image until the writeMetadata() method is called. + */ + virtual void clearMetadata(); + /*! + @brief Returns an ExifData instance containing currently buffered + Exif data. + + The contained Exif data may have been read from the image by + a previous call to readMetadata() or added directly. The Exif + data in the returned instance will be written to the image when + writeMetadata() is called. + + @return modifiable ExifData instance containing Exif values + */ + virtual ExifData& exifData(); + /*! + @brief Returns an IptcData instance containing currently buffered + IPTC data. + + The contained IPTC data may have been read from the image by + a previous call to readMetadata() or added directly. The IPTC + data in the returned instance will be written to the image when + writeMetadata() is called. + + @return modifiable IptcData instance containing IPTC values + */ + virtual IptcData& iptcData(); + /*! + @brief Returns an XmpData instance containing currently buffered + XMP data. + + The contained XMP data may have been read from the image by + a previous call to readMetadata() or added directly. The XMP + data in the returned instance will be written to the image when + writeMetadata() is called. + + @return modifiable XmpData instance containing XMP values + */ + virtual XmpData& xmpData(); + /*! + @brief Return a modifiable reference to the raw XMP packet. + */ + virtual std::string& xmpPacket(); + /*! + @brief Determine the source when writing XMP. + + Depending on the setting of this flag, writeMetadata() writes + XMP from the buffered raw XMP packet or from parsed XMP data. + The default is to write from parsed XMP data. The switch is also + set by all functions to set and clear the buffered raw XMP packet + and parsed XMP data, so using this function should usually not be + necessary. + + If %Exiv2 was compiled without XMP support, the default for this + flag is true and it will never be changed in order to preserve + access to the raw XMP packet. + */ + void writeXmpFromPacket(bool flag); + /*! + @brief Set the byte order to encode the Exif metadata in. + + The setting is only used when new Exif metadata is created and may + not be applicable at all for some image formats. If the target image + already contains Exif metadata, the byte order of the existing data + is used. If byte order is not set when writeMetadata() is called, + little-endian byte order (II) is used by default. + */ + void setByteOrder(ByteOrder byteOrder); + + /*! + @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). + */ + void printTiffStructure(BasicIo& io, std::ostream& out, PrintStructureOption option, int depth, size_t offset = 0); + + /*! + @brief Print out the structure of a TIFF IFD + */ + void printIFDStructure(BasicIo& io, std::ostream& out, Exiv2::PrintStructureOption option, size_t start, bool bSwap, + char c, int depth); + + /*! + @brief is the host platform bigEndian + */ + static bool isBigEndianPlatform(); + + /*! + @brief is the host platform littleEndian + */ + static bool isLittleEndianPlatform(); + + static bool isStringType(uint16_t type); + static bool isShortType(uint16_t type); + static bool isLongType(uint16_t type); + static bool isLongLongType(uint16_t type); + static bool isRationalType(uint16_t type); + static bool is2ByteType(uint16_t type); + static bool is4ByteType(uint16_t type); + static bool is8ByteType(uint16_t type); + static bool isPrintXMP(uint16_t type, Exiv2::PrintStructureOption option); + static bool isPrintICC(uint16_t type, Exiv2::PrintStructureOption option); + + static uint64_t byteSwap(uint64_t value, bool bSwap); + static uint32_t byteSwap(uint32_t value, bool bSwap); + static uint16_t byteSwap(uint16_t value, bool bSwap); + static uint16_t byteSwap2(const DataBuf& buf, size_t offset, bool bSwap); + static uint32_t byteSwap4(const DataBuf& buf, size_t offset, bool bSwap); + static uint64_t byteSwap8(const DataBuf& buf, size_t offset, bool bSwap); + + //@} + + //! @name Accessors + //@{ + /*! + @brief Return the byte order in which the Exif metadata of the image is + encoded. Initially, it is not set (\em invalidByteOrder). + */ + ByteOrder byteOrder() const; + + /*! @brief Check if the Image instance is valid. Use after object construction. + @return true if the Image is in a valid state. + */ + bool good() const; + /*! + @brief Return the MIME type of the image. + + @note For each supported image format, the library knows only one MIME + type. This may not be the most specific MIME type for that format. In + particular, several RAW formats are variants of the TIFF format with + the same magic as TIFF itself. Class TiffImage handles most of them + and thus they all have MIME type "image/tiff", although a more + specific MIME type may exist (e.g., "image/x-nikon-nef"). + */ + virtual std::string mimeType() const = 0; + /*! + @brief Return the pixel width of the image. + */ + virtual uint32_t pixelWidth() const; + /*! + @brief Return the pixel height of the image. + */ + virtual uint32_t pixelHeight() const; + /*! + @brief Returns an ExifData instance containing currently buffered + Exif data. + + The Exif data may have been read from the image by + a previous call to readMetadata() or added directly. The Exif + data in the returned instance will be written to the image when + writeMetadata() is called. + + @return read only ExifData instance containing Exif values + */ + virtual const ExifData& exifData() const; + /*! + @brief Returns an IptcData instance containing currently buffered + IPTC data. + + The contained IPTC data may have been read from the image by + a previous call to readMetadata() or added directly. The IPTC + data in the returned instance will be written to the image when + writeMetadata() is called. + + @return modifiable IptcData instance containing IPTC values + */ + virtual const IptcData& iptcData() const; + /*! + @brief Returns an XmpData instance containing currently buffered + XMP data. + + The contained XMP data may have been read from the image by + a previous call to readMetadata() or added directly. The XMP + data in the returned instance will be written to the image when + writeMetadata() is called. + + @return modifiable XmpData instance containing XMP values + */ + virtual const XmpData& xmpData() const; + /*! + @brief Return a copy of the image comment. May be an empty string. + */ + virtual std::string comment() const; + /*! + @brief Return the raw XMP packet as a string. + */ + virtual const std::string& xmpPacket() const; + /*! + @brief Return a reference to the BasicIo instance being used for Io. + + This refence is particularly useful to reading the results of + operations on a MemIo instance. For example after metadata has + been modified and the writeMetadata() method has been called, + this method can be used to get access to the modified image. + + @return BasicIo instance that can be used to read or write image + data directly. + @note If the returned BasicIo is used to write to the image, the + Image class will not see those changes until the readMetadata() + method is called. + */ + virtual BasicIo& io() const; + /*! + @brief Returns the access mode, i.e., the metadata functions, which + this image supports for the metadata type \em metadataId. + @param metadataId The metadata identifier. + @return Access mode for the requested image type and metadata identifier. + */ + AccessMode checkMode(MetadataId metadataId) const; + /*! + @brief Check if image supports a particular type of metadata. + This method is deprecated. Use checkMode() instead. + */ + bool supportsMetadata(MetadataId metadataId) const; + //! Return the flag indicating the source when writing XMP metadata. + bool writeXmpFromPacket() const; + //! Return list of native previews. This is meant to be used only by the PreviewManager. + const NativePreviewList& nativePreviews() const; + //@} + + //! set type support for this image format + void setTypeSupported(ImageType imageType, uint16_t supportedMetadata) { + imageType_ = imageType; + supportedMetadata_ = supportedMetadata; + } + + //! set type support for this image format + ImageType imageType() const { + return imageType_; + } + + //! @name NOT implemented + //@{ + //! Copy constructor + Image(const Image& rhs) = delete; + //! Assignment operator + Image& operator=(const Image& rhs) = delete; + //@} + + protected: + // DATA + BasicIo::UniquePtr io_; //!< Image data IO pointer + ExifData exifData_; //!< Exif data container + IptcData iptcData_; //!< IPTC data container + XmpData xmpData_; //!< XMP data container + DataBuf iccProfile_; //!< ICC buffer (binary data) + std::string comment_; //!< User comment + std::string xmpPacket_; //!< XMP packet + uint32_t pixelWidth_; //!< image pixel width + uint32_t pixelHeight_; //!< image pixel height + NativePreviewList nativePreviews_; //!< list of native previews + + //! Return tag name for given tag id. + const std::string& tagName(uint16_t tag); + + //! Return tag type for given tag id. + static const char* typeName(uint16_t tag); + + private: + // DATA + ImageType imageType_; //!< Image type + uint16_t supportedMetadata_; //!< Bitmap with all supported metadata types + bool writeXmpFromPacket_; //!< Determines the source when writing XMP + ByteOrder byteOrder_; //!< Byte order + + std::map tags_; //!< Map of tags + bool init_; //!< Flag marking if map of tags needs to be initialized + +}; // class Image + +//! Type for function pointer that creates new Image instances +using NewInstanceFct = Image::UniquePtr (*)(BasicIo::UniquePtr io, bool create); +//! Type for function pointer that checks image types +using IsThisTypeFct = bool (*)(BasicIo& iIo, bool advance); + +/*! + @brief Returns an Image instance of the specified type. + + The factory is implemented as a static class. +*/ +class EXIV2API ImageFactory { + friend bool Image::good() const; + + public: + /*! + @brief Create the appropriate class type implemented BasicIo based on the protocol of the input. + + "-" path implies the data from stdin and it is handled by StdinIo. + Http path can be handled by either HttpIo or CurlIo. Https, ftp paths + are handled by CurlIo. Ssh, sftp paths are handled by SshIo. Others are handled by FileIo. + + @param path %Image file. + @param useCurl Indicate whether the libcurl is used or not. + If it's true, http is handled by CurlIo. Otherwise it is handled by HttpIo. + @return An auto-pointer that owns an BasicIo instance. + @throw Error If the file is not found or it is unable to connect to the server to + read the remote file. + */ + static BasicIo::UniquePtr createIo(const std::string& path, bool useCurl = true); + + /*! + @brief Create an Image subclass of the appropriate type by reading + the specified file. %Image type is derived from the file + contents. + @param path %Image file. The contents of the file are tested to + determine the image type. File extension is ignored. + @param useCurl Indicate whether the libcurl is used or not. + If it's true, http is handled by CurlIo. Otherwise it is handled by HttpIo. + @return An auto-pointer that owns an Image instance whose type + matches that of the file. + @throw Error If opening the file fails or it contains data of an + unknown image type. + */ + static Image::UniquePtr open(const std::string& path, bool useCurl = true); + + /*! + @brief Create an Image subclass of the appropriate type by reading + the provided memory. %Image type is derived from the memory + contents. + @param data Pointer to a data buffer containing an image. The contents + of the memory are tested to determine the image type. + @param size Number of bytes pointed to by \em data. + @return An auto-pointer that owns an Image instance whose type + matches that of the data buffer. + @throw Error If the memory contains data of an unknown image type. + */ + static Image::UniquePtr open(const byte* data, size_t size); + /*! + @brief Create an Image subclass of the appropriate type by reading + the provided BasicIo instance. %Image type is derived from the + data provided by \em io. The passed in \em io instance is + (re)opened by this method. + @param io An auto-pointer that owns a BasicIo instance that provides + image data. The contents of the image data are tested to determine + the type. + @note This method 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. + @return An auto-pointer that owns an Image instance whose type + matches that of the \em io data. If no image type could be + determined, the pointer is 0. + @throw Error If opening the BasicIo fails + */ + static Image::UniquePtr open(BasicIo::UniquePtr io); + /*! + @brief Create an Image subclass of the requested type by creating a + new image file. If the file already exists, it will be overwritten. + @param type Type of the image to be created. + @param path %Image file to create. File extension is ignored. + @return An auto-pointer that owns an Image instance of the requested + type. + @throw Error If the image type is not supported. + */ + static Image::UniquePtr create(ImageType type, const std::string& path); + /*! + @brief Create an Image subclass of the requested type by creating a + new image in memory. + @param type Type of the image to be created. + @return An auto-pointer that owns an Image instance of the requested + type. + @throw Error If the image type is not supported + */ + static Image::UniquePtr create(ImageType type); + + /*! + @brief Create an Image subclass of the requested type by writing a + new image to a BasicIo instance. If the BasicIo instance already + contains data, it will be overwritten. + @param type Type of the image to be created. + @param io An auto-pointer that owns a BasicIo instance that will + be written to when creating a new image. + @note This method 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. + @return An auto-pointer that owns an Image instance of the requested + type. If the image type is not supported, the pointer is 0. + */ + + static Image::UniquePtr create(ImageType type, BasicIo::UniquePtr io); + /*! + @brief Returns the image type of the provided file. + @param path %Image file. The contents of the file are tested to + determine the image type. File extension is ignored. + @return %Image type or Image::none if the type is not recognized. + */ + static ImageType getType(const std::string& path); + /*! + @brief Returns the image type of the provided data buffer. + @param data Pointer to a data buffer containing an image. The contents + of the memory are tested to determine the image type. + @param size Number of bytes pointed to by \em data. + @return %Image type or Image::none if the type is not recognized. + */ + static ImageType getType(const byte* data, size_t size); + /*! + @brief Returns the image type of data provided by a BasicIo instance. + The passed in \em io instance is (re)opened by this method. + @param io A BasicIo instance that provides image data. The contents + of the image data are tested to determine the type. + @return %Image type or Image::none if the type is not recognized. + */ + static ImageType getType(BasicIo& io); + /*! + @brief Returns the access mode or supported metadata functions for an + image type and a metadata type. + @param type The image type. + @param metadataId The metadata identifier. + @return Access mode for the requested image type and metadata identifier. + @throw Error(kerUnsupportedImageType) if the image type is not supported. + */ + static AccessMode checkMode(ImageType type, MetadataId metadataId); + /*! + @brief Determine if the content of \em io is an image of \em type. + + The \em advance flag determines if the read position in the + stream is moved (see below). This applies only if the type + matches and the function returns true. If the type does not + match, the stream position is not changed. However, if + reading from the stream fails, the stream position is + undefined. Consult the stream state to obtain more + information in this case. + + @param type Type of the image. + @param io BasicIo instance to read from. + @param advance Flag indicating whether the position of the io + should be advanced by the number of characters read to + analyse the data (true) or left at its original + position (false). This applies only if the type matches. + @return true if the data matches the type of this class;
+ false if the data does not match + */ + static bool checkType(ImageType type, BasicIo& io, bool advance); + + //! @name Creators + //@{ + //! Prevent construction: not implemented. + ImageFactory() = delete; + //! Prevent copy construction: not implemented. + ImageFactory(const ImageFactory& rhs) = delete; + //@} + +}; // class ImageFactory // ***************************************************************************** // template, inline and free functions - //! Append \em len bytes pointed to by \em buf to \em blob. - EXIV2API void append(Exiv2::Blob& blob, const byte* buf, size_t len); +//! Append \em len bytes pointed to by \em buf to \em blob. +EXIV2API void append(Exiv2::Blob& blob, const byte* buf, size_t len); -} // namespace Exiv2 +} // namespace Exiv2 -#endif // #ifndef IMAGE_HPP_ +#endif // #ifndef IMAGE_HPP_ diff --git a/include/exiv2/image_types.hpp b/include/exiv2/image_types.hpp index 2c22ac55..3c559a95 100644 --- a/include/exiv2/image_types.hpp +++ b/include/exiv2/image_types.hpp @@ -3,40 +3,38 @@ #ifndef IMAGE_TYPES_H #define IMAGE_TYPES_H -namespace Exiv2 -{ - /// Supported Image Formats - enum class ImageType - { - none, - arw, - bigtiff, - bmff, - bmp, ///< Windows bitmap - cr2, - crw, - dng, - eps, - exv, - gif, ///< GIF - jp2, ///< JPEG-2000 - jpeg, - mrw, - nef, - orf, - pef, - png, - pgf, - psd, ///< Photoshop (PSD) - raf, - rw2, - sr2, - srw, - tga, - tiff, - webp, - xmp, ///< XMP sidecar files - }; +namespace Exiv2 { +/// Supported Image Formats +enum class ImageType { + none, + arw, + bigtiff, + bmff, + bmp, ///< Windows bitmap + cr2, + crw, + dng, + eps, + exv, + gif, ///< GIF + jp2, ///< JPEG-2000 + jpeg, + mrw, + nef, + orf, + pef, + png, + pgf, + psd, ///< Photoshop (PSD) + raf, + rw2, + sr2, + srw, + tga, + tiff, + webp, + xmp, ///< XMP sidecar files +}; } // namespace Exiv2 #endif // IMAGE_TYPES_H diff --git a/include/exiv2/ini.hpp b/include/exiv2/ini.hpp old mode 100755 new mode 100644 index 4b53244a..d6999be5 --- a/include/exiv2/ini.hpp +++ b/include/exiv2/ini.hpp @@ -17,7 +17,6 @@ #include namespace Exiv2 { - #ifndef __INI_H__ #define __INI_H__ @@ -72,8 +71,7 @@ int ini_parse_file(FILE* file, ini_handler handler, void* user); @return 0 on success */ -int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler, - void* user); +int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler, void* user); /*! @brief Nonzero to allow multi-line value parsing, in the style of Python's configparser. If allowed, ini_parse() will call the handler with the same @@ -122,76 +120,74 @@ int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler, #endif /* __INI_H__ */ - /*! @brief Read an INI file into easy-to-access name/value pairs. (Note that I've gone for simplicity here rather than speed, but it should be pretty decent.) */ -class EXIV2API INIReader -{ -public: - /*! @brief Construct INIReader and parse given filename. See ini.h for more info - about the parsing. - */ - explicit INIReader(const std::string& filename); +class EXIV2API INIReader { + public: + /*! @brief Construct INIReader and parse given filename. See ini.h for more info + about the parsing. + */ + explicit INIReader(const std::string& filename); - /*! @brief Return the result of ini_parse(), i.e., 0 on success, line number of - first error on parse error, or -1 on file open error. - */ - int ParseError() const; + /*! @brief Return the result of ini_parse(), i.e., 0 on success, line number of + first error on parse error, or -1 on file open error. + */ + int ParseError() const; - /*! @brief Get a string value from INI file, returning default_value if not found. + /*! @brief Get a string value from INI file, returning default_value if not found. - @param section name of section - @param name name of key - @param default_value default if not found + @param section name of section + @param name name of key + @param default_value default if not found - @return value - */ - std::string Get(const std::string& section, const std::string& name, const std::string& default_value); + @return value + */ + std::string Get(const std::string& section, const std::string& name, const std::string& default_value); - /*! @brief Get an integer (long) value from INI file, returning default_value if - not found or not a valid integer (decimal "1234", "-1234", or hex "0x4d2"). + /*! @brief Get an integer (long) value from INI file, returning default_value if + not found or not a valid integer (decimal "1234", "-1234", or hex "0x4d2"). - @param section name of section - @param name name of key - @param default_value default if not found + @param section name of section + @param name name of key + @param default_value default if not found - @return value - */ - long GetInteger(const std::string& section, const std::string& name, long default_value); + @return value + */ + long GetInteger(const std::string& section, const std::string& name, long default_value); - /*! @brief Get a real (floating point double) value from INI file, returning - default_value if not found or not a valid floating point value - according to strtod(). + /*! @brief Get a real (floating point double) value from INI file, returning + default_value if not found or not a valid floating point value + according to strtod(). - @param section name of section - @param name name of key - @param default_value default if not found + @param section name of section + @param name name of key + @param default_value default if not found - @return value - */ - double GetReal(const std::string& section, const std::string& name, double default_value); + @return value + */ + double GetReal(const std::string& section, const std::string& name, double default_value); - /*! @brief Get a boolean value from INI file, returning default_value if not found or if - not a valid true/false value. Valid true values are "true", "yes", "on", "1", - and valid false values are "false", "no", "off", "0" (not case sensitive). + /*! @brief Get a boolean value from INI file, returning default_value if not found or if + not a valid true/false value. Valid true values are "true", "yes", "on", "1", + and valid false values are "false", "no", "off", "0" (not case sensitive). - @param section name of section - @param name name of key - @param default_value default if not found + @param section name of section + @param name name of key + @param default_value default if not found - @return value - */ - bool GetBoolean(const std::string& section, const std::string& name, bool default_value); + @return value + */ + bool GetBoolean(const std::string& section, const std::string& name, bool default_value); -private: - int _error; //!< status - std::map _values; //!< values from file - static std::string MakeKey(const std::string& section, - const std::string& name); //!< return key encoded from section/name - static int ValueHandler(void* user, const char* section, const char* name, - const char* value); //!< value handler + private: + int _error; //!< status + std::map _values; //!< values from file + static std::string MakeKey(const std::string& section, + const std::string& name); //!< return key encoded from section/name + static int ValueHandler(void* user, const char* section, const char* name, + const char* value); //!< value handler }; -} // namespace Exiv2 +} // namespace Exiv2 #endif // __INIREADER_H__ diff --git a/include/exiv2/iptc.hpp b/include/exiv2/iptc.hpp index d1e9375e..c9a745ed 100644 --- a/include/exiv2/iptc.hpp +++ b/include/exiv2/iptc.hpp @@ -11,285 +11,296 @@ #include "exiv2lib_export.h" // included header files -#include "metadatum.hpp" #include "datasets.hpp" +#include "metadatum.hpp" // ***************************************************************************** // namespace extensions namespace Exiv2 { - // ***************************************************************************** // class declarations - class ExifData; +class ExifData; // ***************************************************************************** // class definitions - /*! - @brief An IPTC metadatum ("dataset"), consisting of an IptcKey and a - Value and methods to manipulate these. +/*! + @brief An IPTC metadatum ("dataset"), consisting of an IptcKey and a + Value and methods to manipulate these. - This is referred in the standard as a property. - */ - class EXIV2API Iptcdatum : public Metadatum { - public: - //! @name Creators - //@{ - /*! - @brief Constructor for new tags created by an application. The - %Iptcdatum is created from a key / value pair. %Iptcdatum - copies (clones) the value if one is provided. Alternatively, a - program can create an 'empty' %Iptcdatum with only a key and - set the value using setValue(). + This is referred in the standard as a property. + */ +class EXIV2API Iptcdatum : public Metadatum { + public: + //! @name Creators + //@{ + /*! + @brief Constructor for new tags created by an application. The + %Iptcdatum is created from a key / value pair. %Iptcdatum + copies (clones) the value if one is provided. Alternatively, a + program can create an 'empty' %Iptcdatum with only a key and + set the value using setValue(). - @param key The key of the %Iptcdatum. - @param pValue Pointer to a %Iptcdatum value. - @throw Error if the key cannot be parsed and converted - to a tag number and record id. - */ - explicit Iptcdatum(const IptcKey& key, const Value* pValue = nullptr); - //! Copy constructor - Iptcdatum(const Iptcdatum& rhs); - //! Destructor - ~Iptcdatum() override = default; - //@} + @param key The key of the %Iptcdatum. + @param pValue Pointer to a %Iptcdatum value. + @throw Error if the key cannot be parsed and converted + to a tag number and record id. + */ + explicit Iptcdatum(const IptcKey& key, const Value* pValue = nullptr); + //! Copy constructor + Iptcdatum(const Iptcdatum& rhs); + //! Destructor + ~Iptcdatum() override = default; + //@} - //! @name Manipulators - //@{ - //! Assignment operator - Iptcdatum& operator=(const Iptcdatum& rhs); - /*! - @brief Assign \em value to the %Iptcdatum. The type of the new Value - is set to UShortValue. - */ - Iptcdatum& operator=(const uint16_t& value); - /*! - @brief Assign \em value to the %Iptcdatum. - Calls setValue(const std::string&). - */ - Iptcdatum& operator=(const std::string& value); - /*! - @brief Assign \em value to the %Iptcdatum. - Calls setValue(const Value*). - */ - Iptcdatum& operator=(const Value& value); - void setValue(const Value* pValue) override; - /*! - @brief Set the value to the string \em value, using - Value::read(const std::string&). - If the %Iptcdatum does not have a Value yet, then a %Value of - the correct type for this %Iptcdatum is created. If that - fails (because of an unknown dataset), a StringValue is - created. Return 0 if the value was read successfully. - */ - int setValue(const std::string& value) override; - //@} + //! @name Manipulators + //@{ + //! Assignment operator + Iptcdatum& operator=(const Iptcdatum& rhs); + /*! + @brief Assign \em value to the %Iptcdatum. The type of the new Value + is set to UShortValue. + */ + Iptcdatum& operator=(const uint16_t& value); + /*! + @brief Assign \em value to the %Iptcdatum. + Calls setValue(const std::string&). + */ + Iptcdatum& operator=(const std::string& value); + /*! + @brief Assign \em value to the %Iptcdatum. + Calls setValue(const Value*). + */ + Iptcdatum& operator=(const Value& value); + void setValue(const Value* pValue) override; + /*! + @brief Set the value to the string \em value, using + Value::read(const std::string&). + If the %Iptcdatum does not have a Value yet, then a %Value of + the correct type for this %Iptcdatum is created. If that + fails (because of an unknown dataset), a StringValue is + created. Return 0 if the value was read successfully. + */ + int setValue(const std::string& value) override; + //@} - //! @name Accessors - //@{ - size_t copy(byte* buf, ByteOrder byteOrder) const override; - std::ostream& write(std::ostream& os, const ExifData* pMetadata = nullptr) const override; - /*! - @brief Return the key of the Iptcdatum. The key is of the form - 'Iptc.recordName.datasetName'. Note however that the key - is not necessarily unique, i.e., an IptcData object may contain - multiple metadata with the same key. - */ - std::string key() const override; - /*! - @brief Return the name of the record (deprecated) - @return record name - */ - std::string recordName() const; - /*! - @brief Return the record id - @return record id - */ - uint16_t record() const; - const char* familyName() const override; - std::string groupName() const override; - /*! - @brief Return the name of the tag (aka dataset) - @return tag name - */ - std::string tagName() const override; - std::string tagLabel() const override; - //! Return the tag (aka dataset) number - uint16_t tag() const override; - TypeId typeId() const override; - const char* typeName() const override; - size_t typeSize() const override; - size_t count() const override; - size_t size() const override; - std::string toString() const override; - std::string toString(size_t n) const override; - int64_t toInt64(size_t n = 0) const override; - float toFloat(size_t n = 0) const override; - Rational toRational(size_t n = 0) const override; - Value::UniquePtr getValue() const override; - const Value& value() const override; - //@} + //! @name Accessors + //@{ + size_t copy(byte* buf, ByteOrder byteOrder) const override; + std::ostream& write(std::ostream& os, const ExifData* pMetadata = nullptr) const override; + /*! + @brief Return the key of the Iptcdatum. The key is of the form + 'Iptc.recordName.datasetName'. Note however that the key + is not necessarily unique, i.e., an IptcData object may contain + multiple metadata with the same key. + */ + std::string key() const override; + /*! + @brief Return the name of the record (deprecated) + @return record name + */ + std::string recordName() const; + /*! + @brief Return the record id + @return record id + */ + uint16_t record() const; + const char* familyName() const override; + std::string groupName() const override; + /*! + @brief Return the name of the tag (aka dataset) + @return tag name + */ + std::string tagName() const override; + std::string tagLabel() const override; + //! Return the tag (aka dataset) number + uint16_t tag() const override; + TypeId typeId() const override; + const char* typeName() const override; + size_t typeSize() const override; + size_t count() const override; + size_t size() const override; + std::string toString() const override; + std::string toString(size_t n) const override; + int64_t toInt64(size_t n = 0) const override; + float toFloat(size_t n = 0) const override; + Rational toRational(size_t n = 0) const override; + Value::UniquePtr getValue() const override; + const Value& value() const override; + //@} - private: - // DATA - IptcKey::UniquePtr key_; //!< Key - Value::UniquePtr value_; //!< Value + private: + // DATA + IptcKey::UniquePtr key_; //!< Key + Value::UniquePtr value_; //!< Value - }; // class Iptcdatum +}; // class Iptcdatum - //! Container type to hold all metadata - using IptcMetadata = std::vector; +//! Container type to hold all metadata +using IptcMetadata = std::vector; - /*! - @brief A container for IPTC data. This is a top-level class of the %Exiv2 library. +/*! + @brief A container for IPTC data. This is a top-level class of the %Exiv2 library. - Provide high-level access to the IPTC data of an image: - - read IPTC information from JPEG files - - access metadata through keys and standard C++ iterators - - add, modify and delete metadata - - write IPTC data to JPEG files - - extract IPTC metadata to files, insert from these files - */ - class EXIV2API IptcData { - public: - //! IptcMetadata iterator type - using iterator = IptcMetadata::iterator; - //! IptcMetadata const iterator type - using const_iterator = IptcMetadata::const_iterator; + Provide high-level access to the IPTC data of an image: + - read IPTC information from JPEG files + - access metadata through keys and standard C++ iterators + - add, modify and delete metadata + - write IPTC data to JPEG files + - extract IPTC metadata to files, insert from these files +*/ +class EXIV2API IptcData { + public: + //! IptcMetadata iterator type + using iterator = IptcMetadata::iterator; + //! IptcMetadata const iterator type + using const_iterator = IptcMetadata::const_iterator; - // Use the compiler generated constructors and assignment operator + // Use the compiler generated constructors and assignment operator - //! @name Manipulators - //@{ - /*! - @brief Returns a reference to the %Iptcdatum that is associated with a - particular \em key. If %IptcData does not already contain such - an %Iptcdatum, operator[] adds object \em Iptcdatum(key). + //! @name Manipulators + //@{ + /*! + @brief Returns a reference to the %Iptcdatum that is associated with a + particular \em key. If %IptcData does not already contain such + an %Iptcdatum, operator[] adds object \em Iptcdatum(key). - @note Since operator[] might insert a new element, it can't be a const - member function. - */ - Iptcdatum& operator[](const std::string& key); - /*! - @brief Add an %Iptcdatum from the supplied key and value pair. This - method copies (clones) the value. A check for non-repeatable - datasets is performed. - @return 0 if successful;
- 6 if the dataset already exists and is not repeatable - */ - int add(const IptcKey& key, Value* value); - /*! - @brief Add a copy of the Iptcdatum to the IPTC metadata. A check - for non-repeatable datasets is performed. - @return 0 if successful;
- 6 if the dataset already exists and is not repeatable;
- */ - int add(const Iptcdatum& iptcdatum); - /*! - @brief Delete the Iptcdatum at iterator position pos, return the - position of the next Iptcdatum. Note that iterators into - the metadata, including pos, are potentially invalidated - by this call. - */ - iterator erase(iterator pos); - /*! - @brief Delete all Iptcdatum instances resulting in an empty container. - */ - void clear() { iptcMetadata_.clear(); } - //! Sort metadata by key - void sortByKey(); - //! Sort metadata by tag (aka dataset) - void sortByTag(); - //! Begin of the metadata - iterator begin() { return iptcMetadata_.begin(); } - //! End of the metadata - iterator end() { return iptcMetadata_.end(); } - /*! - @brief Find the first Iptcdatum with the given key, return an iterator - to it. - */ - iterator findKey(const IptcKey& key); - /*! - @brief Find the first Iptcdatum with the given record and dataset it, - return a const iterator to it. - */ - iterator findId(uint16_t dataset, - uint16_t record = IptcDataSets::application2); - //@} + @note Since operator[] might insert a new element, it can't be a const + member function. + */ + Iptcdatum& operator[](const std::string& key); + /*! + @brief Add an %Iptcdatum from the supplied key and value pair. This + method copies (clones) the value. A check for non-repeatable + datasets is performed. + @return 0 if successful;
+ 6 if the dataset already exists and is not repeatable + */ + int add(const IptcKey& key, Value* value); + /*! + @brief Add a copy of the Iptcdatum to the IPTC metadata. A check + for non-repeatable datasets is performed. + @return 0 if successful;
+ 6 if the dataset already exists and is not repeatable;
+ */ + int add(const Iptcdatum& iptcdatum); + /*! + @brief Delete the Iptcdatum at iterator position pos, return the + position of the next Iptcdatum. Note that iterators into + the metadata, including pos, are potentially invalidated + by this call. + */ + iterator erase(iterator pos); + /*! + @brief Delete all Iptcdatum instances resulting in an empty container. + */ + void clear() { + iptcMetadata_.clear(); + } + //! Sort metadata by key + void sortByKey(); + //! Sort metadata by tag (aka dataset) + void sortByTag(); + //! Begin of the metadata + iterator begin() { + return iptcMetadata_.begin(); + } + //! End of the metadata + iterator end() { + return iptcMetadata_.end(); + } + /*! + @brief Find the first Iptcdatum with the given key, return an iterator + to it. + */ + iterator findKey(const IptcKey& key); + /*! + @brief Find the first Iptcdatum with the given record and dataset it, + return a const iterator to it. + */ + iterator findId(uint16_t dataset, uint16_t record = IptcDataSets::application2); + //@} - //! @name Accessors - //@{ - //! Begin of the metadata - const_iterator begin() const { return iptcMetadata_.begin(); } - //! End of the metadata - const_iterator end() const { return iptcMetadata_.end(); } - /*! - @brief Find the first Iptcdatum with the given key, return a const - iterator to it. - */ - const_iterator findKey(const IptcKey& key) const; - /*! - @brief Find the first Iptcdatum with the given record and dataset - number, return a const iterator to it. - */ - const_iterator findId(uint16_t dataset, - uint16_t record = IptcDataSets::application2) const; - //! Return true if there is no IPTC metadata - bool empty() const { return count() == 0; } + //! @name Accessors + //@{ + //! Begin of the metadata + const_iterator begin() const { + return iptcMetadata_.begin(); + } + //! End of the metadata + const_iterator end() const { + return iptcMetadata_.end(); + } + /*! + @brief Find the first Iptcdatum with the given key, return a const + iterator to it. + */ + const_iterator findKey(const IptcKey& key) const; + /*! + @brief Find the first Iptcdatum with the given record and dataset + number, return a const iterator to it. + */ + const_iterator findId(uint16_t dataset, uint16_t record = IptcDataSets::application2) const; + //! Return true if there is no IPTC metadata + bool empty() const { + return count() == 0; + } - //! Get the number of metadata entries - size_t count() const { return iptcMetadata_.size(); } + //! Get the number of metadata entries + size_t count() const { + return iptcMetadata_.size(); + } - //! @brief Return the exact size of all contained IPTC metadata - size_t size() const; + //! @brief Return the exact size of all contained IPTC metadata + size_t size() const; - //! @brief Return the metadata charset name or 0 - const char *detectCharset() const; + //! @brief Return the metadata charset name or 0 + const char* detectCharset() const; - //! @brief dump iptc formatted binary data (used by printStructure kpsRecursive) - static void printStructure(std::ostream& out, const Slice& bytes,uint32_t depth); - //@} + //! @brief dump iptc formatted binary data (used by printStructure kpsRecursive) + static void printStructure(std::ostream& out, const Slice& bytes, uint32_t depth); + //@} - private: - // DATA - IptcMetadata iptcMetadata_; - }; // class IptcData + private: + // DATA + IptcMetadata iptcMetadata_; +}; // class IptcData - /*! - @brief Stateless parser class for IPTC data. Images use this class to - decode and encode binary IPTC data. - */ - class EXIV2API IptcParser { - public: - /*! - @brief Decode binary IPTC data in IPTC IIM4 format from a buffer \em pData - of length \em size to the provided metadata container. +/*! + @brief Stateless parser class for IPTC data. Images use this class to + decode and encode binary IPTC data. + */ +class EXIV2API IptcParser { + public: + /*! + @brief Decode binary IPTC data in IPTC IIM4 format from a buffer \em pData + of length \em size to the provided metadata container. - @param iptcData Metadata container to add the decoded IPTC datasets to. - @param pData Pointer to the data buffer to read from. - @param size Number of bytes in the data buffer. + @param iptcData Metadata container to add the decoded IPTC datasets to. + @param pData Pointer to the data buffer to read from. + @param size Number of bytes in the data buffer. - @return 0 if successful;
- 5 if the binary IPTC data is invalid or corrupt - */ - static int decode(IptcData& iptcData, const byte* pData, size_t size); + @return 0 if successful;
+ 5 if the binary IPTC data is invalid or corrupt + */ + static int decode(IptcData& iptcData, const byte* pData, size_t size); - /*! - @brief Encode the IPTC datasets from \em iptcData to a binary representation in IPTC IIM4 format. + /*! + @brief Encode the IPTC datasets from \em iptcData to a binary representation in IPTC IIM4 format. - Convert the IPTC datasets to binary format and return it. Caller owns - the returned buffer. The copied data follows the IPTC IIM4 standard. + Convert the IPTC datasets to binary format and return it. Caller owns + the returned buffer. The copied data follows the IPTC IIM4 standard. - @return Data buffer containing the binary IPTC data in IPTC IIM4 format. - */ - static DataBuf encode(const IptcData& iptcData); + @return Data buffer containing the binary IPTC data in IPTC IIM4 format. + */ + static DataBuf encode(const IptcData& iptcData); - private: - // Constant data - static const byte marker_; // Dataset marker + private: + // Constant data + static const byte marker_; // Dataset marker - }; // class IptcParser +}; // class IptcParser -} // namespace Exiv2 +} // namespace Exiv2 -#endif // #ifndef IPTC_HPP_ +#endif // #ifndef IPTC_HPP_ diff --git a/include/exiv2/jp2image.hpp b/include/exiv2/jp2image.hpp index ab14d084..0955f8f0 100644 --- a/include/exiv2/jp2image.hpp +++ b/include/exiv2/jp2image.hpp @@ -11,103 +11,101 @@ // ***************************************************************************** // namespace extensions -namespace Exiv2 -{ - +namespace Exiv2 { // ***************************************************************************** // class definitions - /*! - @brief Class to access JPEG-2000 images. - */ - class EXIV2API Jp2Image : public Image { - public: - //! @name Creators - //@{ - /*! - @brief Constructor to open a JPEG-2000 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). - */ - Jp2Image(BasicIo::UniquePtr io, bool create); - //@} +/*! + @brief Class to access JPEG-2000 images. + */ +class EXIV2API Jp2Image : public Image { + public: + //! @name Creators + //@{ + /*! + @brief Constructor to open a JPEG-2000 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). + */ + Jp2Image(BasicIo::UniquePtr io, bool create); + //@} - //! @name Manipulators - //@{ - void readMetadata() override; - void writeMetadata() override; + //! @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 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(ErrorCode::kerInvalidSettingForImage). - */ - void setComment(std::string_view comment) override; - //@} + /*! + @brief Todo: Not supported yet(?). Calling this function will throw + an instance of Error(ErrorCode::kerInvalidSettingForImage). + */ + void setComment(std::string_view comment) override; + //@} - //! @name Accessors - //@{ - std::string mimeType() const override; - //@} + //! @name Accessors + //@{ + std::string mimeType() const override; + //@} - //! @name NOT Implemented - //@{ - //! Copy constructor - Jp2Image(const Jp2Image& rhs) = delete; - //! Assignment operator - Jp2Image& operator=(const Jp2Image& rhs) = delete; + //! @name NOT Implemented + //@{ + //! Copy constructor + Jp2Image(const Jp2Image &rhs) = delete; + //! Assignment operator + Jp2Image &operator=(const Jp2Image &rhs) = delete; - private: - /*! - @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). + private: + /*! + @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); + @return 4 if opening or writing to the associated BasicIo fails + */ + void doWriteMetadata(BasicIo &outIo); - /*! - @brief reformats the Jp2Header to store iccProfile - @param oldData DataBufRef to data in the file. - @param newData DataBufRef with updated data - */ - void encodeJp2Header(const DataBuf& boxBuf, DataBuf& outBuf); - //@} + /*! + @brief reformats the Jp2Header to store iccProfile + @param oldData DataBufRef to data in the file. + @param newData DataBufRef with updated data + */ + void encodeJp2Header(const DataBuf &boxBuf, DataBuf &outBuf); + //@} - }; // class Jp2Image +}; // class Jp2Image // ***************************************************************************** // 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 Jp2Image 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::UniquePtr newJp2Instance(BasicIo::UniquePtr io, bool create); +// These could be static private functions on Image subclasses but then +// ImageFactory needs to be made a friend. +/*! + @brief Create a new Jp2Image 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::UniquePtr newJp2Instance(BasicIo::UniquePtr io, bool create); - //! Check if the file iIo is a JPEG-2000 image. - EXIV2API bool isJp2Type(BasicIo& iIo, bool advance); +//! Check if the file iIo is a JPEG-2000 image. +EXIV2API bool isJp2Type(BasicIo &iIo, bool advance); -} // namespace Exiv2 +} // namespace Exiv2 -#endif // #ifndef JP2IMAGE_HPP_ +#endif // #ifndef JP2IMAGE_HPP_ diff --git a/include/exiv2/jpgimage.hpp b/include/exiv2/jpgimage.hpp index bff2513d..def2a219 100644 --- a/include/exiv2/jpgimage.hpp +++ b/include/exiv2/jpgimage.hpp @@ -9,403 +9,390 @@ #include // included header files -#include "image.hpp" #include "error.hpp" +#include "image.hpp" // ***************************************************************************** // namespace extensions namespace Exiv2 { - // ***************************************************************************** // class definitions - /*! - @brief Helper class, has methods to deal with %Photoshop "Information - Resource Blocks" (IRBs). - */ - struct EXIV2API Photoshop { - // Todo: Public for now - static constexpr std::array irbId_{"8BIM", "AgHg", "DCSR", "PHUT"}; //!< %Photoshop IRB markers - inline static const char* ps3Id_ = "Photoshop 3.0\0"; //!< %Photoshop marker - inline static const char* bimId_ = "8BIM"; //!< %Photoshop IRB marker (deprecated) - inline static const uint16_t iptc_ = 0x0404; //!< %Photoshop IPTC marker - inline static const uint16_t preview_ = 0x040c; //!< %Photoshop preview marker +/*! + @brief Helper class, has methods to deal with %Photoshop "Information + Resource Blocks" (IRBs). + */ +struct EXIV2API Photoshop { + // Todo: Public for now + static constexpr std::array irbId_{"8BIM", "AgHg", "DCSR", "PHUT"}; //!< %Photoshop IRB markers + inline static const char* ps3Id_ = "Photoshop 3.0\0"; //!< %Photoshop marker + inline static const char* bimId_ = "8BIM"; //!< %Photoshop IRB marker (deprecated) + inline static const uint16_t iptc_ = 0x0404; //!< %Photoshop IPTC marker + inline static const uint16_t preview_ = 0x040c; //!< %Photoshop preview marker - /*! - @brief Checks an IRB + /*! + @brief Checks an IRB - @param pPsData Existing IRB buffer - @param sizePsData Size of the IRB buffer - @return true if the IRB marker is known and the buffer is big enough to check this;
- false otherwise - */ - static bool isIrb(const byte* pPsData, size_t sizePsData); - /*! - @brief Validates all IRBs + @param pPsData Existing IRB buffer + @param sizePsData Size of the IRB buffer + @return true if the IRB marker is known and the buffer is big enough to check this;
+ false otherwise + */ + static bool isIrb(const byte* pPsData, size_t sizePsData); + /*! + @brief Validates all IRBs - @param pPsData Existing IRB buffer - @param sizePsData Size of the IRB buffer, may be 0 - @return true if all IRBs are valid;
- false otherwise - */ - static bool valid(const byte* pPsData, size_t sizePsData); - /*! - @brief Locates the data for a %Photoshop tag in a %Photoshop formated memory - buffer. Operates on raw data to simplify reuse. - @param pPsData Pointer to buffer containing entire payload of - %Photoshop formated data, e.g., from APP13 Jpeg segment. - @param sizePsData Size in bytes of pPsData. - @param psTag %Tag number of the block to look for. - @param record Output value that is set to the start of the - data block within pPsData (may not be null). - @param sizeHdr Output value that is set to the size of the header - within the data block pointed to by record (may not be null). - @param sizeData Output value that is set to the size of the actual - data within the data block pointed to by record (may not be null). - @return 0 if successful;
- 3 if no data for psTag was found in pPsData;
- -2 if the pPsData buffer does not contain valid data. - */ - static int locateIrb(const byte *pPsData, - size_t sizePsData, - uint16_t psTag, - const byte **record, - uint32_t *const sizeHdr, - uint32_t *const sizeData); - /*! - @brief Forwards to locateIrb() with \em psTag = \em iptc_ - */ - static int locateIptcIrb(const byte *pPsData, - size_t sizePsData, - const byte **record, - uint32_t *const sizeHdr, - uint32_t *const sizeData); - /*! - @brief Forwards to locatePreviewIrb() with \em psTag = \em preview_ - */ - static int locatePreviewIrb(const byte *pPsData, - size_t sizePsData, - const byte **record, - uint32_t *const sizeHdr, - uint32_t *const sizeData); - /*! - @brief Set the new IPTC IRB, keeps existing IRBs but removes the - IPTC block if there is no new IPTC data to write. + @param pPsData Existing IRB buffer + @param sizePsData Size of the IRB buffer, may be 0 + @return true if all IRBs are valid;
+ false otherwise + */ + static bool valid(const byte* pPsData, size_t sizePsData); + /*! + @brief Locates the data for a %Photoshop tag in a %Photoshop formated memory + buffer. Operates on raw data to simplify reuse. + @param pPsData Pointer to buffer containing entire payload of + %Photoshop formated data, e.g., from APP13 Jpeg segment. + @param sizePsData Size in bytes of pPsData. + @param psTag %Tag number of the block to look for. + @param record Output value that is set to the start of the + data block within pPsData (may not be null). + @param sizeHdr Output value that is set to the size of the header + within the data block pointed to by record (may not be null). + @param sizeData Output value that is set to the size of the actual + data within the data block pointed to by record (may not be null). + @return 0 if successful;
+ 3 if no data for psTag was found in pPsData;
+ -2 if the pPsData buffer does not contain valid data. + */ + static int locateIrb(const byte* pPsData, size_t sizePsData, uint16_t psTag, const byte** record, + uint32_t* const sizeHdr, uint32_t* const sizeData); + /*! + @brief Forwards to locateIrb() with \em psTag = \em iptc_ + */ + static int locateIptcIrb(const byte* pPsData, size_t sizePsData, const byte** record, uint32_t* const sizeHdr, + uint32_t* const sizeData); + /*! + @brief Forwards to locatePreviewIrb() with \em psTag = \em preview_ + */ + static int locatePreviewIrb(const byte* pPsData, size_t sizePsData, const byte** record, uint32_t* const sizeHdr, + uint32_t* const sizeData); + /*! + @brief Set the new IPTC IRB, keeps existing IRBs but removes the + IPTC block if there is no new IPTC data to write. - @param pPsData Existing IRB buffer - @param sizePsData Size of the IRB buffer, may be 0 - @param iptcData Iptc data to embed, may be empty - @return A data buffer containing the new IRB buffer, may have 0 size - */ - static DataBuf setIptcIrb(const byte* pPsData, size_t sizePsData, const IptcData& iptcData); + @param pPsData Existing IRB buffer + @param sizePsData Size of the IRB buffer, may be 0 + @param iptcData Iptc data to embed, may be empty + @return A data buffer containing the new IRB buffer, may have 0 size + */ + static DataBuf setIptcIrb(const byte* pPsData, size_t sizePsData, const IptcData& iptcData); - }; // class Photoshop +}; // class Photoshop - /*! - @brief Abstract helper base class to access JPEG images. - */ - class EXIV2API JpegBase : public Image { - public: - //! @name Manipulators - //@{ - void readMetadata() override; - void writeMetadata() override; - void printStructure(std::ostream& out, PrintStructureOption option, int depth) override; - //@} +/*! + @brief Abstract helper base class to access JPEG images. + */ +class EXIV2API JpegBase : public Image { + public: + //! @name Manipulators + //@{ + void readMetadata() override; + void writeMetadata() override; + void printStructure(std::ostream& out, PrintStructureOption option, int depth) override; + //@} - //! @name NOT implemented - //@{ - //! Default constructor. - JpegBase() = delete; - //! Copy constructor - JpegBase(const JpegBase& rhs) = delete; - //! Assignment operator - JpegBase& operator=(const JpegBase& rhs) = delete; - //@} + //! @name NOT implemented + //@{ + //! Default constructor. + JpegBase() = delete; + //! Copy constructor + JpegBase(const JpegBase& rhs) = delete; + //! Assignment operator + JpegBase& operator=(const JpegBase& rhs) = delete; + //@} - protected: - //! @name Creators - //@{ - /*! - @brief Constructor that can either open an existing image or create - a new image from scratch. If a new image is to be created, any - existing data is overwritten. - @param type Image type. - @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 image should be created (true). - @param initData Data to initialize newly created images. Only used - when \em create is true. Should contain data for the smallest - valid image of the calling subclass. - @param dataSize Size of initData in bytes. - */ - JpegBase(ImageType type, - BasicIo::UniquePtr io, - bool create, - const byte initData[], - size_t dataSize); - //@} + protected: + //! @name Creators + //@{ + /*! + @brief Constructor that can either open an existing image or create + a new image from scratch. If a new image is to be created, any + existing data is overwritten. + @param type Image type. + @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 image should be created (true). + @param initData Data to initialize newly created images. Only used + when \em create is true. Should contain data for the smallest + valid image of the calling subclass. + @param dataSize Size of initData in bytes. + */ + JpegBase(ImageType type, BasicIo::UniquePtr io, bool create, const byte initData[], size_t dataSize); + //@} - //! @name Accessors - //@{ - /*! - @brief Determine if the content of the BasicIo instance is of the - type supported by this class. + //! @name Accessors + //@{ + /*! + @brief Determine if the content of the BasicIo instance is of the + type supported by this class. - The advance flag determines if the read position in the stream is - moved (see below). This applies only if the type matches and the - function returns true. If the type does not match, the stream - position is not changed. However, if reading from the stream fails, - the stream position is undefined. Consult the stream state to obtain - more information in this case. + The advance flag determines if the read position in the stream is + moved (see below). This applies only if the type matches and the + function returns true. If the type does not match, the stream + position is not changed. However, if reading from the stream fails, + the stream position is undefined. Consult the stream state to obtain + more information in this case. - @param iIo BasicIo instance to read from. - @param advance Flag indicating whether the position of the io - should be advanced by the number of characters read to - analyse the data (true) or left at its original - position (false). This applies only if the type matches. - @return true if the data matches the type of this class;
- false if the data does not match - */ - virtual bool isThisType(BasicIo& iIo, bool advance) const =0; - //@} + @param iIo BasicIo instance to read from. + @param advance Flag indicating whether the position of the io + should be advanced by the number of characters read to + analyse the data (true) or left at its original + position (false). This applies only if the type matches. + @return true if the data matches the type of this class;
+ false if the data does not match + */ + virtual bool isThisType(BasicIo& iIo, bool advance) const = 0; + //@} - //! @name Manipulators - //@{ - /*! - @brief Writes the image header (aka signature) to the BasicIo instance. - @param oIo BasicIo instance that the header is written to. - @return 0 if successful;
- 4 if the output file can not be written to - */ - virtual int writeHeader(BasicIo& oIo) const =0; - //@} + //! @name Manipulators + //@{ + /*! + @brief Writes the image header (aka signature) to the BasicIo instance. + @param oIo BasicIo instance that the header is written to. + @return 0 if successful;
+ 4 if the output file can not be written to + */ + virtual int writeHeader(BasicIo& oIo) const = 0; + //@} - // Constant Data - static constexpr byte dht_ = 0xc4; //!< JPEG DHT marker - static constexpr byte dqt_ = 0xdb; //!< JPEG DQT marker - static constexpr byte dri_ = 0xdd; //!< JPEG DRI marker - static constexpr byte sos_ = 0xda; //!< JPEG SOS marker - static constexpr byte eoi_ = 0xd9; //!< JPEG EOI marker - static constexpr byte app0_ = 0xe0; //!< JPEG APP0 marker - static constexpr byte app1_ = 0xe1; //!< JPEG APP1 marker - static constexpr byte app2_ = 0xe2; //!< JPEG APP2 marker - static constexpr byte app13_ = 0xed; //!< JPEG APP13 marker - static constexpr byte com_ = 0xfe; //!< JPEG Comment marker + // Constant Data + static constexpr byte dht_ = 0xc4; //!< JPEG DHT marker + static constexpr byte dqt_ = 0xdb; //!< JPEG DQT marker + static constexpr byte dri_ = 0xdd; //!< JPEG DRI marker + static constexpr byte sos_ = 0xda; //!< JPEG SOS marker + static constexpr byte eoi_ = 0xd9; //!< JPEG EOI marker + static constexpr byte app0_ = 0xe0; //!< JPEG APP0 marker + static constexpr byte app1_ = 0xe1; //!< JPEG APP1 marker + static constexpr byte app2_ = 0xe2; //!< JPEG APP2 marker + static constexpr byte app13_ = 0xed; //!< JPEG APP13 marker + static constexpr byte com_ = 0xfe; //!< JPEG Comment marker - // Start of Frame markers, nondifferential Huffman-coding frames - static constexpr byte sof0_ = 0xc0; //!< JPEG Start-Of-Frame marker - static constexpr byte sof1_ = 0xc1; //!< JPEG Start-Of-Frame marker - static constexpr byte sof2_ = 0xc2; //!< JPEG Start-Of-Frame marker - static constexpr byte sof3_ = 0xc3; //!< JPEG Start-Of-Frame marker + // Start of Frame markers, nondifferential Huffman-coding frames + static constexpr byte sof0_ = 0xc0; //!< JPEG Start-Of-Frame marker + static constexpr byte sof1_ = 0xc1; //!< JPEG Start-Of-Frame marker + static constexpr byte sof2_ = 0xc2; //!< JPEG Start-Of-Frame marker + static constexpr byte sof3_ = 0xc3; //!< JPEG Start-Of-Frame marker - // Start of Frame markers, differential Huffman-coding frames - static constexpr byte sof5_ = 0xc5; //!< JPEG Start-Of-Frame marker - static constexpr byte sof6_ = 0xc6; //!< JPEG Start-Of-Frame marker - static constexpr byte sof7_ = 0xc7; //!< JPEG Start-Of-Frame marker + // Start of Frame markers, differential Huffman-coding frames + static constexpr byte sof5_ = 0xc5; //!< JPEG Start-Of-Frame marker + static constexpr byte sof6_ = 0xc6; //!< JPEG Start-Of-Frame marker + static constexpr byte sof7_ = 0xc7; //!< JPEG Start-Of-Frame marker - // Start of Frame markers, nondifferential arithmetic-coding frames - static constexpr byte sof9_ = 0xc9; //!< JPEG Start-Of-Frame marker - static constexpr byte sof10_ = 0xca; //!< JPEG Start-Of-Frame marker - static constexpr byte sof11_ = 0xcb; //!< JPEG Start-Of-Frame marker + // Start of Frame markers, nondifferential arithmetic-coding frames + static constexpr byte sof9_ = 0xc9; //!< JPEG Start-Of-Frame marker + static constexpr byte sof10_ = 0xca; //!< JPEG Start-Of-Frame marker + static constexpr byte sof11_ = 0xcb; //!< JPEG Start-Of-Frame marker - // Start of Frame markers, differential arithmetic-coding frames - static constexpr byte sof13_ = 0xcd; //!< JPEG Start-Of-Frame marker - static constexpr byte sof14_ = 0xce; //!< JPEG Start-Of-Frame marker - static constexpr byte sof15_ = 0xcf; //!< JPEG Start-Of-Frame marker + // Start of Frame markers, differential arithmetic-coding frames + static constexpr byte sof13_ = 0xcd; //!< JPEG Start-Of-Frame marker + static constexpr byte sof14_ = 0xce; //!< JPEG Start-Of-Frame marker + static constexpr byte sof15_ = 0xcf; //!< JPEG Start-Of-Frame marker - static constexpr auto exifId_ = "Exif\0\0"; //!< Exif identifier - static constexpr auto jfifId_ = "JFIF\0"; //!< JFIF identifier - static constexpr auto xmpId_ = "http://ns.adobe.com/xap/1.0/\0"; //!< XMP packet identifier - static constexpr auto iccId_ = "ICC_PROFILE\0"; //!< ICC profile identifier + static constexpr auto exifId_ = "Exif\0\0"; //!< Exif identifier + static constexpr auto jfifId_ = "JFIF\0"; //!< JFIF identifier + static constexpr auto xmpId_ = "http://ns.adobe.com/xap/1.0/\0"; //!< XMP packet identifier + static constexpr auto iccId_ = "ICC_PROFILE\0"; //!< ICC profile identifier - private: - //! @name Manipulators - //@{ - /*! - @brief Initialize the image with the provided data. - @param initData Data to be written to the associated BasicIo - @param dataSize Size in bytes of data to be written - @return 0 if successful;
- 4 if the image can not be written to. - */ - int initImage(const byte initData[], size_t dataSize); - /*! - @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). + private: + //! @name Manipulators + //@{ + /*! + @brief Initialize the image with the provided data. + @param initData Data to be written to the associated BasicIo + @param dataSize Size in bytes of data to be written + @return 0 if successful;
+ 4 if the image can not be written to. + */ + int initImage(const byte initData[], size_t dataSize); + /*! + @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); - //@} + @return 4 if opening or writing to the associated BasicIo fails + */ + void doWriteMetadata(BasicIo& outIo); + //@} - //! @name Accessors - //@{ - /*! - @brief Advances associated io instance to one byte past the next - Jpeg marker and returns the marker. This method should be called - when the BasicIo instance is positioned one byte past the end of a - Jpeg segment. - @param err the error code to throw if no marker is found - @return the next Jpeg segment marker if successful;
- throws an Error if not successful - */ - byte advanceToMarker(ErrorCode err) const; - //@} + //! @name Accessors + //@{ + /*! + @brief Advances associated io instance to one byte past the next + Jpeg marker and returns the marker. This method should be called + when the BasicIo instance is positioned one byte past the end of a + Jpeg segment. + @param err the error code to throw if no marker is found + @return the next Jpeg segment marker if successful;
+ throws an Error if not successful + */ + byte advanceToMarker(ErrorCode err) const; + //@} - DataBuf readNextSegment(byte marker); + DataBuf readNextSegment(byte marker); - /*! - @brief Is the marker followed by a non-zero payload? - @param marker The marker at the start of a segment - @return true if the marker is followed by a non-zero payload - */ - static bool markerHasLength(byte marker); - }; // class JpegBase + /*! + @brief Is the marker followed by a non-zero payload? + @param marker The marker at the start of a segment + @return true if the marker is followed by a non-zero payload + */ + static bool markerHasLength(byte marker); +}; // class JpegBase - /*! - @brief Class to access JPEG images - */ - class EXIV2API JpegImage : public JpegBase { - friend EXIV2API bool isJpegType(BasicIo& iIo, bool advance); - public: - //! @name Creators - //@{ - /*! - @brief Constructor that can either open an existing Jpeg image or create - a new image from scratch. If a new image is to be created, any - existing data is overwritten. 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). - */ - JpegImage(BasicIo::UniquePtr io, bool create); - //@} - //! @name Accessors - //@{ - std::string mimeType() const override; - //@} +/*! + @brief Class to access JPEG images + */ +class EXIV2API JpegImage : public JpegBase { + friend EXIV2API bool isJpegType(BasicIo& iIo, bool advance); - // NOT Implemented - //! Default constructor - JpegImage() = delete; - //! Copy constructor - JpegImage(const JpegImage& rhs) = delete; - //! Assignment operator - JpegImage& operator=(const JpegImage& rhs) = delete; + public: + //! @name Creators + //@{ + /*! + @brief Constructor that can either open an existing Jpeg image or create + a new image from scratch. If a new image is to be created, any + existing data is overwritten. 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). + */ + JpegImage(BasicIo::UniquePtr io, bool create); + //@} + //! @name Accessors + //@{ + std::string mimeType() const override; + //@} - protected: - //! @name Accessors - //@{ - bool isThisType(BasicIo& iIo, bool advance) const override; - //@} - //! @name Manipulators - //@{ - /*! - @brief Writes a Jpeg header (aka signature) to the BasicIo instance. - @param oIo BasicIo instance that the header is written to. - @return 0 if successful;
- 2 if the input image is invalid or can not be read;
- 4 if the temporary image can not be written to;
- -3 other temporary errors - */ - int writeHeader(BasicIo& outIo) const override; - //@} + // NOT Implemented + //! Default constructor + JpegImage() = delete; + //! Copy constructor + JpegImage(const JpegImage& rhs) = delete; + //! Assignment operator + JpegImage& operator=(const JpegImage& rhs) = delete; - private: - // Constant data - static const byte soi_; // SOI marker - static const byte blank_[]; // Minimal Jpeg image - }; // class JpegImage + protected: + //! @name Accessors + //@{ + bool isThisType(BasicIo& iIo, bool advance) const override; + //@} + //! @name Manipulators + //@{ + /*! + @brief Writes a Jpeg header (aka signature) to the BasicIo instance. + @param oIo BasicIo instance that the header is written to. + @return 0 if successful;
+ 2 if the input image is invalid or can not be read;
+ 4 if the temporary image can not be written to;
+ -3 other temporary errors + */ + int writeHeader(BasicIo& outIo) const override; + //@} - //! Helper class to access %Exiv2 files - class EXIV2API ExvImage : public JpegBase { - friend EXIV2API bool isExvType(BasicIo& iIo, bool advance); - public: - //! @name Creators - //@{ - /*! - @brief Constructor that can either open an existing EXV image or create - a new image from scratch. If a new image is to be created, any - existing data is overwritten. 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). - */ - ExvImage(BasicIo::UniquePtr io, bool create); - //@} - //! @name Accessors - //@{ - std::string mimeType() const override; - //@} + private: + // Constant data + static const byte soi_; // SOI marker + static const byte blank_[]; // Minimal Jpeg image +}; // class JpegImage - // NOT Implemented - //! Default constructor - ExvImage() = delete; - //! Copy constructor - ExvImage(const ExvImage& rhs) = delete; - //! Assignment operator - ExvImage& operator=(const ExvImage& rhs) = delete; +//! Helper class to access %Exiv2 files +class EXIV2API ExvImage : public JpegBase { + friend EXIV2API bool isExvType(BasicIo& iIo, bool advance); - protected: - //! @name Accessors - //@{ - bool isThisType(BasicIo& iIo, bool advance) const override; - //@} - //! @name Manipulators - //@{ - int writeHeader(BasicIo& outIo) const override; - //@} + public: + //! @name Creators + //@{ + /*! + @brief Constructor that can either open an existing EXV image or create + a new image from scratch. If a new image is to be created, any + existing data is overwritten. 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). + */ + ExvImage(BasicIo::UniquePtr io, bool create); + //@} + //! @name Accessors + //@{ + std::string mimeType() const override; + //@} - private: - // Constant data - static constexpr char exiv2Id_[] = "Exiv2"; // EXV identifier - static constexpr byte blank_[] = {0xff, 0x01, 'E', 'x', 'i', 'v', '2', 0xff, 0xd9}; // Minimal exiv2 file + // NOT Implemented + //! Default constructor + ExvImage() = delete; + //! Copy constructor + ExvImage(const ExvImage& rhs) = delete; + //! Assignment operator + ExvImage& operator=(const ExvImage& rhs) = delete; - }; // class ExvImage + protected: + //! @name Accessors + //@{ + bool isThisType(BasicIo& iIo, bool advance) const override; + //@} + //! @name Manipulators + //@{ + int writeHeader(BasicIo& outIo) const override; + //@} + + private: + // Constant data + static constexpr char exiv2Id_[] = "Exiv2"; // EXV identifier + static constexpr byte blank_[] = {0xff, 0x01, 'E', 'x', 'i', 'v', '2', 0xff, 0xd9}; // Minimal exiv2 file + +}; // class ExvImage // ***************************************************************************** // 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 JpegImage 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::UniquePtr newJpegInstance(BasicIo::UniquePtr io, bool create); - //! Check if the file iIo is a JPEG image. - EXIV2API bool isJpegType(BasicIo& iIo, bool advance); - /*! - @brief Create a new ExvImage 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::UniquePtr newExvInstance(BasicIo::UniquePtr io, bool create); - //! Check if the file iIo is an EXV file - EXIV2API bool isExvType(BasicIo& iIo, bool advance); +// These could be static private functions on Image subclasses but then +// ImageFactory needs to be made a friend. +/*! + @brief Create a new JpegImage 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::UniquePtr newJpegInstance(BasicIo::UniquePtr io, bool create); +//! Check if the file iIo is a JPEG image. +EXIV2API bool isJpegType(BasicIo& iIo, bool advance); +/*! + @brief Create a new ExvImage 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::UniquePtr newExvInstance(BasicIo::UniquePtr io, bool create); +//! Check if the file iIo is an EXV file +EXIV2API bool isExvType(BasicIo& iIo, bool advance); -} // namespace Exiv2 +} // namespace Exiv2 -#endif // #ifndef JPGIMAGE_HPP_ +#endif // #ifndef JPGIMAGE_HPP_ diff --git a/include/exiv2/metadatum.hpp b/include/exiv2/metadatum.hpp index 41850dec..facc5d5c 100644 --- a/include/exiv2/metadatum.hpp +++ b/include/exiv2/metadatum.hpp @@ -12,278 +12,277 @@ // ***************************************************************************** // namespace extensions namespace Exiv2 { - // ***************************************************************************** // class declarations - class ExifData; +class ExifData; // ***************************************************************************** // class definitions - /*! - @brief Abstract base class defining the %Key of a metadatum. - Keys are used to identify and group metadata. - */ - class EXIV2API Key { - public: - //! Shortcut for a %Key auto pointer. - using UniquePtr = std::unique_ptr; +/*! + @brief Abstract base class defining the %Key of a metadatum. + Keys are used to identify and group metadata. +*/ +class EXIV2API Key { + public: + //! Shortcut for a %Key auto pointer. + using UniquePtr = std::unique_ptr; - //! @name Creators - //@{ - //! Destructor - virtual ~Key() = default; - //@} + //! @name Creators + //@{ + //! Destructor + virtual ~Key() = default; + //@} - //! @name Accessors - //@{ - /*! - @brief Return the key of the metadatum as a string. The key is of the - form 'familyName.groupName.tagName'. Note however that the - key is not necessarily unique, e.g., an ExifData may contain - multiple metadata with the same key. - */ - virtual std::string key() const =0; - //! Return an identifier for the type of metadata (the first part of the key) - virtual const char* familyName() const =0; - //! Return the name of the group (the second part of the key) - virtual std::string groupName() const =0; - //! Return the name of the tag (which is also the third part of the key) - virtual std::string tagName() const =0; - //! Return a label for the tag - virtual std::string tagLabel() const =0; - //! Return the tag number - virtual uint16_t tag() const =0; - /*! - @brief Return an auto-pointer to a copy of itself (deep copy). - The caller owns this copy and the auto-pointer ensures that it - will be deleted. - */ - UniquePtr clone() const; - /*! - @brief Write the key to an output stream. You do not usually have - to use this function; it is used for the implementation of - the output operator for %Key, - operator<<(std::ostream &os, const Key &key). - */ - std::ostream& write(std::ostream& os) const { return os << key(); } - //@} + //! @name Accessors + //@{ + /*! + @brief Return the key of the metadatum as a string. The key is of the + form 'familyName.groupName.tagName'. Note however that the + key is not necessarily unique, e.g., an ExifData may contain + multiple metadata with the same key. + */ + virtual std::string key() const = 0; + //! Return an identifier for the type of metadata (the first part of the key) + virtual const char* familyName() const = 0; + //! Return the name of the group (the second part of the key) + virtual std::string groupName() const = 0; + //! Return the name of the tag (which is also the third part of the key) + virtual std::string tagName() const = 0; + //! Return a label for the tag + virtual std::string tagLabel() const = 0; + //! Return the tag number + virtual uint16_t tag() const = 0; + /*! + @brief Return an auto-pointer to a copy of itself (deep copy). + The caller owns this copy and the auto-pointer ensures that it + will be deleted. + */ + UniquePtr clone() const; + /*! + @brief Write the key to an output stream. You do not usually have + to use this function; it is used for the implementation of + the output operator for %Key, + operator<<(std::ostream &os, const Key &key). + */ + std::ostream& write(std::ostream& os) const { + return os << key(); + } + //@} - protected: - //! @name Manipulators - //@{ - /*! - @brief Assignment operator. Protected so that it can only be used - by subclasses but not directly. - */ - Key& operator=(const Key& rhs) = default; - //@} + protected: + //! @name Manipulators + //@{ + /*! + @brief Assignment operator. Protected so that it can only be used + by subclasses but not directly. + */ + Key& operator=(const Key& rhs) = default; + //@} - private: - //! Internal virtual copy constructor. - virtual Key* clone_() const =0; + private: + //! Internal virtual copy constructor. + virtual Key* clone_() const = 0; - }; // class Key +}; // class Key - //! Output operator for Key types - inline std::ostream& operator<<(std::ostream& os, const Key& key) - { - return key.write(os); - } +//! Output operator for Key types +inline std::ostream& operator<<(std::ostream& os, const Key& key) { + return key.write(os); +} - /*! - @brief Abstract base class defining the interface to access information - related to one metadata tag. - */ - class EXIV2API Metadatum { - public: - //! @name Creators - //@{ - //! Default Constructor - Metadatum() = default; - //! Copy constructor - Metadatum(const Metadatum& rhs) = default; - //! Destructor - virtual ~Metadatum() = default; - //@} +/*! + @brief Abstract base class defining the interface to access information + related to one metadata tag. + */ +class EXIV2API Metadatum { + public: + //! @name Creators + //@{ + //! Default Constructor + Metadatum() = default; + //! Copy constructor + Metadatum(const Metadatum& rhs) = default; + //! Destructor + virtual ~Metadatum() = default; + //@} - //! @name Manipulators - //@{ - /*! - @brief Set the value. This method copies (clones) the value pointed - to by pValue. - */ - virtual void setValue(const Value* pValue) =0; - /*! - @brief Set the value to the string buf. - Uses Value::read(const std::string& buf). If the metadatum does - not have a value yet, then one is created. See subclasses for - more details. Return 0 if the value was read successfully. - */ - virtual int setValue(const std::string& buf) =0; - //@} + //! @name Manipulators + //@{ + /*! + @brief Set the value. This method copies (clones) the value pointed + to by pValue. + */ + virtual void setValue(const Value* pValue) = 0; + /*! + @brief Set the value to the string buf. + Uses Value::read(const std::string& buf). If the metadatum does + not have a value yet, then one is created. See subclasses for + more details. Return 0 if the value was read successfully. + */ + virtual int setValue(const std::string& buf) = 0; + //@} - //! @name Accessors - //@{ - /*! - @brief Write the interpreted value to a string. + //! @name Accessors + //@{ + /*! + @brief Write the interpreted value to a string. - Implemented in terms of write(), see there. - */ - std::string print(const ExifData* pMetadata = nullptr) const; - /*! - @brief Write value to a data buffer and return the number - of bytes written. + Implemented in terms of write(), see there. + */ + std::string print(const ExifData* pMetadata = nullptr) const; + /*! + @brief Write value to a data buffer and return the number + of bytes written. - The user must ensure that the buffer has enough memory. Otherwise - the call results in undefined behaviour. + The user must ensure that the buffer has enough memory. Otherwise + the call results in undefined behaviour. - @param buf Data buffer to write to. - @param byteOrder Applicable byte order (little or big endian). - @return Number of characters written. - */ - virtual size_t copy(byte* buf, ByteOrder byteOrder) const =0; - /*! - @brief Write the interpreted value to an output stream, return - the stream. + @param buf Data buffer to write to. + @param byteOrder Applicable byte order (little or big endian). + @return Number of characters written. + */ + virtual size_t copy(byte* buf, ByteOrder byteOrder) const = 0; + /*! + @brief Write the interpreted value to an output stream, return + the stream. - The method takes an optional pointer to a metadata container. - Pretty-print functions may use that to refer to other metadata as it - is sometimes not sufficient to know only the value of the metadatum - that should be interpreted. Thus, it is advisable to always call this - method with a pointer to the metadata container if possible. + The method takes an optional pointer to a metadata container. + Pretty-print functions may use that to refer to other metadata as it + is sometimes not sufficient to know only the value of the metadatum + that should be interpreted. Thus, it is advisable to always call this + method with a pointer to the metadata container if possible. - This functionality is currently only implemented for Exif tags. - The pointer is ignored when used to write IPTC datasets or XMP - properties. + This functionality is currently only implemented for Exif tags. + The pointer is ignored when used to write IPTC datasets or XMP + properties. - Without the optional metadata pointer, you do not usually have to use - this function; it is used for the implementation of the output - operator for %Metadatum, - operator<<(std::ostream &os, const Metadatum &md). + Without the optional metadata pointer, you do not usually have to use + this function; it is used for the implementation of the output + operator for %Metadatum, + operator<<(std::ostream &os, const Metadatum &md). - See also print(), which prints the interpreted value to a string. - */ - virtual std::ostream& write(std::ostream& os, const ExifData* pMetadata = nullptr) const = 0; - /*! - @brief Return the key of the metadatum. The key is of the form - 'familyName.groupName.tagName'. Note however that the key - is not necessarily unique, e.g., an ExifData object may - contain multiple metadata with the same key. - */ - virtual std::string key() const =0; - //! Return the name of the metadata family (which is also the first part of the key) - virtual const char* familyName() const =0; - //! Return the name of the metadata group (which is also the second part of the key) - virtual std::string groupName() const =0; - //! Return the name of the tag (which is also the third part of the key) - virtual std::string tagName() const =0; - //! Return a label for the tag - virtual std::string tagLabel() const =0; - //! Return the tag - virtual uint16_t tag() const =0; - //! Return the type id of the value - virtual TypeId typeId() const =0; - //! Return the name of the type - virtual const char* typeName() const =0; - //! Return the size in bytes of one component of this type - virtual size_t typeSize() const =0; - //! Return the number of components in the value - virtual size_t count() const =0; - //! Return the size of the value in bytes - virtual size_t size() const =0; - //! Return the value as a string. - virtual std::string toString() const =0; - /*! - @brief Return the n-th component of the value converted to - a string. The behaviour of the method is undefined if there - is no n-th component. - */ - virtual std::string toString(size_t n) const =0; - /*! - @brief Return the n-th component of the value converted to int64_t. - The return value is -1 if the value is not set and the behaviour - of the method is undefined if there is no n-th component. - */ - virtual int64_t toInt64(size_t n =0) const =0; - /*! - @brief Return the n-th component of the value converted to uint32_t. - */ - uint32_t toUint32(size_t n =0) const; - /*! - @brief Return the n-th component of the value converted to float. - The return value is -1 if the value is not set and the behaviour - of the method is undefined if there is no n-th component. - */ - virtual float toFloat(size_t n =0) const =0; - /*! - @brief Return the n-th component of the value converted to Rational. - The return value is -1/1 if the value is not set and the behaviour - of the method is undefined if there is no n-th component. - */ - virtual Rational toRational(size_t n =0) const =0; - /*! - @brief Return an auto-pointer to a copy (clone) of the value. The - caller owns this copy and the auto-poiner ensures that it will - be deleted. + See also print(), which prints the interpreted value to a string. + */ + virtual std::ostream& write(std::ostream& os, const ExifData* pMetadata = nullptr) const = 0; + /*! + @brief Return the key of the metadatum. The key is of the form + 'familyName.groupName.tagName'. Note however that the key + is not necessarily unique, e.g., an ExifData object may + contain multiple metadata with the same key. + */ + virtual std::string key() const = 0; + //! Return the name of the metadata family (which is also the first part of the key) + virtual const char* familyName() const = 0; + //! Return the name of the metadata group (which is also the second part of the key) + virtual std::string groupName() const = 0; + //! Return the name of the tag (which is also the third part of the key) + virtual std::string tagName() const = 0; + //! Return a label for the tag + virtual std::string tagLabel() const = 0; + //! Return the tag + virtual uint16_t tag() const = 0; + //! Return the type id of the value + virtual TypeId typeId() const = 0; + //! Return the name of the type + virtual const char* typeName() const = 0; + //! Return the size in bytes of one component of this type + virtual size_t typeSize() const = 0; + //! Return the number of components in the value + virtual size_t count() const = 0; + //! Return the size of the value in bytes + virtual size_t size() const = 0; + //! Return the value as a string. + virtual std::string toString() const = 0; + /*! + @brief Return the n-th component of the value converted to + a string. The behaviour of the method is undefined if there + is no n-th component. + */ + virtual std::string toString(size_t n) const = 0; + /*! + @brief Return the n-th component of the value converted to int64_t. + The return value is -1 if the value is not set and the behaviour + of the method is undefined if there is no n-th component. + */ + virtual int64_t toInt64(size_t n = 0) const = 0; + /*! + @brief Return the n-th component of the value converted to uint32_t. + */ + uint32_t toUint32(size_t n = 0) const; + /*! + @brief Return the n-th component of the value converted to float. + The return value is -1 if the value is not set and the behaviour + of the method is undefined if there is no n-th component. + */ + virtual float toFloat(size_t n = 0) const = 0; + /*! + @brief Return the n-th component of the value converted to Rational. + The return value is -1/1 if the value is not set and the behaviour + of the method is undefined if there is no n-th component. + */ + virtual Rational toRational(size_t n = 0) const = 0; + /*! + @brief Return an auto-pointer to a copy (clone) of the value. The + caller owns this copy and the auto-poiner ensures that it will + be deleted. - This method is provided for users who need full control over the - value. A caller may, e.g., downcast the pointer to the appropriate - subclass of Value to make use of the interface of the subclass to set - or modify its contents. + This method is provided for users who need full control over the + value. A caller may, e.g., downcast the pointer to the appropriate + subclass of Value to make use of the interface of the subclass to set + or modify its contents. - @return An auto-pointer containing a pointer to a copy (clone) of the - value, 0 if the value is not set. - */ - virtual Value::UniquePtr getValue() const =0; - /*! - @brief Return a constant reference to the value. + @return An auto-pointer containing a pointer to a copy (clone) of the + value, 0 if the value is not set. + */ + virtual Value::UniquePtr getValue() const = 0; + /*! + @brief Return a constant reference to the value. - This method is provided mostly for convenient and versatile output of - the value which can (to some extent) be formatted through standard - stream manipulators. Do not attempt to write to the value through - this reference. An Error is thrown if the value is not set; as an - alternative to catching it, one can use count() to check if there - is any data before calling this method. + This method is provided mostly for convenient and versatile output of + the value which can (to some extent) be formatted through standard + stream manipulators. Do not attempt to write to the value through + this reference. An Error is thrown if the value is not set; as an + alternative to catching it, one can use count() to check if there + is any data before calling this method. - @return A constant reference to the value. - @throw Error if the value is not set. - */ - virtual const Value& value() const =0; - //@} + @return A constant reference to the value. + @throw Error if the value is not set. + */ + virtual const Value& value() const = 0; + //@} - protected: - //! @name Manipulators - //@{ - /*! - @brief Assignment operator. Protected so that it can only be used - by subclasses but not directly. - */ - Metadatum& operator=(const Metadatum& rhs) = default; - //@} + protected: + //! @name Manipulators + //@{ + /*! + @brief Assignment operator. Protected so that it can only be used + by subclasses but not directly. + */ + Metadatum& operator=(const Metadatum& rhs) = default; + //@} - }; // class Metadatum +}; // class Metadatum - /*! - @brief Output operator for Metadatum types, writing the interpreted - tag value. - */ - inline std::ostream& operator<<(std::ostream& os, const Metadatum& md) - { - return md.write(os); - } +/*! + @brief Output operator for Metadatum types, writing the interpreted + tag value. + */ +inline std::ostream& operator<<(std::ostream& os, const Metadatum& md) { + return md.write(os); +} - /*! - @brief Compare two metadata by tag. Return true if the tag of metadatum - lhs is less than that of rhs. - */ - EXIV2API bool cmpMetadataByTag(const Metadatum& lhs, const Metadatum& rhs); - /*! - @brief Compare two metadata by key. Return true if the key of metadatum - lhs is less than that of rhs. - */ - EXIV2API bool cmpMetadataByKey(const Metadatum& lhs, const Metadatum& rhs); +/*! + @brief Compare two metadata by tag. Return true if the tag of metadatum + lhs is less than that of rhs. + */ +EXIV2API bool cmpMetadataByTag(const Metadatum& lhs, const Metadatum& rhs); +/*! + @brief Compare two metadata by key. Return true if the key of metadatum + lhs is less than that of rhs. + */ +EXIV2API bool cmpMetadataByKey(const Metadatum& lhs, const Metadatum& rhs); -} // namespace Exiv2 +} // namespace Exiv2 -#endif // #ifndef METADATUM_HPP_ +#endif // #ifndef METADATUM_HPP_ diff --git a/include/exiv2/mrwimage.hpp b/include/exiv2/mrwimage.hpp index 47f103f7..281473cc 100644 --- a/include/exiv2/mrwimage.hpp +++ b/include/exiv2/mrwimage.hpp @@ -12,92 +12,91 @@ // ***************************************************************************** // namespace extensions namespace Exiv2 { - // ***************************************************************************** // class definitions - /*! - @brief Class to access raw Minolta MRW images. Exif metadata is supported - directly, IPTC is read from the Exif data, if present. - */ - class EXIV2API MrwImage : public Image { - public: - //! @name NOT Implemented - //@{ - //! Copy constructor - MrwImage(const MrwImage& rhs) = delete; - //! Assignment operator - MrwImage& operator=(const MrwImage& rhs) = delete; - //@} +/*! + @brief Class to access raw Minolta MRW images. Exif metadata is supported + directly, IPTC is read from the Exif data, if present. + */ +class EXIV2API MrwImage : public Image { + public: + //! @name NOT Implemented + //@{ + //! Copy constructor + MrwImage(const MrwImage& rhs) = delete; + //! Assignment operator + MrwImage& operator=(const MrwImage& rhs) = delete; + //@} - //! @name Creators - //@{ - /*! - @brief Constructor that can either open an existing MRW image or create - a new image from scratch. If a new image is to be created, any - existing data is overwritten. 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). - */ - MrwImage(BasicIo::UniquePtr io, bool create); - //@} + //! @name Creators + //@{ + /*! + @brief Constructor that can either open an existing MRW image or create + a new image from scratch. If a new image is to be created, any + existing data is overwritten. 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). + */ + MrwImage(BasicIo::UniquePtr io, bool create); + //@} - //! @name Manipulators - //@{ - void readMetadata() override; - /*! - @brief Todo: Write metadata back to the image. This method is not - yet implemented. Calling it will throw an Error(ErrorCode::kerWritingImageFormatUnsupported). - */ - void writeMetadata() override; - /*! - @brief Todo: Not supported yet, requires writeMetadata(). Calling - this function will throw an Error(ErrorCode::kerInvalidSettingForImage). - */ - void setExifData(const ExifData& exifData) override; - /*! - @brief Todo: Not supported yet, requires writeMetadata(). Calling - this function will throw an Error(ErrorCode::kerInvalidSettingForImage). - */ - void setIptcData(const IptcData& iptcData) override; - /*! - @brief Not supported. MRW format does not contain a comment. - Calling this function will throw an Error(ErrorCode::kerInvalidSettingForImage). - */ - void setComment(std::string_view comment) override; - //@} + //! @name Manipulators + //@{ + void readMetadata() override; + /*! + @brief Todo: Write metadata back to the image. This method is not + yet implemented. Calling it will throw an Error(ErrorCode::kerWritingImageFormatUnsupported). + */ + void writeMetadata() override; + /*! + @brief Todo: Not supported yet, requires writeMetadata(). Calling + this function will throw an Error(ErrorCode::kerInvalidSettingForImage). + */ + void setExifData(const ExifData& exifData) override; + /*! + @brief Todo: Not supported yet, requires writeMetadata(). Calling + this function will throw an Error(ErrorCode::kerInvalidSettingForImage). + */ + void setIptcData(const IptcData& iptcData) override; + /*! + @brief Not supported. MRW format does not contain a comment. + Calling this function will throw an Error(ErrorCode::kerInvalidSettingForImage). + */ + void setComment(std::string_view comment) override; + //@} - //! @name Accessors - //@{ - std::string mimeType() const override; - uint32_t pixelWidth() const override; - uint32_t pixelHeight() const override; - //@} - }; // class MrwImage + //! @name Accessors + //@{ + std::string mimeType() const override; + uint32_t pixelWidth() const override; + uint32_t pixelHeight() const override; + //@} +}; // class MrwImage // ***************************************************************************** // 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 MrwImage 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::UniquePtr newMrwInstance(BasicIo::UniquePtr io, bool create); +// These could be static private functions on Image subclasses but then +// ImageFactory needs to be made a friend. +/*! + @brief Create a new MrwImage 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::UniquePtr newMrwInstance(BasicIo::UniquePtr io, bool create); - //! Check if the file iIo is a MRW image. - EXIV2API bool isMrwType(BasicIo& iIo, bool advance); +//! Check if the file iIo is a MRW image. +EXIV2API bool isMrwType(BasicIo& iIo, bool advance); -} // namespace Exiv2 +} // namespace Exiv2 -#endif // #ifndef MRWIMAGE_HPP_ +#endif // #ifndef MRWIMAGE_HPP_ diff --git a/include/exiv2/orfimage.hpp b/include/exiv2/orfimage.hpp index 313a8f1d..07230098 100644 --- a/include/exiv2/orfimage.hpp +++ b/include/exiv2/orfimage.hpp @@ -12,107 +12,99 @@ // ***************************************************************************** // namespace extensions namespace Exiv2 { - // ***************************************************************************** // class definitions - /*! - @brief Class to access raw Olympus ORF images. Exif metadata is supported - directly, IPTC is read from the Exif data, if present. - */ - class EXIV2API OrfImage : public TiffImage { - public: - //! @name NOT Implemented - //@{ - //! Copy constructor - OrfImage(const OrfImage& rhs) = delete; - //! Assignment operator - OrfImage& operator=(const OrfImage& rhs) = delete; - //@} +/*! + @brief Class to access raw Olympus ORF images. Exif metadata is supported + directly, IPTC is read from the Exif data, if present. + */ +class EXIV2API OrfImage : public TiffImage { + public: + //! @name NOT Implemented + //@{ + //! Copy constructor + OrfImage(const OrfImage& rhs) = delete; + //! Assignment operator + OrfImage& operator=(const OrfImage& rhs) = delete; + //@} - //! @name Creators - //@{ - /*! - @brief Constructor that can either open an existing ORF image or create - a new image from scratch. If a new image is to be created, any - existing data is overwritten. 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). - */ - OrfImage(BasicIo::UniquePtr io, bool create); - //@} + //! @name Creators + //@{ + /*! + @brief Constructor that can either open an existing ORF image or create + a new image from scratch. If a new image is to be created, any + existing data is overwritten. 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). + */ + OrfImage(BasicIo::UniquePtr io, bool create); + //@} - //! @name Manipulators - //@{ - void printStructure(std::ostream& out, PrintStructureOption option, int depth) override; - void readMetadata() override; - void writeMetadata() override; - /*! - @brief Not supported. ORF format does not contain a comment. - Calling this function will throw an Error(ErrorCode::kerInvalidSettingForImage). - */ - void setComment(std::string_view comment) override; - //@} + //! @name Manipulators + //@{ + void printStructure(std::ostream& out, PrintStructureOption option, int depth) override; + void readMetadata() override; + void writeMetadata() override; + /*! + @brief Not supported. ORF format does not contain a comment. + Calling this function will throw an Error(ErrorCode::kerInvalidSettingForImage). + */ + void setComment(std::string_view comment) override; + //@} - //! @name Accessors - //@{ - std::string mimeType() const override; - uint32_t pixelWidth() const override; - uint32_t pixelHeight() const override; - //@} - }; // class OrfImage + //! @name Accessors + //@{ + std::string mimeType() const override; + uint32_t pixelWidth() const override; + uint32_t pixelHeight() const override; + //@} +}; // class OrfImage - /*! - @brief Stateless parser class for data in ORF format. Images use this - class to decode and encode ORF data. - See class TiffParser for details. - */ - class EXIV2API OrfParser { - public: - /*! - @brief Decode metadata from a buffer \em pData of length \em size - with data in ORF format to the provided metadata containers. - See TiffParser::decode(). - */ - static ByteOrder decode(ExifData& exifData, IptcData& iptcData, XmpData& xmpData, const byte* pData, - size_t size); - /*! - @brief Encode metadata from the provided metadata to ORF format. - See TiffParser::encode(). - */ - static WriteMethod encode(BasicIo& io, - const byte* pData, - size_t size, - ByteOrder byteOrder, - const ExifData& exifData, - const IptcData& iptcData, - const XmpData& xmpData - ); - }; // class OrfParser +/*! + @brief Stateless parser class for data in ORF format. Images use this + class to decode and encode ORF data. + See class TiffParser for details. + */ +class EXIV2API OrfParser { + public: + /*! + @brief Decode metadata from a buffer \em pData of length \em size + with data in ORF format to the provided metadata containers. + See TiffParser::decode(). + */ + static ByteOrder decode(ExifData& exifData, IptcData& iptcData, XmpData& xmpData, const byte* pData, size_t size); + /*! + @brief Encode metadata from the provided metadata to ORF format. + See TiffParser::encode(). + */ + static WriteMethod encode(BasicIo& io, const byte* pData, size_t size, ByteOrder byteOrder, const ExifData& exifData, + const IptcData& iptcData, const XmpData& xmpData); +}; // class OrfParser // ***************************************************************************** // 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 OrfImage 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::UniquePtr newOrfInstance(BasicIo::UniquePtr io, bool create); +// These could be static private functions on Image subclasses but then +// ImageFactory needs to be made a friend. +/*! + @brief Create a new OrfImage 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::UniquePtr newOrfInstance(BasicIo::UniquePtr io, bool create); - //! Check if the file iIo is an ORF image. - EXIV2API bool isOrfType(BasicIo& iIo, bool advance); +//! Check if the file iIo is an ORF image. +EXIV2API bool isOrfType(BasicIo& iIo, bool advance); -} // namespace Exiv2 +} // namespace Exiv2 -#endif // #ifndef ORFIMAGE_HPP_ +#endif // #ifndef ORFIMAGE_HPP_ diff --git a/include/exiv2/pgfimage.hpp b/include/exiv2/pgfimage.hpp index abf7d3b4..51d91866 100644 --- a/include/exiv2/pgfimage.hpp +++ b/include/exiv2/pgfimage.hpp @@ -11,94 +11,91 @@ // ***************************************************************************** // namespace extensions -namespace Exiv2 -{ - +namespace Exiv2 { // ***************************************************************************** // class definitions - /*! - @brief Class to access PGF images. Exif and IPTC metadata are supported - directly. - */ - class EXIV2API PgfImage : public Image { - public: - //! @name Creators - //@{ - /*! - @brief Constructor that can either open an existing PGF image or create - a new image from scratch. If a new image is to be created, any - existing data is overwritten. 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). - */ - PgfImage(BasicIo::UniquePtr io, bool create); - //@} +/*! + @brief Class to access PGF images. Exif and IPTC metadata are supported + directly. + */ +class EXIV2API PgfImage : public Image { + public: + //! @name Creators + //@{ + /*! + @brief Constructor that can either open an existing PGF image or create + a new image from scratch. If a new image is to be created, any + existing data is overwritten. 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). + */ + PgfImage(BasicIo::UniquePtr io, bool create); + //@} - //! @name Manipulators - //@{ - void readMetadata() override; - void writeMetadata() override; - //@} + //! @name Manipulators + //@{ + void readMetadata() override; + void writeMetadata() override; + //@} - //! @name Accessors - //@{ - std::string mimeType() const override - { - return "image/pgf"; - } - //@} + //! @name Accessors + //@{ + std::string mimeType() const override { + return "image/pgf"; + } + //@} - //! @name NOT implemented - //@{ - //! Copy constructor - PgfImage(const PgfImage& rhs) = delete; - //! Assignment operator - PgfImage& operator=(const PgfImage& rhs) = delete; + //! @name NOT implemented + //@{ + //! Copy constructor + PgfImage(const PgfImage& rhs) = delete; + //! Assignment operator + PgfImage& operator=(const PgfImage& rhs) = delete; - private: - bool bSwap_; // true for bigEndian hardware, else false - /*! - @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). + private: + bool bSwap_; // true for bigEndian hardware, else false + /*! + @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); - //! Read Magick number. Only version >= 6 is supported. - static byte readPgfMagicNumber(BasicIo& iIo); - //! Read PGF Header size encoded in 32 bits integer. - size_t readPgfHeaderSize(BasicIo& iIo) const; - //! Read header structure. - DataBuf readPgfHeaderStructure(BasicIo& iIo, uint32_t& width, uint32_t& height) const; - //@} + @return 4 if opening or writing to the associated BasicIo fails + */ + void doWriteMetadata(BasicIo& outIo); + //! Read Magick number. Only version >= 6 is supported. + static byte readPgfMagicNumber(BasicIo& iIo); + //! Read PGF Header size encoded in 32 bits integer. + size_t readPgfHeaderSize(BasicIo& iIo) const; + //! Read header structure. + DataBuf readPgfHeaderStructure(BasicIo& iIo, uint32_t& width, uint32_t& height) const; + //@} - }; // class PgfImage +}; // class PgfImage // ***************************************************************************** // 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 PgfImage 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::UniquePtr newPgfInstance(BasicIo::UniquePtr io, bool create); +// These could be static private functions on Image subclasses but then +// ImageFactory needs to be made a friend. +/*! + @brief Create a new PgfImage 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::UniquePtr newPgfInstance(BasicIo::UniquePtr io, bool create); - //! Check if the file iIo is a PGF image. - EXIV2API bool isPgfType(BasicIo& iIo, bool advance); +//! Check if the file iIo is a PGF image. +EXIV2API bool isPgfType(BasicIo& iIo, bool advance); -} // namespace Exiv2 +} // namespace Exiv2 -#endif // #ifndef PGFIMAGE_HPP_ +#endif // #ifndef PGFIMAGE_HPP_ diff --git a/include/exiv2/pngimage.hpp b/include/exiv2/pngimage.hpp index 8f73281c..22670766 100644 --- a/include/exiv2/pngimage.hpp +++ b/include/exiv2/pngimage.hpp @@ -11,94 +11,92 @@ // ***************************************************************************** // namespace extensions -namespace Exiv2 -{ - +namespace Exiv2 { // ***************************************************************************** // class definitions - /*! - @brief Class to access PNG images. Exif and IPTC metadata are supported - directly. - */ - class EXIV2API PngImage : public Image { - public: - //! @name Creators - //@{ - /*! - @brief Constructor that can either open an existing PNG image or create - a new image from scratch. If a new image is to be created, any - existing data is overwritten. 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). - */ - PngImage(BasicIo::UniquePtr io, bool create); - //@} +/*! + @brief Class to access PNG images. Exif and IPTC metadata are supported + directly. + */ +class EXIV2API PngImage : public Image { + public: + //! @name Creators + //@{ + /*! + @brief Constructor that can either open an existing PNG image or create + a new image from scratch. If a new image is to be created, any + existing data is overwritten. 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). + */ + PngImage(BasicIo::UniquePtr io, bool create); + //@} - //! @name Manipulators - //@{ - void readMetadata() override; - void writeMetadata() override; + //! @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 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; + //@} - //! @name Accessors - //@{ - std::string mimeType() const override; - //@} + //! @name Accessors + //@{ + std::string mimeType() const override; + //@} - //! @name NOT implemented - //@{ - //! Copy constructor - PngImage(const PngImage& rhs) = delete; - //! Assignment operator - PngImage& operator=(const PngImage& rhs) = delete; + //! @name NOT implemented + //@{ + //! Copy constructor + PngImage(const PngImage& rhs) = delete; + //! Assignment operator + PngImage& operator=(const PngImage& rhs) = delete; - private: - /*! - @brief Provides the main implementation of writeMetadata() by - writing all buffered metadata to the provided BasicIo. - @throw Error on input-output errors or when the image data is not valid. - @param oIo BasicIo instance to write to (a temporary location). + private: + /*! + @brief Provides the main implementation of writeMetadata() by + writing all buffered metadata to the provided BasicIo. + @throw Error on input-output errors or when the image data is not valid. + @param oIo BasicIo instance to write to (a temporary location). - */ - void doWriteMetadata(BasicIo& outIo); - //@} + */ + void doWriteMetadata(BasicIo& outIo); + //@} - std::string profileName_; + std::string profileName_; - }; // class PngImage +}; // class PngImage // ***************************************************************************** // 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 PngImage 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::UniquePtr newPngInstance(BasicIo::UniquePtr io, bool create); +// These could be static private functions on Image subclasses but then +// ImageFactory needs to be made a friend. +/*! + @brief Create a new PngImage 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::UniquePtr newPngInstance(BasicIo::UniquePtr io, bool create); - //! Check if the file iIo is a PNG image. - EXIV2API bool isPngType(BasicIo& iIo, bool advance); +//! Check if the file iIo is a PNG image. +EXIV2API bool isPngType(BasicIo& iIo, bool advance); -} // namespace Exiv2 +} // namespace Exiv2 -#endif // #ifndef PNGIMAGE_HPP_ +#endif // #ifndef PNGIMAGE_HPP_ diff --git a/include/exiv2/preview.hpp b/include/exiv2/preview.hpp index ea9d9dda..d42db292 100644 --- a/include/exiv2/preview.hpp +++ b/include/exiv2/preview.hpp @@ -11,136 +11,134 @@ // ***************************************************************************** // namespace extensions namespace Exiv2 { +// ***************************************************************************** +// class definitions - // ***************************************************************************** - // class definitions +//! Type of preview image. +using PreviewId = int; - //! Type of preview image. - using PreviewId = int; +/*! + @brief Preview image properties. + */ +struct EXIV2API PreviewProperties { + std::string mimeType_; //!< Preview image mime type. + std::string extension_; //!< Preview image extension. + size_t size_; //!< Preview image size in bytes. + size_t width_; //!< Preview image width in pixels or 0 for unknown width. + size_t height_; //!< Preview image height in pixels or 0 for unknown height. + PreviewId id_; //!< Identifies type of preview image. +}; - /*! - @brief Preview image properties. - */ - struct EXIV2API PreviewProperties - { - std::string mimeType_; //!< Preview image mime type. - std::string extension_; //!< Preview image extension. - size_t size_; //!< Preview image size in bytes. - size_t width_; //!< Preview image width in pixels or 0 for unknown width. - size_t height_; //!< Preview image height in pixels or 0 for unknown height. - PreviewId id_; //!< Identifies type of preview image. - }; +//! Container type to hold all preview images metadata. +using PreviewPropertiesList = std::vector; - //! Container type to hold all preview images metadata. - using PreviewPropertiesList = std::vector; +/*! + @brief Class that holds preview image properties and data buffer. + */ +class EXIV2API PreviewImage { + friend class PreviewManager; - /*! - @brief Class that holds preview image properties and data buffer. - */ - class EXIV2API PreviewImage { - friend class PreviewManager; + public: + //! @name Constructors + //@{ + //! Copy constructor + PreviewImage(const PreviewImage& rhs); + //@} - public: - //! @name Constructors - //@{ - //! Copy constructor - PreviewImage(const PreviewImage& rhs); - //@} + //! @name Manipulators + //@{ + //! Assignment operator + PreviewImage& operator=(const PreviewImage& rhs); + //@} - //! @name Manipulators - //@{ - //! Assignment operator - PreviewImage& operator=(const PreviewImage& rhs); - //@} + //! @name Accessors + //@{ + /*! + @brief Return a copy of the preview image data. The caller owns + this copy and %DataBuf ensures that it will be deleted. + */ + DataBuf copy() const; + /*! + @brief Return a pointer to the image data for read-only access. + */ + const byte* pData() const; + /*! + @brief Return the size of the preview image in bytes. + */ + uint32_t size() const; + /*! + @brief Write the thumbnail image to a file. - //! @name Accessors - //@{ - /*! - @brief Return a copy of the preview image data. The caller owns - this copy and %DataBuf ensures that it will be deleted. - */ - DataBuf copy() const; - /*! - @brief Return a pointer to the image data for read-only access. - */ - const byte* pData() const; - /*! - @brief Return the size of the preview image in bytes. - */ - uint32_t size() const; - /*! - @brief Write the thumbnail image to a file. + A filename extension is appended to \em path according to the image + type of the preview image, so \em path should not include an extension. + The function will overwrite an existing file of the same name. - A filename extension is appended to \em path according to the image - type of the preview image, so \em path should not include an extension. - The function will overwrite an existing file of the same name. + @param path File name of the preview image without extension. + @return The number of bytes written. + */ + size_t writeFile(const std::string& path) const; + /*! + @brief Return the MIME type of the preview image, usually either + \c "image/tiff" or \c "image/jpeg". + */ + std::string mimeType() const; + /*! + @brief Return the file extension for the format of the preview image + (".tif" or ".jpg"). + */ + std::string extension() const; + /*! + @brief Return the width of the preview image in pixels. + */ + size_t width() const; + /*! + @brief Return the height of the preview image in pixels. + */ + size_t height() const; + /*! + @brief Return the preview image type identifier. + */ + PreviewId id() const; + //@} - @param path File name of the preview image without extension. - @return The number of bytes written. - */ - size_t writeFile(const std::string& path) const; - /*! - @brief Return the MIME type of the preview image, usually either - \c "image/tiff" or \c "image/jpeg". - */ - std::string mimeType() const; - /*! - @brief Return the file extension for the format of the preview image - (".tif" or ".jpg"). - */ - std::string extension() const; - /*! - @brief Return the width of the preview image in pixels. - */ - size_t width() const; - /*! - @brief Return the height of the preview image in pixels. - */ - size_t height() const; - /*! - @brief Return the preview image type identifier. - */ - PreviewId id() const; - //@} + private: + //! Private constructor + PreviewImage(PreviewProperties properties, DataBuf&& data); - private: - //! Private constructor - PreviewImage(PreviewProperties properties, DataBuf&& data); + PreviewProperties properties_; //!< Preview image properties + DataBuf preview_; //!< Preview image data - PreviewProperties properties_; //!< Preview image properties - DataBuf preview_; //!< Preview image data +}; // class PreviewImage - }; // class PreviewImage +/*! + @brief Class for extracting preview images from image metadata. + */ +class EXIV2API PreviewManager { + public: + //! @name Constructors + //@{ + //! Constructor. + explicit PreviewManager(const Image& image); + //@} - /*! - @brief Class for extracting preview images from image metadata. - */ - class EXIV2API PreviewManager { - public: - //! @name Constructors - //@{ - //! Constructor. - explicit PreviewManager(const Image& image); - //@} + //! @name Accessors + //@{ + /*! + @brief Return the properties of all preview images in a list + sorted by preview width * height, starting with the smallest + preview image. + */ + PreviewPropertiesList getPreviewProperties() const; + /*! + @brief Return the preview image for the given preview properties. + */ + PreviewImage getPreviewImage(const PreviewProperties& properties) const; + //@} - //! @name Accessors - //@{ - /*! - @brief Return the properties of all preview images in a list - sorted by preview width * height, starting with the smallest - preview image. - */ - PreviewPropertiesList getPreviewProperties() const; - /*! - @brief Return the preview image for the given preview properties. - */ - PreviewImage getPreviewImage(const PreviewProperties& properties) const; - //@} + private: + const Image& image_; - private: - const Image& image_; - - }; // class PreviewManager +}; // class PreviewManager } // namespace Exiv2 #endif // #ifndef PREVIEW_HPP_ diff --git a/include/exiv2/properties.hpp b/include/exiv2/properties.hpp index b77e2548..12f6fd35 100644 --- a/include/exiv2/properties.hpp +++ b/include/exiv2/properties.hpp @@ -7,292 +7,288 @@ #include "exiv2lib_export.h" // included header files -#include "datasets.hpp" #include +#include "datasets.hpp" // ***************************************************************************** // namespace extensions namespace Exiv2 { - // ***************************************************************************** // class declarations - class XmpKey; +class XmpKey; // ***************************************************************************** // class definitions - //! Category of an XMP property - enum XmpCategory { xmpInternal, xmpExternal }; +//! Category of an XMP property +enum XmpCategory { xmpInternal, xmpExternal }; - //! Information about one XMP property. - struct EXIV2API XmpPropertyInfo { - //! Comparison operator for name - bool operator==(const std::string& name) const; +//! Information about one XMP property. +struct EXIV2API XmpPropertyInfo { + //! Comparison operator for name + bool operator==(const std::string& name) const; - const char* name_; //!< Property name - const char* title_; //!< Property title or label - const char* xmpValueType_; //!< XMP value type (for info only) - TypeId typeId_; //!< Exiv2 default type for the property - XmpCategory xmpCategory_; //!< Category (internal or external) - const char* desc_; //!< Property description - }; + const char* name_; //!< Property name + const char* title_; //!< Property title or label + const char* xmpValueType_; //!< XMP value type (for info only) + TypeId typeId_; //!< Exiv2 default type for the property + XmpCategory xmpCategory_; //!< Category (internal or external) + const char* desc_; //!< Property description +}; - //! Structure mapping XMP namespaces and (preferred) prefixes. - struct EXIV2API XmpNsInfo { - //! For comparison with prefix - struct Prefix { - //! Constructor. - explicit Prefix(std::string prefix); - //! The prefix string. - std::string prefix_; - }; - //! For comparison with namespace - struct Ns { - //! Constructor. - explicit Ns(std::string ns); - //! The namespace string - std::string ns_; - }; - //! Comparison operator for namespace - bool operator==(const Ns& ns) const; - //! Comparison operator for prefix - bool operator==(const Prefix& prefix) const; +//! Structure mapping XMP namespaces and (preferred) prefixes. +struct EXIV2API XmpNsInfo { + //! For comparison with prefix + struct Prefix { + //! Constructor. + explicit Prefix(std::string prefix); + //! The prefix string. + std::string prefix_; + }; + //! For comparison with namespace + struct Ns { + //! Constructor. + explicit Ns(std::string ns); + //! The namespace string + std::string ns_; + }; + //! Comparison operator for namespace + bool operator==(const Ns& ns) const; + //! Comparison operator for prefix + bool operator==(const Prefix& prefix) const; - const char* ns_; //!< Namespace - const char* prefix_; //!< (Preferred) prefix - const XmpPropertyInfo* xmpPropertyInfo_; //!< List of known properties - const char* desc_; //!< Brief description of the namespace - }; + const char* ns_; //!< Namespace + const char* prefix_; //!< (Preferred) prefix + const XmpPropertyInfo* xmpPropertyInfo_; //!< List of known properties + const char* desc_; //!< Brief description of the namespace +}; - //! XMP property reference, implemented as a static class. - class EXIV2API XmpProperties { - //! Prevent construction: not implemented. - XmpProperties(); - //! Prevent copy-construction: not implemented. - XmpProperties(const XmpProperties& rhs); - //! Prevent assignment: not implemented. - XmpProperties& operator=(const XmpProperties& rhs); +//! XMP property reference, implemented as a static class. +class EXIV2API XmpProperties { + //! Prevent construction: not implemented. + XmpProperties(); + //! Prevent copy-construction: not implemented. + XmpProperties(const XmpProperties& rhs); + //! Prevent assignment: not implemented. + XmpProperties& operator=(const XmpProperties& rhs); - private: - static const XmpNsInfo* nsInfoUnsafe(const std::string& prefix); - static void unregisterNsUnsafe(const std::string& ns); - static const XmpNsInfo* lookupNsRegistryUnsafe(const XmpNsInfo::Prefix& prefix); + private: + static const XmpNsInfo* nsInfoUnsafe(const std::string& prefix); + static void unregisterNsUnsafe(const std::string& ns); + static const XmpNsInfo* lookupNsRegistryUnsafe(const XmpNsInfo::Prefix& prefix); - public: - /*! - @brief Return the title (label) of the property. - @param key The property key - @return The title (label) of the property, 0 if the - key is of an unknown property. - */ - static const char* propertyTitle(const XmpKey& key); - /*! - @brief Return the description of the property. - @param key The property key - @return The description of the property, 0 if the - key is of an unknown property. - */ - static const char* propertyDesc(const XmpKey& key); - /*! - @brief Return the type for property \em key. The default - for unknown keys is xmpText. - @param key The property key - @return The type of the property - */ - static TypeId propertyType(const XmpKey& key); - /*! - @brief Return information for the property for key. + public: + /*! + @brief Return the title (label) of the property. + @param key The property key + @return The title (label) of the property, 0 if the + key is of an unknown property. + */ + static const char* propertyTitle(const XmpKey& key); + /*! + @brief Return the description of the property. + @param key The property key + @return The description of the property, 0 if the + key is of an unknown property. + */ + static const char* propertyDesc(const XmpKey& key); + /*! + @brief Return the type for property \em key. The default + for unknown keys is xmpText. + @param key The property key + @return The type of the property + */ + static TypeId propertyType(const XmpKey& key); + /*! + @brief Return information for the property for key. - If the key is a path to a nested property (one which contains a slash, - like \c Xmp.MP.RegionInfo/MPRI:Regions), determines the innermost element - (\c Xmp.MPRI.Regions) and returns its property information. + If the key is a path to a nested property (one which contains a slash, + like \c Xmp.MP.RegionInfo/MPRI:Regions), determines the innermost element + (\c Xmp.MPRI.Regions) and returns its property information. - @param key The property key - @return A pointer to the property information, 0 if the - key is of an unknown property. - */ - static const XmpPropertyInfo* propertyInfo(const XmpKey& key); - /*! - @brief Return the namespace name for the schema associated - with \em prefix. - @param prefix Prefix - @return The namespace name - @throw Error if no namespace is registered with \em prefix. - */ - static std::string ns(const std::string& prefix); - /*! - @brief Return the namespace description for the schema associated - with \em prefix. - @param prefix Prefix - @return The namespace description - @throw Error if no namespace is registered with \em prefix. - */ - static const char* nsDesc(const std::string& prefix); - /*! - @brief Return read-only list of built-in properties for \em prefix. - @param prefix Prefix - @return Pointer to the built-in properties for prefix, may be 0 if - none is configured in the namespace info. - @throw Error if no namespace is registered with \em prefix. - */ - static const XmpPropertyInfo* propertyList(const std::string& prefix); - /*! - @brief Return information about a schema namespace for \em prefix. - Always returns a valid pointer. - @param prefix The prefix - @return A pointer to the related information - @throw Error if no namespace is registered with \em prefix. - */ - static const XmpNsInfo* nsInfo(const std::string& prefix); + @param key The property key + @return A pointer to the property information, 0 if the + key is of an unknown property. + */ + static const XmpPropertyInfo* propertyInfo(const XmpKey& key); + /*! + @brief Return the namespace name for the schema associated + with \em prefix. + @param prefix Prefix + @return The namespace name + @throw Error if no namespace is registered with \em prefix. + */ + static std::string ns(const std::string& prefix); + /*! + @brief Return the namespace description for the schema associated + with \em prefix. + @param prefix Prefix + @return The namespace description + @throw Error if no namespace is registered with \em prefix. + */ + static const char* nsDesc(const std::string& prefix); + /*! + @brief Return read-only list of built-in properties for \em prefix. + @param prefix Prefix + @return Pointer to the built-in properties for prefix, may be 0 if + none is configured in the namespace info. + @throw Error if no namespace is registered with \em prefix. + */ + static const XmpPropertyInfo* propertyList(const std::string& prefix); + /*! + @brief Return information about a schema namespace for \em prefix. + Always returns a valid pointer. + @param prefix The prefix + @return A pointer to the related information + @throw Error if no namespace is registered with \em prefix. + */ + static const XmpNsInfo* nsInfo(const std::string& prefix); - /*! - @brief Return the (preferred) prefix for schema namespace \em ns. - @param ns Schema namespace - @return The prefix or an empty string if namespace \em ns is not - registered. - */ - static std::string prefix(const std::string& ns); - //! Print a list of properties of a schema namespace to output stream \em os. - static void printProperties(std::ostream& os, const std::string& prefix); + /*! + @brief Return the (preferred) prefix for schema namespace \em ns. + @param ns Schema namespace + @return The prefix or an empty string if namespace \em ns is not + registered. + */ + static std::string prefix(const std::string& ns); + //! Print a list of properties of a schema namespace to output stream \em os. + static void printProperties(std::ostream& os, const std::string& prefix); - //! Interpret and print the value of an XMP property - static std::ostream& printProperty(std::ostream& os, - const std::string& key, - const Value& value); - /*! - @brief Register namespace \em ns with preferred prefix \em prefix. + //! Interpret and print the value of an XMP property + static std::ostream& printProperty(std::ostream& os, const std::string& key, const Value& value); + /*! + @brief Register namespace \em ns with preferred prefix \em prefix. - If the prefix is a known or previously registered prefix, the - corresponding namespace URI is overwritten. + If the prefix is a known or previously registered prefix, the + corresponding namespace URI is overwritten. - @note This invalidates XMP keys generated with the previous prefix. - */ - static void registerNs(const std::string& ns, const std::string& prefix); - /*! - @brief Unregister a custom namespace \em ns. + @note This invalidates XMP keys generated with the previous prefix. + */ + static void registerNs(const std::string& ns, const std::string& prefix); + /*! + @brief Unregister a custom namespace \em ns. - The function only has an effect if there is a namespace \em ns - registered earlier, it does not unregister built-in namespaces. + The function only has an effect if there is a namespace \em ns + registered earlier, it does not unregister built-in namespaces. - @note This invalidates XMP keys generated in this namespace. - */ - static void unregisterNs(const std::string& ns); + @note This invalidates XMP keys generated in this namespace. + */ + static void unregisterNs(const std::string& ns); - /*! - @brief Lock to be used while modifying properties. + /*! + @brief Lock to be used while modifying properties. - @todo For a proper read-write lock, this shall be improved by a - \em std::shared_timed_mutex (once C++14 is allowed) or - \em std::shared_mutex (once C++17 is allowed). The - read-access locks shall be updated to \em std::shared_lock then. - */ - static std::mutex mutex_; + @todo For a proper read-write lock, this shall be improved by a + \em std::shared_timed_mutex (once C++14 is allowed) or + \em std::shared_mutex (once C++17 is allowed). The + read-access locks shall be updated to \em std::shared_lock then. + */ + static std::mutex mutex_; - /*! - @brief Unregister all custom namespaces. + /*! + @brief Unregister all custom namespaces. - The function only unregisters namespaces registered earlier, it does not - unregister built-in namespaces. + The function only unregisters namespaces registered earlier, it does not + unregister built-in namespaces. - @note This invalidates XMP keys generated in any custom namespace. - */ - static void unregisterNs(); - //! Type for the namespace registry - using NsRegistry = std::map; - /*! - @brief Get the registered namespace for a specific \em prefix from the registry. - */ - static const XmpNsInfo* lookupNsRegistry(const XmpNsInfo::Prefix& prefix); + @note This invalidates XMP keys generated in any custom namespace. + */ + static void unregisterNs(); + //! Type for the namespace registry + using NsRegistry = std::map; + /*! + @brief Get the registered namespace for a specific \em prefix from the registry. + */ + static const XmpNsInfo* lookupNsRegistry(const XmpNsInfo::Prefix& prefix); - // DATA - static NsRegistry nsRegistry_; //!< Namespace registry + // DATA + static NsRegistry nsRegistry_; //!< Namespace registry - /*! - @brief Get all registered namespaces (for both Exiv2 and XMPsdk) - */ - static void registeredNamespaces(Exiv2::Dictionary& nsDict); + /*! + @brief Get all registered namespaces (for both Exiv2 and XMPsdk) + */ + static void registeredNamespaces(Exiv2::Dictionary& nsDict); - }; // class XmpProperties +}; // class XmpProperties - /*! - @brief Concrete keys for XMP metadata. - */ - class EXIV2API XmpKey : public Key - { - public: - //! Shortcut for an %XmpKey auto pointer. - using UniquePtr = std::unique_ptr; +/*! + @brief Concrete keys for XMP metadata. + */ +class EXIV2API XmpKey : public Key { + public: + //! Shortcut for an %XmpKey auto pointer. + using UniquePtr = std::unique_ptr; - //! @name Creators - //@{ - /*! - @brief Constructor to create an XMP key from a key string. + //! @name Creators + //@{ + /*! + @brief Constructor to create an XMP key from a key string. - @param key The key string. - @throw Error if the first part of the key is not 'Xmp' or - the second part of the key cannot be parsed and converted - to a known (i.e., built-in or registered) schema prefix. - */ - explicit XmpKey(const std::string& key); - /*! - @brief Constructor to create an XMP key from a schema prefix - and a property name. + @param key The key string. + @throw Error if the first part of the key is not 'Xmp' or + the second part of the key cannot be parsed and converted + to a known (i.e., built-in or registered) schema prefix. + */ + explicit XmpKey(const std::string& key); + /*! + @brief Constructor to create an XMP key from a schema prefix + and a property name. - @param prefix Schema prefix name - @param property Property name + @param prefix Schema prefix name + @param property Property name - @throw Error if the schema prefix is not known. - */ - XmpKey(const std::string& prefix, const std::string& property); - //! Copy constructor. - XmpKey(const XmpKey& rhs); - //! Virtual destructor. - ~XmpKey() override; - //@} + @throw Error if the schema prefix is not known. + */ + XmpKey(const std::string& prefix, const std::string& property); + //! Copy constructor. + XmpKey(const XmpKey& rhs); + //! Virtual destructor. + ~XmpKey() override; + //@} - //! @name Manipulators - //@{ - //! Assignment operator. - XmpKey& operator=(const XmpKey& rhs); - //@} + //! @name Manipulators + //@{ + //! Assignment operator. + XmpKey& operator=(const XmpKey& rhs); + //@} - //! @name Accessors - //@{ - std::string key() const override; - const char* familyName() const override; - /*! - @brief Return the name of the group (the second part of the key). - For XMP keys, the group name is the schema prefix name. - */ - std::string groupName() const override; - std::string tagName() const override; - std::string tagLabel() const override; - //! Properties don't have a tag number. Return 0. - uint16_t tag() const override; + //! @name Accessors + //@{ + std::string key() const override; + const char* familyName() const override; + /*! + @brief Return the name of the group (the second part of the key). + For XMP keys, the group name is the schema prefix name. + */ + std::string groupName() const override; + std::string tagName() const override; + std::string tagLabel() const override; + //! Properties don't have a tag number. Return 0. + uint16_t tag() const override; - UniquePtr clone() const; + UniquePtr clone() const; - // Todo: Should this be removed? What about tagLabel then? - //! Return the schema namespace for the prefix of the key - std::string ns() const; - //@} + // Todo: Should this be removed? What about tagLabel then? + //! Return the schema namespace for the prefix of the key + std::string ns() const; + //@} - private: - //! Internal virtual copy constructor. - XmpKey* clone_() const override; + private: + //! Internal virtual copy constructor. + XmpKey* clone_() const override; - // Pimpl idiom - struct Impl; - std::unique_ptr p_; + // Pimpl idiom + struct Impl; + std::unique_ptr p_; - }; // class XmpKey +}; // class XmpKey - // ***************************************************************************** - // free functions +// ***************************************************************************** +// free functions - //! Output operator for property info - EXIV2API std::ostream& operator<<(std::ostream& os, const XmpPropertyInfo& propertyInfo); +//! Output operator for property info +EXIV2API std::ostream& operator<<(std::ostream& os, const XmpPropertyInfo& propertyInfo); -} // namespace Exiv2 +} // namespace Exiv2 -#endif // #ifndef PROPERTIES_HPP_ +#endif // #ifndef PROPERTIES_HPP_ diff --git a/include/exiv2/psdimage.hpp b/include/exiv2/psdimage.hpp index cb56911a..1d070292 100644 --- a/include/exiv2/psdimage.hpp +++ b/include/exiv2/psdimage.hpp @@ -12,104 +12,103 @@ // ***************************************************************************** // namespace extensions namespace Exiv2 { - // ***************************************************************************** // class definitions - /*! - @brief Class to access raw Photoshop images. - */ - class EXIV2API PsdImage : public Image { - public: - //! @name NOT Implemented - //@{ - //! Copy constructor - PsdImage(const PsdImage& rhs) = delete; - //! Assignment operator - PsdImage& operator=(const PsdImage& rhs) = delete; - //@} +/*! + @brief Class to access raw Photoshop images. + */ +class EXIV2API PsdImage : public Image { + public: + //! @name NOT Implemented + //@{ + //! Copy constructor + PsdImage(const PsdImage& rhs) = delete; + //! Assignment operator + PsdImage& operator=(const PsdImage& rhs) = delete; + //@} - //! @name Creators - //@{ - /*! - @brief Constructor to open a Photoshop 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. - */ - explicit PsdImage(BasicIo::UniquePtr io); - //@} + //! @name Creators + //@{ + /*! + @brief Constructor to open a Photoshop 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. + */ + explicit PsdImage(BasicIo::UniquePtr io); + //@} - //! @name Manipulators - //@{ - void readMetadata() override; - void writeMetadata() override; - /*! - @brief Not supported. Calling this function will throw an Error(ErrorCode::kerInvalidSettingForImage). - */ - void setComment(std::string_view comment) override; - //@} + //! @name Manipulators + //@{ + void readMetadata() override; + void writeMetadata() override; + /*! + @brief Not supported. Calling this function will throw an Error(ErrorCode::kerInvalidSettingForImage). + */ + void setComment(std::string_view comment) override; + //@} - //! @name Accessors - //@{ - /*! - @brief Return the MIME type of the image. + //! @name Accessors + //@{ + /*! + @brief Return the MIME type of the image. - The MIME type returned for Photoshop images is "image/x-photoshop". + The MIME type returned for Photoshop images is "image/x-photoshop". - @note This should really be "image/vnd.adobe.photoshop" - (officially registered with IANA in December 2005 -- see - http://www.iana.org/assignments/media-types/image/vnd.adobe.photoshop) - but Apple, as of Tiger (10.4.8), maps this official MIME type to a - dynamic UTI, rather than "com.adobe.photoshop-image" as it should. - */ - std::string mimeType() const override; - //@} + @note This should really be "image/vnd.adobe.photoshop" + (officially registered with IANA in December 2005 -- see + http://www.iana.org/assignments/media-types/image/vnd.adobe.photoshop) + but Apple, as of Tiger (10.4.8), maps this official MIME type to a + dynamic UTI, rather than "com.adobe.photoshop-image" as it should. + */ + std::string mimeType() const override; + //@} - private: - //! @name Manipulators - //@{ - void readResourceBlock(uint16_t resourceId, uint32_t resourceSize); - /*! - @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). + private: + //! @name Manipulators + //@{ + void readResourceBlock(uint16_t resourceId, uint32_t resourceSize); + /*! + @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); - uint32_t writeExifData(const ExifData& exifData, BasicIo& out); - //@} + @return 4 if opening or writing to the associated BasicIo fails + */ + void doWriteMetadata(BasicIo& outIo); + uint32_t writeExifData(const ExifData& exifData, BasicIo& out); + //@} - //! @name Accessors - //@{ - static uint32_t writeIptcData(const IptcData& iptcData, BasicIo& out); - uint32_t writeXmpData(const XmpData& xmpData, BasicIo& out) const; - //@} + //! @name Accessors + //@{ + static uint32_t writeIptcData(const IptcData& iptcData, BasicIo& out); + uint32_t writeXmpData(const XmpData& xmpData, BasicIo& out) const; + //@} - }; // class PsdImage +}; // class PsdImage // ***************************************************************************** // 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 PsdImage 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::UniquePtr newPsdInstance(BasicIo::UniquePtr io, bool create); +// These could be static private functions on Image subclasses but then +// ImageFactory needs to be made a friend. +/*! + @brief Create a new PsdImage 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::UniquePtr newPsdInstance(BasicIo::UniquePtr io, bool create); - //! Check if the file iIo is a Photoshop image. - EXIV2API bool isPsdType(BasicIo& iIo, bool advance); +//! Check if the file iIo is a Photoshop image. +EXIV2API bool isPsdType(BasicIo& iIo, bool advance); -} // namespace Exiv2 +} // namespace Exiv2 -#endif // #ifndef PSDIMAGE_HPP_ +#endif // #ifndef PSDIMAGE_HPP_ diff --git a/include/exiv2/rafimage.hpp b/include/exiv2/rafimage.hpp index 1db1c005..9b675116 100644 --- a/include/exiv2/rafimage.hpp +++ b/include/exiv2/rafimage.hpp @@ -12,94 +12,93 @@ // ***************************************************************************** // namespace extensions namespace Exiv2 { - // ***************************************************************************** // class definitions - /*! - @brief Class to access raw Fujifilm RAF images. Exif metadata is - supported directly, IPTC is read from the Exif data, if present. - */ - class EXIV2API RafImage : public Image { - public: - //! @name Creators - //@{ - /*! - @brief Constructor that can either open an existing RAF image or create - a new image from scratch. If a new image is to be created, any - existing data is overwritten. 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). - */ - RafImage(BasicIo::UniquePtr io, bool create); - //@} +/*! + @brief Class to access raw Fujifilm RAF images. Exif metadata is + supported directly, IPTC is read from the Exif data, if present. + */ +class EXIV2API RafImage : public Image { + public: + //! @name Creators + //@{ + /*! + @brief Constructor that can either open an existing RAF image or create + a new image from scratch. If a new image is to be created, any + existing data is overwritten. 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). + */ + RafImage(BasicIo::UniquePtr io, bool create); + //@} - //! @name Manipulators - //@{ - void printStructure(std::ostream& out, PrintStructureOption option, int depth) override; - void readMetadata() override; - /*! - @brief Todo: Write metadata back to the image. This method is not - yet implemented. Calling it will throw an Error(ErrorCode::kerWritingImageFormatUnsupported). - */ - void writeMetadata() override; - /*! - @brief Todo: Not supported yet, requires writeMetadata(). Calling - this function will throw an Error(ErrorCode::kerInvalidSettingForImage). - */ - void setExifData(const ExifData& exifData) override; - /*! - @brief Todo: Not supported yet, requires writeMetadata(). Calling - this function will throw an Error(ErrorCode::kerInvalidSettingForImage). - */ - void setIptcData(const IptcData& iptcData) override; - /*! - @brief Not supported. RAF format does not contain a comment. - Calling this function will throw an Error(ErrorCode::kerInvalidSettingForImage). - */ - void setComment(std::string_view comment) override; - //@} + //! @name Manipulators + //@{ + void printStructure(std::ostream& out, PrintStructureOption option, int depth) override; + void readMetadata() override; + /*! + @brief Todo: Write metadata back to the image. This method is not + yet implemented. Calling it will throw an Error(ErrorCode::kerWritingImageFormatUnsupported). + */ + void writeMetadata() override; + /*! + @brief Todo: Not supported yet, requires writeMetadata(). Calling + this function will throw an Error(ErrorCode::kerInvalidSettingForImage). + */ + void setExifData(const ExifData& exifData) override; + /*! + @brief Todo: Not supported yet, requires writeMetadata(). Calling + this function will throw an Error(ErrorCode::kerInvalidSettingForImage). + */ + void setIptcData(const IptcData& iptcData) override; + /*! + @brief Not supported. RAF format does not contain a comment. + Calling this function will throw an Error(ErrorCode::kerInvalidSettingForImage). + */ + void setComment(std::string_view comment) override; + //@} - //! @name Accessors - //@{ - std::string mimeType() const override; - uint32_t pixelWidth() const override; - uint32_t pixelHeight() const override; - //@} + //! @name Accessors + //@{ + std::string mimeType() const override; + uint32_t pixelWidth() const override; + uint32_t pixelHeight() const override; + //@} - //! @name NOT implemented - //@{ - //! Copy constructor - RafImage(const RafImage& rhs) = delete; - //! Assignment operator - RafImage& operator=(const RafImage& rhs) = delete; - //@} + //! @name NOT implemented + //@{ + //! Copy constructor + RafImage(const RafImage& rhs) = delete; + //! Assignment operator + RafImage& operator=(const RafImage& rhs) = delete; + //@} - }; // class RafImage +}; // class RafImage // ***************************************************************************** // 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 RafImage 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::UniquePtr newRafInstance(BasicIo::UniquePtr io, bool create); +// These could be static private functions on Image subclasses but then +// ImageFactory needs to be made a friend. +/*! + @brief Create a new RafImage 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::UniquePtr newRafInstance(BasicIo::UniquePtr io, bool create); - //! Check if the file iIo is a RAF image. - EXIV2API bool isRafType(BasicIo& iIo, bool advance); +//! Check if the file iIo is a RAF image. +EXIV2API bool isRafType(BasicIo& iIo, bool advance); -} // namespace Exiv2 +} // namespace Exiv2 -#endif // #ifndef RAFIMAGE_HPP_ +#endif // #ifndef RAFIMAGE_HPP_ diff --git a/include/exiv2/rw2image.hpp b/include/exiv2/rw2image.hpp index 878e601b..01cb3fea 100644 --- a/include/exiv2/rw2image.hpp +++ b/include/exiv2/rw2image.hpp @@ -12,113 +12,107 @@ // ***************************************************************************** // namespace extensions namespace Exiv2 { - // ***************************************************************************** // class definitions - /*! - @brief Class to access raw Panasonic RW2 images. Exif metadata is - supported directly, IPTC and XMP are read from the Exif data, if - present. - */ - class EXIV2API Rw2Image : public Image { - public: - //! @name Creators - //@{ - /*! - @brief Constructor to open an existing RW2 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. - */ - explicit Rw2Image(BasicIo::UniquePtr io); - //@} +/*! + @brief Class to access raw Panasonic RW2 images. Exif metadata is + supported directly, IPTC and XMP are read from the Exif data, if + present. + */ +class EXIV2API Rw2Image : public Image { + public: + //! @name Creators + //@{ + /*! + @brief Constructor to open an existing RW2 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. + */ + explicit Rw2Image(BasicIo::UniquePtr io); + //@} - //! @name Manipulators - //@{ - void printStructure(std::ostream& out, PrintStructureOption option, int depth) override; - void readMetadata() override; - /*! - @brief Todo: Write metadata back to the image. This method is not - yet implemented. Calling it will throw an Error(ErrorCode::kerWritingImageFormatUnsupported). - */ - void writeMetadata() override; - /*! - @brief Todo: Not supported yet, requires writeMetadata(). Calling - this function will throw an Error(ErrorCode::kerInvalidSettingForImage). - */ - void setExifData(const ExifData& exifData) override; - /*! - @brief Todo: Not supported yet, requires writeMetadata(). Calling - this function will throw an Error(ErrorCode::kerInvalidSettingForImage). - */ - void setIptcData(const IptcData& iptcData) override; - /*! - @brief Not supported. RW2 format does not contain a comment. - Calling this function will throw an Error(ErrorCode::kerInvalidSettingForImage). - */ - void setComment(std::string_view comment) override; - //@} + //! @name Manipulators + //@{ + void printStructure(std::ostream& out, PrintStructureOption option, int depth) override; + void readMetadata() override; + /*! + @brief Todo: Write metadata back to the image. This method is not + yet implemented. Calling it will throw an Error(ErrorCode::kerWritingImageFormatUnsupported). + */ + void writeMetadata() override; + /*! + @brief Todo: Not supported yet, requires writeMetadata(). Calling + this function will throw an Error(ErrorCode::kerInvalidSettingForImage). + */ + void setExifData(const ExifData& exifData) override; + /*! + @brief Todo: Not supported yet, requires writeMetadata(). Calling + this function will throw an Error(ErrorCode::kerInvalidSettingForImage). + */ + void setIptcData(const IptcData& iptcData) override; + /*! + @brief Not supported. RW2 format does not contain a comment. + Calling this function will throw an Error(ErrorCode::kerInvalidSettingForImage). + */ + void setComment(std::string_view comment) override; + //@} - //! @name Accessors - //@{ - std::string mimeType() const override; - uint32_t pixelWidth() const override; - uint32_t pixelHeight() const override; - //@} + //! @name Accessors + //@{ + std::string mimeType() const override; + uint32_t pixelWidth() const override; + uint32_t pixelHeight() const override; + //@} - //! @name NOT implemented - //@{ - //! Copy constructor - Rw2Image(const Rw2Image& rhs) = delete; - //! Assignment operator - Rw2Image& operator=(const Rw2Image& rhs) = delete; - //@} + //! @name NOT implemented + //@{ + //! Copy constructor + Rw2Image(const Rw2Image& rhs) = delete; + //! Assignment operator + Rw2Image& operator=(const Rw2Image& rhs) = delete; + //@} - }; // class Rw2Image +}; // class Rw2Image - /*! - @brief Stateless parser class for data in RW2 format. Images use this - class to decode and encode RW2 data. Only decoding is currently - implemented. See class TiffParser for details. - */ - class EXIV2API Rw2Parser { - public: - /*! - @brief Decode metadata from a buffer \em pData of length \em size - with data in RW2 format to the provided metadata containers. - See TiffParser::decode(). - */ - static ByteOrder decode(ExifData& exifData, - IptcData& iptcData, - XmpData& xmpData, - const byte* pData, - size_t size - ); +/*! + @brief Stateless parser class for data in RW2 format. Images use this + class to decode and encode RW2 data. Only decoding is currently + implemented. See class TiffParser for details. + */ +class EXIV2API Rw2Parser { + public: + /*! + @brief Decode metadata from a buffer \em pData of length \em size + with data in RW2 format to the provided metadata containers. + See TiffParser::decode(). + */ + static ByteOrder decode(ExifData& exifData, IptcData& iptcData, XmpData& xmpData, const byte* pData, size_t size); - }; // class Rw2Parser +}; // class Rw2Parser // ***************************************************************************** // 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 Rw2Image 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::UniquePtr newRw2Instance(BasicIo::UniquePtr io, bool create); +// These could be static private functions on Image subclasses but then +// ImageFactory needs to be made a friend. +/*! + @brief Create a new Rw2Image 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::UniquePtr newRw2Instance(BasicIo::UniquePtr io, bool create); - //! Check if the file iIo is a RW2 image. - EXIV2API bool isRw2Type(BasicIo& iIo, bool advance); +//! Check if the file iIo is a RW2 image. +EXIV2API bool isRw2Type(BasicIo& iIo, bool advance); -} // namespace Exiv2 +} // namespace Exiv2 -#endif // #ifndef RW2IMAGE_HPP_ +#endif // #ifndef RW2IMAGE_HPP_ diff --git a/include/exiv2/slice.hpp b/include/exiv2/slice.hpp index 5477e66f..a7a282fa 100644 --- a/include/exiv2/slice.hpp +++ b/include/exiv2/slice.hpp @@ -8,643 +8,588 @@ #include #include -namespace Exiv2 -{ - namespace Internal - { - /*! - * Common base class of all slice implementations. - * - * Implements only the most basic functions, which do not require any - * knowledge about the stored data. - */ - struct SliceBase - { - inline SliceBase(size_t begin, size_t end) : begin_(begin), end_(end) - { - if (begin >= end) { - throw std::out_of_range("Begin must be smaller than end"); - } - } - - /*! - * Return the number of elements in the slice. - */ - inline size_t size() const noexcept - { - // cannot underflow, as we know that begin < end - return end_ - begin_; - } - - protected: - /*! - * Throw an exception when index is too large. - * - * @throw std::out_of_range when `index` will access an element - * outside of the slice - */ - inline void rangeCheck(size_t index) const - { - if (index >= size()) { - throw std::out_of_range("Index outside of the slice"); - } - } - - /*! - * lower and upper bounds of the slice with respect to the - * container/array stored in storage_ - */ - const size_t begin_, end_; - }; - - /*! - * @brief This class provides the public-facing const-qualified methods - * of a slice. - * - * The public methods are implemented in a generic fashion using a - * storage_type. This type contains the actual reference to the data to - * which the slice points and provides the following methods: - * - * - (const) value_type& unsafeAt(size_t index) (const) - * Return the value at the given index of the underlying container, - * without promising to perform a range check and without any - * knowledge of the slices' size - * - * - const_iterator/iterator unsafeGetIteratorAt(size_t index) (const) - * Return a (constant) iterator at the given index of the underlying - * container. Again, no range checks are promised. - * - * - Constructor(data_type& data, size_t begin, size_t end) - * Can use `begin` & `end` to perform range checks on `data`, but - * should not store both values. Must not take ownership of `data`! - * - * - Must save data as a public member named `data_`. - * - * - Must provide appropriate typedefs for iterator, const_iterator and - * value_type - */ - template