Add constructor that takes generic std::istream objects https://github.com/cdcseacave/TinyEXIF/commit/d75f772ffa330b28539a0c6493803c9205b281a6 --- TinyEXIF.cpp.orig 2019-01-16 07:26:30.000000000 -0600 +++ TinyEXIF.cpp 2024-12-02 05:58:01.000000000 -0600 @@ -39,6 +39,7 @@ #include #include #include +#include #ifdef _MSC_VER #include @@ -332,6 +333,9 @@ EXIFInfo::EXIFInfo(EXIFStream& stream) { parseFrom(stream); } +EXIFInfo::EXIFInfo(std::istream& stream) { + parseFrom(stream); +} EXIFInfo::EXIFInfo(const uint8_t* data, unsigned length) { parseFrom(data, length); } @@ -838,6 +842,36 @@ 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: --- TinyEXIF.h.orig 2024-12-02 06:00:04.000000000 -0600 +++ TinyEXIF.h 2024-12-02 06:00:04.000000000 -0600 @@ -101,6 +101,7 @@ 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. @@ -111,6 +112,7 @@ // 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() --- main.cpp +++ 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; }