use crate::item::Node;
use crate::parser::combinators::alt::{alt3, alt4};
use crate::parser::combinators::delimited::delimited;
use crate::parser::combinators::many::many0;
use crate::parser::combinators::map::map;
use crate::parser::combinators::tag::tag;
use crate::parser::combinators::take::{take_until, take_until_either_or_min1, take_until_end};
use crate::parser::combinators::tuple::{tuple2, tuple9};
use crate::parser::combinators::wellformed::{wellformed, wellformed_ver};
use crate::parser::combinators::whitespace::{whitespace0, whitespace1};
use crate::parser::common::{is_char10, is_unrestricted_char11};
use crate::parser::xml::chardata::chardata_unicode_codepoint;
use crate::parser::xml::dtd::externalid::textexternalid;
use crate::parser::xml::dtd::intsubset::intsubset;
use crate::parser::xml::dtd::pereference::petextreference;
use crate::parser::xml::qname::qualname_to_parts;
use crate::parser::{ParseError, ParseInput, StaticState};
use qualname::{NamespacePrefix, NamespaceUri};
pub(crate) fn pedecl<'a, N: Node, L>()
-> impl Fn(ParseInput<'a, N>, &mut StaticState<L>) -> Result<(ParseInput<'a, N>, ()), ParseError>
where
L: FnMut(&NamespacePrefix) -> Result<NamespaceUri, ParseError>,
{
move |input, ss| match wellformed_ver(
tuple9(
tag("<!ENTITY"),
whitespace1(),
tag("%"),
whitespace1(),
wellformed(
qualname_to_parts(),
|(p, _)| p.is_none(),
"colon in parameter entity name not allowed",
),
whitespace1(),
alt3(
textexternalid(),
delimited(tag("'"), take_until("'"), tag("'")),
delimited(tag("\""), take_until("\""), tag("\"")),
),
whitespace0(),
tag(">"),
),
|(_, _, _, _, _, _, s, _, _)| !s.contains(|c: char| !is_char10(&c)), |(_, _, _, _, _, _, s, _, _)| !s.contains(|c: char| !is_unrestricted_char11(&c)), "invalid character in entity declaration",
)(input, ss)
{
Ok(((input2, mut state2), (_, _, _, _, (_, l), _, s, _, _))) => {
if !state2.currentlyexternal && s.contains('%') {
return Err(ParseError::NotWellFormed(format!(
"unable to expand parameter entity \"{}\"",
s
)));
}
let entityparse = map(
tuple2(
map(
many0(alt4(
map(chardata_unicode_codepoint(), |c| c.to_string()),
petextreference(),
map(delimited(tag("&"), take_until(";"), tag(";")), |s| {
["&".to_string(), s, ";".to_string()].concat()
}),
take_until_either_or_min1("&", "%"),
)),
|ve| ve.concat(),
),
wellformed(
take_until_end(),
|s| !s.contains('&') && !s.contains('%'),
"entity has invalid character",
),
),
|(a, b)| [a, b].concat(),
)((s.as_str(), state2.clone()), ss);
match entityparse {
Ok(((_, _), res)) => {
if !state2.currentlyexternal {
match intsubset()((res.as_str(), state2.clone()), ss) {
Ok(((_i, _s), _)) => {}
Err(_) => {
return Err(ParseError::NotWellFormed(format!(
"unable to parse entity \"{}\"",
res.clone()
)));
}
}
};
let replaceable = state2.currentlyexternal;
match state2.dtd.paramentities.get(l.as_str()) {
None => {
state2.dtd.paramentities.insert(l, (res, replaceable));
Ok(((input2, state2), ()))
}
Some((_, true)) => {
state2
.dtd
.paramentities
.entry(l)
.or_insert((res, replaceable));
Ok(((input2, state2), ()))
}
_ => Ok(((input2, state2), ())),
}
}
Err(e) => Err(e),
}
}
Err(err) => Err(err),
}
}