#include "image_io/jpeg/jpeg_xmp_data_extractor.h" #include #include #include #include "image_io/base/message_handler.h" #include "image_io/jpeg/jpeg_marker.h" #include "image_io/jpeg/jpeg_segment.h" /// Set this flag to 1 for debugging output. #define PHOTOS_EDITING_FORMATS_IMAGE_IO_JPEG_JPEG_XMP_DATA_EXTRACTOR_DEBUG 0 namespace photos_editing_formats { namespace image_io { using std::string; using std::stringstream; void JpegXmpDataExtractor::StartTransfer() { data_destination_->StartTransfer(); } DataDestination::TransferStatus JpegXmpDataExtractor::Transfer( const DataRange& transfer_range, const DataSegment& data_segment) { if (HasError()) { return kTransferError; } #if PHOTOS_EDITING_FORMATS_IMAGE_IO_JPEG_JPEG_XMP_DATA_EXTRACTOR_DEBUG stringstream sstream1; sstream1 << "Segment " << segment_index_ << " of " << last_segment_index_ << " - data range from " << transfer_range.GetBegin() << " to " << transfer_range.GetEnd(); MessageHandler::Get()->ReportMessage(Message::kStatus, sstream1.str()); #endif // PHOTOS_EDITING_FORMATS_IMAGE_IO_JPEG_JPEG_XMP_DATA_EXTRACTOR_DEBUG const size_t xmp_header_length = JpegMarker::kLength + JpegSegment::kVariablePayloadDataOffset + kXmpExtendedHeaderSize; size_t encoded_data_begin = transfer_range.GetBegin() + xmp_header_length; size_t xmp_data_begin = encoded_data_begin; size_t xmp_data_end = transfer_range.GetEnd(); if (segment_index_ == 0) { string property_name = JpegXmpInfo::GetDataPropertyName(xmp_info_type_); size_t gdepth_data_location = data_segment.Find( encoded_data_begin, property_name.c_str(), property_name.length()); if (gdepth_data_location != transfer_range.GetEnd()) { size_t quote_location = data_segment.Find(gdepth_data_location, '"'); if (quote_location != transfer_range.GetEnd()) { xmp_data_begin = quote_location + 1; } } if (xmp_data_begin == encoded_data_begin) { if (message_handler_) { message_handler_->ReportMessage(Message::kStringNotFoundError, property_name + "=\""); } has_error_ = true; return kTransferError; } } if (segment_index_ == last_segment_index_) { xmp_data_end = data_segment.Find(xmp_data_begin, '"'); if (xmp_data_end == transfer_range.GetEnd()) { if (message_handler_) { message_handler_->ReportMessage(Message::kStringNotFoundError, "\""); } has_error_ = true; return kTransferError; } } DataRange xmp_data_range(xmp_data_begin, xmp_data_end); #if PHOTOS_EDITING_FORMATS_IMAGE_IO_JPEG_JPEG_XMP_DATA_EXTRACTOR_DEBUG string strb((const char*)data_segment.GetBuffer(xmp_data_range.GetBegin()), 50); string stre((const char*)data_segment.GetBuffer(xmp_data_end - 50), 50); stringstream sstream2; sstream2 << " " << xmp_data_begin << ":" << xmp_data_end << " = " << xmp_data_range.GetLength() << " bytes: [" << strb << "..." << stre << "] - "; MessageHandler::Get()->ReportMessage(Message::kStatus, sstream2.str()); for (size_t i = transfer_range.GetBegin(); i < data_segment.GetEnd(); i += 32) { stringstream hex_stream, ascii_stream; hex_stream << std::hex << std::setfill('0') << std::setw(2) << std::uppercase; for (size_t j = 0; j < 32 && (i + j) < data_segment.GetEnd(); ++j) { Byte value = data_segment.GetValidatedByte(i + j).value; hex_stream << " " << size_t(value); ascii_stream << (isprint(value) ? static_cast(value) : '.'); } stringstream sstream3; sstream3 << " * " << std::hex << std::setfill('0') << std::setw(8) << std::uppercase << i; sstream3 << ":" << hex_stream.str() << " [" << ascii_stream.str() << "]"; MessageHandler::Get()->ReportMessage(Message::kStatus, sstream3.str()); } #endif // PHOTOS_EDITING_FORMATS_IMAGE_IO_JPEG_JPEG_XMP_DATA_EXTRACTOR_DEBUG return data_destination_->Transfer(xmp_data_range, data_segment); } void JpegXmpDataExtractor::FinishTransfer() { data_destination_->FinishTransfer(); } } // namespace image_io } // namespace photos_editing_formats