1pub mod props;
4pub mod range;
5pub mod rtpinfo;
6pub mod session;
7pub mod speed;
8pub mod transport;
9
10use std::fmt::{self, Display, Formatter};
11
12use str_reader::{ParseError, StringReader};
13
14use crate::Error;
15
16pub use crate::ttpkit::header::{
17 FieldIter, HeaderField, HeaderFieldDecoder, HeaderFieldEncoder, HeaderFieldName,
18 HeaderFieldValue, HeaderFields, Iter, ValueParseError,
19};
20
21pub use self::{
22 props::MediaPropertiesHeader,
23 rtpinfo::RTPInfo,
24 session::SessionHeader,
25 speed::SpeedHeader,
26 transport::{TransportHeader, TransportHeaderV10, TransportHeaderV20},
27};
28
29#[derive(Clone)]
31pub struct ValueListDisplay<S, T> {
32 separator: S,
33 items: T,
34}
35
36impl<S, T> ValueListDisplay<S, T> {
37 #[inline]
39 pub const fn new(separator: S, items: T) -> Self {
40 Self { separator, items }
41 }
42}
43
44impl<S, T, I> Display for ValueListDisplay<S, T>
45where
46 S: Display,
47 T: IntoIterator<Item = I> + Clone,
48 I: Display,
49{
50 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
51 let mut items = self.items.clone().into_iter();
52
53 if let Some(item) = items.next() {
54 Display::fmt(&item, f)?;
55 }
56
57 for item in items {
58 write!(f, "{}{}", self.separator, item)?;
59 }
60
61 Ok(())
62 }
63}
64
65impl<S, T, I> From<ValueListDisplay<S, T>> for HeaderFieldValue
66where
67 S: Display,
68 T: IntoIterator<Item = I> + Clone,
69 I: Display,
70{
71 fn from(value: ValueListDisplay<S, T>) -> Self {
72 HeaderFieldValue::from(value.to_string())
73 }
74}
75
76fn parse_header_parameter(s: &str) -> (&str, &str) {
78 let (n, v) = s.split_once('=').unwrap_or((s, ""));
79
80 let name = n.trim();
81 let value = v.trim();
82
83 (name, value)
84}
85
86trait CharExt {
88 fn is_rtsp_token(&self) -> bool;
90
91 fn is_rtsp_unreserved(&self) -> bool;
93}
94
95impl CharExt for char {
96 fn is_rtsp_token(&self) -> bool {
97 match *self {
98 '!' | '#' | '$' | '%' | '&' | '\'' | '*' | '+' | '-' | '.' | '^' | '_' | '`' | '|'
99 | '~' => true,
100 _ => self.is_ascii_alphanumeric(),
101 }
102 }
103
104 fn is_rtsp_unreserved(&self) -> bool {
105 match *self {
106 '!' | '$' | '\'' | '(' | ')' | '*' | '+' | '-' | '.' | '_' => true,
107 _ => self.is_ascii_alphanumeric(),
108 }
109 }
110}
111
112trait StringReaderExt<'a> {
114 fn read_while<F>(&mut self, condition: F) -> &'a str
116 where
117 F: FnMut(char) -> bool;
118
119 fn match_rtsp_separator(&mut self, separator: char) -> Result<(), ParseError>;
121
122 fn read_rtsp_token(&mut self) -> Result<&'a str, Error>;
124
125 fn read_positive_float(&mut self) -> Result<&'a str, Error>;
127
128 fn parse_positive_f32(&mut self) -> Result<f32, Error>;
130
131 fn read_float(&mut self) -> Result<&'a str, Error>;
133
134 fn parse_f32(&mut self) -> Result<f32, Error>;
136
137 fn read_rtsp_quoted_string(&mut self) -> Result<&'a str, Error>;
139
140 fn parse_rtsp_quoted_string(&mut self) -> Result<String, Error>;
142}
143
144impl<'a> StringReaderExt<'a> for StringReader<'a> {
145 fn read_while<F>(&mut self, mut condition: F) -> &'a str
146 where
147 F: FnMut(char) -> bool,
148 {
149 self.read_until(|char| !condition(char))
150 }
151
152 fn match_rtsp_separator(&mut self, separator: char) -> Result<(), ParseError> {
153 let mut reader = StringReader::new(self.as_str());
154
155 reader.skip_whitespace();
156 reader.match_char(separator)?;
157 reader.skip_whitespace();
158
159 *self = reader;
160
161 Ok(())
162 }
163
164 fn read_rtsp_token(&mut self) -> Result<&'a str, Error> {
165 let res = self.read_while(|c| c.is_rtsp_token());
166
167 if !res.is_empty() {
168 Ok(res)
169 } else if self.is_empty() {
170 Err(Error::from_static_msg("unexpected end of input"))
171 } else {
172 Err(Error::from_static_msg("invalid RTSP token"))
173 }
174 }
175
176 fn read_positive_float(&mut self) -> Result<&'a str, Error> {
177 let s = self.as_str();
178
179 let mut reader = StringReader::new(s);
180
181 reader.read_while(|c| c.is_ascii_digit());
182
183 if reader.match_char('.').is_ok() {
184 reader.read_while(|c| c.is_ascii_digit());
185 }
186
187 *self = reader;
188
189 let r = self.as_str();
190
191 let original_len = s.len();
192 let remaining_len = r.len();
193
194 let len = original_len - remaining_len;
195
196 if len == 0 {
197 Err(Error::from_static_msg("invalid float number"))
198 } else {
199 Ok(&s[..len])
200 }
201 }
202
203 fn parse_positive_f32(&mut self) -> Result<f32, Error> {
204 self.read_positive_float()
205 .ok()
206 .map(|v| v.parse())
207 .and_then(|r| r.ok())
208 .ok_or_else(|| Error::from_static_msg("invalid float number"))
209 }
210
211 fn read_float(&mut self) -> Result<&'a str, Error> {
212 let s = self.as_str();
213
214 let mut reader = StringReader::new(s);
215
216 let _ = reader.match_char('-');
217
218 reader.read_positive_float()?;
219
220 *self = reader;
221
222 let r = self.as_str();
223
224 let original_len = s.len();
225 let remaining_len = r.len();
226
227 let len = original_len - remaining_len;
228
229 Ok(&s[..len])
230 }
231
232 fn parse_f32(&mut self) -> Result<f32, Error> {
233 self.read_float()
234 .ok()
235 .map(|v| v.parse())
236 .and_then(|r| r.ok())
237 .ok_or_else(|| Error::from_static_msg("invalid float number"))
238 }
239
240 fn read_rtsp_quoted_string(&mut self) -> Result<&'a str, Error> {
241 let s = self.as_str();
242
243 let mut reader = StringReader::new(s);
244
245 reader.match_char('"')?;
246
247 loop {
248 match reader.read_char()? {
249 '"' => break,
250 '\\' => match reader.read_char()? {
251 '"' | '\\' => (),
252 _ => return Err(Error::from_static_msg("unexpected escape character")),
253 },
254 _ => (),
255 }
256 }
257
258 *self = reader;
259
260 let r = self.as_str();
261
262 let original_len = s.len();
263 let remaining_len = r.len();
264
265 let len = original_len - remaining_len;
266
267 Ok(&s[..len])
268 }
269
270 fn parse_rtsp_quoted_string(&mut self) -> Result<String, Error> {
271 let res = self
272 .read_rtsp_quoted_string()?
273 .trim_matches('"')
274 .replace("\\\"", "\"")
275 .replace("\\\\", "\\");
276
277 Ok(res)
278 }
279}
280
281#[cfg(test)]
282mod tests {
283 use str_reader::StringReader;
284
285 use super::StringReaderExt;
286
287 #[test]
288 fn test_match_rtsp_separator() {
289 let mut reader = StringReader::new("a,b ,c, d , e\t, f\n,g ; h");
290
291 assert!(reader.match_str("a").is_ok());
292 assert!(reader.match_rtsp_separator(',').is_ok());
293 assert!(reader.match_str("b").is_ok());
294 assert!(reader.match_rtsp_separator(',').is_ok());
295 assert!(reader.match_str("c").is_ok());
296 assert!(reader.match_rtsp_separator(',').is_ok());
297 assert!(reader.match_str("d").is_ok());
298 assert!(reader.match_rtsp_separator(',').is_ok());
299 assert!(reader.match_str("e").is_ok());
300 assert!(reader.match_rtsp_separator(',').is_ok());
301 assert!(reader.match_str("f").is_ok());
302 assert!(reader.match_rtsp_separator(',').is_ok());
303 assert!(reader.match_str("g").is_ok());
304
305 assert!(reader.match_rtsp_separator(',').is_err());
306
307 assert_eq!(reader.as_str(), " ; h");
308
309 assert!(reader.match_rtsp_separator(';').is_ok());
310 assert!(reader.match_str("h").is_ok());
311
312 assert!(reader.is_empty());
313 }
314
315 #[test]
316 fn test_read_rtsp_quoted_string() {
317 let mut reader = StringReader::new("");
318
319 assert!(reader.read_rtsp_quoted_string().is_err());
320
321 let mut reader = StringReader::new("a");
322
323 assert!(reader.read_rtsp_quoted_string().is_err());
324
325 let mut reader = StringReader::new(" \"\" ");
326
327 assert!(reader.read_rtsp_quoted_string().is_err());
328
329 let mut reader = StringReader::new("\" ");
330
331 assert!(reader.read_rtsp_quoted_string().is_err());
332
333 let mut reader = StringReader::new("\"\\\"");
334
335 assert!(reader.read_rtsp_quoted_string().is_err());
336
337 let mut reader = StringReader::new("\"\\a\"");
338
339 assert!(reader.read_rtsp_quoted_string().is_err());
340
341 let mut reader = StringReader::new("\"\" ");
342
343 let res = reader.read_rtsp_quoted_string();
344
345 assert!(matches!(res, Ok("\"\"")));
346 assert_eq!(reader.as_str(), " ");
347
348 let mut reader = StringReader::new("\"abc \t\n\\\"\\\\def \"");
349
350 assert!(matches!(
351 reader.read_rtsp_quoted_string(),
352 Ok("\"abc \t\n\\\"\\\\def \"")
353 ));
354 }
355
356 #[test]
357 fn test_parse_rtsp_quoted_string() {
358 let mut reader = StringReader::new("\"\" ");
359
360 let res = reader.parse_rtsp_quoted_string();
361
362 assert!(matches!(res.as_deref(), Ok("")));
363 assert_eq!(reader.as_str(), " ");
364
365 let mut reader = StringReader::new("\"abc \t\n\\\"\\\\def \"");
366
367 let res = reader.parse_rtsp_quoted_string();
368
369 assert!(matches!(res.as_deref(), Ok("abc \t\n\"\\def ")));
370 }
371
372 #[test]
373 fn test_read_rtsp_token() {
374 let input = " abc \nd1f\tfoo-bar";
375 let mut reader = StringReader::new(input);
376
377 assert!(reader.read_rtsp_token().is_err());
378 assert_eq!(reader.as_str(), input);
379
380 reader.skip_whitespace();
381
382 assert!(matches!(reader.read_rtsp_token(), Ok("abc")));
383
384 reader.skip_whitespace();
385
386 assert!(matches!(reader.read_rtsp_token(), Ok("d1f")));
387
388 reader.skip_whitespace();
389
390 assert!(matches!(reader.read_rtsp_token(), Ok("foo-bar")));
391
392 assert!(reader.is_empty());
393 }
394
395 #[test]
396 fn test_parse_f32() {
397 let mut reader = StringReader::new("1.0");
398
399 assert!(matches!(reader.parse_f32(), Ok(1.0)));
400 assert!(reader.is_empty());
401
402 let mut reader = StringReader::new("-1.0");
403
404 assert!(matches!(reader.parse_f32(), Ok(-1.0)));
405 assert!(reader.is_empty());
406
407 let mut reader = StringReader::new("1.0 ");
408
409 assert!(matches!(reader.parse_f32(), Ok(1.0)));
410 assert_eq!(reader.as_str(), " ");
411
412 let mut reader = StringReader::new("1.0a");
413
414 assert!(matches!(reader.parse_f32(), Ok(1.0)));
415 assert_eq!(reader.as_str(), "a");
416
417 let mut reader = StringReader::new("a1.0");
418
419 assert!(reader.parse_f32().is_err());
420 assert_eq!(reader.as_str(), "a1.0");
421 }
422}