use core::marker::{PhantomData, PhantomPinned};
use std::env;
use std::ffi::CString;
use super::Schema;
use crate::error::InternalError;
use libc::{c_char, c_int, c_uint};
#[repr(C)]
#[derive(Clone, Copy)]
struct XmlSchemaPtr {
_data: [u8; 0],
_marker: PhantomData<(*mut u8, PhantomPinned)>,
}
pub(super) struct XmlSchema(*mut XmlSchemaPtr);
impl XmlSchema {
pub(super) fn from_parser(
mut parser: XmlSchemaParserCtxt,
schema_type: &Schema,
schema_dir: &str,
) -> Result<Self, InternalError> {
let schema_ptr = match schema_type {
Schema::OrderXmlV3_4 => {
let cwd =
env::current_dir().map_err(|err| InternalError::from_source(Box::new(err)))?;
env::set_current_dir(schema_dir)
.map_err(|err| InternalError::from_source(Box::new(err)))?;
let schema_ptr = unsafe { xmlSchemaParse(parser.as_ptr()) };
env::set_current_dir(cwd)
.map_err(|err| InternalError::from_source(Box::new(err)))?;
schema_ptr
}
Schema::GdsnXmlV3_1 => unsafe { xmlSchemaParse(parser.as_ptr()) },
};
if schema_ptr.is_null() {
return Err(InternalError::with_message(
"`xmlSchemaParse` returned a null pointer".to_string(),
));
}
Ok(Self(schema_ptr))
}
fn as_ptr(&mut self) -> *mut XmlSchemaPtr {
self.0
}
}
impl Drop for XmlSchema {
fn drop(&mut self) {
unsafe {
xmlSchemaFree(self.as_ptr());
}
}
}
#[repr(C)]
#[derive(Clone, Copy)]
struct XmlSchemaParserCtxtPtr {
_data: [u8; 0],
_marker: PhantomData<(*mut u8, PhantomPinned)>,
}
pub(super) struct XmlSchemaParserCtxt(*mut XmlSchemaParserCtxtPtr);
impl XmlSchemaParserCtxt {
pub(super) fn from_buffer(schema: &[u8]) -> Result<Self, InternalError> {
let buff = schema.as_ptr() as *const c_char;
let size = schema.len() as *const i32;
let parser_ctxt_ptr = unsafe { xmlSchemaNewMemParserCtxt(buff, size) };
if parser_ctxt_ptr.is_null() {
return Err(InternalError::with_message(
"`xmlSchemaNewMemParserCtxt` returned a null pointer".to_string(),
));
}
Ok(Self(parser_ctxt_ptr))
}
fn as_ptr(&mut self) -> *mut XmlSchemaParserCtxtPtr {
self.0
}
}
impl Drop for XmlSchemaParserCtxt {
fn drop(&mut self) {
unsafe {
xmlSchemaFreeParserCtxt(self.as_ptr());
}
}
}
#[repr(C)]
#[derive(Clone, Copy)]
struct XmlSchemaValidCtxtPtr {
_data: [u8; 0],
_marker: PhantomData<(*mut u8, PhantomPinned)>,
}
pub(super) struct XmlSchemaValidCtxt(*mut XmlSchemaValidCtxtPtr);
impl XmlSchemaValidCtxt {
fn from_schema(schema: &mut XmlSchema) -> Result<Self, InternalError> {
let ctxt_ptr = unsafe { xmlSchemaNewValidCtxt(schema.as_ptr()) };
if ctxt_ptr.is_null() {
return Err(InternalError::with_message(
"Unable to build XmlSchemaValidCtxt from null pointer".to_string(),
));
}
Ok(Self(ctxt_ptr))
}
fn as_ptr(&mut self) -> *mut XmlSchemaValidCtxtPtr {
self.0
}
}
impl Drop for XmlSchemaValidCtxt {
fn drop(&mut self) {
unsafe {
xmlSchemaFreeValidCtxt(self.as_ptr());
}
}
}
pub(super) fn validate_doc(schema: &mut XmlSchema, mut doc: XmlDoc) -> Result<i32, InternalError> {
let mut ctxt = XmlSchemaValidCtxt::from_schema(schema)?;
let result = unsafe { xmlSchemaValidateDoc(ctxt.as_ptr(), doc.as_ptr(), 0) };
Ok(result)
}
pub(super) fn validate_file(schema: &mut XmlSchema, data: &str) -> Result<i32, InternalError> {
let mut ctxt = XmlSchemaValidCtxt::from_schema(schema)?;
let path = CString::new(data).map_err(|err| InternalError::from_source(Box::new(err)))?;
let result = unsafe { xmlSchemaValidateFile(ctxt.as_ptr(), path.as_ptr(), 0) };
Ok(result)
}
#[repr(C)]
#[derive(Clone, Copy)]
struct XmlDocPtr {
_data: [u8; 0],
_marker: PhantomData<(*mut u8, PhantomPinned)>,
}
pub(super) struct XmlDoc(*mut XmlDocPtr);
impl XmlDoc {
pub(super) fn from_str(data: &str) -> Result<Self, InternalError> {
let doc_ptr = unsafe {
let data_string =
CString::new(data).map_err(|err| InternalError::from_source(Box::new(err)))?;
xmlParseDoc(data_string.as_ptr())
};
if doc_ptr.is_null() {
return Err(InternalError::with_message(
"`xmlParseDoc` returned a null pointer".to_string(),
));
}
Ok(Self(doc_ptr))
}
fn as_ptr(&mut self) -> *mut XmlDocPtr {
self.0
}
}
impl Drop for XmlDoc {
fn drop(&mut self) {
unsafe { xmlFreeDoc(self.as_ptr()) }
}
}
#[link(name = "xml2")]
extern "C" {
fn xmlParseDoc(cur: *const c_char) -> *mut XmlDocPtr;
fn xmlSchemaNewMemParserCtxt(
buffer: *const c_char,
size: *const c_int,
) -> *mut XmlSchemaParserCtxtPtr;
fn xmlSchemaParse(ctxt: *mut XmlSchemaParserCtxtPtr) -> *mut XmlSchemaPtr;
fn xmlSchemaNewValidCtxt(schema: *mut XmlSchemaPtr) -> *mut XmlSchemaValidCtxtPtr;
fn xmlSchemaValidateDoc(
ctxt: *mut XmlSchemaValidCtxtPtr,
doc: *mut XmlDocPtr,
options: c_uint,
) -> c_int;
fn xmlSchemaValidateFile(
ctxt: *mut XmlSchemaValidCtxtPtr,
file_name: *const c_char,
options: c_uint,
) -> c_int;
fn xmlSchemaFreeValidCtxt(ctxt: *mut XmlSchemaValidCtxtPtr);
fn xmlSchemaFreeParserCtxt(ctxt: *mut XmlSchemaParserCtxtPtr);
fn xmlSchemaFree(schema: *mut XmlSchemaPtr);
fn xmlFreeDoc(doc: *mut XmlDocPtr);
}