use std::{ffi::c_void, ptr::null_mut};
use crate::{
globals::{
GenericErrorContext, get_keep_blanks_default_value, get_line_numbers_default_value,
get_pedantic_parser_default_value, get_substitute_entities_default_value,
set_indent_tree_output, set_keep_blanks_default_value, set_line_numbers_default_value,
set_pedantic_parser_default_value, set_substitute_entities_default_value,
},
parser::{XmlSAXHandler, xml_init_parser},
tree::{XmlDocPtr, XmlDtdPtr, XmlGenericNodePtr, xml_free_doc},
};
#[doc(alias = "xmlParseDoc")]
#[deprecated = "Use xmlReadDoc"]
#[cfg(feature = "sax1")]
pub fn xml_parse_doc(cur: &[u8]) -> Option<XmlDocPtr> {
xml_sax_parse_doc(None, cur, 0)
}
#[doc(alias = "xmlParseFile")]
#[deprecated = "Use xmlReadFile"]
#[cfg(feature = "sax1")]
pub fn xml_parse_file(filename: Option<&str>) -> Option<XmlDocPtr> {
xml_sax_parse_file(None, filename, false)
}
#[doc(alias = "xmlParseMemory")]
#[deprecated = "Use xmlReadMemory"]
#[cfg(feature = "sax1")]
pub fn xml_parse_memory(buffer: &[u8]) -> Option<XmlDocPtr> {
xml_sax_parse_memory(None, buffer, false)
}
#[doc(alias = "xmlSubstituteEntitiesDefault")]
#[deprecated = "Use the modern options API with XML_PARSE_NOENT"]
pub fn xml_substitute_entities_default(val: bool) -> bool {
let old = get_substitute_entities_default_value();
set_substitute_entities_default_value(val);
old
}
#[doc(alias = "xmlKeepBlanksDefault")]
#[deprecated = "Use the modern options API with XML_PARSE_NOBLANKS"]
pub fn xml_keep_blanks_default(val: bool) -> bool {
let old = get_keep_blanks_default_value();
set_keep_blanks_default_value(val);
if !val {
set_indent_tree_output(1);
}
old
}
#[doc(alias = "xmlPedanticParserDefault")]
#[deprecated = "Use the modern options API with XML_PARSE_PEDANTIC"]
pub fn xml_pedantic_parser_default(val: bool) -> bool {
let old = get_pedantic_parser_default_value();
set_pedantic_parser_default_value(val);
old
}
#[doc(alias = "xmlLineNumbersDefault")]
#[deprecated = "The modern options API always enables line numbers"]
pub fn xml_line_numbers_default(val: i32) -> i32 {
let old = get_line_numbers_default_value();
set_line_numbers_default_value(val);
old
}
#[doc(alias = "xmlRecoverDoc")]
#[deprecated = "Use xmlReadDoc with XML_PARSE_RECOVER"]
#[cfg(feature = "sax1")]
pub fn xml_recover_doc(cur: &[u8]) -> Option<XmlDocPtr> {
xml_sax_parse_doc(None, cur, 1)
}
#[doc(alias = "xmlRecoverMemory")]
#[deprecated = "Use xmlReadMemory with XML_PARSE_RECOVER"]
#[cfg(feature = "sax1")]
pub fn xml_recover_memory(buffer: &[u8]) -> Option<XmlDocPtr> {
xml_sax_parse_memory(None, buffer, true)
}
#[doc(alias = "xmlRecoverFile")]
#[deprecated = "Use xmlReadFile with XML_PARSE_RECOVER"]
#[cfg(feature = "sax1")]
pub fn xml_recover_file(filename: Option<&str>) -> Option<XmlDocPtr> {
xml_sax_parse_file(None, filename, true)
}
#[doc(alias = "xmlSAXUserParseFile")]
#[deprecated = "Use xmlNewSAXParserCtxt and xmlCtxtReadFile"]
#[cfg(feature = "sax1")]
pub fn xml_sax_user_parse_file(
sax: Option<Box<XmlSAXHandler>>,
user_data: Option<GenericErrorContext>,
filename: Option<&str>,
) -> i32 {
use super::XmlParserCtxt;
let ret: i32;
let Some(mut ctxt) = XmlParserCtxt::from_filename(filename) else {
return -1;
};
ctxt.sax = sax;
ctxt.detect_sax2();
ctxt.user_data = user_data;
ctxt.parse_document();
if ctxt.well_formed {
ret = 0;
} else if ctxt.err_no != 0 {
ret = ctxt.err_no;
} else {
ret = -1;
}
ctxt.sax = None;
if let Some(my_doc) = ctxt.my_doc.take() {
unsafe {
xml_free_doc(my_doc);
}
}
ret
}
#[doc(alias = "xmlSAXUserParseMemory")]
#[deprecated = "Use xmlNewSAXParserCtxt and xmlCtxtReadMemory"]
#[cfg(feature = "sax1")]
pub fn xml_sax_user_parse_memory(
sax: Option<Box<XmlSAXHandler>>,
user_data: Option<GenericErrorContext>,
buffer: &[u8],
) -> i32 {
use super::XmlParserCtxt;
let ret: i32;
xml_init_parser();
let Some(mut ctxt) = XmlParserCtxt::from_memory(buffer) else {
return -1;
};
ctxt.sax = sax;
ctxt.detect_sax2();
ctxt.user_data = user_data;
ctxt.parse_document();
if ctxt.well_formed {
ret = 0;
} else if ctxt.err_no != 0 {
ret = ctxt.err_no;
} else {
ret = -1;
}
ctxt.sax = None;
if let Some(my_doc) = ctxt.my_doc.take() {
unsafe {
xml_free_doc(my_doc);
}
}
ret
}
#[doc(alias = "xmlSAXParseDoc")]
#[deprecated = "Use xmlNewSAXParserCtxt and xmlCtxtReadDoc"]
#[cfg(feature = "sax1")]
pub fn xml_sax_parse_doc(
sax: Option<Box<XmlSAXHandler>>,
cur: &[u8],
recovery: i32,
) -> Option<XmlDocPtr> {
use super::XmlParserCtxt;
let replaced = sax.is_some();
let mut oldsax = None;
let mut ctxt = XmlParserCtxt::from_memory(cur)?;
if let Some(sax) = sax {
oldsax = ctxt.sax.replace(sax);
ctxt.user_data = None;
}
ctxt.detect_sax2();
ctxt.parse_document();
let ret = if ctxt.well_formed || recovery != 0 {
ctxt.my_doc
} else {
if let Some(my_doc) = ctxt.my_doc.take() {
unsafe {
xml_free_doc(my_doc);
}
}
None
};
if replaced {
ctxt.sax = oldsax;
}
ret
}
#[doc(alias = "xmlSAXParseMemory")]
#[deprecated = "Use xmlNewSAXParserCtxt and xmlCtxtReadMemory"]
#[cfg(feature = "sax1")]
pub fn xml_sax_parse_memory(
sax: Option<Box<XmlSAXHandler>>,
buffer: &[u8],
recovery: bool,
) -> Option<XmlDocPtr> {
xml_sax_parse_memory_with_data(sax, buffer, recovery, null_mut())
}
#[doc(alias = "xmlSAXParseMemoryWithData")]
#[deprecated = "Use xmlNewSAXParserCtxt and xmlCtxtReadMemory"]
#[cfg(feature = "sax1")]
pub fn xml_sax_parse_memory_with_data(
sax: Option<Box<XmlSAXHandler>>,
buffer: &[u8],
recovery: bool,
data: *mut c_void,
) -> Option<XmlDocPtr> {
use super::XmlParserCtxt;
let replaced = sax.is_some();
xml_init_parser();
let mut ctxt = XmlParserCtxt::from_memory(buffer)?;
if let Some(sax) = sax {
ctxt.sax = Some(sax);
}
ctxt.detect_sax2();
if !data.is_null() {
ctxt._private = data;
}
ctxt.recovery = recovery;
ctxt.parse_document();
let ret = if ctxt.well_formed || recovery {
ctxt.my_doc
} else {
if let Some(my_doc) = ctxt.my_doc.take() {
unsafe {
xml_free_doc(my_doc);
}
}
None
};
if replaced {
ctxt.sax = None;
}
ret
}
#[doc(alias = "xmlSAXParseFile")]
#[deprecated = "Use xmlNewSAXParserCtxt and xmlCtxtReadFile"]
#[cfg(feature = "sax1")]
pub fn xml_sax_parse_file(
sax: Option<Box<XmlSAXHandler>>,
filename: Option<&str>,
recovery: bool,
) -> Option<XmlDocPtr> {
xml_sax_parse_file_with_data(sax, filename, recovery, null_mut())
}
#[doc(alias = "xmlSAXParseFileWithData")]
#[deprecated = "Use xmlNewSAXParserCtxt and xmlCtxtReadFile"]
#[cfg(feature = "sax1")]
pub fn xml_sax_parse_file_with_data(
sax: Option<Box<XmlSAXHandler>>,
filename: Option<&str>,
recovery: bool,
data: *mut c_void,
) -> Option<XmlDocPtr> {
use crate::parser::XmlParserCtxt;
use crate::io::xml_parser_get_directory;
let replaced = sax.is_some();
xml_init_parser();
let mut ctxt = XmlParserCtxt::from_filename(filename)?;
if let Some(sax) = sax {
ctxt.sax = Some(sax);
}
ctxt.detect_sax2();
if !data.is_null() {
ctxt._private = data;
}
if ctxt.directory.is_none() {
if let Some(filename) = filename {
if let Some(dir) = xml_parser_get_directory(filename) {
ctxt.directory = Some(dir.to_string_lossy().into_owned());
}
}
}
ctxt.recovery = recovery;
ctxt.parse_document();
let ret = if ctxt.well_formed || recovery {
ctxt.my_doc
} else {
if let Some(my_doc) = ctxt.my_doc.take() {
unsafe {
xml_free_doc(my_doc);
}
}
None
};
if replaced {
ctxt.sax = None;
}
ret
}
#[doc(alias = "xmlSAXParseEntity")]
#[deprecated]
#[cfg(feature = "sax1")]
pub(crate) fn xml_sax_parse_entity(
sax: Option<Box<XmlSAXHandler>>,
filename: Option<&str>,
) -> Option<XmlDocPtr> {
use super::XmlParserCtxt;
let replaced = sax.is_some();
let mut ctxt = XmlParserCtxt::from_filename(filename)?;
if let Some(sax) = sax {
ctxt.sax = Some(sax);
ctxt.user_data = None;
}
ctxt.parse_ext_parsed_ent();
let ret = if ctxt.well_formed {
ctxt.my_doc
} else {
if let Some(my_doc) = ctxt.my_doc.take() {
unsafe {
xml_free_doc(my_doc);
}
}
None
};
if replaced {
ctxt.sax = None;
}
ret
}
#[doc(alias = "xmlParseEntity")]
#[deprecated]
#[cfg(feature = "sax1")]
pub fn xml_parse_entity(filename: Option<&str>) -> Option<XmlDocPtr> {
xml_sax_parse_entity(None, filename)
}
#[doc(alias = "xmlSAXParseDTD")]
#[deprecated]
#[cfg(feature = "libxml_valid")]
pub(crate) fn xml_sax_parse_dtd(
sax: Option<Box<XmlSAXHandler>>,
external_id: Option<&str>,
system_id: Option<&str>,
) -> Option<XmlDtdPtr> {
use crate::{
encoding::detect_encoding,
parser::{XmlParserCtxt, XmlParserOption, xml_err_memory},
tree::{XmlDocProperties, xml_new_doc, xml_new_dtd},
uri::canonic_path,
};
if external_id.is_none() && system_id.is_none() {
return None;
}
let Ok(mut ctxt) = XmlParserCtxt::new_sax_parser(sax, None) else {
return None;
};
ctxt.options |= XmlParserOption::XmlParseDTDLoad as i32;
let system_id_canonic = system_id.map(|s| canonic_path(s));
let input = ctxt
.sax
.as_deref_mut()
.and_then(|sax| sax.resolve_entity)
.and_then(|resolve_entity| {
resolve_entity(&mut ctxt, external_id, system_id_canonic.as_deref())
})?;
if ctxt.push_input(input).is_err() {
return None;
}
if ctxt.input().unwrap().remainder_len() >= 4 {
let enc = detect_encoding(&ctxt.content_bytes()[..4]);
ctxt.switch_encoding(enc);
}
if let Some(input) = ctxt.input_mut() {
if input.filename.is_none() {
if let Some(canonic) = system_id_canonic {
input.filename = Some(canonic.into_owned());
}
}
input.line = 1;
input.col = 1;
input.base += input.cur;
input.cur = 0;
}
ctxt.in_subset = 2;
ctxt.my_doc = xml_new_doc(Some("1.0"));
let Some(mut my_doc) = ctxt.my_doc else {
xml_err_memory(Some(&mut ctxt), Some("New Doc failed"));
return None;
};
my_doc.properties = XmlDocProperties::XmlDocInternal as i32;
my_doc.ext_subset = xml_new_dtd(ctxt.my_doc, Some("none"), external_id, system_id);
ctxt.parse_external_subset(external_id, system_id);
let mut ret = None;
if let Some(mut my_doc) = ctxt.my_doc.take() {
if ctxt.well_formed {
ret = my_doc.ext_subset.take();
if let Some(mut ret) = ret {
ret.doc = None;
let mut tmp = ret.children;
while let Some(mut now) = tmp {
now.set_document(None);
tmp = now.next();
}
}
} else {
ret = None;
}
unsafe {
xml_free_doc(my_doc);
}
}
ret
}
#[doc(alias = "xmlParseBalancedChunkMemory")]
#[cfg(feature = "sax1")]
pub unsafe fn xml_parse_balanced_chunk_memory(
doc: Option<XmlDocPtr>,
sax: Option<Box<XmlSAXHandler>>,
user_data: Option<GenericErrorContext>,
depth: i32,
string: &str,
lst: Option<&mut Option<XmlGenericNodePtr>>,
) -> i32 {
unsafe { xml_parse_balanced_chunk_memory_recover(doc, sax, user_data, depth, string, lst, 0) }
}
#[doc(alias = "xmlParseBalancedChunkMemoryRecover")]
#[cfg(feature = "sax1")]
pub unsafe fn xml_parse_balanced_chunk_memory_recover(
doc: Option<XmlDocPtr>,
sax: Option<Box<XmlSAXHandler>>,
user_data: Option<GenericErrorContext>,
depth: i32,
string: &str,
mut lst: Option<&mut Option<XmlGenericNodePtr>>,
recover: i32,
) -> i32 {
use crate::{
error::XmlParserErrors,
parser::{XmlParserCtxt, XmlParserInputState, XmlParserOption, xml_fatal_err},
tree::{NodeCommon, XML_XML_NAMESPACE, XmlDocProperties, xml_new_doc, xml_new_doc_node},
};
unsafe {
let replaced = sax.is_some();
let mut oldsax = None;
let ret: i32;
if depth > 40 {
return XmlParserErrors::XmlErrEntityLoop as i32;
}
if let Some(lst) = lst.as_mut() {
**lst = None;
}
let Some(mut ctxt) = XmlParserCtxt::from_memory(string.as_bytes()) else {
return -1;
};
ctxt.user_data = None;
if let Some(sax) = sax {
oldsax = ctxt.sax.replace(sax);
if user_data.is_some() {
ctxt.user_data = user_data;
}
}
let Some(mut new_doc) = xml_new_doc(Some("1.0")) else {
return -1;
};
new_doc.properties = XmlDocProperties::XmlDocInternal as i32;
ctxt.use_options_internal(XmlParserOption::XmlParseNoDict as i32, None);
if let Some(doc) = doc {
new_doc.int_subset = doc.int_subset;
new_doc.ext_subset = doc.ext_subset;
}
let Some(new_root) = xml_new_doc_node(Some(new_doc), None, "pseudoroot", None) else {
if replaced {
ctxt.sax = oldsax;
}
new_doc.int_subset = None;
new_doc.ext_subset = None;
xml_free_doc(new_doc);
return -1;
};
new_doc.add_child(new_root.into());
ctxt.node_push(new_root);
if let Some(mut doc) = doc {
ctxt.my_doc = Some(new_doc);
new_doc.children().unwrap().set_document(Some(doc));
let d = doc;
doc.search_ns_by_href(Some(d), XML_XML_NAMESPACE);
new_doc.old_ns = doc.old_ns;
} else {
ctxt.my_doc = Some(new_doc);
}
ctxt.instate = XmlParserInputState::XmlParserContent;
ctxt.input_id = 2;
ctxt.depth = depth;
ctxt.validate = false;
ctxt.loadsubset = 0;
ctxt.detect_sax2();
if let Some(mut doc) = doc {
let content = doc.children.take();
ctxt.parse_content();
doc.children = content;
} else {
ctxt.parse_content();
}
if ctxt.current_byte() == b'<' && ctxt.nth_byte(1) == b'/' {
xml_fatal_err(&mut ctxt, XmlParserErrors::XmlErrNotWellBalanced, None);
} else if ctxt.current_byte() != 0 {
xml_fatal_err(&mut ctxt, XmlParserErrors::XmlErrExtraContent, None);
}
if new_doc.children != ctxt.node.map(|node| node.into()) {
xml_fatal_err(&mut ctxt, XmlParserErrors::XmlErrNotWellBalanced, None);
}
if !ctxt.well_formed {
if ctxt.err_no == 0 {
ret = 1;
} else {
ret = ctxt.err_no;
}
} else {
ret = 0;
}
if let Some(lst) = lst {
if ret == 0 || recover == 1 {
let mut cur = new_doc.children().unwrap().children();
*lst = cur;
while let Some(mut now) = cur {
now.set_doc(doc);
now.set_parent(None);
cur = now.next();
}
new_doc.children().unwrap().set_children(None);
}
}
if replaced {
ctxt.sax = oldsax;
}
new_doc.int_subset = None;
new_doc.ext_subset = None;
new_doc.old_ns = None;
xml_free_doc(new_doc);
ret
}
}