From d75f772ffa330b28539a0c6493803c9205b281a6 Mon Sep 17 00:00:00 2001 From: Juha Reunanen Date: Fri, 2 Apr 2021 20:31:04 +0300 Subject: [PATCH] Add constructor that takes generic std::istream objects (#11) --- README.md | 11 +++-------- TinyEXIF.cpp | 34 ++++++++++++++++++++++++++++++++++ TinyEXIF.h | 2 ++ main.cpp | 27 +++------------------------ 4 files changed, 42 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index decd06a..1d14e38 100644 --- a/README.md +++ b/README.md @@ -18,16 +18,11 @@ int main(int argc, const char** argv) { return -1; } - // read entire image file - std::ifstream file(argv[1], std::ifstream::in|std::ifstream::binary); - file.seekg(0,std::ios::end); - std::streampos length = file.tellg(); - file.seekg(0,std::ios::beg); - std::vector data(length); - file.read((char*)data.data(), length); + // open a stream to read just the necessary parts of the image file + std::ifstream istream(argv[1], std::ifstream::binary); // parse image EXIF and XMP metadata - TinyEXIF::EXIFInfo imageEXIF(data.data(), length); + TinyEXIF::EXIFInfo imageEXIF(istream); if (imageEXIF.Fields) std::cout << "Image Description " << imageEXIF.ImageDescription << "\n" diff --git a/TinyEXIF.cpp b/TinyEXIF.cpp index 5943c6e..73c0086 100644 --- a/TinyEXIF.cpp +++ b/TinyEXIF.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #ifdef _MSC_VER namespace { @@ -338,6 +339,9 @@ EXIFInfo::EXIFInfo() : Fields(FIELD_NA) { EXIFInfo::EXIFInfo(EXIFStream& stream) { parseFrom(stream); } +EXIFInfo::EXIFInfo(std::istream& stream) { + parseFrom(stream); +} EXIFInfo::EXIFInfo(const uint8_t* data, unsigned length) { parseFrom(data, length); } @@ -848,6 +852,36 @@ int EXIFInfo::parseFrom(EXIFStream& stream) { return app1s(); } + +int EXIFInfo::parseFrom(std::istream& stream) { + class EXIFStdStream : public EXIFStream { + public: + EXIFStdStream(std::istream& stream) + : stream(stream) { + // Would be nice to assert here that the stream was opened in binary mode, but + // apparently that's not possible: https://stackoverflow.com/a/224259/19254 + } + bool IsValid() const override { + return !!stream; + } + const uint8_t* GetBuffer(unsigned desiredLength) override { + buffer.resize(desiredLength); + if (!stream.read(reinterpret_cast(buffer.data()), desiredLength)) + return NULL; + return buffer.data(); + } + bool SkipBuffer(unsigned desiredLength) override { + return (bool)stream.seekg(desiredLength, std::ios::cur); + } + private: + std::istream& stream; + std::vector buffer; + }; + EXIFStdStream streamWrapper(stream); + return parseFrom(streamWrapper); +} + + int EXIFInfo::parseFrom(const uint8_t* buf, unsigned len) { class EXIFStreamBuffer : public EXIFStream { public: diff --git a/TinyEXIF.h b/TinyEXIF.h index 09c26f7..4f66590 100644 --- a/TinyEXIF.h +++ b/TinyEXIF.h @@ -100,6 +100,7 @@ class TINYEXIF_LIB EXIFInfo { public: EXIFInfo(); EXIFInfo(EXIFStream& stream); + EXIFInfo(std::istream& stream); // NB: the stream must have been opened in binary mode EXIFInfo(const uint8_t* data, unsigned length); // Parsing function for an entire JPEG image stream. @@ -110,6 +111,7 @@ public: // RETURN: PARSE_SUCCESS (0) on success with 'result' filled out // error code otherwise, as defined by the PARSE_* macros int parseFrom(EXIFStream& stream); + int parseFrom(std::istream& stream); // NB: the stream must have been opened in binary mode int parseFrom(const uint8_t* data, unsigned length); // Parsing function for an EXIF segment. This is used internally by parseFrom() diff --git a/main.cpp b/main.cpp index 476c476..ddd5212 100644 --- a/main.cpp +++ b/main.cpp @@ -9,27 +9,6 @@ #include // std::vector #include // std::setprecision -class EXIFStreamFile : public TinyEXIF::EXIFStream { -public: - explicit EXIFStreamFile(const char* fileName) - : file(fileName, std::ifstream::in|std::ifstream::binary) {} - bool IsValid() const override { - return file.is_open(); - } - const uint8_t* GetBuffer(unsigned desiredLength) override { - buffer.resize(desiredLength); - if (!file.read((char*)buffer.data(), desiredLength)) - return NULL; - return buffer.data(); - } - bool SkipBuffer(unsigned desiredLength) override { - return (bool)file.seekg(desiredLength,std::ios::cur); - } -private: - std::ifstream file; - std::vector buffer; -}; - int main(int argc, const char** argv) { if (argc != 2) { @@ -37,9 +16,9 @@ int main(int argc, const char** argv) return -1; } - // read entire image file - EXIFStreamFile stream(argv[1]); - if (!stream.IsValid()) { + // open a stream to read just the necessary parts of the image file + std::ifstream stream(argv[1], std::ios::binary); + if (!stream) { std::cout << "error: can not open '" << argv[1] << "'\n"; return -2; }