• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include "image_io/jpeg/jpeg_segment.h"
2 
3 #include <cctype>
4 #include <iomanip>
5 #include <sstream>
6 #include <string>
7 
8 namespace photos_editing_formats {
9 namespace image_io {
10 
11 using std::string;
12 using std::stringstream;
13 
14 /// Finds the character allowing it to be preceded by whitespace characters.
15 /// @param segment The segment in which to look for the character.
16 /// @param start_location The location at which to start looking.
17 /// @param value The character value to look for.
18 /// @return The location of the character or segment.GetEnd() if not found,
19 ///     of non whitespace characters are found first.
SkipWhiteSpaceFindChar(const JpegSegment & segment,size_t start_location,char value)20 static size_t SkipWhiteSpaceFindChar(const JpegSegment& segment,
21                                      size_t start_location, char value) {
22   for (size_t location = start_location; location < segment.GetEnd();
23        ++location) {
24     ValidatedByte validated_byte = segment.GetValidatedByte(location);
25     if (!validated_byte.is_valid) {
26       return segment.GetEnd();
27     }
28     if (validated_byte.value == Byte(value)) {
29       return location;
30     }
31     if (!std::isspace(validated_byte.value)) {
32       return segment.GetEnd();
33     }
34   }
35   return segment.GetEnd();
36 }
37 
GetVariablePayloadSize() const38 size_t JpegSegment::GetVariablePayloadSize() const {
39   if (!GetMarker().HasVariablePayloadSize()) {
40     return 0;
41   }
42   size_t payload_location = GetPayloadLocation();
43   ValidatedByte hi = GetValidatedByte(payload_location);
44   ValidatedByte lo = GetValidatedByte(payload_location + 1);
45   if (!hi.is_valid || !lo.is_valid) {
46     return 0;
47   }
48   return static_cast<size_t>(hi.value) << 8 | static_cast<size_t>(lo.value);
49 }
50 
BytesAtLocationStartWith(size_t location,const char * str) const51 bool JpegSegment::BytesAtLocationStartWith(size_t location,
52                                            const char* str) const {
53   while (*str && Contains(location)) {
54     ValidatedByte validated_byte = GetValidatedByte(location++);
55     if (!validated_byte.is_valid || Byte(*str++) != validated_byte.value) {
56       return false;
57     }
58   }
59   return *str == 0;
60 }
61 
BytesAtLocationContain(size_t location,const char * str) const62 bool JpegSegment::BytesAtLocationContain(size_t location,
63                                          const char* str) const {
64   return Find(location, str) != GetEnd();
65 }
66 
Find(size_t location,const char * str) const67 size_t JpegSegment::Find(size_t location, const char* str) const {
68   Byte byte0 = static_cast<Byte>(*str);
69   while ((location = Find(location, byte0)) < GetEnd()) {
70     if (BytesAtLocationStartWith(location, str)) {
71       return location;
72     }
73     ++location;
74   }
75   return GetEnd();
76 }
77 
Find(size_t start_location,Byte value) const78 size_t JpegSegment::Find(size_t start_location, Byte value) const {
79   if (!begin_segment_ && !end_segment_) {
80     return GetEnd();
81   }
82   size_t value_location = GetEnd();
83   if (begin_segment_ && !end_segment_) {
84     value_location = begin_segment_->Find(start_location, value);
85   } else {
86     value_location =
87       DataSegment::Find(start_location, value, begin_segment_, end_segment_);
88   }
89   return Contains(value_location) ? value_location : GetEnd();
90 }
91 
ExtractXmpPropertyValue(size_t start_location,const char * property_name) const92 std::string JpegSegment::ExtractXmpPropertyValue(
93     size_t start_location, const char* property_name) const {
94   size_t begin_value_location =
95       FindXmpPropertyValueBegin(start_location, property_name);
96   if (begin_value_location != GetEnd()) {
97     size_t end_value_location = FindXmpPropertyValueEnd(begin_value_location);
98     if (end_value_location != GetEnd()) {
99       DataRange data_range(begin_value_location, end_value_location);
100       return ExtractString(data_range);
101     }
102   }
103   return "";
104 }
105 
FindXmpPropertyValueBegin(size_t start_location,const char * property_name) const106 size_t JpegSegment::FindXmpPropertyValueBegin(size_t start_location,
107                                               const char* property_name) const {
108   size_t property_location = Find(start_location, property_name);
109   if (property_location != GetEnd()) {
110     size_t equal_location = SkipWhiteSpaceFindChar(
111         *this, property_location + strlen(property_name), '=');
112     if (equal_location != GetEnd()) {
113       size_t quote_location =
114           SkipWhiteSpaceFindChar(*this, equal_location + 1, '"');
115       if (quote_location != GetEnd()) {
116         return quote_location + 1;
117       }
118     }
119   }
120   return GetEnd();
121 }
122 
FindXmpPropertyValueEnd(size_t start_location) const123 size_t JpegSegment::FindXmpPropertyValueEnd(size_t start_location) const {
124   return Find(start_location, Byte('"'));
125 }
126 
ExtractString(const DataRange & data_range) const127 std::string JpegSegment::ExtractString(const DataRange& data_range) const {
128   std::string value;
129   if (Contains(data_range.GetBegin()) && data_range.GetEnd() <= GetEnd()) {
130     size_t start_location = data_range.GetBegin();
131     size_t length = data_range.GetLength();
132     value.resize(length, ' ');
133     for (size_t index = 0; index < length; ++index) {
134       ValidatedByte validated_byte = GetValidatedByte(start_location + index);
135       if (!validated_byte.value) {  // Invalid bytes have a zero value.
136         value.resize(0);
137         break;
138       }
139       value[index] = static_cast<char>(validated_byte.value);
140     }
141   }
142   return value;
143 }
144 
GetPayloadHexDumpStrings(size_t byte_count,std::string * hex_string,std::string * ascii_string) const145 void JpegSegment::GetPayloadHexDumpStrings(size_t byte_count,
146                                            std::string* hex_string,
147                                            std::string* ascii_string) const {
148   stringstream ascii_stream;
149   stringstream hex_stream;
150   hex_stream << std::hex << std::uppercase;
151 
152   size_t dump_count = GetMarker().IsEntropySegmentDelimiter()
153                           ? byte_count
154                           : std::min(byte_count, GetLength() - 2);
155   for (size_t index = 0; index < dump_count; ++index) {
156     ValidatedByte payload_byte = GetValidatedByte(GetPayloadLocation() + index);
157     if (!payload_byte.is_valid) {
158       break;
159     }
160     Byte value = payload_byte.value;
161     hex_stream << std::setfill('0') << std::setw(2) << static_cast<int>(value);
162     ascii_stream << (isprint(value) ? static_cast<char>(value) : '.');
163   }
164   size_t current_count = ascii_stream.str().length();
165   for (size_t index = current_count; index < byte_count; ++index) {
166     hex_stream << "  ";
167     ascii_stream << ".";
168   }
169   *hex_string = hex_stream.str();
170   *ascii_string = ascii_stream.str();
171 }
172 
173 }  // namespace image_io
174 }  // namespace photos_editing_formats
175