1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
//!
//! Wrapping of the Parser Context (xmlSchemaParserCtxt)
//!
use super::common;

use crate::bindings;
use crate::error::StructuredError;
use crate::tree::document::Document;

use std::ffi::CString;
use std::os::raw::c_char;

/// Wrapper on xmlSchemaParserCtxt
pub struct SchemaParserContext {
  inner: *mut bindings::_xmlSchemaParserCtxt,
  errlog: *mut Vec<StructuredError>,
}

impl SchemaParserContext {
  /// Create a schema parsing context from a Document object
  pub fn from_document(doc: &Document) -> Self {
    let parser = unsafe { bindings::xmlSchemaNewDocParserCtxt(doc.doc_ptr()) };

    if parser.is_null() {
      panic!("Failed to create schema parser context from XmlDocument"); // TODO error handling
    }

    Self::from_raw(parser)
  }

  /// Create a schema parsing context from a buffer in memory
  pub fn from_buffer<Bytes: AsRef<[u8]>>(buff: Bytes) -> Self {
    let buff_bytes = buff.as_ref();
    let buff_ptr = buff_bytes.as_ptr() as *const c_char;
    let buff_len = buff_bytes.len() as i32;

    let parser = unsafe { bindings::xmlSchemaNewMemParserCtxt(buff_ptr, buff_len) };

    if parser.is_null() {
      panic!("Failed to create schema parser context from buffer"); // TODO error handling
    }

    Self::from_raw(parser)
  }

  /// Create a schema parsing context from an URL
  pub fn from_file(path: &str) -> Self {
    let path = CString::new(path).unwrap(); // TODO error handling for \0 containing strings
    let path_ptr = path.as_bytes_with_nul().as_ptr() as *const c_char;

    let parser = unsafe { bindings::xmlSchemaNewParserCtxt(path_ptr) };

    if parser.is_null() {
      panic!("Failed to create schema parser context from path"); // TODO error handling
    }

    Self::from_raw(parser)
  }

  /// Drains error log from errors that might have accumulated while parsing schema
  pub fn drain_errors(&mut self) -> Vec<StructuredError> {
    assert!(!self.errlog.is_null());
    let errors = unsafe { &mut *self.errlog };
    errors.drain(0..).collect()
  }

  /// Return a raw pointer to the underlying xmlSchemaParserCtxt structure
  pub fn as_ptr(&self) -> *mut bindings::_xmlSchemaParserCtxt {
    self.inner
  }
}

/// Private Interface
impl SchemaParserContext {
  fn from_raw(parser: *mut bindings::_xmlSchemaParserCtxt) -> Self {
    let errors: Box<Vec<StructuredError>> = Box::new(Vec::new());

    unsafe {
      let reference: *mut Vec<StructuredError> = std::mem::transmute(errors);
      bindings::xmlSchemaSetParserStructuredErrors(
        parser,
        Some(common::structured_error_handler),
        reference as *mut _,
      );

      Self {
        inner: parser,
        errlog: reference,
      }
    }
  }
}

impl Drop for SchemaParserContext {
  fn drop(&mut self) {
    unsafe {
      bindings::xmlSchemaFreeParserCtxt(self.inner);
      if !self.errlog.is_null() {
        let errors: Box<Vec<StructuredError>> = std::mem::transmute(self.errlog);
        drop(errors)
      }
    }
  }
}