Move Photoshopb class to internal namespace

main
Luis Díaz Más 3 years ago
parent 047f6b733e
commit f942ba89bd

@ -13,6 +13,7 @@
#include "xmp_exiv2.hpp"
#include <algorithm>
#include <array>
#include <cctype>
#include <cstring>
#include <fstream>

@ -29,6 +29,7 @@
#include "exiv2/mrwimage.hpp"
#include "exiv2/orfimage.hpp"
#include "exiv2/pgfimage.hpp"
#include "exiv2/photoshop.hpp"
#ifdef EXV_HAVE_LIBZ
#include "exiv2/pngimage.hpp"

@ -3,11 +3,8 @@
#ifndef JPGIMAGE_HPP_
#define JPGIMAGE_HPP_
// *****************************************************************************
#include "exiv2lib_export.h"
#include <array>
// included header files
#include "error.hpp"
#include "image.hpp"
@ -18,59 +15,6 @@ 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
static constexpr auto ps3Id_ = "Photoshop 3.0\0"; //!< %Photoshop marker
static constexpr uint16_t iptc_ = 0x0404; //!< %Photoshop IPTC marker
static constexpr uint16_t preview_ = 0x040c; //!< %Photoshop preview marker
/// @brief Checks an IRB
/// @param pPsData Existing IRB buffer. It is expected to be of size 4.
/// @return true if the IRB marker is known
/// @todo This should be an implementation detail and not exposed in the API. An attacker could try to pass
/// a smaller buffer or null pointer.
static bool isIrb(const byte* pPsData);
/// @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;<BR> 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 (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;<BR>
/// 3 if no data for psTag was found in pPsData;<BR>
/// -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);
};
/*!
@brief Abstract helper base class to access JPEG images.
*/

@ -0,0 +1,70 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#ifndef PHOTOSHOP_INT_HPP
#define PHOTOSHOP_INT_HPP
#include "exiv2lib_export.h"
#include "types.hpp"
#include <array>
namespace Exiv2 {
// Forward declarations
class IptcData;
/// @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
static constexpr auto ps3Id_ = "Photoshop 3.0\0"; //!< %Photoshop marker
static constexpr uint16_t iptc_ = 0x0404; //!< %Photoshop IPTC marker
static constexpr uint16_t preview_ = 0x040c; //!< %Photoshop preview marker
/// @brief Checks an IRB
/// @param pPsData Existing IRB buffer. It is expected to be of size 4.
/// @return true if the IRB marker is known
/// @todo This should be an implementation detail and not exposed in the API. An attacker could try to pass
/// a smaller buffer or null pointer.
static bool isIrb(const byte* pPsData);
/// @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;<BR> 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 (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;<BR>
/// 3 if no data for psTag was found in pPsData;<BR>
/// -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);
};
} // namespace Exiv2
#endif // PHOTOSHOP_INT_HPP

