diff options
32 files changed, 572 insertions, 245 deletions
diff --git a/includes/image_io/base/istream_data_source.h b/includes/image_io/base/istream_data_source.h index 4564e14..9b87542 100644 --- a/includes/image_io/base/istream_data_source.h +++ b/includes/image_io/base/istream_data_source.h @@ -1,46 +1,28 @@ #ifndef IMAGE_IO_BASE_ISTREAM_DATA_SOURCE_H_ // NOLINT #define IMAGE_IO_BASE_ISTREAM_DATA_SOURCE_H_ // NOLINT -#include <iostream> #include <memory> #include <utility> -#include "image_io/base/data_source.h" +#include "image_io/base/istream_ref_data_source.h" namespace photos_editing_formats { namespace image_io { -/// A DataSource that obtains data from an istream. -class IStreamDataSource : public DataSource { +/// A DataSource that obtains data from an istream that it owns. +class IStreamDataSource : public IStreamRefDataSource { public: /// Constructs an IStreamDataSource using the given istream. /// @param istram_ptr The istream from which to read. explicit IStreamDataSource(std::unique_ptr<std::istream> istream_ptr) - : istream_(std::move(istream_ptr)) {} - - void Reset() override; - std::shared_ptr<DataSegment> GetDataSegment(size_t begin, - size_t min_size) override; - TransferDataResult TransferData(const DataRange& data_range, size_t best_size, - DataDestination* data_destination) override; - - private: - /// The worker function to create a DataSegment and fill it with the given - /// number of bytes read from the istream, starting at the given location. - /// @param begin The location in the istream at which to start reading. - /// @param count The number of bytes to read. - /// @return A DataSegment pointer, or nullptr if the read failed. - std::shared_ptr<DataSegment> Read(size_t begin, size_t count); + : IStreamRefDataSource(*istream_ptr), istream_(std::move(istream_ptr)) {} private: - /// The istream from which to read. + /// The istream that is owned by this data source. std::unique_ptr<std::istream> istream_; - - /// The current data segment that was read in the GetDataSegment() function. - std::shared_ptr<DataSegment> current_data_segment_; }; } // namespace image_io } // namespace photos_editing_formats -#endif // IMAGE_IO_BASE_ISTREAM_DATA_SOURCE_H_ // NOLINT +#endif // IMAGE_IO_BASE_ISTREAM_DATA_SOURCE_H_ // NOLINT diff --git a/includes/image_io/base/istream_ref_data_source.h b/includes/image_io/base/istream_ref_data_source.h new file mode 100644 index 0000000..2460bb1 --- /dev/null +++ b/includes/image_io/base/istream_ref_data_source.h @@ -0,0 +1,46 @@ +#ifndef IMAGE_IO_BASE_ISTREAM_REF_DATA_SOURCE_H_ // NOLINT +#define IMAGE_IO_BASE_ISTREAM_REF_DATA_SOURCE_H_ // NOLINT + +#include <iostream> + +#include "image_io/base/data_source.h" + +namespace photos_editing_formats { +namespace image_io { + +/// A DataSource that obtains data from an istream held as a reference. +class IStreamRefDataSource : public DataSource { + public: + /// Constructs an IStreamDataSource using the given istream. + /// @param istream_ref The istream from which to read. + explicit IStreamRefDataSource(std::istream& istream_ref) + : istream_ref_(istream_ref) {} + IStreamRefDataSource(const IStreamRefDataSource&) = delete; + IStreamRefDataSource& operator=(const IStreamRefDataSource&) = delete; + + void Reset() override; + std::shared_ptr<DataSegment> GetDataSegment(size_t begin, + size_t min_size) override; + TransferDataResult TransferData(const DataRange& data_range, size_t best_size, + DataDestination* data_destination) override; + + private: + /// The worker function to create a DataSegment and fill it with the given + /// number of bytes read from the istream, starting at the given location. + /// @param begin The location in the istream at which to start reading. + /// @param count The number of bytes to read. + /// @return A DataSegment pointer, or nullptr if the read failed. + std::shared_ptr<DataSegment> Read(size_t begin, size_t count); + + private: + /// The istream from which to read. + std::istream& istream_ref_; + + /// The current data segment that was read in the GetDataSegment() function. + std::shared_ptr<DataSegment> current_data_segment_; +}; + +} // namespace image_io +} // namespace photos_editing_formats + +#endif // IMAGE_IO_BASE_ISTREAM_REF_DATA_SOURCE_H_ // NOLINT diff --git a/includes/image_io/base/message.h b/includes/image_io/base/message.h index 8c225d8..fef2fd6 100644 --- a/includes/image_io/base/message.h +++ b/includes/image_io/base/message.h @@ -15,6 +15,9 @@ class Message { /// A Status message. kStatus, + /// A Warning message. + kWarning, + /// An error from the stdlib was detected. The std::errno variable can be /// used to programmatically decide what to do, or use the std::strerror /// function to get a string description of the error. @@ -66,6 +69,17 @@ class Message { /// @return The text of the message. const std::string& GetText() const { return text_; } + /// @return Whether the message is an error message. + bool IsError() const { + return type_ != Message::kStatus && type_ != Message::kWarning; + } + + /// @return Whether the message is a warning message. + bool IsWarning() const { return type_ == Message::kWarning; } + + /// @return Whether the message is a status message. + bool IsStatus() const { return type_ == Message::kStatus; } + private: /// The type of message. Type type_; diff --git a/includes/image_io/base/message_handler.h b/includes/image_io/base/message_handler.h index dc33679..b60a593 100644 --- a/includes/image_io/base/message_handler.h +++ b/includes/image_io/base/message_handler.h @@ -5,6 +5,7 @@ #include <vector> #include "image_io/base/message.h" +#include "image_io/base/message_stats.h" #include "image_io/base/message_store.h" #include "image_io/base/message_writer.h" @@ -15,20 +16,9 @@ namespace image_io { /// to report status and error conditions. class MessageHandler { public: - /// Initializes the MessageHandler for client use. Multithread applications - /// might find this function useful to call in their initialization section, - /// to guarentee that threads will not create race conditions when calling the - /// Get function for the first time. - static void Init(std::unique_ptr<MessageWriter> message_writer, - std::unique_ptr<MessageStore> message_store); - - /// This function is thread-safe as long as the Init() function is called in - /// non-multiple-threaded startup code; if the Init() fucnction was not called - /// there may be race conditions that causes the message handler returned from - /// Get() called in one thread to be different from that returned by the call - /// in a different thread. - /// @return The message handler used by the code in this library. - static MessageHandler* Get(); + /// The default constructor for MessageHandler creates a MessageWriter and + /// VectorMessageStore for handling writing and storing messages. + MessageHandler(); /// Sets the message writer to use when ReportMessage() is called. If client /// code does not call this function, the MessageHandler returned by the Get() @@ -55,14 +45,29 @@ class MessageHandler { /// should call this function again so that memory is not leaked when it is /// done using this library. void ClearMessages() { + message_stats_->Clear(); if (message_store_) { message_store_->ClearMessages(); } } /// @return Whether the message handler's store has error messages or not. - bool HasErrorMessages() const { - return message_store_ ? message_store_->HasErrorMessages() : false; + bool HasErrorMessages() const { return GetErrorMessageCount() > 0; } + + /// @return The number of error messages reported. + size_t GetErrorMessageCount() const { return message_stats_->error_count; } + + /// @return The number of warning messages reported. + size_t GetWarningMessageCount() const { + return message_stats_->warning_count; + } + + /// @return The number of status messages reported. + size_t GetStatusMessageCount() const { return message_stats_->status_count; } + + /// @return The message stats object as a shared pointer. + std::shared_ptr<MessageStats> GetMessageStats() const { + return message_stats_; } /// @return The vector of errors maintained by the message handler's store. @@ -85,15 +90,14 @@ class MessageHandler { void ReportMessage(const Message& message); private: - MessageHandler() = default; - ~MessageHandler(); - - private: /// The message writer used by ReportMessage, or null. std::unique_ptr<MessageWriter> message_writer_; /// The message store for saving messages for later, or null. std::unique_ptr<MessageStore> message_store_; + + /// The message stats for counting messages. + std::shared_ptr<MessageStats> message_stats_; }; } // namespace image_io diff --git a/includes/image_io/base/message_stats.h b/includes/image_io/base/message_stats.h new file mode 100644 index 0000000..6b338f0 --- /dev/null +++ b/includes/image_io/base/message_stats.h @@ -0,0 +1,21 @@ +#ifndef IMAGE_IO_BASE_MESSAGE_STATS_H_ // NOLINT +#define IMAGE_IO_BASE_MESSAGE_STATS_H_ // NOLINT + +#include "image_io/base/types.h" + +namespace photos_editing_formats { +namespace image_io { + +/// A structure for holding message stats. +struct MessageStats { + MessageStats() { Clear(); } + void Clear() { error_count = warning_count = status_count = 0; } + size_t error_count; + size_t warning_count; + size_t status_count; +}; + +} // namespace image_io +} // namespace photos_editing_formats + +#endif // IMAGE_IO_BASE_MESSAGE_STATS_H_ // NOLINT diff --git a/includes/image_io/base/message_store.h b/includes/image_io/base/message_store.h index 1d492f1..8db0b9f 100644 --- a/includes/image_io/base/message_store.h +++ b/includes/image_io/base/message_store.h @@ -61,7 +61,7 @@ class ErrorFlagMessageStore : public MessageStore { ErrorFlagMessageStore() : has_error_(false) {} void ClearMessages() override { has_error_ = false; } void AddMessage(const Message& message) override { - if (message.GetType() != Message::kStatus) { + if (message.IsError()) { has_error_ = true; } } diff --git a/includes/image_io/base/ostream_data_destination.h b/includes/image_io/base/ostream_data_destination.h index 15a1155..d0cf04c 100644 --- a/includes/image_io/base/ostream_data_destination.h +++ b/includes/image_io/base/ostream_data_destination.h @@ -1,58 +1,31 @@ #ifndef IMAGE_IO_BASE_OSTREAM_DATA_DESTINATION_H_ // NOLINT #define IMAGE_IO_BASE_OSTREAM_DATA_DESTINATION_H_ // NOLINT -#include <iostream> #include <memory> -#include <string> #include <utility> -#include "image_io/base/data_destination.h" +#include "image_io/base/ostream_ref_data_destination.h" namespace photos_editing_formats { namespace image_io { /// A DataDestination that writes its output to an ostream. -class OStreamDataDestination : public DataDestination { +class OStreamDataDestination : public OStreamRefDataDestination { public: /// Constructs an OStreamDataDestination using the given ostream. /// @param ostream_ptr The ostream to which data is written. - explicit OStreamDataDestination(std::unique_ptr<std::ostream> ostream_ptr) - : ostream_(std::move(ostream_ptr)), - bytes_transferred_(0), - has_error_(false) {} - - /// @param name A name to associate with the ostream. Used for error messages. - void SetName(const std::string& name) { name_ = name; } - - /// @return The name associated with the ostream. - const std::string& GetName() const { return name_; } - - /// @return The number of bytes written to the ostream. - size_t GetBytesTransferred() const override { return bytes_transferred_; } - - /// @return True if errors were encountered while writing to the ostream. - bool HasError() const { return has_error_; } - - void StartTransfer() override; - TransferStatus Transfer(const DataRange& transfer_range, - const DataSegment& data_segment) override; - void FinishTransfer() override; + /// @param message_handler An option message handler for writing messages. + OStreamDataDestination(std::unique_ptr<std::ostream> ostream_ptr, + MessageHandler* message_handler) + : OStreamRefDataDestination(*ostream_ptr, message_handler), + ostream_(std::move(ostream_ptr)) {} private: - /// The ostream written to. + /// The ostream that is owned by this data destination. std::unique_ptr<std::ostream> ostream_; - - /// The number of bytes written so far. - size_t bytes_transferred_; - - /// A (file) name to associate with the ostream, used with error messages. - std::string name_; - - /// If true indicates an error has occurred writing to the ostream. - bool has_error_; }; } // namespace image_io } // namespace photos_editing_formats -#endif // IMAGE_IO_BASE_OSTREAM_DATA_DESTINATION_H_ // NOLINT +#endif // IMAGE_IO_BASE_OSTREAM_DATA_DESTINATION_H_ // NOLINT diff --git a/includes/image_io/base/ostream_ref_data_destination.h b/includes/image_io/base/ostream_ref_data_destination.h new file mode 100644 index 0000000..266e2be --- /dev/null +++ b/includes/image_io/base/ostream_ref_data_destination.h @@ -0,0 +1,66 @@ +#ifndef IMAGE_IO_BASE_OSTREAM_REF_DATA_DESTINATION_H_ // NOLINT +#define IMAGE_IO_BASE_OSTREAM_REF_DATA_DESTINATION_H_ // NOLINT + +#include <iostream> +#include <string> + +#include "image_io/base/data_destination.h" +#include "image_io/base/message_handler.h" + +namespace photos_editing_formats { +namespace image_io { + +/// A DataDestination that writes its output to an ostream held as a reference. +class OStreamRefDataDestination : public DataDestination { + public: + /// Constructs an OStreamDataDestination using the given ostream. + /// @param ostream_ref The ostream to which data is written. + /// @param message_handler An option message handler for writing messages. + OStreamRefDataDestination(std::ostream& ostream_ref, + MessageHandler* message_handler) + : ostream_ref_(ostream_ref), + message_handler_(message_handler), + bytes_transferred_(0), + has_error_(false) {} + OStreamRefDataDestination(const OStreamRefDataDestination&) = delete; + OStreamRefDataDestination& operator=(const OStreamRefDataDestination&) = + delete; + + /// @param name A name to associate with the ostream. Used for error messages. + void SetName(const std::string& name) { name_ = name; } + + /// @return The name associated with the ostream. + const std::string& GetName() const { return name_; } + + /// @return The number of bytes written to the ostream. + size_t GetBytesTransferred() const override { return bytes_transferred_; } + + /// @return True if errors were encountered while writing to the ostream. + bool HasError() const { return has_error_; } + + void StartTransfer() override; + TransferStatus Transfer(const DataRange& transfer_range, + const DataSegment& data_segment) override; + void FinishTransfer() override; + + private: + /// The ostream written to. + std::ostream& ostream_ref_; + + /// An optional message handler to write messages to. + MessageHandler* message_handler_; + + /// The number of bytes written so far. + size_t bytes_transferred_; + + /// A (file) name to associate with the ostream, used with error messages. + std::string name_; + + /// If true indicates an error has occurred writing to the ostream. + bool has_error_; +}; + +} // namespace image_io +} // namespace photos_editing_formats + +#endif // IMAGE_IO_BASE_OSTREAM_REF_DATA_DESTINATION_H_ // NOLINT diff --git a/includes/image_io/base/types.h b/includes/image_io/base/types.h index aaa88b3..ed49350 100644 --- a/includes/image_io/base/types.h +++ b/includes/image_io/base/types.h @@ -7,8 +7,14 @@ namespace photos_editing_formats { namespace image_io { -/// Byte is the noumenon unit of data. +/// The various integer and byte types used in this package. using Byte = std::uint8_t; +using Int32 = std::int32_t; +using Int64 = std::int64_t; +using UInt8 = std::uint8_t; +using UInt16 = std::uint16_t; +using UInt32 = std::uint32_t; +using UInt64 = std::uint64_t; /// A Byte value and a validity flag. struct ValidatedByte { diff --git a/includes/image_io/base/validated_number.h b/includes/image_io/base/validated_number.h new file mode 100644 index 0000000..ead5ab3 --- /dev/null +++ b/includes/image_io/base/validated_number.h @@ -0,0 +1,38 @@ +#ifndef IMAGE_IO_BASE_VALIDATED_NUMBER_H_ // NOLINT +#define IMAGE_IO_BASE_VALIDATED_NUMBER_H_ // NOLINT + +#include <sstream> +#include <string> + +namespace photos_editing_formats { +namespace image_io { + +template <class T> +struct ValidatedNumber { + ValidatedNumber() : ValidatedNumber(T(), false) {} + ValidatedNumber(const T& value_, bool is_valid_) + : value(value_), is_valid(is_valid_) {} + using value_type = T; + T value; + bool is_valid; +}; + +template <class T> +ValidatedNumber<T> GetValidatedNumber(const std::string& str) { + std::stringstream ss(str); + ValidatedNumber<T> result; + ss >> result.value; + if (!ss.fail()) { + std::string extra; + ss >> extra; + if (extra.empty()) { + result.is_valid = true; + } + } + return result; +} + +} // namespace image_io +} // namespace photos_editing_formats + +#endif // IMAGE_IO_BASE_VALIDATED_NUMBER_H_ // NOLINT diff --git a/includes/image_io/extras/base64_decoder_data_destination.h b/includes/image_io/extras/base64_decoder_data_destination.h index cde1dbc..107ea4b 100644 --- a/includes/image_io/extras/base64_decoder_data_destination.h +++ b/includes/image_io/extras/base64_decoder_data_destination.h @@ -5,6 +5,7 @@ #include <vector> #include "image_io/base/data_destination.h" +#include "image_io/base/message_handler.h" namespace photos_editing_formats { namespace image_io { @@ -16,8 +17,11 @@ class Base64DecoderDataDestination : public DataDestination { public: /// @param next_destination The next DataDestination in the chain which will /// be sent the decoded bytes received by the Transfer() function. - explicit Base64DecoderDataDestination(DataDestination* next_destination) + /// @param message_handler An optional message handler to write messages to. + Base64DecoderDataDestination(DataDestination* next_destination, + MessageHandler* message_handler) : next_destination_(next_destination), + message_handler_(message_handler), next_decoded_location_(0), has_error_(false) {} @@ -39,6 +43,9 @@ class Base64DecoderDataDestination : public DataDestination { /// The destination that the decoded data is sent to. DataDestination* next_destination_; + /// An optional message handler to write messages to. + MessageHandler* message_handler_; + /// If the transfer_range parameter of the Transfer function does not have a /// length that is a multiple of 4, then the leftover bytes are placed in this /// vector and are prepended to the data in the next call to Transfer. diff --git a/includes/image_io/gcontainer/gcontainer.h b/includes/image_io/gcontainer/gcontainer.h index c0bd66f..118956c 100644 --- a/includes/image_io/gcontainer/gcontainer.h +++ b/includes/image_io/gcontainer/gcontainer.h @@ -1,6 +1,7 @@ #ifndef IMAGE_IO_GCONTAINER_GCONTAINER_H_ // NOLINT #define IMAGE_IO_GCONTAINER_GCONTAINER_H_ // NOLINT +#include <iostream> #include <string> #include <vector> @@ -29,6 +30,11 @@ bool ParseFileAfterImage(const std::string& input_file_name, size_t file_start_offset, size_t file_length, std::string* out_file_contents); +// Used by AOSP. +bool ParseFileAfterImageFromStream(size_t start_offset, size_t length, + std::istream& input_jpeg_stream, + std::string* out_contents); + } // namespace gcontainer } // namespace image_io } // namespace photos_editing_formats diff --git a/includes/image_io/jpeg/jpeg_apple_depth_builder.h b/includes/image_io/jpeg/jpeg_apple_depth_builder.h index 7f5c595..4c0f192 100644 --- a/includes/image_io/jpeg/jpeg_apple_depth_builder.h +++ b/includes/image_io/jpeg/jpeg_apple_depth_builder.h @@ -6,6 +6,7 @@ #include "image_io/base/data_destination.h" #include "image_io/base/data_range.h" #include "image_io/base/data_source.h" +#include "image_io/base/message_handler.h" namespace photos_editing_formats { namespace image_io { @@ -14,8 +15,9 @@ namespace image_io { /// and original depth image. class JpegAppleDepthBuilder { public: - JpegAppleDepthBuilder() - : primary_image_data_source_(nullptr), + explicit JpegAppleDepthBuilder(MessageHandler* message_handler) + : message_handler_(message_handler), + primary_image_data_source_(nullptr), depth_image_data_source_(nullptr), data_destination_(nullptr) {} @@ -69,6 +71,9 @@ class JpegAppleDepthBuilder { /// @param data_range The data range in the data source to transfer. bool TransferData(DataSource *data_source, const DataRange& data_range); + /// An optional message handler to write messages to. + MessageHandler* message_handler_; + /// The data source containing the primary image. DataSource* primary_image_data_source_; diff --git a/includes/image_io/jpeg/jpeg_image_extractor.h b/includes/image_io/jpeg/jpeg_image_extractor.h index 91237e5..966f609 100644 --- a/includes/image_io/jpeg/jpeg_image_extractor.h +++ b/includes/image_io/jpeg/jpeg_image_extractor.h @@ -3,6 +3,7 @@ #include "image_io/base/data_destination.h" #include "image_io/base/data_source.h" +#include "image_io/base/message_handler.h" #include "image_io/jpeg/jpeg_info.h" namespace photos_editing_formats { @@ -15,8 +16,12 @@ class JpegImageExtractor { public: /// @param jpeg_info The JpegInfo instance containing depth/image data. /// @param data_source The DataSource from which to transfer depth/image data. - JpegImageExtractor(const JpegInfo& jpeg_info, DataSource* data_source) - : jpeg_info_(jpeg_info), data_source_(data_source) {} + /// @param message_handler An optional message handler to write messages to. + JpegImageExtractor(const JpegInfo& jpeg_info, DataSource* data_source, + MessageHandler* message_handler) + : jpeg_info_(jpeg_info), + data_source_(data_source), + message_handler_(message_handler) {} /// This function extracts the Apple depth image from the DataSource and sends /// the bytes to the DataDestination. @@ -65,6 +70,9 @@ class JpegImageExtractor { /// The data source from which the images are extracted. DataSource* data_source_; + + /// An optional message handler to write messages to. + MessageHandler* message_handler_; }; } // namespace image_io diff --git a/includes/image_io/jpeg/jpeg_info_builder.h b/includes/image_io/jpeg/jpeg_info_builder.h index ee4d611..a9f1928 100644 --- a/includes/image_io/jpeg/jpeg_info_builder.h +++ b/includes/image_io/jpeg/jpeg_info_builder.h @@ -34,6 +34,12 @@ class JpegInfoBuilder : public JpegSegmentProcessor { /// @param type The type of segment info to capture the value of. void SetCaptureSegmentBytes(const std::string& segment_info_type); + /// @return True if the segment is a primary Xmp segment. + bool IsPrimaryXmpSegment(const JpegSegment& segment) const; + + /// @return True if the segment is an extended Xmp segment. + bool IsExtendedXmpSegment(const JpegSegment& segment) const; + void Start(JpegScanner* scanner) override; void Process(JpegScanner* scanner, const JpegSegment& segment) override; void Finish(JpegScanner* scanner) override; @@ -45,12 +51,6 @@ class JpegInfoBuilder : public JpegSegmentProcessor { /// @return True if the data members indicate Apple matte is present. bool HasAppleMatte() const; - /// @return True if the segment is a primary Xmp segment. - bool IsPrimaryXmpSegment(const JpegSegment& segment) const; - - /// @return True if the segment is an extended Xmp segment. - bool IsExtendedXmpSegment(const JpegSegment& segment) const; - /// @return True if the segment is an Mpf segment. bool IsMpfSegment(const JpegSegment& segment) const; diff --git a/includes/image_io/jpeg/jpeg_scanner.h b/includes/image_io/jpeg/jpeg_scanner.h index 0ab0488..932d3db 100644 --- a/includes/image_io/jpeg/jpeg_scanner.h +++ b/includes/image_io/jpeg/jpeg_scanner.h @@ -5,6 +5,7 @@ #include "image_io/base/data_segment.h" #include "image_io/base/data_source.h" +#include "image_io/base/message_handler.h" #include "image_io/jpeg/jpeg_marker.h" #include "image_io/jpeg/jpeg_segment_processor.h" @@ -16,8 +17,9 @@ namespace image_io { /// examination. class JpegScanner { public: - JpegScanner() - : data_source_(nullptr), + explicit JpegScanner(MessageHandler* message_handler) + : message_handler_(message_handler), + data_source_(nullptr), segment_processor_(nullptr), current_location_(0), done_(false), @@ -70,6 +72,9 @@ class JpegScanner { void GetNextSegment(); private: + /// An optional message handler to write messages to. + MessageHandler* message_handler_; + /// The DataSource from which DataSegments are obtained. DataSource* data_source_; diff --git a/includes/image_io/jpeg/jpeg_xmp_data_extractor.h b/includes/image_io/jpeg/jpeg_xmp_data_extractor.h index 30d62a1..29b16b6 100644 --- a/includes/image_io/jpeg/jpeg_xmp_data_extractor.h +++ b/includes/image_io/jpeg/jpeg_xmp_data_extractor.h @@ -2,6 +2,7 @@ #define IMAGE_IO_JPEG_JPEG_XMP_DATA_EXTRACTOR_H_ // NOLINT #include "image_io/base/data_destination.h" +#include "image_io/base/message_handler.h" #include "image_io/jpeg/jpeg_info.h" namespace photos_editing_formats { @@ -17,10 +18,13 @@ class JpegXmpDataExtractor : public DataDestination { /// @param data_destination The destination to which the extracted xmp data /// is to be sent. JpegXmpDataExtractor(JpegXmpInfo::Type xmp_info_type, size_t segment_count, - DataDestination* data_destination) + DataDestination* data_destination, + MessageHandler* message_handler) : xmp_info_type_(xmp_info_type), last_segment_index_(segment_count - 1), data_destination_(data_destination), + message_handler_(message_handler), + segment_index_(0), has_error_(false) {} /// Set the current segment index to the given value. @@ -52,6 +56,9 @@ class JpegXmpDataExtractor : public DataDestination { /// The DataDestination that the extracted xmp data is sent to. DataDestination* data_destination_; + /// An optional message handler to write messages to. + MessageHandler* message_handler_; + /// The xmp data is spread over one or more segments in the DataSource. This /// index tracks which one is being transferred. size_t segment_index_; diff --git a/includes/image_io/utils/file_utils.h b/includes/image_io/utils/file_utils.h index d1a469d..3a8d2c6 100644 --- a/includes/image_io/utils/file_utils.h +++ b/includes/image_io/utils/file_utils.h @@ -6,34 +6,35 @@ #include <string> #include "image_io/base/data_segment.h" +#include "image_io/base/message_handler.h" namespace photos_editing_formats { namespace image_io { -/// A policy that controls whether an error is reported or not. -enum class ReportErrorPolicy { kDontReportError, kReportError }; - /// @param file_name The name of the file to get the size in bytes of. /// @param size A pointer to a variable to receive the size. /// @return Whether file size was obtained properly. bool GetFileSize(const std::string& file_name, size_t* size); /// @param file_name The name of the file to open for output. +/// @param message_handler Optional message handler to write messages to. /// @return An ostream pointer or nullptr if the open failed. -std::unique_ptr<std::ostream> OpenOutputFile( - const std::string& file_name, ReportErrorPolicy report_error_policy); +std::unique_ptr<std::ostream> OpenOutputFile(const std::string& file_name, + MessageHandler* message_handler); /// @param file_name The name of the file to open for input. +/// @param message_handler Optional message handler to write messages to. /// @return An istream pointer or nullptr if the open failed. -std::unique_ptr<std::istream> OpenInputFile( - const std::string& file_name, ReportErrorPolicy report_error_policy); +std::unique_ptr<std::istream> OpenInputFile(const std::string& file_name, + MessageHandler* message_handler); /// Opens the named file for input, gets its size, and reads the entire contents /// into a data segment that is returned to the caller. /// @param file_name The name of the file to open for input. +/// @param message_handler Optional message handler to write messages to. /// @return A DataSegment pointer or nullptr if the open and reading failed. -std::shared_ptr<DataSegment> ReadEntireFile( - const std::string& file_name, ReportErrorPolicy report_error_policy); +std::shared_ptr<DataSegment> ReadEntireFile(const std::string& file_name, + MessageHandler* message_handler); } // namespace image_io } // namespace photos_editing_formats diff --git a/includes/image_io/utils/message_stats_writer.h b/includes/image_io/utils/message_stats_writer.h new file mode 100644 index 0000000..24dd6b1 --- /dev/null +++ b/includes/image_io/utils/message_stats_writer.h @@ -0,0 +1,47 @@ +#ifndef IMAGE_IO_UTILS_MESSAGE_STATS_WRITER_H_ // NOLINT +#define IMAGE_IO_UTILS_MESSAGE_STATS_WRITER_H_ // NOLINT + +#include <memory> +#include <sstream> +#include <string> + +#include "image_io/base/message_stats.h" +#include "image_io/utils/string_outputter.h" + +namespace photos_editing_formats { +namespace image_io { + +/// A class to write the message stats for error and warning counts. The output +/// is written when the writer object is destroyed, making this a conveneient +/// class to use in functions that have multiple return points and for which +/// such output is desired at all return points. +class MessageStatsWriter { + public: + /// @param message_stats The message stats object holding the counts. + /// @param outputter The outputter function to write the stats to. + /// @param name The name of the tool or function that is "finished". + MessageStatsWriter(const std::shared_ptr<MessageStats>& message_stats, + const std::string& name, const StringOutputter& outputter) + : stats_(message_stats), outputter_(outputter), name_(name) {} + + /// Writes the finished message with the stats to the outputter function. + ~MessageStatsWriter() { + const string kError = stats_->error_count == 1 ? "error" : "errors"; + const string kWarning = stats_->warning_count == 1 ? "warning" : "warnings"; + std::stringstream ss; + ss << std::endl + << name_ << " finished, " << stats_->error_count << " " << kError << ", " + << stats_->warning_count << " " << kWarning << std::endl; + outputter_(ss.str()); + } + + private: + std::shared_ptr<MessageStats> stats_; + StringOutputter outputter_; + std::string name_; +}; + +} // namespace image_io +} // namespace photos_editing_formats + +#endif // IMAGE_IO_UTILS_MESSAGE_STATS_WRITER_H_ // NOLINT diff --git a/includes/image_io/utils/string_outputter.h b/includes/image_io/utils/string_outputter.h new file mode 100644 index 0000000..b6ea013 --- /dev/null +++ b/includes/image_io/utils/string_outputter.h @@ -0,0 +1,19 @@ +#ifndef IMAGE_IO_UTILS_STRING_OUTPUTTER_H_ // NOLINT +#define IMAGE_IO_UTILS_STRING_OUTPUTTER_H_ // NOLINT + +#include <functional> +#include <string> + +namespace photos_editing_formats { +namespace image_io { + +/// A typedef for a function that accepts a string and writes it somewhere. +/// These types of functions are typically used in command line tools to write +/// the output of the tool to stdout or some other location. The function +/// should not write its own new line at the end of the str. +using StringOutputter = std::function<void(const std::string& str)>; + +} // namespace image_io +} // namespace photos_editing_formats + +#endif // IMAGE_IO_UTILS_STRING_OUTPUTTER_H_ // NOLINT diff --git a/includes/image_io/utils/string_outputter_message_writer.h b/includes/image_io/utils/string_outputter_message_writer.h new file mode 100644 index 0000000..f34d975 --- /dev/null +++ b/includes/image_io/utils/string_outputter_message_writer.h @@ -0,0 +1,28 @@ +#ifndef IMAGE_IO_UTILS_STRING_OUTPUTTER_MESSAGE_WRITER_H_ // NOLINT +#define IMAGE_IO_UTILS_STRING_OUTPUTTER_MESSAGE_WRITER_H_ // NOLINT + +#include "image_io/base/message_writer.h" +#include "image_io/utils/string_outputter.h" + +namespace photos_editing_formats { +namespace image_io { + +/// A MessageWriter that writes the messages to the StringOutputter function. +class StringOutputterMessageWriter : public MessageWriter { + public: + /// @param outputter The outputter function to write messages to. + explicit StringOutputterMessageWriter(const StringOutputter& outputter) + : outputter_(outputter) {} + void WriteMessage(const Message& message) override { + outputter_(GetFormattedMessage(message)); + outputter_("\n"); + } + + private: + StringOutputter outputter_; +}; + +} // namespace image_io +} // namespace photos_editing_formats + +#endif // IMAGE_IO_UTILS_STRING_OUTPUTTER_MESSAGE_WRITER_H_ // NOLINT diff --git a/src/base/istream_data_source.cc b/src/base/istream_ref_data_source.cc index d1d66f0..5e3d126 100644 --- a/src/base/istream_data_source.cc +++ b/src/base/istream_ref_data_source.cc @@ -1,4 +1,4 @@ -#include "image_io/base/istream_data_source.h" +#include "image_io/base/istream_ref_data_source.h" #include "image_io/base/data_destination.h" #include "image_io/base/data_segment.h" @@ -6,13 +6,13 @@ namespace photos_editing_formats { namespace image_io { -void IStreamDataSource::Reset() { - istream_->clear(); - istream_->seekg(0); +void IStreamRefDataSource::Reset() { + istream_ref_.clear(); + istream_ref_.seekg(0); current_data_segment_.reset(); } -std::shared_ptr<DataSegment> IStreamDataSource::GetDataSegment( +std::shared_ptr<DataSegment> IStreamRefDataSource::GetDataSegment( size_t begin, size_t min_size) { if (current_data_segment_ && current_data_segment_->Contains(begin)) { return current_data_segment_; @@ -21,7 +21,7 @@ std::shared_ptr<DataSegment> IStreamDataSource::GetDataSegment( return current_data_segment_; } -DataSource::TransferDataResult IStreamDataSource::TransferData( +DataSource::TransferDataResult IStreamRefDataSource::TransferData( const DataRange &data_range, size_t best_size, DataDestination *data_destination) { bool data_transferred = false; @@ -34,7 +34,7 @@ DataSource::TransferDataResult IStreamDataSource::TransferData( status = data_destination->Transfer(data_range, *current_data_segment_); data_transferred = true; } else { - istream_->clear(); + istream_ref_.clear(); size_t chunk_size = min_size; for (size_t begin = data_range.GetBegin(); begin < data_range.GetEnd(); begin += chunk_size) { @@ -63,14 +63,14 @@ DataSource::TransferDataResult IStreamDataSource::TransferData( } } -std::shared_ptr<DataSegment> IStreamDataSource::Read(size_t begin, - size_t count) { +std::shared_ptr<DataSegment> IStreamRefDataSource::Read(size_t begin, + size_t count) { std::shared_ptr<DataSegment> shared_data_segment; - istream_->seekg(begin); - if (istream_->rdstate() == std::ios_base::goodbit) { + istream_ref_.seekg(begin); + if (istream_ref_.rdstate() == std::ios_base::goodbit) { Byte *buffer = new Byte[count]; - istream_->read(reinterpret_cast<char *>(buffer), count); - size_t bytes_read = istream_->gcount(); + istream_ref_.read(reinterpret_cast<char *>(buffer), count); + size_t bytes_read = istream_ref_.gcount(); shared_data_segment = DataSegment::Create(DataRange(begin, begin + bytes_read), buffer); } diff --git a/src/base/message_handler.cc b/src/base/message_handler.cc index 70959c0..fdacc66 100644 --- a/src/base/message_handler.cc +++ b/src/base/message_handler.cc @@ -12,34 +12,10 @@ namespace image_io { using std::string; using std::unique_ptr; -/// The message handler. No effort made to delete it at program's end. -static MessageHandler* gMessageHandler = nullptr; - -void MessageHandler::Init(std::unique_ptr<MessageWriter> message_writer, - std::unique_ptr<MessageStore> message_store) { - auto* old_handler = gMessageHandler; - gMessageHandler = new MessageHandler; - gMessageHandler->SetMessageWriter(std::move(message_writer)); - gMessageHandler->SetMessageStore(std::move(message_store)); - delete old_handler; -} - -MessageHandler* MessageHandler::Get() { - if (!gMessageHandler) { - gMessageHandler = new MessageHandler; - gMessageHandler->SetMessageWriter( - unique_ptr<MessageWriter>(new CoutMessageWriter)); - gMessageHandler->SetMessageStore( - unique_ptr<MessageStore>(new VectorMessageStore)); - } - return gMessageHandler; -} - -MessageHandler::~MessageHandler() { - if (gMessageHandler == this) { - gMessageHandler = nullptr; - } -} +MessageHandler::MessageHandler() + : message_writer_(new CoutMessageWriter), + message_store_(new VectorMessageStore), + message_stats_(new MessageStats) {} void MessageHandler::SetMessageWriter( std::unique_ptr<MessageWriter> message_writer) { @@ -57,6 +33,13 @@ void MessageHandler::ReportMessage(Message::Type type, const string& text) { } void MessageHandler::ReportMessage(const Message& message) { + if (message.IsError()) { + message_stats_->error_count++; + } else if (message.IsWarning()) { + message_stats_->warning_count++; + } else { + message_stats_->status_count++; + } if (message_store_) { message_store_->AddMessage(message); } diff --git a/src/base/message_writer.cc b/src/base/message_writer.cc index d13dc41..2f9e0f0 100644 --- a/src/base/message_writer.cc +++ b/src/base/message_writer.cc @@ -12,19 +12,37 @@ using std::stringstream; string MessageWriter::GetFormattedMessage(const Message& message) const { stringstream message_stream; - message_stream << GetTypeCategory(message.GetType()) << ":" - << GetTypeDescription(message.GetType(), - message.GetSystemErrno()) - << ":" << message.GetText(); + auto type = message.GetType(); + if (type != Message::kStatus) { + message_stream << GetTypeCategory(type) << ":"; + } + if (type == Message::kInternalError || type == Message::kStdLibError) { + message_stream << GetTypeDescription(type, message.GetSystemErrno()) << ":"; + } + message_stream << message.GetText(); return message_stream.str(); } string MessageWriter::GetTypeCategory(Message::Type type) const { - if (type == Message::kStatus) { - return "STATUS"; - } else { - return "ERROR"; + string category; + switch (type) { + case Message::kStatus: + category = "STATUS"; + break; + case Message::kWarning: + category = "WARNING"; + break; + case Message::kStdLibError: + case Message::kPrematureEndOfDataError: + case Message::kStringNotFoundError: + case Message::kDecodingError: + case Message::kSyntaxError: + case Message::kValueError: + case Message::kInternalError: + category = "ERROR"; + break; } + return category; } string MessageWriter::GetTypeDescription(Message::Type type, @@ -33,6 +51,8 @@ string MessageWriter::GetTypeDescription(Message::Type type, switch (type) { case Message::kStatus: break; + case Message::kWarning: + break; case Message::kStdLibError: description = system_errno > 0 ? std::strerror(system_errno) : "Unknown"; break; diff --git a/src/base/ostream_data_destination.cc b/src/base/ostream_ref_data_destination.cc index 97915c9..3658022 100644 --- a/src/base/ostream_data_destination.cc +++ b/src/base/ostream_ref_data_destination.cc @@ -1,33 +1,34 @@ -#include "image_io/base/ostream_data_destination.h" +#include "image_io/base/ostream_ref_data_destination.h" #include "image_io/base/data_range.h" #include "image_io/base/data_segment.h" -#include "image_io/base/message_handler.h" namespace photos_editing_formats { namespace image_io { using std::ostream; -void OStreamDataDestination::StartTransfer() {} +void OStreamRefDataDestination::StartTransfer() {} -DataDestination::TransferStatus OStreamDataDestination::Transfer( +DataDestination::TransferStatus OStreamRefDataDestination::Transfer( const DataRange& transfer_range, const DataSegment& data_segment) { - if (ostream_ && transfer_range.IsValid() && !HasError()) { + if (transfer_range.IsValid() && !HasError()) { size_t bytes_written = 0; size_t bytes_to_write = transfer_range.GetLength(); const Byte* buffer = data_segment.GetBuffer(transfer_range.GetBegin()); if (buffer) { - ostream::pos_type prewrite_pos = ostream_->tellp(); - ostream_->write(reinterpret_cast<const char*>(buffer), bytes_to_write); - ostream::pos_type postwrite_pos = ostream_->tellp(); + ostream::pos_type prewrite_pos = ostream_ref_.tellp(); + ostream_ref_.write(reinterpret_cast<const char*>(buffer), bytes_to_write); + ostream::pos_type postwrite_pos = ostream_ref_.tellp(); if (postwrite_pos != EOF) { - bytes_written = ostream_->tellp() - prewrite_pos; + bytes_written = ostream_ref_.tellp() - prewrite_pos; bytes_transferred_ += bytes_written; } } if (bytes_written != bytes_to_write) { - MessageHandler::Get()->ReportMessage(Message::kStdLibError, name_); + if (message_handler_) { + message_handler_->ReportMessage(Message::kStdLibError, name_); + } has_error_ = true; return kTransferError; } @@ -35,10 +36,8 @@ DataDestination::TransferStatus OStreamDataDestination::Transfer( return kTransferOk; } -void OStreamDataDestination::FinishTransfer() { - if (ostream_) { - ostream_->flush(); - } +void OStreamRefDataDestination::FinishTransfer() { + ostream_ref_.flush(); } } // namespace image_io diff --git a/src/extras/base64_decoder_data_destination.cc b/src/extras/base64_decoder_data_destination.cc index a15b997..8ba8bb2 100644 --- a/src/extras/base64_decoder_data_destination.cc +++ b/src/extras/base64_decoder_data_destination.cc @@ -127,7 +127,9 @@ DataDestination::TransferStatus Base64DecoderDataDestination::Transfer( decoded_buffer.get(), &pad_count1); if (total_bytes_decoded + pad_count1 != number_leftover_and_stolen_decoded_bytes) { - MessageHandler::Get()->ReportMessage(Message::kDecodingError, ""); + if (message_handler_) { + message_handler_->ReportMessage(Message::kDecodingError, ""); + } has_error_ = true; return kTransferError; } @@ -142,7 +144,9 @@ DataDestination::TransferStatus Base64DecoderDataDestination::Transfer( total_bytes_decoded += number_bytes_decoded; if (total_bytes_decoded + pad_count1 + pad_count2 != decoded_buffer_length) { - MessageHandler::Get()->ReportMessage(Message::kDecodingError, ""); + if (message_handler_) { + message_handler_->ReportMessage(Message::kDecodingError, ""); + } has_error_ = true; return kTransferError; } @@ -177,7 +181,9 @@ DataDestination::TransferStatus Base64DecoderDataDestination::Transfer( void Base64DecoderDataDestination::FinishTransfer() { if (leftover_bytes_.size() % 4) { - MessageHandler::Get()->ReportMessage(Message::kDecodingError, ""); + if (message_handler_) { + message_handler_->ReportMessage(Message::kDecodingError, ""); + } has_error_ = true; } next_destination_->FinishTransfer(); diff --git a/src/gcontainer/gcontainer.cc b/src/gcontainer/gcontainer.cc index 1179778..b97fdd7 100644 --- a/src/gcontainer/gcontainer.cc +++ b/src/gcontainer/gcontainer.cc @@ -4,6 +4,7 @@ #include "image_io/base/data_segment.h" #include "image_io/base/data_segment_data_source.h" +#include "image_io/base/istream_data_source.h" #include "image_io/base/message_handler.h" #include "image_io/base/ostream_data_destination.h" #include "image_io/jpeg/jpeg_info.h" @@ -19,44 +20,44 @@ namespace { using photos_editing_formats::image_io::DataRange; using photos_editing_formats::image_io::DataSegment; using photos_editing_formats::image_io::DataSegmentDataSource; +using photos_editing_formats::image_io::IStreamRefDataSource; using photos_editing_formats::image_io::JpegInfoBuilder; using photos_editing_formats::image_io::JpegScanner; using photos_editing_formats::image_io::Message; using photos_editing_formats::image_io::MessageHandler; using photos_editing_formats::image_io::OStreamDataDestination; -using photos_editing_formats::image_io::ReportErrorPolicy; using std::string; // Populates first_image_range with the first image (from the header metadata // to the EOI marker) present in the JPEG file input_file_name. Returns true if // such a first image is found, false otherwise. // -// input_file_name must be a JPEG file. +// input_jpeg_stream must be a JPEG stream. // image_data_segment is populated with the DataSegment for // input_file_name, and is populated only in the successful case. // first_image_range is populated with the first image found in the input file, // only if such an image is found. -bool ExtractFirstImageInJpeg(const string& input_file_name, - std::shared_ptr<DataSegment>* image_data_segment, + +bool ExtractFirstImageInJpeg(std::istream& input_jpeg_stream, + MessageHandler* message_handler, DataRange* first_image_range) { if (first_image_range == nullptr) { return false; } // Get the input and output setup. - MessageHandler::Get()->ClearMessages(); - auto data_segment = - ReadEntireFile(input_file_name, ReportErrorPolicy::kReportError); - if (!data_segment) { - return false; + if (message_handler) { + message_handler->ClearMessages(); } // Get the jpeg info and first image range from the input. - DataSegmentDataSource data_source(data_segment); + IStreamRefDataSource data_source(input_jpeg_stream); JpegInfoBuilder jpeg_info_builder; jpeg_info_builder.SetImageLimit(1); - JpegScanner jpeg_scanner; + JpegScanner jpeg_scanner(message_handler); jpeg_scanner.Run(&data_source, &jpeg_info_builder); + data_source.Reset(); + if (jpeg_scanner.HasError()) { return false; } @@ -64,12 +65,13 @@ bool ExtractFirstImageInJpeg(const string& input_file_name, const auto& jpeg_info = jpeg_info_builder.GetInfo(); const auto& image_ranges = jpeg_info.GetImageRanges(); if (image_ranges.empty()) { - MessageHandler::Get()->ReportMessage(Message::kPrematureEndOfDataError, - "No Images Found"); + if (message_handler) { + message_handler->ReportMessage(Message::kPrematureEndOfDataError, + "No Images Found"); + } return false; } - *image_data_segment = data_segment; *first_image_range = image_ranges[0]; return true; } @@ -79,23 +81,27 @@ bool ExtractFirstImageInJpeg(const string& input_file_name, bool WriteImageAndFiles(const string& input_file_name, const std::vector<string>& other_files, const string& output_file_name) { - auto output_stream = - OpenOutputFile(output_file_name, ReportErrorPolicy::kReportError); + MessageHandler message_handler; + auto output_stream = OpenOutputFile(output_file_name, &message_handler); if (!output_stream) { return false; } - OStreamDataDestination output_destination(std::move(output_stream)); + OStreamDataDestination output_destination(std::move(output_stream), + &message_handler); output_destination.SetName(output_file_name); DataRange image_range; - std::shared_ptr<DataSegment> data_segment; - if (!ExtractFirstImageInJpeg(input_file_name, &data_segment, &image_range)) { + std::unique_ptr<std::istream> input_stream = + OpenInputFile(input_file_name, &message_handler); + + if (!ExtractFirstImageInJpeg(*input_stream, &message_handler, &image_range)) { return false; } output_destination.StartTransfer(); - DataSegmentDataSource data_source(data_segment); + IStreamDataSource data_source( + OpenInputFile(input_file_name, &message_handler)); data_source.TransferData(image_range, image_range.GetLength(), &output_destination); @@ -104,8 +110,7 @@ bool WriteImageAndFiles(const string& input_file_name, if (tack_on_file.empty()) { continue; } - auto tack_on_data_segment = - ReadEntireFile(tack_on_file, ReportErrorPolicy::kReportError); + auto tack_on_data_segment = ReadEntireFile(tack_on_file, &message_handler); if (!tack_on_data_segment) { continue; } @@ -122,25 +127,40 @@ bool WriteImageAndFiles(const string& input_file_name, !output_destination.HasError(); } -bool ParseFileAfterImage(const string& input_file_name, +bool ParseFileAfterImage(const std::string& input_file_name, size_t file_start_offset, size_t file_length, - string* out_file_contents) { - if (out_file_contents == nullptr || file_start_offset < 0 || - file_length == 0) { + std::string* out_file_contents) { + std::ifstream input_stream(input_file_name); + if (!input_stream.is_open()) { return false; } + return ParseFileAfterImageFromStream(file_start_offset, file_length, + input_stream, out_file_contents); +} + +bool ParseFileAfterImageFromStream(size_t start_offset, size_t length, + std::istream& input_jpeg_stream, + std::string* out_contents) { + if (out_contents == nullptr || start_offset < 0 || length == 0) { + return false; + } + + size_t curr_posn = input_jpeg_stream.tellg(); + input_jpeg_stream.seekg(0, input_jpeg_stream.end); + size_t stream_size = input_jpeg_stream.tellg(); + input_jpeg_stream.seekg(curr_posn, input_jpeg_stream.beg); DataRange image_range; - std::shared_ptr<DataSegment> data_segment; - if (!ExtractFirstImageInJpeg(input_file_name, &data_segment, &image_range)) { + MessageHandler message_handler; + if (!ExtractFirstImageInJpeg(input_jpeg_stream, &message_handler, + &image_range)) { return false; } size_t image_bytes_end_offset = image_range.GetEnd(); - size_t image_file_end = data_segment->GetEnd(); - size_t file_start_in_image = image_bytes_end_offset + file_start_offset; - size_t file_end_in_image = file_start_in_image + file_length; - if (image_file_end < file_end_in_image) { + size_t file_start_in_image = image_bytes_end_offset + start_offset; + size_t file_end_in_image = file_start_in_image + length; + if (stream_size < file_end_in_image) { // Requested file is past the end of the image file. return false; } @@ -151,10 +171,9 @@ bool ParseFileAfterImage(const string& input_file_name, // TODO(miraleung): Consider subclassing image_io/data_destination.h and // transferring bytes directly into the string. TBD pending additional mime // type getters. - std::ifstream input_file_stream(input_file_name); - input_file_stream.seekg(file_range.GetBegin()); - out_file_contents->resize(file_range_size); - input_file_stream.read(&(*out_file_contents)[0], file_range_size); + input_jpeg_stream.seekg(file_range.GetBegin(), input_jpeg_stream.beg); + out_contents->resize(file_range_size); + input_jpeg_stream.read(&(*out_contents)[0], file_range_size); return true; } diff --git a/src/jpeg/jpeg_apple_depth_builder.cc b/src/jpeg/jpeg_apple_depth_builder.cc index ce83f9f..a45837e 100644 --- a/src/jpeg/jpeg_apple_depth_builder.cc +++ b/src/jpeg/jpeg_apple_depth_builder.cc @@ -45,12 +45,14 @@ constexpr size_t kBestDataSize = 0x10000; /// @param image_limit The limit on the number of images to get info of. /// @param data_source The data source from which to get info. /// @param info A pointer to the jpeg_info object to receive the info. +/// @param message_handler For use when reporting messages. /// @return Whether the info was obtained successfully or not. -bool GetJpegInfo(int image_limit, DataSource* data_source, JpegInfo* info) { +bool GetJpegInfo(int image_limit, DataSource* data_source, JpegInfo* info, + MessageHandler* message_handler) { JpegInfoBuilder info_builder; info_builder.SetImageLimit(image_limit); info_builder.SetCaptureSegmentBytes(kJfif); - JpegScanner scanner; + JpegScanner scanner(message_handler); scanner.Run(data_source, &info_builder); if (scanner.HasError()) { return false; @@ -68,13 +70,17 @@ bool JpegAppleDepthBuilder::Run(DataSource* primary_image_data_source, depth_image_data_source_ = depth_image_data_source; data_destination_ = data_destination; if (!GetPrimaryImageData()) { - MessageHandler::Get()->ReportMessage(Message::kDecodingError, - "Primary image data"); + if (message_handler_) { + message_handler_->ReportMessage(Message::kDecodingError, + "Primary image data"); + } return false; } if (!GetDepthImageData()) { - MessageHandler::Get()->ReportMessage(Message::kDecodingError, - "Depth image data"); + if (message_handler_) { + message_handler_->ReportMessage(Message::kDecodingError, + "Depth image data"); + } return false; } data_destination->StartTransfer(); @@ -88,7 +94,7 @@ bool JpegAppleDepthBuilder::Run(DataSource* primary_image_data_source, bool JpegAppleDepthBuilder::GetPrimaryImageData() { JpegInfo info; - if (!GetJpegInfo(1, primary_image_data_source_, &info)) { + if (!GetJpegInfo(1, primary_image_data_source_, &info, message_handler_)) { return false; } if (info.GetImageRanges().empty()) { @@ -119,7 +125,7 @@ bool JpegAppleDepthBuilder::GetPrimaryImageData() { bool JpegAppleDepthBuilder::GetDepthImageData() { JpegInfo info; - if (!GetJpegInfo(2, depth_image_data_source_, &info)) { + if (!GetJpegInfo(2, depth_image_data_source_, &info, message_handler_)) { return false; } if (!info.HasAppleDepth()) { @@ -239,10 +245,13 @@ bool JpegAppleDepthBuilder::TransferData(DataSource* data_source, data_destination_->GetBytesTransferred() - old_byte_count; if (bytes_transferred != data_range.GetLength()) { result = DataSource::kTransferDataError; - std::stringstream ss; - ss << "JpegAppleDepthBuilder:data source transferred " - << bytes_transferred << " bytes instead of " << data_range.GetLength(); - MessageHandler::Get()->ReportMessage(Message::kInternalError, ss.str()); + if (message_handler_) { + std::stringstream ss; + ss << "JpegAppleDepthBuilder:data source transferred " + << bytes_transferred << " bytes instead of " + << data_range.GetLength(); + message_handler_->ReportMessage(Message::kInternalError, ss.str()); + } } } return result == DataSource::kTransferDataSuccess; diff --git a/src/jpeg/jpeg_image_extractor.cc b/src/jpeg/jpeg_image_extractor.cc index 82f8fce..b915839 100644 --- a/src/jpeg/jpeg_image_extractor.cc +++ b/src/jpeg/jpeg_image_extractor.cc @@ -51,8 +51,9 @@ bool JpegImageExtractor::ExtractImage(const DataRange& image_range, data_range_destination.HasDisjointTransferRanges() || data_range_destination.GetTrackedDataRange() != image_range) { has_errors = true; - MessageHandler::Get()->ReportMessage(Message::kPrematureEndOfDataError, - ""); + if (message_handler_) { + message_handler_->ReportMessage(Message::kPrematureEndOfDataError, ""); + } } } data_range_destination.FinishTransfer(); @@ -73,12 +74,13 @@ bool JpegImageExtractor::ExtractImage(JpegXmpInfo::Type xmp_info_type, DataDestination* image_destination) { bool has_errors = false; const bool has_image = jpeg_info_.HasImage(xmp_info_type); - Base64DecoderDataDestination base64_decoder(image_destination); + Base64DecoderDataDestination base64_decoder(image_destination, + message_handler_); const vector<DataRange>& data_ranges = jpeg_info_.GetSegmentDataRanges(xmp_info_type); size_t data_ranges_count = data_ranges.size(); JpegXmpDataExtractor xmp_data_extractor(xmp_info_type, data_ranges_count, - &base64_decoder); + &base64_decoder, message_handler_); xmp_data_extractor.StartTransfer(); if (has_image) { for (size_t index = 0; index < data_ranges_count; ++index) { @@ -97,8 +99,10 @@ bool JpegImageExtractor::ExtractImage(JpegXmpInfo::Type xmp_info_type, break; } else if (result == DataSource::kTransferDataNone) { has_errors = true; - MessageHandler::Get()->ReportMessage(Message::kPrematureEndOfDataError, - ""); + if (message_handler_) { + message_handler_->ReportMessage(Message::kPrematureEndOfDataError, + ""); + } } } } diff --git a/src/jpeg/jpeg_scanner.cc b/src/jpeg/jpeg_scanner.cc index 85426b2..c039f70 100644 --- a/src/jpeg/jpeg_scanner.cc +++ b/src/jpeg/jpeg_scanner.cc @@ -93,10 +93,12 @@ ValidatedByte JpegScanner::GetValidatedByte(size_t location) { if (next_segment_ && next_segment_->Contains(location)) { return next_segment_->GetValidatedByte(location); } - stringstream sstream; - sstream << location; - MessageHandler::Get()->ReportMessage(Message::kPrematureEndOfDataError, - sstream.str()); + if (message_handler_) { + stringstream sstream; + sstream << location; + message_handler_->ReportMessage(Message::kPrematureEndOfDataError, + sstream.str()); + } return InvalidByte(); } diff --git a/src/jpeg/jpeg_xmp_data_extractor.cc b/src/jpeg/jpeg_xmp_data_extractor.cc index f59dea5..68475f0 100644 --- a/src/jpeg/jpeg_xmp_data_extractor.cc +++ b/src/jpeg/jpeg_xmp_data_extractor.cc @@ -50,8 +50,10 @@ DataDestination::TransferStatus JpegXmpDataExtractor::Transfer( } } if (xmp_data_begin == encoded_data_begin) { - MessageHandler::Get()->ReportMessage(Message::kStringNotFoundError, - property_name + "=\""); + if (message_handler_) { + message_handler_->ReportMessage(Message::kStringNotFoundError, + property_name + "=\""); + } has_error_ = true; return kTransferError; } @@ -59,7 +61,9 @@ DataDestination::TransferStatus JpegXmpDataExtractor::Transfer( if (segment_index_ == last_segment_index_) { xmp_data_end = data_segment.Find(xmp_data_begin, '"'); if (xmp_data_end == transfer_range.GetEnd()) { - MessageHandler::Get()->ReportMessage(Message::kStringNotFoundError, "\""); + if (message_handler_) { + message_handler_->ReportMessage(Message::kStringNotFoundError, "\""); + } has_error_ = true; return kTransferError; } diff --git a/src/utils/file_utils.cc b/src/utils/file_utils.cc index d61a2cd..626d537 100644 --- a/src/utils/file_utils.cc +++ b/src/utils/file_utils.cc @@ -6,7 +6,6 @@ #import <memory> #include "image_io/base/data_range.h" -#include "image_io/base/message_handler.h" namespace photos_editing_formats { namespace image_io { @@ -29,38 +28,38 @@ bool GetFileSize(const std::string& file_name, size_t* size) { } unique_ptr<ostream> OpenOutputFile(const std::string& file_name, - ReportErrorPolicy report_error_policy) { + MessageHandler* message_handler) { auto* file_stream = new fstream(file_name, std::ios::out | std::ios::binary); if (file_stream && !file_stream->is_open()) { delete file_stream; file_stream = nullptr; - if (report_error_policy == ReportErrorPolicy::kReportError) { - MessageHandler::Get()->ReportMessage(Message::kStdLibError, file_name); + if (message_handler) { + message_handler->ReportMessage(Message::kStdLibError, file_name); } } return unique_ptr<ostream>(file_stream); } unique_ptr<istream> OpenInputFile(const std::string& file_name, - ReportErrorPolicy report_error_policy) { + MessageHandler* message_handler) { auto* file_stream = new fstream(file_name, std::ios::in | std::ios::binary); if (file_stream && !file_stream->is_open()) { delete file_stream; file_stream = nullptr; - if (report_error_policy == ReportErrorPolicy::kReportError) { - MessageHandler::Get()->ReportMessage(Message::kStdLibError, file_name); + if (message_handler) { + message_handler->ReportMessage(Message::kStdLibError, file_name); } } return unique_ptr<istream>(file_stream); } -std::shared_ptr<DataSegment> ReadEntireFile( - const std::string& file_name, ReportErrorPolicy report_error_policy) { +std::shared_ptr<DataSegment> ReadEntireFile(const std::string& file_name, + MessageHandler* message_handler) { size_t buffer_size = 0; std::shared_ptr<DataSegment> shared_data_segment; if (GetFileSize(file_name, &buffer_size)) { unique_ptr<istream> shared_istream = - OpenInputFile(file_name, ReportErrorPolicy::kDontReportError); + OpenInputFile(file_name, message_handler); if (shared_istream) { Byte* buffer = new Byte[buffer_size]; if (buffer) { @@ -74,9 +73,8 @@ std::shared_ptr<DataSegment> ReadEntireFile( } } } - if (!shared_data_segment && - report_error_policy == ReportErrorPolicy::kReportError) { - MessageHandler::Get()->ReportMessage(Message::kStdLibError, file_name); + if (!shared_data_segment && message_handler) { + message_handler->ReportMessage(Message::kStdLibError, file_name); } return shared_data_segment; } |