/src/libtorrent/src/xml_parse.cpp
Line | Count | Source |
1 | | /* |
2 | | |
3 | | Copyright (c) 2014-2019, Arvid Norberg |
4 | | Copyright (c) 2016-2017, Alden Torres |
5 | | All rights reserved. |
6 | | |
7 | | Redistribution and use in source and binary forms, with or without |
8 | | modification, are permitted provided that the following conditions |
9 | | are met: |
10 | | |
11 | | * Redistributions of source code must retain the above copyright |
12 | | notice, this list of conditions and the following disclaimer. |
13 | | * Redistributions in binary form must reproduce the above copyright |
14 | | notice, this list of conditions and the following disclaimer in |
15 | | the documentation and/or other materials provided with the distribution. |
16 | | * Neither the name of the author nor the names of its |
17 | | contributors may be used to endorse or promote products derived |
18 | | from this software without specific prior written permission. |
19 | | |
20 | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
21 | | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
22 | | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
23 | | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
24 | | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
25 | | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
26 | | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
27 | | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
28 | | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
29 | | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
30 | | POSSIBILITY OF SUCH DAMAGE. |
31 | | |
32 | | */ |
33 | | |
34 | | #include <cstring> |
35 | | |
36 | | #include "libtorrent/xml_parse.hpp" |
37 | | #include "libtorrent/string_util.hpp" |
38 | | |
39 | | namespace libtorrent { |
40 | | |
41 | | void xml_parse(string_view input |
42 | | , std::function<void(int, string_view, string_view)> callback) |
43 | 0 | { |
44 | 0 | char const* p = input.data(); |
45 | 0 | char const* end = input.data() + input.size(); |
46 | 0 | for (;p != end; ++p) |
47 | 0 | { |
48 | 0 | char const* start = p; |
49 | | // look for tag start |
50 | 0 | for (; p != end && *p != '<'; ++p); |
51 | |
|
52 | 0 | if (p != start) |
53 | 0 | { |
54 | 0 | callback(xml_string, {start, std::size_t(p - start)}, {}); |
55 | 0 | } |
56 | |
|
57 | 0 | if (p == end) break; |
58 | | |
59 | | // skip '<' |
60 | 0 | ++p; |
61 | 0 | if (p != end && p + 8 < end && string_begins_no_case("![CDATA[", p)) |
62 | 0 | { |
63 | | // CDATA. match '![CDATA[' |
64 | 0 | p += 8; |
65 | 0 | start = p; |
66 | 0 | while (p != end && !string_begins_no_case("]]>", p - 2)) ++p; |
67 | | |
68 | | // parse error |
69 | 0 | if (p == end) |
70 | 0 | { |
71 | 0 | callback(xml_parse_error, "unexpected end of file", {}); |
72 | 0 | break; |
73 | 0 | } |
74 | | |
75 | 0 | callback(xml_string, {start, std::size_t(p - start - 2)}, {}); |
76 | 0 | continue; |
77 | 0 | } |
78 | | |
79 | | // parse the name of the tag. |
80 | 0 | for (start = p; p != end && *p != '>' && !is_space(*p); ++p); |
81 | |
|
82 | 0 | char const* tag_name_end = p; |
83 | | |
84 | | // skip the attributes for now |
85 | 0 | for (; p != end && *p != '>'; ++p); |
86 | | |
87 | | // parse error |
88 | 0 | if (p == end) |
89 | 0 | { |
90 | 0 | callback(xml_parse_error, "unexpected end of file", {}); |
91 | 0 | break; |
92 | 0 | } |
93 | | |
94 | 0 | TORRENT_ASSERT(*p == '>'); |
95 | |
|
96 | 0 | char const* tag_end = p; |
97 | 0 | if (*start == '/') |
98 | 0 | { |
99 | 0 | ++start; |
100 | 0 | callback(xml_end_tag, {start, std::size_t(tag_name_end - start)}, {}); |
101 | 0 | } |
102 | 0 | else if (*(p - 1) == '/') |
103 | 0 | { |
104 | 0 | callback(xml_empty_tag, {start, std::size_t(std::min(tag_name_end - start, p - start - 1))}, {}); |
105 | 0 | tag_end = p - 1; |
106 | 0 | } |
107 | 0 | else if (*start == '?' && *(p - 1) == '?') |
108 | 0 | { |
109 | 0 | ++start; |
110 | 0 | callback(xml_declaration_tag, {start, std::size_t(std::min(tag_name_end - start, p - start - 1))}, {}); |
111 | 0 | tag_end = p - 1; |
112 | 0 | } |
113 | 0 | else if (start + 5 < p && std::memcmp(start, "!--", 3) == 0 && std::memcmp(p - 2, "--", 2) == 0) |
114 | 0 | { |
115 | 0 | start += 3; |
116 | 0 | callback(xml_comment, {start, std::size_t(tag_name_end - start - 2)}, {}); |
117 | 0 | continue; |
118 | 0 | } |
119 | 0 | else |
120 | 0 | { |
121 | 0 | callback(xml_start_tag, {start, std::size_t(tag_name_end - start)}, {}); |
122 | 0 | } |
123 | | |
124 | | // parse attributes |
125 | 0 | for (char const* i = tag_name_end; i < tag_end; ++i) |
126 | 0 | { |
127 | 0 | char const* val_start = nullptr; |
128 | | |
129 | | // find start of attribute name |
130 | 0 | while (i != tag_end && is_space(*i)) ++i; |
131 | 0 | if (i == tag_end) break; |
132 | 0 | start = i; |
133 | | // find end of attribute name |
134 | 0 | while (i != tag_end && *i != '=' && !is_space(*i)) ++i; |
135 | 0 | auto const name_len = static_cast<std::size_t>(i - start); |
136 | | |
137 | | // look for equality sign |
138 | 0 | for (; i != tag_end && *i != '='; ++i); |
139 | | |
140 | | // no equality sign found. Report this as xml_tag_content |
141 | | // instead of a series of key value pairs |
142 | 0 | if (i == tag_end) |
143 | 0 | { |
144 | 0 | callback(xml_tag_content, {start, std::size_t(i - start)}, {}); |
145 | 0 | break; |
146 | 0 | } |
147 | | |
148 | 0 | ++i; |
149 | 0 | while (i != tag_end && is_space(*i)) ++i; |
150 | | // check for parse error (values must be quoted) |
151 | 0 | if (i == tag_end || (*i != '\'' && *i != '\"')) |
152 | 0 | { |
153 | 0 | callback(xml_parse_error, "unquoted attribute value", {}); |
154 | 0 | break; |
155 | 0 | } |
156 | 0 | char quote = *i; |
157 | 0 | ++i; |
158 | 0 | val_start = i; |
159 | 0 | for (; i != tag_end && *i != quote; ++i); |
160 | | // parse error (missing end quote) |
161 | 0 | if (i == tag_end) |
162 | 0 | { |
163 | 0 | callback(xml_parse_error, "missing end quote on attribute", {}); |
164 | 0 | break; |
165 | 0 | } |
166 | 0 | callback(xml_attribute, {start, name_len}, {val_start, std::size_t(i - val_start)}); |
167 | 0 | } |
168 | 0 | } |
169 | 0 | } |
170 | | |
171 | | } |