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