1 #include "image_io/xml/xml_token_context.h"
2
3 #include <string>
4
5 #include "image_io/xml/xml_action.h"
6 #include "image_io/xml/xml_terminal.h"
7
8 namespace photos_editing_formats {
9 namespace image_io {
10
11 using std::vector;
12
13 namespace {
14
15 const XmlPortion kAllPortions =
16 XmlPortion::kBegin | XmlPortion::kMiddle | XmlPortion::kEnd;
17
GetPortion(const XmlActionContext & context)18 XmlPortion GetPortion(const XmlActionContext& context) {
19 return XmlTokenContext::ComputeTokenPortion(
20 context.GetTerminal()->GetScanner()->GetScanCallCount(),
21 context.GetResult().GetType());
22 }
23
24 } // namespace
25
XmlTokenContext(const XmlActionContext & context)26 XmlTokenContext::XmlTokenContext(const XmlActionContext& context)
27 : DataContext(context),
28 result_(context.GetResult()),
29 token_range_(context.GetTerminal()->GetScanner()->GetTokenRange()),
30 token_portion_(GetPortion(context)) {}
31
XmlTokenContext(size_t location,const DataRange & range,const DataSegment & segment,const DataLineMap & data_line_map,const DataMatchResult & result,const DataRange & token_range,const XmlPortion & token_portion)32 XmlTokenContext::XmlTokenContext(size_t location, const DataRange& range,
33 const DataSegment& segment,
34 const DataLineMap& data_line_map,
35 const DataMatchResult& result,
36 const DataRange& token_range,
37 const XmlPortion& token_portion)
38 : DataContext(location, range, segment, data_line_map),
39 result_(result),
40 token_range_(token_range),
41 token_portion_(token_portion) {}
42
BuildTokenValue(std::string * value,bool trim_first_and_last_chars) const43 bool XmlTokenContext::BuildTokenValue(std::string* value,
44 bool trim_first_and_last_chars) const {
45 bool contains_end = ContainsAny(token_portion_, XmlPortion::kEnd);
46 size_t end_delta = trim_first_and_last_chars && contains_end ? 1 : 0;
47 size_t begin_delta = 0;
48 if (ContainsAny(token_portion_, XmlPortion::kBegin)) {
49 begin_delta = trim_first_and_last_chars ? 1 : 0;
50 value->clear();
51 }
52 if (ContainsAny(token_portion_, kAllPortions)) {
53 const auto& segment = GetSegment();
54 DataRange range_with_deltas(token_range_.GetBegin() + begin_delta,
55 token_range_.GetEnd() - end_delta);
56 auto clipped_range = GetRange().GetIntersection(range_with_deltas);
57 if (clipped_range.IsValid()) {
58 const char* cbytes = reinterpret_cast<const char*>(
59 segment.GetBuffer(clipped_range.GetBegin()));
60 value->append(cbytes, clipped_range.GetLength());
61 }
62 }
63 return contains_end;
64 }
65
BuildTokenValueRanges(vector<DataRange> * value_ranges,bool trim_first_and_last_chars) const66 bool XmlTokenContext::BuildTokenValueRanges(
67 vector<DataRange>* value_ranges, bool trim_first_and_last_chars) const {
68 size_t delta = trim_first_and_last_chars ? 1 : 0;
69 auto clipped_range = GetRange().GetIntersection(token_range_);
70 if (ContainsAny(token_portion_, XmlPortion::kBegin)) {
71 value_ranges->clear();
72 if (clipped_range.IsValid()) {
73 value_ranges->push_back(
74 DataRange(clipped_range.GetBegin() + delta, clipped_range.GetEnd()));
75 }
76
77 } else if (ContainsAny(token_portion_, kAllPortions)) {
78 if (clipped_range.IsValid()) {
79 if (!value_ranges->empty() &&
80 value_ranges->back().GetEnd() == clipped_range.GetBegin()) {
81 value_ranges->back() =
82 DataRange(value_ranges->back().GetBegin(), clipped_range.GetEnd());
83 } else {
84 value_ranges->push_back(clipped_range);
85 }
86 }
87 }
88 bool has_end = ContainsAny(token_portion_, XmlPortion::kEnd);
89 if (has_end && !value_ranges->empty() && clipped_range.IsValid() &&
90 trim_first_and_last_chars) {
91 auto& back_range = value_ranges->back();
92 back_range = DataRange(back_range.GetBegin(), back_range.GetEnd() - delta);
93 }
94 return has_end;
95 }
96
ComputeTokenPortion(size_t token_scan_count,DataMatchResult::Type result_type)97 XmlPortion XmlTokenContext::ComputeTokenPortion(
98 size_t token_scan_count, DataMatchResult::Type result_type) {
99 const bool first_scan = token_scan_count == 1;
100 const bool subsequent_scan = token_scan_count > 1;
101 const bool full_match = result_type == DataMatchResult::kFull;
102 const bool partial_match =
103 result_type == DataMatchResult::kPartialOutOfData ||
104 result_type == DataMatchResult::kPartial;
105 XmlPortion portion = XmlPortion::kNone;
106 if (first_scan && full_match) {
107 portion = kAllPortions;
108 } else if (first_scan && partial_match) {
109 portion = XmlPortion::kBegin | XmlPortion::kMiddle;
110 } else if (subsequent_scan && full_match) {
111 portion = XmlPortion::kMiddle | XmlPortion::kEnd;
112 } else if (subsequent_scan && partial_match) {
113 portion = XmlPortion::kMiddle;
114 }
115 return portion;
116 }
117
118 } // namespace image_io
119 } // namespace photos_editing_formats
120