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