1#![allow(dead_code)]
3
4use crate::parser::html::attribute_list;
5use crate::parser::html::tag_a_opening as href_tag_a_opening;
6use crate::parser::Link;
7use html_escape::decode_html_entities;
8use nom::branch::alt;
9use nom::bytes::complete::is_not;
10use nom::bytes::complete::tag;
11use nom::error::Error;
12use nom::error::ErrorKind;
13use nom::sequence::tuple;
14use std::borrow::Cow;
15
16pub fn html_img_link(i: &str) -> nom::IResult<&str, Link> {
19 let (i, (alt, src)) = html_img(i)?;
20 Ok((i, Link::Image(alt, src)))
21}
22
23pub fn html_img(i: &str) -> nom::IResult<&str, (Cow<str>, Cow<str>)> {
39 tag_img(i)
40}
41
42#[inline]
45fn tag_img(i: &str) -> nom::IResult<&str, (Cow<str>, Cow<str>)> {
46 nom::sequence::delimited(
47 alt((tag("<img "), tag("<IMG "))),
50 nom::combinator::map_parser(is_not(">"), parse_attributes),
51 tag(">"),
52 )(i)
53}
54
55pub fn html_img2dest_link(i: &str) -> nom::IResult<&str, Link> {
58 let (i, (text1, img_alt, img_src, text2, dest, title)) = html_img2dest(i)?;
59 Ok((
60 i,
61 Link::Image2Dest(text1, img_alt, img_src, text2, dest, title),
62 ))
63}
64
65pub fn html_img2dest(
87 i: &str,
88) -> nom::IResult<&str, (Cow<str>, Cow<str>, Cow<str>, Cow<str>, Cow<str>, Cow<str>)> {
89 let (i, ((dest, title), text)) = nom::sequence::terminated(
90 nom::sequence::pair(
91 href_tag_a_opening,
92 alt((
93 nom::bytes::complete::take_until("</a>"),
94 nom::bytes::complete::take_until("</A>"),
95 )),
96 ),
97 alt((tag("</a>"), tag("</A>"))),
100 )(i)?;
101
102 let (_, (text1, (img_alt, img_src), text2)) = tuple((
103 nom::bytes::complete::take_until("<img"),
104 html_img,
105 nom::combinator::rest,
106 ))(text)?;
107
108 let text1 = decode_html_entities(text1);
109 let text2 = decode_html_entities(text2);
110
111 Ok((i, (text1, img_alt, img_src, text2, dest, title)))
112}
113
114fn parse_attributes(i: &str) -> nom::IResult<&str, (Cow<str>, Cow<str>)> {
118 let (i, attributes) = attribute_list(i)?;
119 let mut src = Cow::Borrowed("");
120 let mut alt = Cow::Borrowed("");
121
122 for (name, value) in attributes {
123 if name == "src" {
124 if !(&*src).is_empty() {
127 return Err(nom::Err::Error(Error::new(name, ErrorKind::ManyMN)));
128 }
129 src = value;
130 } else if name == "alt" {
131 if !(&*alt).is_empty() {
134 return Err(nom::Err::Error(Error::new(name, ErrorKind::ManyMN)));
135 }
136 alt = value;
137 }
138 }
139
140 if (&*src).is_empty() {
142 return Err(nom::Err::Error(Error::new(i, ErrorKind::Eof)));
143 };
144
145 Ok((i, (alt, src)))
146}
147
148#[cfg(test)]
149mod tests {
150 use super::*;
151 use crate::parser::html::attribute_list;
152
153 #[test]
154 fn test_tag_img() {
155 let expected = (
156 "abc",
157 (
158 Cow::from("My dog"),
159 Cow::from("http://getreu.net/my&dog.png"),
160 ),
161 );
162 assert_eq!(
163 tag_img(r#"<img src="http://getreu.net/my&dog.png" alt="My dog">abc"#).unwrap(),
164 expected
165 );
166 assert_eq!(
167 tag_img(r#"<IMG src="http://getreu.net/my&dog.png" alt="My dog">abc"#).unwrap(),
168 expected
169 );
170 assert_eq!(
171 tag_img(r#"<IMG src="http://getreu.net/my&dog.png" alt="My dog"/>abc"#).unwrap(),
172 expected
173 );
174 assert_eq!(
175 tag_img(r#"<IMG src="http://getreu.net/my&dog.png" alt="My dog" />abc"#).unwrap(),
176 expected
177 );
178
179 let expected = (
180 "abc",
181 (Cow::from("Some picture"), Cow::from("t%20m%20p.jpg")),
182 );
183 assert_eq!(
184 tag_img(r#"<img src="t%20m%20p.jpg" alt="Some picture" />abc"#).unwrap(),
185 expected
186 );
187 }
188
189 #[test]
190 fn test_parse_attributes() {
191 let expected = (
192 "",
193 (
194 Cow::from("My dog"),
195 Cow::from("http://getreu.net/my&dog.png"),
196 ),
197 );
198 assert_eq!(
199 parse_attributes(r#"abc src="http://getreu.net/my&dog.png" abc alt="My dog" abc"#)
200 .unwrap(),
201 expected
202 );
203
204 let expected =
205 nom::Err::Error(nom::error::Error::new("src", nom::error::ErrorKind::ManyMN));
206 assert_eq!(
207 parse_attributes(r#" src="http://getreu.net" src="http://blog.getreu.net" "#)
208 .unwrap_err(),
209 expected
210 );
211
212 let expected =
213 nom::Err::Error(nom::error::Error::new("alt", nom::error::ErrorKind::ManyMN));
214 assert_eq!(
215 parse_attributes(r#" src="http://getreu.net" alt="a" alt="b" "#).unwrap_err(),
216 expected
217 );
218
219 let expected = nom::Err::Error(nom::error::Error::new("", nom::error::ErrorKind::Eof));
220 assert_eq!(
221 parse_attributes(r#" title="title" "#).unwrap_err(),
222 expected
223 );
224 }
225
226 #[test]
227 fn test_attribute_list() {
228 let expected = (
229 "",
230 vec![
231 ("", Cow::from("")),
232 ("src", Cow::from("http://getreu.net/my&dog.png")),
233 ("", Cow::from("")),
234 ("alt", Cow::from("My dog")),
235 ("", Cow::from("")),
236 ],
237 );
238 assert_eq!(
239 attribute_list(r#"abc src="http://getreu.net/my&dog.png" abc alt="My dog" abc"#)
240 .unwrap(),
241 expected
242 );
243 }
244}