1*ca0779ebSJerome Gaillard #include "image_io/xml/xml_rule.h"
2*ca0779ebSJerome Gaillard
3*ca0779ebSJerome Gaillard #include <string>
4*ca0779ebSJerome Gaillard #include <utility>
5*ca0779ebSJerome Gaillard
6*ca0779ebSJerome Gaillard #include "image_io/base/data_scanner.h"
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::unique_ptr;
13*ca0779ebSJerome Gaillard
14*ca0779ebSJerome Gaillard namespace {
15*ca0779ebSJerome Gaillard
16*ca0779ebSJerome Gaillard /// A scanner is reentrant if it ran out of data. In these cases, the next data
17*ca0779ebSJerome Gaillard /// segment sent into the rule for parsing may be non-contiguous with the
18*ca0779ebSJerome Gaillard /// previous one. If that is the case, update the scanner's token length to
19*ca0779ebSJerome Gaillard /// account for the missing bytes. (Scanner token ranges represent a bounding
20*ca0779ebSJerome Gaillard /// box around the token value - in these cases the actual token value is really
21*ca0779ebSJerome Gaillard /// a vector of ranges. Client handlers are responsible for dealing with that
22*ca0779ebSJerome Gaillard /// reality, not the scanner or rule).
23*ca0779ebSJerome Gaillard /// @param scanner The current possibly reentrant scanner.
24*ca0779ebSJerome Gaillard /// @param context_range The new data range that is to be parsed.
MaybeUpdateTokenLengthForReentrantScanner(DataScanner * scanner,const DataRange & context_range)25*ca0779ebSJerome Gaillard void MaybeUpdateTokenLengthForReentrantScanner(DataScanner* scanner,
26*ca0779ebSJerome Gaillard const DataRange& context_range) {
27*ca0779ebSJerome Gaillard const auto& token_range = scanner->GetTokenRange();
28*ca0779ebSJerome Gaillard if (scanner->GetScanCallCount() > 0 && token_range.IsValid() &&
29*ca0779ebSJerome Gaillard context_range.GetBegin() > token_range.GetEnd()) {
30*ca0779ebSJerome Gaillard size_t skipped_byte_count = context_range.GetBegin() - token_range.GetEnd();
31*ca0779ebSJerome Gaillard scanner->ExtendTokenLength(skipped_byte_count);
32*ca0779ebSJerome Gaillard }
33*ca0779ebSJerome Gaillard }
34*ca0779ebSJerome Gaillard
35*ca0779ebSJerome Gaillard } // namespace
36*ca0779ebSJerome Gaillard
XmlRule(const std::string & name)37*ca0779ebSJerome Gaillard XmlRule::XmlRule(const std::string& name) : name_(name), terminal_index_(0) {}
38*ca0779ebSJerome Gaillard
AddLiteralTerminal(const std::string & literal)39*ca0779ebSJerome Gaillard XmlTerminal& XmlRule::AddLiteralTerminal(const std::string& literal) {
40*ca0779ebSJerome Gaillard terminals_.emplace_back(DataScanner::CreateLiteralScanner(literal));
41*ca0779ebSJerome Gaillard return terminals_.back();
42*ca0779ebSJerome Gaillard }
43*ca0779ebSJerome Gaillard
AddNameTerminal()44*ca0779ebSJerome Gaillard XmlTerminal& XmlRule::AddNameTerminal() {
45*ca0779ebSJerome Gaillard terminals_.emplace_back(DataScanner::CreateNameScanner());
46*ca0779ebSJerome Gaillard return terminals_.back();
47*ca0779ebSJerome Gaillard }
48*ca0779ebSJerome Gaillard
AddQuotedStringTerminal()49*ca0779ebSJerome Gaillard XmlTerminal& XmlRule::AddQuotedStringTerminal() {
50*ca0779ebSJerome Gaillard terminals_.emplace_back(DataScanner::CreateQuotedStringScanner());
51*ca0779ebSJerome Gaillard return terminals_.back();
52*ca0779ebSJerome Gaillard }
53*ca0779ebSJerome Gaillard
AddSentinelTerminal(const std::string & sentinels)54*ca0779ebSJerome Gaillard XmlTerminal& XmlRule::AddSentinelTerminal(const std::string& sentinels) {
55*ca0779ebSJerome Gaillard terminals_.emplace_back(DataScanner::CreateSentinelScanner(sentinels));
56*ca0779ebSJerome Gaillard return terminals_.back();
57*ca0779ebSJerome Gaillard }
58*ca0779ebSJerome Gaillard
AddThroughLiteralTerminal(const std::string & literal)59*ca0779ebSJerome Gaillard XmlTerminal& XmlRule::AddThroughLiteralTerminal(const std::string& literal) {
60*ca0779ebSJerome Gaillard terminals_.emplace_back(DataScanner::CreateThroughLiteralScanner(literal));
61*ca0779ebSJerome Gaillard return terminals_.back();
62*ca0779ebSJerome Gaillard }
63*ca0779ebSJerome Gaillard
AddWhitespaceTerminal()64*ca0779ebSJerome Gaillard XmlTerminal& XmlRule::AddWhitespaceTerminal() {
65*ca0779ebSJerome Gaillard terminals_.emplace_back(DataScanner::CreateWhitespaceScanner());
66*ca0779ebSJerome Gaillard return terminals_.back();
67*ca0779ebSJerome Gaillard }
68*ca0779ebSJerome Gaillard
AddOptionalWhitespaceTerminal()69*ca0779ebSJerome Gaillard XmlTerminal& XmlRule::AddOptionalWhitespaceTerminal() {
70*ca0779ebSJerome Gaillard terminals_.emplace_back(DataScanner::CreateOptionalWhitespaceScanner());
71*ca0779ebSJerome Gaillard return terminals_.back();
72*ca0779ebSJerome Gaillard }
73*ca0779ebSJerome Gaillard
GetTerminalIndexFromName(const std::string name) const74*ca0779ebSJerome Gaillard size_t XmlRule::GetTerminalIndexFromName(const std::string name) const {
75*ca0779ebSJerome Gaillard if (!name.empty()) {
76*ca0779ebSJerome Gaillard for (size_t index = 0; index < terminals_.size(); ++index) {
77*ca0779ebSJerome Gaillard if (terminals_[index].GetName() == name) {
78*ca0779ebSJerome Gaillard return index;
79*ca0779ebSJerome Gaillard }
80*ca0779ebSJerome Gaillard }
81*ca0779ebSJerome Gaillard }
82*ca0779ebSJerome Gaillard return terminals_.size();
83*ca0779ebSJerome Gaillard }
84*ca0779ebSJerome Gaillard
SetTerminalIndex(size_t terminal_index)85*ca0779ebSJerome Gaillard void XmlRule::SetTerminalIndex(size_t terminal_index) {
86*ca0779ebSJerome Gaillard terminal_index_ = terminal_index;
87*ca0779ebSJerome Gaillard }
88*ca0779ebSJerome Gaillard
GetCurrentTerminal()89*ca0779ebSJerome Gaillard XmlTerminal* XmlRule::GetCurrentTerminal() {
90*ca0779ebSJerome Gaillard return terminal_index_ < terminals_.size() ? &terminals_[terminal_index_]
91*ca0779ebSJerome Gaillard : nullptr;
92*ca0779ebSJerome Gaillard }
93*ca0779ebSJerome Gaillard
GetTerminal(size_t index)94*ca0779ebSJerome Gaillard XmlTerminal* XmlRule::GetTerminal(size_t index) {
95*ca0779ebSJerome Gaillard return index < terminals_.size() ? &terminals_[index] : nullptr;
96*ca0779ebSJerome Gaillard }
97*ca0779ebSJerome Gaillard
ResetTerminalScanners()98*ca0779ebSJerome Gaillard void XmlRule::ResetTerminalScanners() {
99*ca0779ebSJerome Gaillard for (auto& terminal : terminals_) {
100*ca0779ebSJerome Gaillard terminal.GetScanner()->Reset();
101*ca0779ebSJerome Gaillard }
102*ca0779ebSJerome Gaillard }
103*ca0779ebSJerome Gaillard
IsPermissibleToFinish(std::string *) const104*ca0779ebSJerome Gaillard bool XmlRule::IsPermissibleToFinish(std::string*) const {
105*ca0779ebSJerome Gaillard return false;
106*ca0779ebSJerome Gaillard }
107*ca0779ebSJerome Gaillard
Parse(XmlHandlerContext context)108*ca0779ebSJerome Gaillard DataMatchResult XmlRule::Parse(XmlHandlerContext context) {
109*ca0779ebSJerome Gaillard DataMatchResult result;
110*ca0779ebSJerome Gaillard if (!context.IsValidLocationAndRange()) {
111*ca0779ebSJerome Gaillard result.SetType(DataMatchResult::kError);
112*ca0779ebSJerome Gaillard result.SetMessage(Message::kInternalError,
113*ca0779ebSJerome Gaillard context.GetInvalidLocationAndRangeErrorText());
114*ca0779ebSJerome Gaillard return result;
115*ca0779ebSJerome Gaillard }
116*ca0779ebSJerome Gaillard bool force_parse_return = false;
117*ca0779ebSJerome Gaillard size_t bytes_available = context.GetBytesAvailable();
118*ca0779ebSJerome Gaillard size_t current_terminal_index = GetTerminalIndex();
119*ca0779ebSJerome Gaillard if (current_terminal_index < terminals_.size()) {
120*ca0779ebSJerome Gaillard MaybeUpdateTokenLengthForReentrantScanner(
121*ca0779ebSJerome Gaillard terminals_[current_terminal_index].GetScanner(), context.GetRange());
122*ca0779ebSJerome Gaillard }
123*ca0779ebSJerome Gaillard while (!force_parse_return && current_terminal_index < terminals_.size() &&
124*ca0779ebSJerome Gaillard bytes_available > 0) {
125*ca0779ebSJerome Gaillard SetTerminalIndex(current_terminal_index);
126*ca0779ebSJerome Gaillard auto& terminal = terminals_[current_terminal_index];
127*ca0779ebSJerome Gaillard DataMatchResult scanner_result = terminal.GetScanner()->Scan(context);
128*ca0779ebSJerome Gaillard if (terminal.GetAction() &&
129*ca0779ebSJerome Gaillard (scanner_result.GetType() == DataMatchResult::kFull ||
130*ca0779ebSJerome Gaillard scanner_result.GetType() == DataMatchResult::kPartialOutOfData)) {
131*ca0779ebSJerome Gaillard XmlActionContext action_context(context, &terminal, scanner_result);
132*ca0779ebSJerome Gaillard scanner_result = terminal.GetAction()(action_context);
133*ca0779ebSJerome Gaillard }
134*ca0779ebSJerome Gaillard result.SetType(scanner_result.GetType());
135*ca0779ebSJerome Gaillard result.IncrementBytesConsumed(scanner_result.GetBytesConsumed());
136*ca0779ebSJerome Gaillard context.IncrementLocation(scanner_result.GetBytesConsumed());
137*ca0779ebSJerome Gaillard bytes_available -= scanner_result.GetBytesConsumed();
138*ca0779ebSJerome Gaillard switch (scanner_result.GetType()) {
139*ca0779ebSJerome Gaillard case DataMatchResult::kError:
140*ca0779ebSJerome Gaillard result.SetMessage(scanner_result.GetMessage());
141*ca0779ebSJerome Gaillard force_parse_return = true;
142*ca0779ebSJerome Gaillard break;
143*ca0779ebSJerome Gaillard case DataMatchResult::kNone:
144*ca0779ebSJerome Gaillard result.SetType(DataMatchResult::kError);
145*ca0779ebSJerome Gaillard result.SetMessage(
146*ca0779ebSJerome Gaillard Message::kInternalError,
147*ca0779ebSJerome Gaillard context.GetErrorText("Invalid scanner match result",
148*ca0779ebSJerome Gaillard terminal.GetScanner()->GetDescription()));
149*ca0779ebSJerome Gaillard force_parse_return = true;
150*ca0779ebSJerome Gaillard break;
151*ca0779ebSJerome Gaillard case DataMatchResult::kPartial:
152*ca0779ebSJerome Gaillard case DataMatchResult::kPartialOutOfData:
153*ca0779ebSJerome Gaillard if (scanner_result.HasMessage()) {
154*ca0779ebSJerome Gaillard result.SetMessage(scanner_result.GetMessage());
155*ca0779ebSJerome Gaillard }
156*ca0779ebSJerome Gaillard force_parse_return = true;
157*ca0779ebSJerome Gaillard break;
158*ca0779ebSJerome Gaillard case DataMatchResult::kFull:
159*ca0779ebSJerome Gaillard if (scanner_result.HasMessage() && !result.HasMessage()) {
160*ca0779ebSJerome Gaillard result.SetMessage(scanner_result.GetMessage());
161*ca0779ebSJerome Gaillard }
162*ca0779ebSJerome Gaillard current_terminal_index = current_terminal_index == GetTerminalIndex()
163*ca0779ebSJerome Gaillard ? current_terminal_index + 1
164*ca0779ebSJerome Gaillard : GetTerminalIndex();
165*ca0779ebSJerome Gaillard SetTerminalIndex(current_terminal_index);
166*ca0779ebSJerome Gaillard if (current_terminal_index < GetTerminalCount()) {
167*ca0779ebSJerome Gaillard result.SetType(DataMatchResult::kPartial);
168*ca0779ebSJerome Gaillard }
169*ca0779ebSJerome Gaillard force_parse_return = HasNextRule();
170*ca0779ebSJerome Gaillard break;
171*ca0779ebSJerome Gaillard }
172*ca0779ebSJerome Gaillard }
173*ca0779ebSJerome Gaillard return result;
174*ca0779ebSJerome Gaillard }
175*ca0779ebSJerome Gaillard
HasNextRule() const176*ca0779ebSJerome Gaillard bool XmlRule::HasNextRule() const { return next_rule_ != nullptr; }
177*ca0779ebSJerome Gaillard
ReleaseNextRule()178*ca0779ebSJerome Gaillard std::unique_ptr<XmlRule> XmlRule::ReleaseNextRule() {
179*ca0779ebSJerome Gaillard return std::move(next_rule_);
180*ca0779ebSJerome Gaillard }
181*ca0779ebSJerome Gaillard
SetNextRule(std::unique_ptr<XmlRule> next_rule)182*ca0779ebSJerome Gaillard void XmlRule::SetNextRule(std::unique_ptr<XmlRule> next_rule) {
183*ca0779ebSJerome Gaillard next_rule_ = std::move(next_rule);
184*ca0779ebSJerome Gaillard }
185*ca0779ebSJerome Gaillard
186*ca0779ebSJerome Gaillard } // namespace image_io
187*ca0779ebSJerome Gaillard } // namespace photos_editing_formats
188