Sync libimage_io to CL: #231067980
Changes included:
- [ddepth] Add GetItemPayload for istream
- Adds IStreamRefDataSource and OStreamRefDataDestination to the ImageIO
library.
- Adds GDepthMetadata and readers and writers.
- Adds XmpGImageMetadata and related classes/changes.
- Adds a motion photo builder program and enhances/fixes other
components.
- Adds some new util classes for use with motion photos builder/checker.
- Eliminates the global vars used by image_io::MessageHandler::Get().
- Adds ability to read and check the MP4 part of a motion photo.
- [rosie] Unify all minimum_os_version flags to a minimum_os.bzl file.
- Adds the beginnings of the motion photo checker feature.
- Adds camera and container metadata to motion_photos and updates video
metadata.
- Adds classes/functions to xml/xmp in preparation for motion photo XMP
processing.
- Adds classes/functions to base/xmp in preparation for motion photo XMP
processing.
- Adds the photos/editing/formats/motion_photo and image_io/iso
libraries.
Bug: 123316622
Test: Camera CTS
Change-Id: Ida94bd36cbe45346e493959c32dd713e1b786abb
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;
+ : IStreamRefDataSource(*istream_ptr), istream_(std::move(istream_ptr)) {}
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.
+ /// 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 @@
/// 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 @@
/// @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 @@
/// 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 @@
/// 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 @@
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 @@
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 @@
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 @@
/// 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 @@
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 @@
/// 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 @@
/// @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 @@
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 @@
/// 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 @@
/// @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 @@
/// @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 @@
/// 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 @@
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 @@
/// @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 @@
/// 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
similarity index 78%
rename from src/base/istream_data_source.cc
rename to 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 @@
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 @@
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 @@
}
}
-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 @@
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(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 @@
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 @@
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_data_destination.cc
deleted file mode 100644
index 97915c9..0000000
--- a/src/base/ostream_data_destination.cc
+++ /dev/null
@@ -1,45 +0,0 @@
-#include "image_io/base/ostream_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() {}
-
-DataDestination::TransferStatus OStreamDataDestination::Transfer(
- const DataRange& transfer_range, const DataSegment& data_segment) {
- if (ostream_ && 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();
- if (postwrite_pos != EOF) {
- bytes_written = ostream_->tellp() - prewrite_pos;
- bytes_transferred_ += bytes_written;
- }
- }
- if (bytes_written != bytes_to_write) {
- MessageHandler::Get()->ReportMessage(Message::kStdLibError, name_);
- has_error_ = true;
- return kTransferError;
- }
- }
- return kTransferOk;
-}
-
-void OStreamDataDestination::FinishTransfer() {
- if (ostream_) {
- ostream_->flush();
- }
-}
-
-} // namespace image_io
-} // namespace photos_editing_formats
diff --git a/src/base/ostream_ref_data_destination.cc b/src/base/ostream_ref_data_destination.cc
new file mode 100644
index 0000000..3658022
--- /dev/null
+++ b/src/base/ostream_ref_data_destination.cc
@@ -0,0 +1,44 @@
+#include "image_io/base/ostream_ref_data_destination.h"
+
+#include "image_io/base/data_range.h"
+#include "image_io/base/data_segment.h"
+
+namespace photos_editing_formats {
+namespace image_io {
+
+using std::ostream;
+
+void OStreamRefDataDestination::StartTransfer() {}
+
+DataDestination::TransferStatus OStreamRefDataDestination::Transfer(
+ const DataRange& transfer_range, const DataSegment& data_segment) {
+ 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_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_ref_.tellp() - prewrite_pos;
+ bytes_transferred_ += bytes_written;
+ }
+ }
+ if (bytes_written != bytes_to_write) {
+ if (message_handler_) {
+ message_handler_->ReportMessage(Message::kStdLibError, name_);
+ }
+ has_error_ = true;
+ return kTransferError;
+ }
+ }
+ return kTransferOk;
+}
+
+void OStreamRefDataDestination::FinishTransfer() {
+ ostream_ref_.flush();
+}
+
+} // namespace image_io
+} // namespace photos_editing_formats
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 @@
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 @@
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 @@
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 @@
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 @@
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 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 @@
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 @@
!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 @@
// 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 @@
/// @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 @@
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::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::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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
}
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 @@
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 @@
}
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 @@
}
}
}
- 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;
}