rust_rcs_client/messaging/ft_http/
resume_info_xml.rs

1// Copyright 2023 宋昊文
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use 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}