@ -65,6 +65,7 @@ set(PUBLIC_HEADERS
../include/exiv2/mrwimage.hpp
../include/exiv2/orfimage.hpp
../include/exiv2/pgfimage.hpp
../include/exiv2/photoshop.hpp
../include/exiv2/preview.hpp
../include/exiv2/properties.hpp
../include/exiv2/psdimage.hpp
@ -107,6 +108,7 @@ add_library( exiv2lib
mrwimage.cpp
orfimage.cpp
pgfimage.cpp
photoshop.cpp
preview.cpp
properties.cpp
psdimage.cpp

@ -38,6 +38,7 @@
#include "xmpsidecar.hpp"
// + standard includes
#include <array>
#include <cstdio>
#include <cstring>
#include <limits>

@ -9,6 +9,7 @@
#include "helper_functions.hpp"
#include "image_int.hpp"
#include "jpgimage.hpp"
#include "photoshop.hpp"
#include "safe_op.hpp"
#ifdef WIN32
@ -21,12 +22,14 @@
#include "fff.h"
#include <array>
#include <iostream>
// *****************************************************************************
// class member definitions
namespace Exiv2 {
namespace {
// JPEG Segment markers (The first byte is always 0xFF, the value of these constants correspond to the 2nd byte)
constexpr byte sos_ = 0xda; //!< JPEG SOS marker
@ -79,183 +82,8 @@ void readSegmentSize(const byte marker, BasicIo& io, std::array<byte, 2>& buf, s
enforce(size >= 2, ErrorCode::kerFailedToReadImageData);
}
}
} // namespace
bool Photoshop::isIrb(const byte* pPsData) {
if (pPsData == nullptr) {
return false;
}
/// \todo check if direct array comparison is faster than a call to memcmp
return std::any_of(irbId_.begin(), irbId_.end(), [pPsData](auto id) { return memcmp(pPsData, id, 4) == 0; });
}
bool Photoshop::valid(const byte* pPsData, size_t sizePsData) {
const byte* record = nullptr;
uint32_t sizeIptc = 0;
uint32_t sizeHdr = 0;
const byte* pCur = pPsData;
const byte* pEnd = pPsData + sizePsData;
int ret = 0;
while (pCur < pEnd && 0 == (ret = Photoshop::locateIptcIrb(pCur, (pEnd - pCur), &record, &sizeHdr, &sizeIptc))) {
pCur = record + sizeHdr + sizeIptc + (sizeIptc & 1);
}
return ret >= 0;
}
// Todo: Generalised from JpegBase::locateIptcData without really understanding
// the format (in particular the header). So it remains to be confirmed
// if this also makes sense for psTag != Photoshop::iptc
int Photoshop::locateIrb(const byte* pPsData, size_t sizePsData, uint16_t psTag, const byte** record,
uint32_t* const sizeHdr, uint32_t* const sizeData) {
if (sizePsData < 12) {
return 3;
}
// Used for error checking
size_t position = 0;
#ifdef EXIV2_DEBUG_MESSAGES
std::cerr << "Photoshop::locateIrb: ";
#endif
// Data should follow Photoshop format, if not exit
while (position <= (sizePsData - 12) && isIrb(pPsData + position)) {
const byte* hrd = pPsData + position;
position += 4;
uint16_t type = getUShort(pPsData + position, bigEndian);
position += 2;
#ifdef EXIV2_DEBUG_MESSAGES
std::cerr << "0x" << std::hex << type << std::dec << " ";
#endif
// Pascal string is padded to have an even size (including size byte)
byte psSize = pPsData[position] + 1;
psSize += (psSize & 1);
position += psSize;
if (position + 4 > sizePsData) {
#ifdef EXIV2_DEBUG_MESSAGES
std::cerr << "Warning: "
<< "Invalid or extended Photoshop IRB\n";
#endif
return -2;
}
uint32_t dataSize = getULong(pPsData + position, bigEndian);
position += 4;
if (dataSize > (sizePsData - position)) {
#ifdef EXIV2_DEBUG_MESSAGES
std::cerr << "Warning: "
<< "Invalid Photoshop IRB data size " << dataSize << " or extended Photoshop IRB\n";
#endif
return -2;
}
#ifdef EXIV2_DEBUG_MESSAGES
if ((dataSize & 1) && position + dataSize == sizePsData) {
std::cerr << "Warning: "
<< "Photoshop IRB data is not padded to even size\n";
}
#endif
if (type == psTag) {
#ifdef EXIV2_DEBUG_MESSAGES
std::cerr << "ok\n";
#endif
*sizeData = dataSize;
*sizeHdr = psSize + 10;
*record = hrd;
return 0;
}
// Data size is also padded to be even
position += dataSize + (dataSize & 1);
}
#ifdef EXIV2_DEBUG_MESSAGES
std::cerr << "pPsData doesn't start with '8BIM'\n";
#endif
if (position < sizePsData) {
#ifdef EXIV2_DEBUG_MESSAGES
std::cerr << "Warning: "
<< "Invalid or extended Photoshop IRB\n";
#endif
return -2;
}
return 3;
}
int Photoshop::locateIptcIrb(const byte* pPsData, size_t sizePsData, const byte** record, uint32_t* const sizeHdr,
uint32_t* const sizeData) {
return locateIrb(pPsData, sizePsData, iptc_, record, sizeHdr, sizeData);
}
int Photoshop::locatePreviewIrb(const byte* pPsData, size_t sizePsData, const byte** record, uint32_t* const sizeHdr,
uint32_t* const sizeData) {
return locateIrb(pPsData, sizePsData, preview_, record, sizeHdr, sizeData);
}
DataBuf Photoshop::setIptcIrb(const byte* pPsData, size_t sizePsData, const IptcData& iptcData) {
#ifdef EXIV2_DEBUG_MESSAGES
std::cerr << "IRB block at the beginning of Photoshop::setIptcIrb\n";
if (sizePsData == 0)
std::cerr << " None.\n";
else
hexdump(std::cerr, pPsData, sizePsData);
#endif
const byte* record = pPsData;
uint32_t sizeIptc = 0;
uint32_t sizeHdr = 0;
DataBuf rc;
if (0 > Photoshop::locateIptcIrb(pPsData, sizePsData, &record, &sizeHdr, &sizeIptc)) {
return rc;
}
Blob psBlob;
const auto sizeFront = static_cast<size_t>(record - pPsData);
// Write data before old record.
if (sizePsData > 0 && sizeFront > 0) {
append(psBlob, pPsData, sizeFront);
}
// Write new iptc record if we have it
DataBuf rawIptc = IptcParser::encode(iptcData);
if (!rawIptc.empty()) {
std::array<byte, 12> tmpBuf;
std::copy_n(Photoshop::irbId_[0], 4, tmpBuf.data());
us2Data(tmpBuf.data() + 4, iptc_, bigEndian);
tmpBuf[6] = 0;
tmpBuf[7] = 0;
ul2Data(tmpBuf.data() + 8, static_cast<uint32_t>(rawIptc.size()), bigEndian);
append(psBlob, tmpBuf.data(), 12);
append(psBlob, rawIptc.c_data(), rawIptc.size());
// Data is padded to be even (but not included in size)
if (rawIptc.size() & 1)
psBlob.push_back(0x00);
}
// Write existing stuff after record, skip the current and all remaining IPTC blocks
size_t pos = sizeFront;
auto nextSizeData = Safe::add<long>(static_cast<long>(sizePsData), -static_cast<long>(pos));
enforce(nextSizeData >= 0, ErrorCode::kerCorruptedMetadata);
while (0 == Photoshop::locateIptcIrb(pPsData + pos, nextSizeData, &record, &sizeHdr, &sizeIptc)) {
const auto newPos = static_cast<size_t>(record - pPsData);
if (newPos > pos) { // Copy data up to the IPTC IRB
append(psBlob, pPsData + pos, newPos - pos);
}
pos = newPos + sizeHdr + sizeIptc + (sizeIptc & 1); // Skip the IPTC IRB
nextSizeData = Safe::add<long>(static_cast<long>(sizePsData), -static_cast<long>(pos));
enforce(nextSizeData >= 0, ErrorCode::kerCorruptedMetadata);
}
if (pos < sizePsData) {
append(psBlob, pPsData + pos, sizePsData - pos);
}
// Data is rounded to be even
if (!psBlob.empty())
rc = DataBuf(&psBlob[0], psBlob.size());
#ifdef EXIV2_DEBUG_MESSAGES
std::cerr << "IRB block at the end of Photoshop::setIptcIrb\n";
if (rc.empty())
std::cerr << " None.\n";
else
hexdump(std::cerr, rc.c_data(), rc.size());
#endif
return rc;
}
JpegBase::JpegBase(ImageType type, BasicIo::UniquePtr io, bool create, const byte initData[], size_t dataSize) :
Image(type, mdExif | mdIptc | mdXmp | mdComment, std::move(io)) {
if (create) {
@ -282,7 +110,6 @@ byte JpegBase::advanceToMarker(ErrorCode err) const {
throw Error(err);
}
/// \todo should we check for validity of the marker? 0x59 does not look fine
// Markers can start with any number of 0xff
while ((c = io_->getb()) == 0xff) {
}
@ -316,7 +143,6 @@ void JpegBase::readMetadata() {
byte marker = advanceToMarker(ErrorCode::kerNotAJpeg);
while (marker != sos_ && marker != eoi_ && search > 0) {
/// @todo the block to read the size of the segment is repeated in 3 places. Factor-out
std::array<byte, 2> sizebuf; // 2-byte buffer for reading the size.
uint16_t size = 0; // Size of the segment, including the 2-byte size field
readSegmentSize(marker, *io_, sizebuf, size);

@ -0,0 +1,182 @@
#include "photoshop.hpp"
#include "enforce.hpp"
#include "image.hpp"
#include "safe_op.hpp"
namespace Exiv2 {
bool Photoshop::isIrb(const byte* data) {
if (data == nullptr) {
return false;
}
return std::any_of(irbId_.begin(), irbId_.end(), [data](auto id) { return memcmp(data, id, 4) == 0; });
}
bool Photoshop::valid(const byte* pPsData, size_t sizePsData) {
const byte* record = nullptr;
uint32_t sizeIptc = 0;
uint32_t sizeHdr = 0;
const byte* pCur = pPsData;
const byte* pEnd = pPsData + sizePsData;
int ret = 0;
while (pCur < pEnd && 0 == (ret = Photoshop::locateIptcIrb(pCur, (pEnd - pCur), &record, &sizeHdr, &sizeIptc))) {
pCur = record + sizeHdr + sizeIptc + (sizeIptc & 1);
}
return ret >= 0;
}
// Todo: Generalised from JpegBase::locateIptcData without really understanding
// the format (in particular the header). So it remains to be confirmed
// if this also makes sense for psTag != Photoshop::iptc
int Photoshop::locateIrb(const byte* pPsData, size_t sizePsData, uint16_t psTag, const byte** record,
uint32_t* const sizeHdr, uint32_t* const sizeData) {
if (sizePsData < 12) {
return 3;
}
// Used for error checking
size_t position = 0;
#ifdef EXIV2_DEBUG_MESSAGES
std::cerr << "Photoshop::locateIrb: ";
#endif
// Data should follow Photoshop format, if not exit
while (position <= (sizePsData - 12) && isIrb(pPsData + position)) {
const byte* hrd = pPsData + position;
position += 4;
uint16_t type = getUShort(pPsData + position, bigEndian);
position += 2;
#ifdef EXIV2_DEBUG_MESSAGES
std::cerr << "0x" << std::hex << type << std::dec << " ";
#endif
// Pascal string is padded to have an even size (including size byte)
byte psSize = pPsData[position] + 1;
psSize += (psSize & 1);
position += psSize;
if (position + 4 > sizePsData) {
#ifdef EXIV2_DEBUG_MESSAGES
std::cerr << "Warning: "
<< "Invalid or extended Photoshop IRB\n";
#endif
return -2;
}
uint32_t dataSize = getULong(pPsData + position, bigEndian);
position += 4;
if (dataSize > (sizePsData - position)) {
#ifdef EXIV2_DEBUG_MESSAGES
std::cerr << "Warning: "
<< "Invalid Photoshop IRB data size " << dataSize << " or extended Photoshop IRB\n";
#endif
return -2;
}
#ifdef EXIV2_DEBUG_MESSAGES
if ((dataSize & 1) && position + dataSize == sizePsData) {
std::cerr << "Warning: "
<< "Photoshop IRB data is not padded to even size\n";
}
#endif
if (type == psTag) {
#ifdef EXIV2_DEBUG_MESSAGES
std::cerr << "ok\n";
#endif
*sizeData = dataSize;
*sizeHdr = psSize + 10;
*record = hrd;
return 0;
}
// Data size is also padded to be even
position += dataSize + (dataSize & 1);
}
#ifdef EXIV2_DEBUG_MESSAGES
std::cerr << "pPsData doesn't start with '8BIM'\n";
#endif
if (position < sizePsData) {
#ifdef EXIV2_DEBUG_MESSAGES
std::cerr << "Warning: "
<< "Invalid or extended Photoshop IRB\n";
#endif
return -2;
}
return 3;
}
int Photoshop::locateIptcIrb(const byte* pPsData, size_t sizePsData, const byte** record, uint32_t* const sizeHdr,
uint32_t* const sizeData) {
return locateIrb(pPsData, sizePsData, iptc_, record, sizeHdr, sizeData);
}
int Photoshop::locatePreviewIrb(const byte* pPsData, size_t sizePsData, const byte** record, uint32_t* const sizeHdr,
uint32_t* const sizeData) {
return locateIrb(pPsData, sizePsData, preview_, record, sizeHdr, sizeData);
}
DataBuf Photoshop::setIptcIrb(const byte* pPsData, size_t sizePsData, const IptcData& iptcData) {
#ifdef EXIV2_DEBUG_MESSAGES
std::cerr << "IRB block at the beginning of Photoshop::setIptcIrb\n";
if (sizePsData == 0)
std::cerr << " None.\n";
else
hexdump(std::cerr, pPsData, sizePsData);
#endif
const byte* record = pPsData;
uint32_t sizeIptc = 0;
uint32_t sizeHdr = 0;
DataBuf rc;
if (0 > Photoshop::locateIptcIrb(pPsData, sizePsData, &record, &sizeHdr, &sizeIptc)) {
return rc;
}
Blob psBlob;
const auto sizeFront = static_cast<size_t>(record - pPsData);
// Write data before old record.
if (sizePsData > 0 && sizeFront > 0) {
append(psBlob, pPsData, sizeFront);
}
// Write new iptc record if we have it
DataBuf rawIptc = IptcParser::encode(iptcData);
if (!rawIptc.empty()) {
std::array<byte, 12> tmpBuf;
std::copy_n(Photoshop::irbId_[0], 4, tmpBuf.data());
us2Data(tmpBuf.data() + 4, iptc_, bigEndian);
tmpBuf[6] = 0;
tmpBuf[7] = 0;
ul2Data(tmpBuf.data() + 8, static_cast<uint32_t>(rawIptc.size()), bigEndian);
append(psBlob, tmpBuf.data(), 12);
append(psBlob, rawIptc.c_data(), rawIptc.size());
// Data is padded to be even (but not included in size)
if (rawIptc.size() & 1)
psBlob.push_back(0x00);
}
// Write existing stuff after record, skip the current and all remaining IPTC blocks
size_t pos = sizeFront;
long nextSizeData = Safe::add<long>(static_cast<long>(sizePsData), -static_cast<long>(pos));
enforce(nextSizeData >= 0, ErrorCode::kerCorruptedMetadata);
while (0 == Photoshop::locateIptcIrb(pPsData + pos, nextSizeData, &record, &sizeHdr, &sizeIptc)) {
const auto newPos = static_cast<size_t>(record - pPsData);
if (newPos > pos) { // Copy data up to the IPTC IRB
append(psBlob, pPsData + pos, newPos - pos);
}
pos = newPos + sizeHdr + sizeIptc + (sizeIptc & 1); // Skip the IPTC IRB
nextSizeData = Safe::add<long>(static_cast<long>(sizePsData), -static_cast<long>(pos));
enforce(nextSizeData >= 0, ErrorCode::kerCorruptedMetadata);
}
if (pos < sizePsData) {
append(psBlob, pPsData + pos, sizePsData - pos);
}
// Data is rounded to be even
if (!psBlob.empty())
rc = DataBuf(&psBlob[0], psBlob.size());
#ifdef EXIV2_DEBUG_MESSAGES
std::cerr << "IRB block at the end of Photoshop::setIptcIrb\n";
if (rc.empty())
std::cerr << " None.\n";
else
hexdump(std::cerr, rc.c_data(), rc.size());
#endif
return rc;
}
} // namespace Exiv2

@ -13,12 +13,14 @@
#include "image.hpp"
#include "iptc.hpp"
#include "jpgimage.hpp"
#include "photoshop.hpp"
#include "pngchunk_int.hpp"
#include "safe_op.hpp"
#include "tiffimage.hpp"
// standard includes
#include <algorithm>
#include <array>
#include <cstdio>
#include <cstring>
#include <iomanip>

@ -13,11 +13,13 @@
#include "image.hpp"
#include "image_int.hpp"
#include "jpgimage.hpp"
#include "photoshop.hpp"
#include "pngchunk_int.hpp"
#include "pngimage.hpp"
#include "tiffimage.hpp"
#include "types.hpp"
#include <array>
#include <iostream>
namespace {

@ -8,6 +8,7 @@
#include "futils.hpp"
#include "image.hpp"
#include "jpgimage.hpp"
#include "photoshop.hpp"
#include "safe_op.hpp"
#include "tiffimage.hpp"
#include "tiffimage_int.hpp"

@ -10,6 +10,7 @@
#include "futils.hpp"
#include "image.hpp"
#include "jpgimage.hpp"
#include "photoshop.hpp"
#include <iostream>

@ -8,6 +8,7 @@
#include "iptc.hpp"
#include "jpgimage.hpp"
#include "makernote_int.hpp"
#include "photoshop.hpp"
#include "sonymn_int.hpp"
#include "tiffcomposite_int.hpp" // Do not change the order of these 2 includes,
#include "tiffimage_int.hpp"

@ -1,6 +1,9 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include <exiv2/jpgimage.hpp>
#include "photoshop.hpp"
#include "error.hpp"
#include "iptc.hpp"
#include <gtest/gtest.h>

Loading…
Cancel
Save