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