xref: /aosp_15_r20/external/image_io/src/xml/xml_reader.cc (revision ca0779eb572efbbfda2e47f806647c3c7eeea8c3)
1 #include "image_io/xml/xml_reader.h"
2 
3 #include <iomanip>
4 #include <sstream>
5 #include <string>
6 #include <utility>
7 
8 #include "image_io/base/message.h"
9 #include "image_io/base/message_handler.h"
10 
11 namespace photos_editing_formats {
12 namespace image_io {
13 
14 namespace {
15 
16 /// The reader name used for error messages.
17 const char kReaderName[] = "XmlReader";
18 
19 }  // namespace
20 
StartParse(std::unique_ptr<XmlRule> rule)21 bool XmlReader::StartParse(std::unique_ptr<XmlRule> rule) {
22   bytes_parsed_ = 0;
23   rule_stack_.clear();
24   if (!rule) {
25     std::string text = std::string(kReaderName) + ":StartParse:NoTopLevelRule";
26     Message message(Message::kInternalError, 0, text);
27     ReportError(message);
28     return false;
29   }
30   rule_stack_.push_back(std::move(rule));
31   has_internal_or_syntax_error_ = false;
32   has_errors_ = false;
33   return true;
34 }
35 
FinishParse()36 bool XmlReader::FinishParse() {
37   if (has_internal_or_syntax_error_) {
38     return false;
39   }
40   std::string error_text;
41   if (rule_stack_.empty() ||
42       (rule_stack_.size() == 1 &&
43        rule_stack_.back()->IsPermissibleToFinish(&error_text))) {
44     return true;
45   }
46   std::stringstream ss;
47   ss << kReaderName << ":";
48   if (error_text.empty()) {
49     ss << "While parsing text with rule:";
50     ss << rule_stack_.back()->GetName();
51     XmlTerminal* terminal = rule_stack_.back()->GetCurrentTerminal();
52     if (terminal) {
53       if (!terminal->GetName().empty()) {
54         ss << ":" << terminal->GetName();
55       }
56       ss << ":" << terminal->GetScanner()->GetDescription();
57     }
58   } else {
59     ss << error_text;
60   }
61   Message message(Message::kPrematureEndOfDataError, 0, ss.str());
62   has_internal_or_syntax_error_ = true;
63   ReportError(message);
64   return false;
65 }
66 
Parse(const std::string & value)67 bool XmlReader::Parse(const std::string& value) {
68   size_t location = GetBytesParsed();
69   DataRange range(location, location + value.length());
70   const Byte* bytes = reinterpret_cast<const Byte*>(value.c_str());
71   auto segment = DataSegment::Create(range, bytes, DataSegment::kDontDelete);
72   return Parse(location, range, *segment);
73 }
74 
Parse(size_t start_location,const DataRange & range,const DataSegment & segment)75 bool XmlReader::Parse(size_t start_location, const DataRange& range,
76                       const DataSegment& segment) {
77   if (has_internal_or_syntax_error_) {
78     return false;
79   }
80   XmlHandlerContext context(start_location, range, segment, *data_line_map_,
81                             handler_);
82   InitializeContextNameList(&context);
83   if (!context.IsValidLocationAndRange()) {
84     DataMatchResult result;
85     result.SetMessage(Message::kInternalError,
86                       context.GetInvalidLocationAndRangeErrorText());
87     ReportError(result, context);
88     return false;
89   }
90   if (rule_stack_.empty()) {
91     DataMatchResult result;
92     result.SetMessage(Message::kInternalError, "NoActiveRule");
93     ReportError(result, context);
94     return false;
95   }
96   if (data_line_map_ == &internal_data_line_map_) {
97     internal_data_line_map_.FindDataLines(range, segment);
98   }
99   size_t bytes_remaining = range.GetEnd() - start_location;
100   while (bytes_remaining > 0 && !rule_stack_.empty() &&
101          !has_internal_or_syntax_error_) {
102     auto& rule = rule_stack_.back();
103     InitializeContextNameList(&context);
104     DataMatchResult result = rule->Parse(context);
105     switch (result.GetType()) {
106       case DataMatchResult::kError:
107       case DataMatchResult::kNone:
108         ReportError(result, context);
109         break;
110       case DataMatchResult::kPartial:
111         ReportMessageIfNeeded(result);
112         bytes_parsed_ += result.GetBytesConsumed();
113         bytes_remaining -= result.GetBytesConsumed();
114         context.IncrementLocation(result.GetBytesConsumed());
115         if (rule->HasNextRule()) {
116           // Delegation by child rule: push the next.
117           rule_stack_.push_back(rule->ReleaseNextRule());
118         }
119         break;
120       case DataMatchResult::kPartialOutOfData:
121         ReportMessageIfNeeded(result);
122         bytes_parsed_ += result.GetBytesConsumed();
123         return true;
124       case DataMatchResult::kFull:
125         ReportMessageIfNeeded(result);
126         bytes_parsed_ += result.GetBytesConsumed();
127         bytes_remaining -= result.GetBytesConsumed();
128         context.IncrementLocation(result.GetBytesConsumed());
129         if (rule->HasNextRule()) {
130           // Delegation by chaining: pop the current rule and push the next.
131           auto next_rule = rule->ReleaseNextRule();
132           rule_stack_.pop_back();
133           rule_stack_.push_back(std::move(next_rule));
134         } else {
135           rule_stack_.pop_back();
136         }
137         break;
138     }
139   }
140   if (bytes_remaining > 0 && rule_stack_.empty()) {
141     InitializeContextNameList(&context);
142     std::string text = context.GetErrorText("NoActiveRule", "");
143     Message message(Message::kSyntaxError, 0, text);
144     ReportError(message);
145     return false;
146   }
147   return !has_internal_or_syntax_error_;
148 }
149 
InitializeContextNameList(XmlHandlerContext * context)150 void XmlReader::InitializeContextNameList(XmlHandlerContext* context) {
151   auto name_list = context->GetNameList();
152   name_list.clear();
153   name_list.push_back(kReaderName);
154   if (!rule_stack_.empty()) {
155     name_list.push_back(rule_stack_.back()->GetName());
156   }
157 }
158 
ReportMessageIfNeeded(const DataMatchResult & result)159 void XmlReader::ReportMessageIfNeeded(const DataMatchResult& result) {
160   if (result.HasMessage()) {
161     ReportError(result.GetMessage());
162   }
163 }
164 
ReportError(const DataMatchResult & result,const DataContext & context)165 void XmlReader::ReportError(const DataMatchResult& result,
166                             const DataContext& context) {
167   if (!result.HasMessage()) {
168     Message message(Message::kInternalError, 0,
169                     context.GetErrorText("Rule had error but no message", ""));
170     ReportError(message);
171   }
172   ReportError(result.GetMessage());
173 }
174 
ReportError(const Message & message)175 void XmlReader::ReportError(const Message& message) {
176   if (message_handler_) {
177     message_handler_->ReportMessage(message);
178   }
179   if (message.GetType() == Message::kInternalError ||
180       message.GetType() == Message::kSyntaxError) {
181     has_internal_or_syntax_error_ = true;
182   }
183   if (message.IsError()) {
184     has_errors_ = true;
185   }
186 }
187 
188 }  // namespace image_io
189 }  // namespace photos_editing_formats
190