1pub struct Captures<'a> {
2 pub begin: &'a [u8],
3 pub data: &'a [u8],
4 pub end: &'a [u8],
5}
6
7pub fn parse_captures<'a>(input: &'a [u8]) -> Option<Captures<'a>> {
8 parser_inner(input).map(|(_, cap)| cap)
9}
10pub fn parse_captures_iter<'a>(input: &'a [u8]) -> CaptureMatches<'a> {
11 CaptureMatches { input }
12}
13
14pub struct CaptureMatches<'a> {
15 input: &'a [u8],
16}
17impl<'a> Iterator for CaptureMatches<'a> {
18 type Item = Captures<'a>;
19 fn next(&mut self) -> Option<Self::Item> {
20 if self.input.is_empty() {
21 return None;
22 }
23 match parser_inner(self.input) {
24 Some((remaining, captures)) => {
25 self.input = remaining;
26 Some(captures)
27 }
28 None => {
29 self.input = &[];
30 None
31 }
32 }
33 }
34}
35
36fn parse_begin<'a>(input: &'a [u8]) -> Option<(&'a [u8], &'a [u8])> {
37 let (input, _) = read_until(input, b"-----BEGIN ")?;
38 let (input, begin) = read_until(input, b"-----")?;
39 let input = skip_whitespace(input);
40 Some((input, begin))
41}
42
43fn parse_payload<'a>(input: &'a [u8]) -> Option<(&'a [u8], &'a [u8])> {
44 read_until(input, b"-----END ")
45}
46
47fn extract_headers_and_data<'a>(input: &'a [u8]) -> (&'a [u8], &'a [u8]) {
48 if let Some((rest, headers)) = read_until(input, b"\n\n") {
49 (headers, rest)
50 } else if let Some((rest, headers)) = read_until(input, b"\r\n\r\n") {
51 (headers, rest)
52 } else {
53 (&[], input)
54 }
55}
56
57fn parse_end<'a>(input: &'a [u8]) -> Option<(&'a [u8], &'a [u8])> {
58 let (remaining, end) = read_until(input, b"-----")?;
59 let remaining = skip_whitespace(remaining);
60 Some((remaining, end))
61}
62
63fn parser_inner<'a>(input: &'a [u8]) -> Option<(&'a [u8], Captures<'a>)> {
64 let (input, begin) = parse_begin(input)?;
73 let (input, payload) = parse_payload(input)?;
74 let (_headers, data) = extract_headers_and_data(payload);
75 let (remaining, end) = parse_end(input)?;
76
77 let captures = Captures { begin, data, end };
78 Some((remaining, captures))
79}
80
81fn skip_whitespace(mut input: &[u8]) -> &[u8] {
83 while let Some(b) = input.first() {
84 match b {
85 b' ' | b'\t' | b'\n' | b'\r' => {
86 input = &input[1..];
87 }
88 _ => break,
89 }
90 }
91 input
92}
93fn read_until<'a, 'b>(input: &'a [u8], marker: &'b [u8]) -> Option<(&'a [u8], &'a [u8])> {
96 if marker.is_empty() {
98 return Some((&[], input));
99 }
100 let mut index = 0;
101 let mut found = 0;
102 while input.len() - index >= marker.len() - found {
103 if input[index] == marker[found] {
104 found += 1;
105 } else {
106 found = 0;
107 }
108 index += 1;
109 if found == marker.len() {
110 let remaining = &input[index..];
111 let matched = &input[..index - found];
112 return Some((remaining, matched));
113 }
114 }
115 None
116}