xref: /aosp_15_r20/external/image_io/src/base/data_scanner.cc (revision ca0779eb572efbbfda2e47f806647c3c7eeea8c3)
1*ca0779ebSJerome Gaillard #include "image_io/base/data_scanner.h"
2*ca0779ebSJerome Gaillard 
3*ca0779ebSJerome Gaillard #include <algorithm>
4*ca0779ebSJerome Gaillard 
5*ca0779ebSJerome Gaillard namespace photos_editing_formats {
6*ca0779ebSJerome Gaillard namespace image_io {
7*ca0779ebSJerome Gaillard 
8*ca0779ebSJerome Gaillard using std::string;
9*ca0779ebSJerome Gaillard 
10*ca0779ebSJerome Gaillard namespace {
11*ca0779ebSJerome Gaillard 
12*ca0779ebSJerome Gaillard const char kWhitespaceChars[] = " \t\n\r";
13*ca0779ebSJerome Gaillard const char kBase64PadChar = '=';
14*ca0779ebSJerome Gaillard const char kBase64Chars[] =
15*ca0779ebSJerome Gaillard     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
16*ca0779ebSJerome Gaillard 
17*ca0779ebSJerome Gaillard /// This function is like strspn but does not assume a null-terminated string.
memspn(const char * s,size_t slen,const char * accept)18*ca0779ebSJerome Gaillard size_t memspn(const char* s, size_t slen, const char* accept) {
19*ca0779ebSJerome Gaillard   const char* p = s;
20*ca0779ebSJerome Gaillard   const char* spanp;
21*ca0779ebSJerome Gaillard   char c, sc;
22*ca0779ebSJerome Gaillard 
23*ca0779ebSJerome Gaillard cont:
24*ca0779ebSJerome Gaillard   c = *p++;
25*ca0779ebSJerome Gaillard   if (slen-- == 0) return p - 1 - s;
26*ca0779ebSJerome Gaillard   for (spanp = accept; (sc = *spanp++) != '\0';)
27*ca0779ebSJerome Gaillard     if (sc == c) goto cont;
28*ca0779ebSJerome Gaillard   return p - 1 - s;
29*ca0779ebSJerome Gaillard }
30*ca0779ebSJerome Gaillard 
31*ca0779ebSJerome Gaillard /// @return Whether value is in the range [lo:hi].
InRange(char value,char lo,char hi)32*ca0779ebSJerome Gaillard bool InRange(char value, char lo, char hi) {
33*ca0779ebSJerome Gaillard   return value >= lo && value <= hi;
34*ca0779ebSJerome Gaillard }
35*ca0779ebSJerome Gaillard 
36*ca0779ebSJerome Gaillard /// @return Whether the value is the first character of a kName type scanner.
IsFirstNameChar(char value)37*ca0779ebSJerome Gaillard bool IsFirstNameChar(char value) {
38*ca0779ebSJerome Gaillard   return InRange(value, 'A', 'Z') || InRange(value, 'a', 'z') || value == '_' ||
39*ca0779ebSJerome Gaillard          value == ':';
40*ca0779ebSJerome Gaillard }
41*ca0779ebSJerome Gaillard 
42*ca0779ebSJerome Gaillard /// Scans the characters in the s string, where the characters can be any legal
43*ca0779ebSJerome Gaillard /// character in the name.
44*ca0779ebSJerome Gaillard /// @return The number of name characters scanned.
ScanOptionalNameChars(const char * s,size_t slen)45*ca0779ebSJerome Gaillard size_t ScanOptionalNameChars(const char* s, size_t slen) {
46*ca0779ebSJerome Gaillard   const char* kOptionalChars =
47*ca0779ebSJerome Gaillard       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.-_:";
48*ca0779ebSJerome Gaillard   return memspn(s, slen, kOptionalChars);
49*ca0779ebSJerome Gaillard }
50*ca0779ebSJerome Gaillard 
51*ca0779ebSJerome Gaillard /// Scans the whitespace characters in the s string.
52*ca0779ebSJerome Gaillard /// @return The number of whitepace characters scanned.
ScanWhitespaceChars(const char * s,size_t slen)53*ca0779ebSJerome Gaillard size_t ScanWhitespaceChars(const char* s, size_t slen) {
54*ca0779ebSJerome Gaillard   return memspn(s, slen, kWhitespaceChars);
55*ca0779ebSJerome Gaillard }
56*ca0779ebSJerome Gaillard 
57*ca0779ebSJerome Gaillard }  // namespace
58*ca0779ebSJerome Gaillard 
GetWhitespaceChars()59*ca0779ebSJerome Gaillard string DataScanner::GetWhitespaceChars() { return kWhitespaceChars; }
60*ca0779ebSJerome Gaillard 
GetBase64Chars(bool include_pad_char)61*ca0779ebSJerome Gaillard string DataScanner::GetBase64Chars(bool include_pad_char) {
62*ca0779ebSJerome Gaillard   string chars(kBase64Chars);
63*ca0779ebSJerome Gaillard   if (include_pad_char) chars += kBase64PadChar;
64*ca0779ebSJerome Gaillard   return chars;
65*ca0779ebSJerome Gaillard }
66*ca0779ebSJerome Gaillard 
GetBase64PadChar()67*ca0779ebSJerome Gaillard string DataScanner::GetBase64PadChar() { return string(1, kBase64PadChar); }
68*ca0779ebSJerome Gaillard 
CreateLiteralScanner(const string & literal)69*ca0779ebSJerome Gaillard DataScanner DataScanner::CreateLiteralScanner(const string& literal) {
70*ca0779ebSJerome Gaillard   return DataScanner(DataScanner::kLiteral, literal);
71*ca0779ebSJerome Gaillard }
72*ca0779ebSJerome Gaillard 
CreateNameScanner()73*ca0779ebSJerome Gaillard DataScanner DataScanner::CreateNameScanner() {
74*ca0779ebSJerome Gaillard   return DataScanner(DataScanner::kName);
75*ca0779ebSJerome Gaillard }
76*ca0779ebSJerome Gaillard 
CreateQuotedStringScanner()77*ca0779ebSJerome Gaillard DataScanner DataScanner::CreateQuotedStringScanner() {
78*ca0779ebSJerome Gaillard   return DataScanner(DataScanner::kQuotedString);
79*ca0779ebSJerome Gaillard }
80*ca0779ebSJerome Gaillard 
CreateSentinelScanner(const string & sentinels)81*ca0779ebSJerome Gaillard DataScanner DataScanner::CreateSentinelScanner(const string& sentinels) {
82*ca0779ebSJerome Gaillard   return DataScanner(DataScanner::kSentinel, sentinels);
83*ca0779ebSJerome Gaillard }
84*ca0779ebSJerome Gaillard 
CreateThroughLiteralScanner(const string & literal)85*ca0779ebSJerome Gaillard DataScanner DataScanner::CreateThroughLiteralScanner(const string& literal) {
86*ca0779ebSJerome Gaillard   return DataScanner(DataScanner::kThroughLiteral, literal);
87*ca0779ebSJerome Gaillard }
88*ca0779ebSJerome Gaillard 
CreateWhitespaceScanner()89*ca0779ebSJerome Gaillard DataScanner DataScanner::CreateWhitespaceScanner() {
90*ca0779ebSJerome Gaillard   return DataScanner(DataScanner::kWhitespace);
91*ca0779ebSJerome Gaillard }
92*ca0779ebSJerome Gaillard 
CreateOptionalWhitespaceScanner()93*ca0779ebSJerome Gaillard DataScanner DataScanner::CreateOptionalWhitespaceScanner() {
94*ca0779ebSJerome Gaillard   return DataScanner(DataScanner::kOptionalWhitespace);
95*ca0779ebSJerome Gaillard }
96*ca0779ebSJerome Gaillard 
ScanChars(const char * s,size_t slen,const char * scanset)97*ca0779ebSJerome Gaillard size_t DataScanner::ScanChars(const char* s, size_t slen, const char* scanset) {
98*ca0779ebSJerome Gaillard   return memspn(s, slen, scanset);
99*ca0779ebSJerome Gaillard }
100*ca0779ebSJerome Gaillard 
ExtendTokenLength(size_t delta_length)101*ca0779ebSJerome Gaillard size_t DataScanner::ExtendTokenLength(size_t delta_length) {
102*ca0779ebSJerome Gaillard   token_range_ =
103*ca0779ebSJerome Gaillard       DataRange(token_range_.GetBegin(), token_range_.GetEnd() + delta_length);
104*ca0779ebSJerome Gaillard   return token_range_.GetLength();
105*ca0779ebSJerome Gaillard }
106*ca0779ebSJerome Gaillard 
SetInternalError(const DataContext & context,const string & error_description,DataMatchResult * result)107*ca0779ebSJerome Gaillard void DataScanner::SetInternalError(const DataContext& context,
108*ca0779ebSJerome Gaillard                                    const string& error_description,
109*ca0779ebSJerome Gaillard                                    DataMatchResult* result) {
110*ca0779ebSJerome Gaillard   result->SetType(DataMatchResult::kError);
111*ca0779ebSJerome Gaillard   result->SetMessage(
112*ca0779ebSJerome Gaillard       Message::kInternalError,
113*ca0779ebSJerome Gaillard       context.GetErrorText({}, {GetDescription()}, error_description, ""));
114*ca0779ebSJerome Gaillard }
115*ca0779ebSJerome Gaillard 
SetSyntaxError(const DataContext & context,const string & error_description,DataMatchResult * result)116*ca0779ebSJerome Gaillard void DataScanner::SetSyntaxError(const DataContext& context,
117*ca0779ebSJerome Gaillard                                  const string& error_description,
118*ca0779ebSJerome Gaillard                                  DataMatchResult* result) {
119*ca0779ebSJerome Gaillard   result->SetType(DataMatchResult::kError);
120*ca0779ebSJerome Gaillard   result->SetMessage(Message::kSyntaxError,
121*ca0779ebSJerome Gaillard                      context.GetErrorText(error_description, GetDescription()));
122*ca0779ebSJerome Gaillard }
123*ca0779ebSJerome Gaillard 
ScanLiteral(const char * cbytes,size_t bytes_available,const DataContext & context)124*ca0779ebSJerome Gaillard DataMatchResult DataScanner::ScanLiteral(const char* cbytes,
125*ca0779ebSJerome Gaillard                                          size_t bytes_available,
126*ca0779ebSJerome Gaillard                                          const DataContext& context) {
127*ca0779ebSJerome Gaillard   DataMatchResult result;
128*ca0779ebSJerome Gaillard   size_t token_length = token_range_.GetLength();
129*ca0779ebSJerome Gaillard   if (token_length >= literal_or_sentinels_.length()) {
130*ca0779ebSJerome Gaillard     SetInternalError(context, "Literal already scanned", &result);
131*ca0779ebSJerome Gaillard     return result;
132*ca0779ebSJerome Gaillard   }
133*ca0779ebSJerome Gaillard   size_t bytes_still_needed = literal_or_sentinels_.length() - token_length;
134*ca0779ebSJerome Gaillard   size_t bytes_to_compare = std::min(bytes_still_needed, bytes_available);
135*ca0779ebSJerome Gaillard   if (strncmp(&literal_or_sentinels_[token_length], cbytes, bytes_to_compare) ==
136*ca0779ebSJerome Gaillard       0) {
137*ca0779ebSJerome Gaillard     token_length = ExtendTokenLength(bytes_to_compare);
138*ca0779ebSJerome Gaillard     result.SetBytesConsumed(bytes_to_compare);
139*ca0779ebSJerome Gaillard     result.SetType(token_length == literal_or_sentinels_.length()
140*ca0779ebSJerome Gaillard                        ? DataMatchResult::kFull
141*ca0779ebSJerome Gaillard                        : DataMatchResult::kPartialOutOfData);
142*ca0779ebSJerome Gaillard   } else {
143*ca0779ebSJerome Gaillard     SetSyntaxError(context, "Expected literal", &result);
144*ca0779ebSJerome Gaillard   }
145*ca0779ebSJerome Gaillard   return result;
146*ca0779ebSJerome Gaillard }
147*ca0779ebSJerome Gaillard 
ScanName(const char * cbytes,size_t bytes_available,const DataContext & context)148*ca0779ebSJerome Gaillard DataMatchResult DataScanner::ScanName(const char* cbytes,
149*ca0779ebSJerome Gaillard                                       size_t bytes_available,
150*ca0779ebSJerome Gaillard                                       const DataContext& context) {
151*ca0779ebSJerome Gaillard   DataMatchResult result;
152*ca0779ebSJerome Gaillard   size_t token_length = token_range_.GetLength();
153*ca0779ebSJerome Gaillard   if (token_length == 0) {
154*ca0779ebSJerome Gaillard     if (!IsFirstNameChar(*cbytes)) {
155*ca0779ebSJerome Gaillard       SetSyntaxError(context, "Expected first character of a name", &result);
156*ca0779ebSJerome Gaillard       return result;
157*ca0779ebSJerome Gaillard     }
158*ca0779ebSJerome Gaillard     token_length = ExtendTokenLength(1);
159*ca0779ebSJerome Gaillard     result.SetBytesConsumed(1);
160*ca0779ebSJerome Gaillard     bytes_available -= 1;
161*ca0779ebSJerome Gaillard     cbytes += 1;
162*ca0779ebSJerome Gaillard   }
163*ca0779ebSJerome Gaillard   size_t optional_bytes_consumed =
164*ca0779ebSJerome Gaillard       ScanOptionalNameChars(cbytes, bytes_available);
165*ca0779ebSJerome Gaillard   token_length = ExtendTokenLength(optional_bytes_consumed);
166*ca0779ebSJerome Gaillard   result.IncrementBytesConsumed(optional_bytes_consumed);
167*ca0779ebSJerome Gaillard   if (result.GetBytesConsumed() == 0 && token_length > 0) {
168*ca0779ebSJerome Gaillard     result.SetType(DataMatchResult::kFull);
169*ca0779ebSJerome Gaillard   } else if (optional_bytes_consumed < bytes_available) {
170*ca0779ebSJerome Gaillard     result.SetType(DataMatchResult::kFull);
171*ca0779ebSJerome Gaillard   } else {
172*ca0779ebSJerome Gaillard     result.SetType(DataMatchResult::kPartialOutOfData);
173*ca0779ebSJerome Gaillard   }
174*ca0779ebSJerome Gaillard   return result;
175*ca0779ebSJerome Gaillard }
176*ca0779ebSJerome Gaillard 
ScanQuotedString(const char * cbytes,size_t bytes_available,const DataContext & context)177*ca0779ebSJerome Gaillard DataMatchResult DataScanner::ScanQuotedString(const char* cbytes,
178*ca0779ebSJerome Gaillard                                               size_t bytes_available,
179*ca0779ebSJerome Gaillard                                               const DataContext& context) {
180*ca0779ebSJerome Gaillard   const size_t kStart = 0;
181*ca0779ebSJerome Gaillard   const size_t kDone = '.';
182*ca0779ebSJerome Gaillard   const size_t kSquote = '\'';
183*ca0779ebSJerome Gaillard   const size_t kDquote = '"';
184*ca0779ebSJerome Gaillard   DataMatchResult result;
185*ca0779ebSJerome Gaillard   size_t token_length = token_range_.GetLength();
186*ca0779ebSJerome Gaillard   if ((data_ == kStart && token_length != 0) ||
187*ca0779ebSJerome Gaillard       (data_ != kStart && data_ != kSquote && data_ != kDquote)) {
188*ca0779ebSJerome Gaillard     SetInternalError(context, "Inconsistent state", &result);
189*ca0779ebSJerome Gaillard     return result;
190*ca0779ebSJerome Gaillard   }
191*ca0779ebSJerome Gaillard   if (data_ == kStart) {
192*ca0779ebSJerome Gaillard     if (*cbytes != kSquote && *cbytes != kDquote) {
193*ca0779ebSJerome Gaillard       SetSyntaxError(context, "Expected start of a quoted string", &result);
194*ca0779ebSJerome Gaillard       return result;
195*ca0779ebSJerome Gaillard     }
196*ca0779ebSJerome Gaillard     data_ = *cbytes++;
197*ca0779ebSJerome Gaillard     bytes_available--;
198*ca0779ebSJerome Gaillard     result.SetBytesConsumed(1);
199*ca0779ebSJerome Gaillard     token_length = ExtendTokenLength(1);
200*ca0779ebSJerome Gaillard   }
201*ca0779ebSJerome Gaillard   const char* ebytes = reinterpret_cast<const char*>(
202*ca0779ebSJerome Gaillard       memchr(cbytes, static_cast<int>(data_), bytes_available));
203*ca0779ebSJerome Gaillard   size_t bytes_scanned = ebytes ? ebytes - cbytes : bytes_available;
204*ca0779ebSJerome Gaillard   result.IncrementBytesConsumed(bytes_scanned);
205*ca0779ebSJerome Gaillard   token_length = ExtendTokenLength(bytes_scanned);
206*ca0779ebSJerome Gaillard   if (bytes_scanned == bytes_available) {
207*ca0779ebSJerome Gaillard     result.SetType(DataMatchResult::kPartialOutOfData);
208*ca0779ebSJerome Gaillard   } else {
209*ca0779ebSJerome Gaillard     result.SetType(DataMatchResult::kFull);
210*ca0779ebSJerome Gaillard     result.IncrementBytesConsumed(1);
211*ca0779ebSJerome Gaillard     ExtendTokenLength(1);
212*ca0779ebSJerome Gaillard     data_ = kDone;
213*ca0779ebSJerome Gaillard   }
214*ca0779ebSJerome Gaillard   return result;
215*ca0779ebSJerome Gaillard }
216*ca0779ebSJerome Gaillard 
ScanSentinel(const char * cbytes,size_t bytes_available,const DataContext & context)217*ca0779ebSJerome Gaillard DataMatchResult DataScanner::ScanSentinel(const char* cbytes,
218*ca0779ebSJerome Gaillard                                           size_t bytes_available,
219*ca0779ebSJerome Gaillard                                           const DataContext& context) {
220*ca0779ebSJerome Gaillard   DataMatchResult result;
221*ca0779ebSJerome Gaillard   if (data_ != 0) {
222*ca0779ebSJerome Gaillard     SetInternalError(context, "Sentinel already scanned", &result);
223*ca0779ebSJerome Gaillard     return result;
224*ca0779ebSJerome Gaillard   }
225*ca0779ebSJerome Gaillard   char cbyte = *cbytes;
226*ca0779ebSJerome Gaillard   for (size_t index = 0; index < literal_or_sentinels_.size(); ++index) {
227*ca0779ebSJerome Gaillard     char sentinel = literal_or_sentinels_[index];
228*ca0779ebSJerome Gaillard     if ((sentinel == '~' && IsFirstNameChar(cbyte)) || cbyte == sentinel) {
229*ca0779ebSJerome Gaillard       ExtendTokenLength(1);
230*ca0779ebSJerome Gaillard       result.SetBytesConsumed(1).SetType(DataMatchResult::kFull);
231*ca0779ebSJerome Gaillard       data_ = sentinel;
232*ca0779ebSJerome Gaillard       break;
233*ca0779ebSJerome Gaillard     }
234*ca0779ebSJerome Gaillard   }
235*ca0779ebSJerome Gaillard   if (result.GetBytesConsumed() == 0) {
236*ca0779ebSJerome Gaillard     SetSyntaxError(context, "Unexpected character encountered", &result);
237*ca0779ebSJerome Gaillard   }
238*ca0779ebSJerome Gaillard   return result;
239*ca0779ebSJerome Gaillard }
240*ca0779ebSJerome Gaillard 
ScanThroughLiteral(const char * cbytes,size_t bytes_available,const DataContext & context)241*ca0779ebSJerome Gaillard DataMatchResult DataScanner::ScanThroughLiteral(const char* cbytes,
242*ca0779ebSJerome Gaillard                                                 size_t bytes_available,
243*ca0779ebSJerome Gaillard                                                 const DataContext& context) {
244*ca0779ebSJerome Gaillard   DataMatchResult result;
245*ca0779ebSJerome Gaillard   size_t& scanned_literal_length = data_;
246*ca0779ebSJerome Gaillard   if (scanned_literal_length >= literal_or_sentinels_.length()) {
247*ca0779ebSJerome Gaillard     SetInternalError(context, "Literal already scanned", &result);
248*ca0779ebSJerome Gaillard     return result;
249*ca0779ebSJerome Gaillard   }
250*ca0779ebSJerome Gaillard   while (bytes_available > 0) {
251*ca0779ebSJerome Gaillard     if (scanned_literal_length == 0) {
252*ca0779ebSJerome Gaillard       // Literal scan not in progress. Find the first char of the literal.
253*ca0779ebSJerome Gaillard       auto* matched_byte = reinterpret_cast<const char*>(
254*ca0779ebSJerome Gaillard           memchr(cbytes, literal_or_sentinels_[0], bytes_available));
255*ca0779ebSJerome Gaillard       if (matched_byte == nullptr) {
256*ca0779ebSJerome Gaillard         // first char not found and chars exhausted.
257*ca0779ebSJerome Gaillard         ExtendTokenLength(bytes_available);
258*ca0779ebSJerome Gaillard         result.IncrementBytesConsumed(bytes_available);
259*ca0779ebSJerome Gaillard         result.SetType(DataMatchResult::kPartialOutOfData);
260*ca0779ebSJerome Gaillard         break;
261*ca0779ebSJerome Gaillard       } else {
262*ca0779ebSJerome Gaillard         // found the first char of the literal.
263*ca0779ebSJerome Gaillard         size_t bytes_scanned = (matched_byte - cbytes) + 1;
264*ca0779ebSJerome Gaillard         result.IncrementBytesConsumed(bytes_scanned);
265*ca0779ebSJerome Gaillard         bytes_available -= bytes_scanned;
266*ca0779ebSJerome Gaillard         cbytes += bytes_scanned;
267*ca0779ebSJerome Gaillard         ExtendTokenLength(bytes_scanned);
268*ca0779ebSJerome Gaillard         scanned_literal_length = 1;
269*ca0779ebSJerome Gaillard       }
270*ca0779ebSJerome Gaillard     }
271*ca0779ebSJerome Gaillard     // check if the rest of the literal is there.
272*ca0779ebSJerome Gaillard     size_t bytes_still_needed =
273*ca0779ebSJerome Gaillard         literal_or_sentinels_.length() - scanned_literal_length;
274*ca0779ebSJerome Gaillard     size_t bytes_to_compare = std::min(bytes_still_needed, bytes_available);
275*ca0779ebSJerome Gaillard     if (strncmp(&literal_or_sentinels_[scanned_literal_length], cbytes,
276*ca0779ebSJerome Gaillard                 bytes_to_compare) == 0) {
277*ca0779ebSJerome Gaillard       // Yes, the whole literal is there or chars are exhausted.
278*ca0779ebSJerome Gaillard       ExtendTokenLength(bytes_to_compare);
279*ca0779ebSJerome Gaillard       scanned_literal_length += bytes_to_compare;
280*ca0779ebSJerome Gaillard       result.IncrementBytesConsumed(bytes_to_compare);
281*ca0779ebSJerome Gaillard       result.SetType(scanned_literal_length == literal_or_sentinels_.length()
282*ca0779ebSJerome Gaillard                          ? DataMatchResult::kFull
283*ca0779ebSJerome Gaillard                          : DataMatchResult::kPartialOutOfData);
284*ca0779ebSJerome Gaillard       break;
285*ca0779ebSJerome Gaillard     }
286*ca0779ebSJerome Gaillard     // false alarm, the firsts char of the literal were found, but not the
287*ca0779ebSJerome Gaillard     // whole enchilada. Keep searching at one past the first char of the match.
288*ca0779ebSJerome Gaillard     scanned_literal_length = 0;
289*ca0779ebSJerome Gaillard   }
290*ca0779ebSJerome Gaillard   return result;
291*ca0779ebSJerome Gaillard }
292*ca0779ebSJerome Gaillard 
ScanWhitespace(const char * cbytes,size_t bytes_available,const DataContext & context)293*ca0779ebSJerome Gaillard DataMatchResult DataScanner::ScanWhitespace(const char* cbytes,
294*ca0779ebSJerome Gaillard                                             size_t bytes_available,
295*ca0779ebSJerome Gaillard                                             const DataContext& context) {
296*ca0779ebSJerome Gaillard   DataMatchResult result;
297*ca0779ebSJerome Gaillard   size_t token_length = token_range_.GetLength();
298*ca0779ebSJerome Gaillard   result.SetBytesConsumed(ScanWhitespaceChars(cbytes, bytes_available));
299*ca0779ebSJerome Gaillard   token_length = ExtendTokenLength(result.GetBytesConsumed());
300*ca0779ebSJerome Gaillard   if (result.GetBytesConsumed() == 0) {
301*ca0779ebSJerome Gaillard     if (token_length == 0 && type_ == kWhitespace) {
302*ca0779ebSJerome Gaillard       SetSyntaxError(context, "Expected whitespace", &result);
303*ca0779ebSJerome Gaillard     } else {
304*ca0779ebSJerome Gaillard       result.SetType(DataMatchResult::kFull);
305*ca0779ebSJerome Gaillard     }
306*ca0779ebSJerome Gaillard   } else {
307*ca0779ebSJerome Gaillard     result.SetType((result.GetBytesConsumed() < bytes_available)
308*ca0779ebSJerome Gaillard                        ? DataMatchResult::kFull
309*ca0779ebSJerome Gaillard                        : DataMatchResult::kPartialOutOfData);
310*ca0779ebSJerome Gaillard   }
311*ca0779ebSJerome Gaillard   return result;
312*ca0779ebSJerome Gaillard }
313*ca0779ebSJerome Gaillard 
Scan(const DataContext & context)314*ca0779ebSJerome Gaillard DataMatchResult DataScanner::Scan(const DataContext& context) {
315*ca0779ebSJerome Gaillard   scan_call_count_ += 1;
316*ca0779ebSJerome Gaillard   DataMatchResult result;
317*ca0779ebSJerome Gaillard   if (!context.IsValidLocationAndRange()) {
318*ca0779ebSJerome Gaillard     SetInternalError(context, context.GetInvalidLocationAndRangeErrorText(),
319*ca0779ebSJerome Gaillard                      &result);
320*ca0779ebSJerome Gaillard     return result;
321*ca0779ebSJerome Gaillard   }
322*ca0779ebSJerome Gaillard   if (!token_range_.IsValid()) {
323*ca0779ebSJerome Gaillard     token_range_ = DataRange(context.GetLocation(), context.GetLocation());
324*ca0779ebSJerome Gaillard   }
325*ca0779ebSJerome Gaillard   size_t bytes_available = context.GetRange().GetEnd() - context.GetLocation();
326*ca0779ebSJerome Gaillard   const char* cbytes = context.GetCharBytes();
327*ca0779ebSJerome Gaillard   switch (type_) {
328*ca0779ebSJerome Gaillard     case kLiteral:
329*ca0779ebSJerome Gaillard       result = ScanLiteral(cbytes, bytes_available, context);
330*ca0779ebSJerome Gaillard       break;
331*ca0779ebSJerome Gaillard     case kName:
332*ca0779ebSJerome Gaillard       result = ScanName(cbytes, bytes_available, context);
333*ca0779ebSJerome Gaillard       break;
334*ca0779ebSJerome Gaillard     case kQuotedString:
335*ca0779ebSJerome Gaillard       result = ScanQuotedString(cbytes, bytes_available, context);
336*ca0779ebSJerome Gaillard       break;
337*ca0779ebSJerome Gaillard     case kSentinel:
338*ca0779ebSJerome Gaillard       result = ScanSentinel(cbytes, bytes_available, context);
339*ca0779ebSJerome Gaillard       break;
340*ca0779ebSJerome Gaillard     case kThroughLiteral:
341*ca0779ebSJerome Gaillard       result = ScanThroughLiteral(cbytes, bytes_available, context);
342*ca0779ebSJerome Gaillard       break;
343*ca0779ebSJerome Gaillard     case kWhitespace:
344*ca0779ebSJerome Gaillard     case kOptionalWhitespace:
345*ca0779ebSJerome Gaillard       result = ScanWhitespace(cbytes, bytes_available, context);
346*ca0779ebSJerome Gaillard       break;
347*ca0779ebSJerome Gaillard     default:
348*ca0779ebSJerome Gaillard       SetInternalError(context, "Undefined scanner type", &result);
349*ca0779ebSJerome Gaillard       break;
350*ca0779ebSJerome Gaillard   }
351*ca0779ebSJerome Gaillard   return result;
352*ca0779ebSJerome Gaillard }
353*ca0779ebSJerome Gaillard 
ResetTokenRange()354*ca0779ebSJerome Gaillard void DataScanner::ResetTokenRange() { token_range_ = DataRange(); }
355*ca0779ebSJerome Gaillard 
Reset()356*ca0779ebSJerome Gaillard void DataScanner::Reset() {
357*ca0779ebSJerome Gaillard   data_ = 0;
358*ca0779ebSJerome Gaillard   scan_call_count_ = 0;
359*ca0779ebSJerome Gaillard   ResetTokenRange();
360*ca0779ebSJerome Gaillard }
361*ca0779ebSJerome Gaillard 
GetDescription() const362*ca0779ebSJerome Gaillard string DataScanner::GetDescription() const {
363*ca0779ebSJerome Gaillard   if (!description_.empty()) {
364*ca0779ebSJerome Gaillard     return description_;
365*ca0779ebSJerome Gaillard   }
366*ca0779ebSJerome Gaillard   string description;
367*ca0779ebSJerome Gaillard   switch (type_) {
368*ca0779ebSJerome Gaillard     case kLiteral:
369*ca0779ebSJerome Gaillard       description = "Literal:'";
370*ca0779ebSJerome Gaillard       description += literal_or_sentinels_;
371*ca0779ebSJerome Gaillard       description += "'";
372*ca0779ebSJerome Gaillard       break;
373*ca0779ebSJerome Gaillard     case kName:
374*ca0779ebSJerome Gaillard       description = "Name";
375*ca0779ebSJerome Gaillard       break;
376*ca0779ebSJerome Gaillard     case kQuotedString:
377*ca0779ebSJerome Gaillard       description = "QuotedString";
378*ca0779ebSJerome Gaillard       break;
379*ca0779ebSJerome Gaillard     case kSentinel:
380*ca0779ebSJerome Gaillard       description = "OneOf:'";
381*ca0779ebSJerome Gaillard       description += literal_or_sentinels_;
382*ca0779ebSJerome Gaillard       description += "'";
383*ca0779ebSJerome Gaillard       break;
384*ca0779ebSJerome Gaillard     case kThroughLiteral:
385*ca0779ebSJerome Gaillard       description = "ThruLiteral:'";
386*ca0779ebSJerome Gaillard       description += literal_or_sentinels_;
387*ca0779ebSJerome Gaillard       description += "'";
388*ca0779ebSJerome Gaillard       break;
389*ca0779ebSJerome Gaillard     case kWhitespace:
390*ca0779ebSJerome Gaillard       description = "Whitespace";
391*ca0779ebSJerome Gaillard       break;
392*ca0779ebSJerome Gaillard     case kOptionalWhitespace:
393*ca0779ebSJerome Gaillard       description = "OptionalWhitespace";
394*ca0779ebSJerome Gaillard       break;
395*ca0779ebSJerome Gaillard   }
396*ca0779ebSJerome Gaillard   return description;
397*ca0779ebSJerome Gaillard }
398*ca0779ebSJerome Gaillard 
GetLiteral() const399*ca0779ebSJerome Gaillard string DataScanner::GetLiteral() const {
400*ca0779ebSJerome Gaillard   return type_ == kLiteral || type_ == kThroughLiteral ? literal_or_sentinels_
401*ca0779ebSJerome Gaillard                                                        : "";
402*ca0779ebSJerome Gaillard }
403*ca0779ebSJerome Gaillard 
GetSentenels() const404*ca0779ebSJerome Gaillard string DataScanner::GetSentenels() const {
405*ca0779ebSJerome Gaillard   return type_ == kSentinel ? literal_or_sentinels_ : "";
406*ca0779ebSJerome Gaillard }
407*ca0779ebSJerome Gaillard 
GetSentinel() const408*ca0779ebSJerome Gaillard char DataScanner::GetSentinel() const { return type_ == kSentinel ? data_ : 0; }
409*ca0779ebSJerome Gaillard 
410*ca0779ebSJerome Gaillard }  // namespace image_io
411*ca0779ebSJerome Gaillard }  // namespace photos_editing_formats
412