blob: 68475f06be1d47378aeb3056382dd715e9c35130 [file] [log] [blame]
#include "image_io/jpeg/jpeg_xmp_data_extractor.h"
#include <iomanip>
#include <sstream>
#include <string>
#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<char>(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