use super::config::{EntityPolicy, FromXmlConfig};
use hedl_core::lex::parse_expression_token;
use hedl_core::Value;
pub(crate) fn parse_value_with_config(s: &str, config: &FromXmlConfig) -> Result<Value, String> {
let trimmed = s.trim();
if trimmed.contains('&') && trimmed.contains(';') {
if config.log_security_events {
eprintln!("[SECURITY] Entity reference detected in value: {}", trimmed);
}
if (trimmed.contains("&xxe;")
|| trimmed.contains("&file;")
|| trimmed.contains("&passwd;")
|| trimmed.contains("&secret;"))
&& config.entity_policy == EntityPolicy::WarnOnEntities
{
eprintln!(
"[WARNING] Suspicious entity reference detected: {}",
trimmed
);
}
}
if trimmed.is_empty() {
return Ok(Value::Null);
}
if trimmed.starts_with("$(") && trimmed.ends_with(')') {
let expr =
parse_expression_token(trimmed).map_err(|e| format!("Invalid expression: {}", e))?;
return Ok(Value::Expression(Box::new(expr)));
}
if trimmed == "true" {
return Ok(Value::Bool(true));
}
if trimmed == "false" {
return Ok(Value::Bool(false));
}
if let Ok(i) = trimmed.parse::<i64>() {
return Ok(Value::Int(i));
}
if let Ok(f) = trimmed.parse::<f64>() {
return Ok(Value::Float(f));
}
Ok(Value::String(trimmed.to_string().into()))
}
#[cfg(test)]
pub(crate) fn parse_value(s: &str) -> Result<Value, String> {
let config = FromXmlConfig::default();
parse_value_with_config(s, &config)
}
pub(crate) fn parse_version(s: &str) -> Option<(u32, u32)> {
let parts: Vec<&str> = s.split('.').collect();
if parts.len() >= 2 {
let major = parts[0].parse().ok()?;
let minor = parts[1].parse().ok()?;
Some((major, minor))
} else {
None
}
}