1 #include "image_io/jpeg/jpeg_xmp_data_extractor.h"
2 
3 #include <iomanip>
4 #include <sstream>
5 #include <string>
6 
7 #include "image_io/base/message_handler.h"
8 #include "image_io/jpeg/jpeg_marker.h"
9 #include "image_io/jpeg/jpeg_segment.h"
10 
11 /// Set this flag to 1 for debugging output.
12 #define PHOTOS_EDITING_FORMATS_IMAGE_IO_JPEG_JPEG_XMP_DATA_EXTRACTOR_DEBUG 0
13 
14 namespace photos_editing_formats {
15 namespace image_io {
16 
17 using std::string;
18 using std::stringstream;
19 
StartTransfer()20 void JpegXmpDataExtractor::StartTransfer() {
21   data_destination_->StartTransfer();
22 }
23 
Transfer(const DataRange & transfer_range,const DataSegment & data_segment)24 DataDestination::TransferStatus JpegXmpDataExtractor::Transfer(
25     const DataRange& transfer_range, const DataSegment& data_segment) {
26   if (HasError()) {
27     return kTransferError;
28   }
29 #if PHOTOS_EDITING_FORMATS_IMAGE_IO_JPEG_JPEG_XMP_DATA_EXTRACTOR_DEBUG
30   stringstream sstream1;
31   sstream1 << "Segment " << segment_index_ << " of " << last_segment_index_
32            << " - data range from " << transfer_range.GetBegin() << " to "
33            << transfer_range.GetEnd();
34   MessageHandler::Get()->ReportMessage(Message::kStatus, sstream1.str());
35 #endif  // PHOTOS_EDITING_FORMATS_IMAGE_IO_JPEG_JPEG_XMP_DATA_EXTRACTOR_DEBUG
36   const size_t xmp_header_length = JpegMarker::kLength +
37                                    JpegSegment::kVariablePayloadDataOffset +
38                                    kXmpExtendedHeaderSize;
39   size_t encoded_data_begin = transfer_range.GetBegin() + xmp_header_length;
40   size_t xmp_data_begin = encoded_data_begin;
41   size_t xmp_data_end = transfer_range.GetEnd();
42   if (segment_index_ == 0) {
43     string property_name = JpegXmpInfo::GetDataPropertyName(xmp_info_type_);
44     size_t gdepth_data_location = data_segment.Find(
45         encoded_data_begin, property_name.c_str(), property_name.length());
46     if (gdepth_data_location != transfer_range.GetEnd()) {
47       size_t quote_location = data_segment.Find(gdepth_data_location, '"');
48       if (quote_location != transfer_range.GetEnd()) {
49         xmp_data_begin = quote_location + 1;
50       }
51     }
52     if (xmp_data_begin == encoded_data_begin) {
53       if (message_handler_) {
54         message_handler_->ReportMessage(Message::kStringNotFoundError,
55                                         property_name + "=\"");
56       }
57       has_error_ = true;
58       return kTransferError;
59     }
60   }
61   if (segment_index_ == last_segment_index_) {
62     xmp_data_end = data_segment.Find(xmp_data_begin, '"');
63     if (xmp_data_end == transfer_range.GetEnd()) {
64       if (message_handler_) {
65         message_handler_->ReportMessage(Message::kStringNotFoundError, "\"");
66       }
67       has_error_ = true;
68       return kTransferError;
69     }
70   }
71 
72   DataRange xmp_data_range(xmp_data_begin, xmp_data_end);
73 #if PHOTOS_EDITING_FORMATS_IMAGE_IO_JPEG_JPEG_XMP_DATA_EXTRACTOR_DEBUG
74   string strb((const char*)data_segment.GetBuffer(xmp_data_range.GetBegin()),
75               50);
76   string stre((const char*)data_segment.GetBuffer(xmp_data_end - 50), 50);
77   stringstream sstream2;
78   sstream2 << "  " << xmp_data_begin << ":" << xmp_data_end << " = "
79            << xmp_data_range.GetLength() << " bytes: [" << strb << "..." << stre
80            << "] - ";
81   MessageHandler::Get()->ReportMessage(Message::kStatus, sstream2.str());
82   for (size_t i = transfer_range.GetBegin(); i < data_segment.GetEnd();
83        i += 32) {
84     stringstream hex_stream, ascii_stream;
85     hex_stream << std::hex << std::setfill('0') << std::setw(2)
86                << std::uppercase;
87     for (size_t j = 0; j < 32 && (i + j) < data_segment.GetEnd(); ++j) {
88       Byte value = data_segment.GetValidatedByte(i + j).value;
89       hex_stream << " " << size_t(value);
90       ascii_stream << (isprint(value) ? static_cast<char>(value) : '.');
91     }
92     stringstream sstream3;
93     sstream3 << "  * " << std::hex << std::setfill('0') << std::setw(8)
94              << std::uppercase << i;
95     sstream3 << ":" << hex_stream.str() << "  [" << ascii_stream.str() << "]";
96     MessageHandler::Get()->ReportMessage(Message::kStatus, sstream3.str());
97   }
98 #endif  // PHOTOS_EDITING_FORMATS_IMAGE_IO_JPEG_JPEG_XMP_DATA_EXTRACTOR_DEBUG
99   return data_destination_->Transfer(xmp_data_range, data_segment);
100 }
101 
FinishTransfer()102 void JpegXmpDataExtractor::FinishTransfer() {
103   data_destination_->FinishTransfer();
104 }
105 
106 }  // namespace image_io
107 }  // namespace photos_editing_formats
108