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