rust_rcs_client/messaging/ft_http/
resume_info_xml.rs1use quick_xml::{
16 events::{BytesStart, Event},
17 Reader,
18};
19
20pub struct ResumeInfo {
21 pub range_start: usize,
22 pub range_end: usize,
23 pub data_url: String,
24}
25
26fn parse_file_range_element<R>(
27 xml_reader: &mut Reader<R>,
28 buf: &mut Vec<u8>,
29 e: &BytesStart,
30 _level: i32,
31) -> Option<(usize, usize)>
32where
33 R: std::io::BufRead,
34{
35 let mut start: Option<usize> = None;
36 let mut end: Option<usize> = None;
37
38 for attribute in e.attributes() {
39 if let Ok(attribute) = attribute {
40 if attribute.key.as_ref() == b"start" {
41 if let Ok(attribute_value) = attribute.unescape_value() {
42 if let Ok(attribute_value) = attribute_value.parse::<usize>() {
43 start.replace(attribute_value);
44 }
45 }
46 } else if attribute.key.as_ref() == b"end" {
47 if let Ok(attribute_value) = attribute.unescape_value() {
48 if let Ok(attribute_value) = attribute_value.parse::<usize>() {
49 end.replace(attribute_value);
50 }
51 }
52 }
53 }
54 }
55
56 let mut level = 1;
57
58 loop {
59 match xml_reader.read_event_into(buf) {
60 Ok(Event::Start(ref _e)) => {
61 level += 1;
62 }
63
64 Ok(Event::End(_)) => {
65 level -= 1;
66 if level == 0 {
67 break;
68 }
69 }
70
71 Ok(Event::Eof) | Err(_) => {
72 break;
73 }
74
75 _ => {}
76 }
77 }
78
79 if let (Some(start), Some(end)) = (start, end) {
80 return Some((start, end));
81 }
82
83 None
84}
85
86fn parse_data_element<R>(
87 xml_reader: &mut Reader<R>,
88 buf: &mut Vec<u8>,
89 e: &BytesStart,
90 _level: i32,
91) -> Option<String>
92where
93 R: std::io::BufRead,
94{
95 let mut url: Option<String> = None;
96
97 for attribute in e.attributes() {
98 if let Ok(attribute) = attribute {
99 if attribute.key.as_ref() == b"url" {
100 if let Ok(attribute_value) = attribute.unescape_value() {
101 url.replace(attribute_value.into_owned());
102 }
103 }
104 }
105 }
106
107 let mut level = 1;
108
109 loop {
110 match xml_reader.read_event_into(buf) {
111 Ok(Event::Start(ref _e)) => {
112 level += 1;
113 }
114
115 Ok(Event::End(_)) => {
116 level -= 1;
117 if level == 0 {
118 break;
119 }
120 }
121
122 Ok(Event::Eof) | Err(_) => {
123 break;
124 }
125
126 _ => {}
127 }
128 }
129
130 return url;
131}
132
133fn parse_file_resume_info<R>(
134 xml_reader: &mut Reader<R>,
135 buf: &mut Vec<u8>,
136 _e: &BytesStart,
137 level: i32,
138) -> Option<ResumeInfo>
139where
140 R: std::io::BufRead,
141{
142 let mut file_range = None;
143 let mut data = None;
144
145 let mut handle_element = |xml_reader: &mut Reader<R>, e: &BytesStart, level: i32| -> bool {
146 if e.name().as_ref().eq_ignore_ascii_case(b"file-range") {
147 let mut buf = Vec::new();
148 file_range = parse_file_range_element(xml_reader, &mut buf, e, level);
149 return true;
150 } else if e.name().as_ref().eq_ignore_ascii_case(b"data") {
151 let mut buf = Vec::new();
152 data = parse_data_element(xml_reader, &mut buf, e, level);
153 return true;
154 }
155
156 false
157 };
158
159 let mut level = level;
160
161 if level > 0 {
162 loop {
163 match xml_reader.read_event_into(buf) {
164 Ok(Event::Start(ref e)) => {
165 if !handle_element(xml_reader, e, 1) {
166 level += 1;
167 }
168 }
169
170 Ok(Event::Empty(ref e)) => {
171 handle_element(xml_reader, e, 0);
172 }
173
174 Ok(Event::End(_)) => {
175 level -= 1;
176 if level == 0 {
177 break;
178 }
179 }
180
181 Ok(Event::Eof) | Err(_) => {
182 break;
183 }
184
185 _ => {}
186 }
187 }
188 }
189
190 if let (Some((range_start, range_end)), Some(data_url)) = (file_range, data) {
191 return Some(ResumeInfo {
192 range_start,
193 range_end,
194 data_url,
195 });
196 }
197
198 None
199}
200
201pub fn parse_xml(data: &[u8]) -> Option<ResumeInfo> {
202 let mut xml_reader = Reader::from_reader(data);
203
204 let mut buf = Vec::new();
205 loop {
206 match xml_reader.read_event_into(&mut buf) {
207 Ok(Event::Start(ref e)) => {
208 if e.name().as_ref().eq_ignore_ascii_case(b"file-resume-info") {
209 let mut buf = Vec::new();
210 return parse_file_resume_info(&mut xml_reader, &mut buf, e, 1);
211 }
212 }
213
214 Ok(Event::Empty(ref e)) => {
215 if e.name().as_ref().eq_ignore_ascii_case(b"file-resume-info") {
216 let mut buf = Vec::new();
217 return parse_file_resume_info(&mut xml_reader, &mut buf, e, 0);
218 }
219 }
220
221 Ok(Event::Eof) | Err(_) => {
222 break;
223 }
224
225 _ => {}
226 }
227 }
228
229 None
230}