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