exml/tree/
namespace.rs

1// Copyright of the original code is the following.
2// --------
3// Summary: interfaces for tree manipulation
4// Description: this module describes the structures found in an tree resulting
5//              from an XML or HTML parsing, as well as the API provided for
6//              various processing on that tree
7//
8// Copy: See Copyright for the status of this software.
9//
10// Author: Daniel Veillard
11// --------
12// tree.c : implementation of access function for an XML tree.
13//
14// References:
15//   XHTML 1.0 W3C REC: http://www.w3.org/TR/2002/REC-xhtml1-20020801/
16//
17// See Copyright for the status of this software.
18//
19// daniel@veillard.com
20
21use std::{
22    any::type_name,
23    borrow::Cow,
24    ops::{Deref, DerefMut},
25    os::raw::c_void,
26    ptr::{NonNull, null_mut},
27};
28
29use super::{
30    InvalidNodePointerCastError, NodeCommon, XML_LOCAL_NAMESPACE, XML_XML_NAMESPACE, XmlDocPtr,
31    XmlElementType, XmlGenericNodePtr, XmlNodePtr, XmlNsType, xml_tree_err_memory,
32};
33
34#[repr(C)]
35pub struct XmlNs {
36    pub next: Option<XmlNsPtr>,            /* next Ns link for this node  */
37    pub(crate) typ: XmlNsType,             /* global or local */
38    pub href: Option<Box<str>>,            /* URL for the namespace */
39    pub prefix: Option<Box<str>>,          /* prefix for the namespace */
40    pub _private: *mut c_void,             /* application data */
41    pub(crate) context: Option<XmlDocPtr>, /* normally an xmlDoc */
42    /// For XPath. Not used except for XPath.
43    /// In the original libxml2, in order to handle namespaces and nodes as a set,
44    /// the `next` is set to the node that will be the set.
45    /// However, this crate provides a separate member for XPath.
46    pub node: Option<XmlGenericNodePtr>,
47}
48
49impl XmlNs {
50    pub fn prefix(&self) -> Option<Cow<'_, str>> {
51        self.prefix.as_deref().map(Cow::Borrowed)
52    }
53
54    pub fn href(&self) -> Option<Cow<'_, str>> {
55        self.href.as_deref().map(Cow::Borrowed)
56    }
57
58    /// Read the value of a node, this can be either the text carried
59    /// directly by this node if it's a TEXT node or the aggregate string
60    /// of the values carried by this node child's (TEXT and ENTITY_REF).  
61    ///
62    /// Entity references are substituted.
63    ///
64    /// Returns a new #XmlChar * or null_mut() if no content is available.  
65    /// It's up to the caller to free the memory with xml_free().
66    #[doc(alias = "xmlNodeGetContent")]
67    pub fn get_content(&self) -> Option<String> {
68        assert!(matches!(
69            self.element_type(),
70            XmlElementType::XmlNamespaceDecl
71        ));
72        self.href().map(|href| href.into_owned())
73    }
74
75    /// Read the value of a node `cur`, this can be either the text carried
76    /// directly by this node if it's a TEXT node or the aggregate string
77    /// of the values carried by this node child's (TEXT and ENTITY_REF).
78    ///
79    /// Entity references are substituted. Fills up the buffer `buf` with this value.
80    ///
81    /// Returns 0 in case of success and -1 in case of error.
82    #[doc(alias = "xmlBufGetNodeContent")]
83    pub fn get_content_to(&self, buf: &mut String) -> i32 {
84        assert!(matches!(
85            self.element_type(),
86            XmlElementType::XmlNamespaceDecl
87        ));
88        buf.push_str(self.href().unwrap().as_ref());
89
90        0
91    }
92}
93
94impl Default for XmlNs {
95    fn default() -> Self {
96        Self {
97            next: None,
98            typ: XmlNsType::XmlNamespaceDecl,
99            href: None,
100            prefix: None,
101            _private: null_mut(),
102            context: None,
103            node: None,
104        }
105    }
106}
107
108impl NodeCommon for XmlNs {
109    fn document(&self) -> Option<XmlDocPtr> {
110        self.context
111    }
112    fn set_document(&mut self, doc: Option<XmlDocPtr>) {
113        self.context = doc;
114    }
115    fn element_type(&self) -> XmlElementType {
116        self.typ
117    }
118    fn name(&self) -> Option<Cow<'_, str>> {
119        self.href()
120    }
121    fn children(&self) -> Option<XmlGenericNodePtr> {
122        None
123    }
124    fn set_children(&mut self, _children: Option<XmlGenericNodePtr>) {}
125    fn last(&self) -> Option<XmlGenericNodePtr> {
126        None
127    }
128    fn set_last(&mut self, _last: Option<XmlGenericNodePtr>) {}
129    fn next(&self) -> Option<XmlGenericNodePtr> {
130        self.next.map(|ns| ns.into())
131    }
132    fn set_next(&mut self, next: Option<XmlGenericNodePtr>) {
133        self.next = next.map(|p| XmlNsPtr::try_from(p).unwrap());
134    }
135    fn prev(&self) -> Option<XmlGenericNodePtr> {
136        None
137    }
138    fn set_prev(&mut self, _prev: Option<XmlGenericNodePtr>) {}
139    fn parent(&self) -> Option<XmlGenericNodePtr> {
140        None
141    }
142    fn set_parent(&mut self, _parent: Option<XmlGenericNodePtr>) {}
143
144    fn unlink(&mut self) {}
145}
146
147#[derive(PartialEq, Eq, PartialOrd, Ord)]
148pub struct XmlNsPtr(NonNull<XmlNs>);
149
150impl XmlNsPtr {
151    /// Allocate new memory and create new `XmlNsPtr` from an owned xml node.
152    ///
153    /// This method leaks allocated memory.  
154    /// Users can use `free` method for deallocating memory.
155    pub(crate) fn new(node: XmlNs) -> Option<Self> {
156        let boxed = Box::new(node);
157        NonNull::new(Box::leak(boxed)).map(Self)
158    }
159
160    /// Create `XmlNsPtr` from a raw pointer.  
161    ///
162    /// If `ptr` is a NULL pointer, return `Ok(None)`.  
163    /// If `ptr` is a valid pointer of `XmlNs`, return `Ok(Some(Self))`.  
164    /// Otherwise, return `Err`.
165    ///
166    /// # Safety
167    /// - `ptr` must be a pointer of types that is implemented `NodeCommon` at least.
168    ///
169    /// # Todo
170    /// - Fix to the private method.
171    pub unsafe fn from_raw(ptr: *mut XmlNs) -> Result<Option<Self>, InvalidNodePointerCastError> {
172        unsafe {
173            if ptr.is_null() {
174                return Ok(None);
175            }
176            match (*ptr).element_type() {
177                XmlElementType::XmlNamespaceDecl => Ok(Some(Self(NonNull::new_unchecked(ptr)))),
178                _ => Err(InvalidNodePointerCastError {
179                    from: (*ptr).element_type(),
180                    to: type_name::<Self>(),
181                }),
182            }
183        }
184    }
185
186    // pub(crate) fn as_ptr(self) -> *mut XmlNs {
187    //     self.0.as_ptr()
188    // }
189
190    /// Deallocate memory.
191    ///
192    /// # Safety
193    /// This method should be called only once.  
194    /// If called more than twice, the behavior is undefined.
195    pub(crate) unsafe fn free(self) {
196        unsafe {
197            let _ = *Box::from_raw(self.0.as_ptr());
198        }
199    }
200
201    // /// Acquire the ownership of the inner value.
202    // /// As a result, `self` will be invalid. `self` must not be used after performs this method.
203    // ///
204    // /// # Safety
205    // /// This method should be called only once.
206    // /// If called more than twice, the behavior is undefined.
207    // pub(crate) unsafe fn into_inner(self) -> Box<XmlNs> {
208    //     unsafe { Box::from_raw(self.0.as_ptr()) }
209    // }
210}
211
212impl Clone for XmlNsPtr {
213    fn clone(&self) -> Self {
214        *self
215    }
216}
217
218impl Copy for XmlNsPtr {}
219
220impl Deref for XmlNsPtr {
221    type Target = XmlNs;
222    fn deref(&self) -> &Self::Target {
223        // # Safety
224        // I don't implement the pointer casting and addition/subtraction methods
225        // and don't expose the inner `NonNull` for `*mut XmlNs`.
226        // Therefore, as long as the constructor is correctly implemented,
227        // the pointer dereference is valid.
228        unsafe { self.0.as_ref() }
229    }
230}
231
232impl DerefMut for XmlNsPtr {
233    fn deref_mut(&mut self) -> &mut Self::Target {
234        // # Safety
235        // I don't implement the pointer casting and addition/subtraction methods
236        // and don't expose the inner `NonNull` for `*mut XmlNs`.
237        // Therefore, as long as the constructor is correctly implemented,
238        // the pointer dereference is valid.
239        unsafe { self.0.as_mut() }
240    }
241}
242
243impl TryFrom<XmlGenericNodePtr> for XmlNsPtr {
244    type Error = InvalidNodePointerCastError;
245
246    fn try_from(value: XmlGenericNodePtr) -> Result<Self, Self::Error> {
247        match value.element_type() {
248            XmlElementType::XmlNamespaceDecl => Ok(Self(value.0.cast())),
249            _ => Err(InvalidNodePointerCastError {
250                from: value.element_type(),
251                to: type_name::<Self>(),
252            }),
253        }
254    }
255}
256
257impl From<XmlNsPtr> for XmlGenericNodePtr {
258    fn from(value: XmlNsPtr) -> Self {
259        Self(value.0 as NonNull<dyn NodeCommon>)
260    }
261}
262
263impl From<XmlNsPtr> for *mut XmlNs {
264    fn from(value: XmlNsPtr) -> Self {
265        value.0.as_ptr()
266    }
267}
268
269/// Creation of a new Namespace. This function will refuse to create
270/// a namespace with a similar prefix than an existing one present on this node.
271/// Note that for a default namespace, `prefix` should be NULL.
272///
273/// We use href == NULL in the case of an element creation where the namespace was not defined.
274///
275/// Returns a new namespace pointer or NULL
276#[doc(alias = "xmlNewNs")]
277pub fn xml_new_ns(
278    node: Option<XmlNodePtr>,
279    href: Option<&str>,
280    prefix: Option<&str>,
281) -> Option<XmlNsPtr> {
282    if node.is_some_and(|node| node.element_type() != XmlElementType::XmlElementNode) {
283        return None;
284    }
285
286    if prefix == Some("xml") {
287        // xml namespace is predefined, no need to add it
288        if href == Some(XML_XML_NAMESPACE) {
289            return None;
290        }
291
292        // Problem, this is an attempt to bind xml prefix to a wrong
293        // namespace, which breaks
294        // Namespace constraint: Reserved Prefixes and Namespace Names
295        // from XML namespace. But documents authors may not care in
296        // their context so let's proceed.
297    }
298
299    // Allocate a new Namespace and fill the fields.
300    let Some(mut cur) = XmlNsPtr::new(XmlNs {
301        typ: XML_LOCAL_NAMESPACE,
302        ..Default::default()
303    }) else {
304        xml_tree_err_memory("building namespace");
305        return None;
306    };
307
308    cur.href = href.map(|href| href.into());
309    cur.prefix = prefix.map(|prefix| prefix.into());
310
311    // Add it at the end to preserve parsing order ...
312    // and checks for existing use of the prefix
313    if let Some(mut node) = node {
314        if let Some(ns_def) = node.ns_def {
315            let mut prev = ns_def;
316            if prev.prefix == cur.prefix {
317                unsafe {
318                    // # Safety
319                    // `cur` is created this function and it is not leaked from here.
320                    xml_free_ns(cur);
321                }
322                return None;
323            }
324            while let Some(next) = prev.next {
325                prev = next;
326                if prev.prefix == cur.prefix {
327                    unsafe {
328                        // # Safety
329                        // `cur` is created this function and it is not leaked from here.
330                        xml_free_ns(cur);
331                    }
332                    return None;
333                }
334            }
335            prev.next = Some(cur);
336        } else {
337            node.ns_def = Some(cur);
338        }
339    }
340    Some(cur)
341}
342
343/// Free up the structures associated to a namespace
344#[doc(alias = "xmlFreeNs")]
345pub unsafe fn xml_free_ns(cur: XmlNsPtr) {
346    unsafe {
347        cur.free();
348    }
349}
350
351/// Free up all the structures associated to the chained namespaces.
352#[doc(alias = "xmlFreeNsList")]
353pub unsafe fn xml_free_ns_list(cur: XmlNsPtr) {
354    unsafe {
355        let mut next = cur.next;
356        xml_free_ns(cur);
357        while let Some(now) = next {
358            next = now.next;
359            xml_free_ns(now);
360        }
361    }
362}