xref: /aosp_15_r20/external/image_io/src/xml/xml_rule.cc (revision ca0779eb572efbbfda2e47f806647c3c7eeea8c3)
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