xavier-internal 0.1.7

Internal module of Xavier. Xavier is a lightweight and versatile XML parsing library designed to streamline the process of handling XML data with ease and efficiency.
Documentation
use std::str::FromStr;
use quick_xml::events::{BytesStart, Event};
use quick_xml::Reader;
use crate::deserialize::error::PError;
use crate::deserialize::macro_trait::XmlDeserializable;
use crate::deserialize::decode::{decode_xml, strip_cdata};

trait Number {}
impl Number for i8 {}
impl Number for i16 {}
impl Number for i32 {}
impl Number for i64 {}
impl Number for i128 {}
impl Number for u8 {}
impl Number for u16 {}
impl Number for u32 {}
impl Number for u64 {}
impl Number for u128 {}
impl Number for isize {}
impl Number for usize {}
impl Number for f32 {}
impl Number for f64  {}

fn contains_malicious_characters(input: &str) -> bool {
    for c in input.chars() {
        match c as u32 {
            0x00..=0x08 | 0x0B | 0x0C | 0x0E..=0x1F | 0x7F => {
                return true;
            }
            _ => {}
        }
    }
    false
}

fn contains_malicious_entities(input: &str) -> bool {
    let malicious_patterns = [
        "�", "", "", "", "", "", "", "", "",
        "", "", "", "", "", "", "", "", "",
        "", "", "", "", "", "", "", "", "",
        "", "", ""
    ];
    
    for pattern in &malicious_patterns {
        if input.contains(pattern) {
            return true;
        }
    }
    
    false
}

impl XmlDeserializable for String {
    fn from_xml(reader: &mut Reader<&[u8]>, _: Option<&BytesStart>, _tag_name: Option<&str>) -> Result<Option<Self>, PError> {
        let mut current_value = String::new();
        loop {
            match reader.read_event() {
                Err(error) => { return Err(PError::new(&format!("Error at position {}: {:?}", reader.buffer_position(), error))) },
                Ok(Event::Eof) => { },
                Ok(Event::Start(_)) => {},
                Ok(Event::End(_)) => { return Ok(Some(current_value)); },
                Ok(Event::Empty(_)) => { return Ok(None); },
                Ok(Event::Comment(_)) => {},
                Ok(Event::Text(event)) => { 
                    let raw_string = String::from_utf8(event.to_vec())?;
                    if contains_malicious_entities(&raw_string) {
                        return Err(PError::new("Malicious XML entities detected"));
                    }
                    let cdata_stripped = strip_cdata(&raw_string);
                    let decoded = decode_xml(&cdata_stripped);
                    
                    if contains_malicious_characters(&decoded) {
                        return Err(PError::new("Malicious characters detected in XML content"));
                    }

                    current_value.push_str(decoded.as_str());
                },
                Ok(Event::CData(event)) => { 
                    let raw_string = String::from_utf8(event.to_vec())?;

                    if contains_malicious_entities(&raw_string) {
                        return Err(PError::new("Malicious XML entities detected"));
                    }
                    
                    let decoded = decode_xml(&raw_string);
                    
                    if contains_malicious_characters(&decoded) {
                        return Err(PError::new("Malicious characters detected in XML content"));
                    }

                    current_value.push_str(decoded.as_str());
                },
                Ok(Event::Decl(_)) => {},
                Ok(Event::PI(_)) => {},
                Ok(Event::DocType(_)) => {},
            }
        }
    }
}

impl XmlDeserializable for char {
    fn from_xml(reader: &mut Reader<&[u8]>, _: Option<&BytesStart>, _tag_name: Option<&str>) -> Result<Option<Self>, PError> {
        loop {
            match reader.read_event() {
                Err(error) => { return Err(PError::new(&format!("Error at position {}: {:?}", reader.buffer_position(), error))) },
                Ok(Event::Eof) => { },
                Ok(Event::Start(_)) => {},
                Ok(Event::End(_)) => { return Ok(None); },
                Ok(Event::Empty(_)) => { return Ok(None); },
                Ok(Event::Comment(_)) => {},
                Ok(Event::Text(event)) => { 
                    let raw_string = String::from_utf8(event.to_vec())?;
                    let trimmed = raw_string.trim();
                    if trimmed.is_empty() {
                        return Ok(Some(' '));
                    }
                    if raw_string.chars().count()  > 1 {
                        return Err(PError::new("It's supposed to be a char and string was found!"));
                    }
                    return Ok(Some(trimmed.chars().next().ok_or_else(|| PError::new("Empty string cannot be parsed as char"))?));
                },
                Ok(Event::CData(event)) => { 
                    let raw_string = String::from_utf8(event.to_vec())?;
                    let trimmed = raw_string.trim();
                    if trimmed.is_empty() {
                        return Ok(Some(' '));
                    }
                    return Ok(Some(trimmed.chars().next().ok_or_else(|| PError::new("Empty string cannot be parsed as char"))?));
                },
                Ok(Event::Decl(_)) => {},
                Ok(Event::PI(_)) => {},
                Ok(Event::DocType(_)) => {},
            }
        }
    }
}

impl <T: FromStr + Number> XmlDeserializable for T
    where PError: From<<T as FromStr>::Err> {
    fn from_xml(reader: &mut Reader<&[u8]>, _: Option<&BytesStart>, _tag_name: Option<&str>)  -> Result<Option<Self>, PError> {

        loop {
              match reader.read_event() {
                Err(error) =>  { return Err(PError::new(&format!("Error at position {}: {:?}", reader.buffer_position(), error))) },
                Ok(Event::Eof) => {},
                Ok(Event::Start(_)) => {},
                Ok(Event::End(_)) => {  return Ok(Some("0".parse()?)); },
                Ok(Event::Empty(_)) => { return Ok(Some("0".parse()?)); },
                Ok(Event::Comment(_)) => {},
                Ok(Event::Text(event)) => {
                    let raw_string = String::from_utf8(event.to_vec())?;
                    return if raw_string.is_empty() { Ok(Some("0".parse()?)) } else { Ok(Some(raw_string.parse()?)) };
                },
                Ok(Event::CData(event)) => {
                    let raw_string = String::from_utf8(event.to_vec())?;
                    return if raw_string.is_empty() { Ok(Some("0".parse()?)) } else { Ok(Some(raw_string.parse()?)) };
                },
                Ok(Event::Decl(_)) => {},
                Ok(Event::PI(_)) => {},
                Ok(Event::DocType(_)) => {},
            }
        }
    }
}


impl XmlDeserializable for bool {
    fn from_xml(reader: &mut Reader<&[u8]>, _: Option<&BytesStart>, _tag_name: Option<&str>)  -> Result<Option<Self>, PError> {
        loop {
            match reader.read_event() {
                Err(error) =>  { return Err(PError::new(&format!("Error at position {}: {:?}", reader.buffer_position(), error))) },
                Ok(Event::Eof) => {},
                Ok(Event::Start(_)) => {},
                Ok(Event::End(_)) => { return Ok(None); },
                Ok(Event::Empty(_)) => { return Ok(None); },
                Ok(Event::Comment(_)) => {},
                Ok(Event::Text(event)) => {
                    return Ok(Some(String::from_utf8(event.to_vec())?.parse()?))
                },
                Ok(Event::CData(event)) => {
                    return Ok(Some(String::from_utf8(event.to_vec())?.parse()?))
                },
                Ok(Event::Decl(_)) => {},
                Ok(Event::PI(_)) => {},
                Ok(Event::DocType(_)) => {},
            }
        }
    }
}