Skip to main content

libxml_rs/abi/
exports_xml2.rs

1//! C ABI exports for libxml2.so.2 — no_mangle extern "C" functions (§1, §16).
2//!
3//! This module contains all `#[no_mangle] pub extern "C"` function definitions
4//! that form the public ABI of libxml2.so.2. Every function here corresponds to
5//! a function in the upstream libxml2 headers.
6//!
7//! # Phase 1 status
8//!
9//! Complete — all major ABI entry points are implemented. Functions that require
10//! modules not yet implemented (tree, parser, etc.) call into those modules,
11//! which will be filled in as Phase 1 continues.
12//!
13//! # Organization
14//!
15//! Exports are grouped by subsystem in the order they appear in upstream headers:
16//!
17//! 1. Initialization / Cleanup
18//! 2. Version
19//! 3. Memory / Allocator
20//! 4. Error handling
21//! 5. String utilities
22//! 6. Tree (document, node, attribute, namespace, DTD, entity)
23//! 7. Parser (SAX, DOM, push, reader)
24//! 8. I/O
25//! 9. Dictionary
26//! 10. Hash table
27//! 11. List
28//! 12. Buffer
29//! 13. Encoding
30//! 14. XPath
31//! 15. XInclude
32//! 16. Catalog
33//! 17. HTML
34//! 18. Debug/misc
35
36#![allow(non_snake_case)]
37#![allow(unused_variables)]
38#![allow(clippy::missing_safety_doc)]
39#![allow(clippy::not_unsafe_ptr_arg_deref)]
40
41use core::ffi::c_void;
42use core::ptr;
43use std::mem::size_of;
44use std::os::raw::{c_char, c_int, c_uint};
45
46use crate::abi::allocator::*;
47use crate::abi::callbacks::*;
48use crate::abi::ownership::*;
49use crate::abi::structs::*;
50use crate::abi::types::xmlAttributeType::XML_ATTRIBUTE_CDATA;
51use crate::abi::types::xmlElementType::*;
52use crate::abi::types::xmlErrorLevel::XML_ERR_NONE;
53use crate::abi::types::*;
54use crate::abi::versioning::*;
55
56// ═══════════════════════════════════════════════════════════════════════════════
57// 1. Initialization / Cleanup
58// ═══════════════════════════════════════════════════════════════════════════════
59
60/// Initialize the parser library.
61///
62/// Must be called before any other libxml2 functions.
63/// Safe to call multiple times (reference-counted in modern libxml2).
64///
65/// # UPSTREAM-PARITY
66///
67/// ```c
68/// void xmlInitParser(void);
69/// ```
70#[no_mangle]
71pub unsafe extern "C" fn xmlInitParser() {
72    crate::internal::globals::init_parser();
73}
74
75/// Clean up the parser library.
76///
77/// Should be called when the library is no longer needed.
78///
79/// # UPSTREAM-PARITY
80///
81/// ```c
82/// void xmlCleanupParser(void);
83/// ```
84#[no_mangle]
85pub unsafe extern "C" fn xmlCleanupParser() {
86    crate::internal::globals::cleanup_parser();
87}
88
89/// Initialize threading support.
90///
91/// # UPSTREAM-PARITY
92///
93/// ```c
94/// int xmlInitThreads(void);
95/// ```
96///
97/// Returns 0 on success.
98#[no_mangle]
99pub unsafe extern "C" fn xmlInitThreads() -> c_int {
100    crate::internal::globals::init_threads()
101}
102
103/// Clean up threading support.
104///
105/// # UPSTREAM-PARITY
106///
107/// ```c
108/// void xmlCleanupThreads(void);
109/// ```
110#[no_mangle]
111pub unsafe extern "C" fn xmlCleanupThreads() {
112    crate::xml::threads::cleanup_threads();
113}
114
115/// Check whether the library has been initialized.
116///
117/// # UPSTREAM-PARITY
118///
119/// ```c
120/// int xmlIsInitialized(void);
121/// ```
122#[no_mangle]
123pub extern "C" fn xmlIsInitialized() -> c_int {
124    if crate::abi::versioning::is_initialized() {
125        1
126    } else {
127        0
128    }
129}
130
131/// Initialize a set of threads (libxml2 compat).
132///
133/// # UPSTREAM-PARITY
134///
135/// ```c
136/// int xmlInitThreads(void);
137/// ```
138/// This is an alias.
139#[no_mangle]
140pub unsafe extern "C" fn xmlLockLibrary() {
141    crate::xml::threads::lock_library();
142}
143
144/// Unlock the library (libxml2 compat).
145///
146/// # UPSTREAM-PARITY
147///
148/// ```c
149/// void xmlUnlockLibrary(void);
150/// ```
151#[no_mangle]
152pub unsafe extern "C" fn xmlUnlockLibrary() {
153    crate::xml::threads::unlock_library();
154}
155
156// ═══════════════════════════════════════════════════════════════════════════════
157// 4. Error Handling
158// ═══════════════════════════════════════════════════════════════════════════════
159
160/// Set the generic error handler.
161///
162/// # UPSTREAM-PARITY
163///
164/// ```c
165/// void xmlSetGenericErrorFunc(void *ctx, xmlGenericErrorFunc handler);
166/// ```
167///
168/// # SAFETY
169///
170/// - `handler` must be a valid function pointer or NULL (to reset to default).
171/// - If non-NULL, the handler may be called at any time with `ctx`.
172#[no_mangle]
173pub unsafe extern "C" fn xmlSetGenericErrorFunc(
174    ctx: *mut c_void,
175    handler: Option<xmlGenericErrorFunc>,
176) {
177    // SAFETY: Delegates to xml::errors with same safety contract.
178    unsafe { crate::xml::errors::set_generic_error_func(ctx, handler) };
179}
180
181/// Set the structured error handler.
182///
183/// # UPSTREAM-PARITY
184///
185/// ```c
186/// void xmlSetStructuredErrorFunc(void *ctx, xmlStructuredErrorFunc handler);
187/// ```
188///
189/// # SAFETY
190///
191/// - `handler` must be a valid function pointer or NULL.
192#[no_mangle]
193pub unsafe extern "C" fn xmlSetStructuredErrorFunc(
194    ctx: *mut c_void,
195    handler: Option<xmlStructuredErrorFunc>,
196) {
197    // SAFETY: Delegates to xml::errors with same safety contract.
198    unsafe { crate::xml::errors::set_structured_error_func(ctx, handler) };
199}
200
201/// Get the last error for the current thread.
202///
203/// # UPSTREAM-PARITY
204///
205/// ```c
206/// xmlErrorPtr xmlGetLastError(void);
207/// ```
208///
209/// Returns a pointer to the last error, or NULL if no error occurred.
210/// The returned pointer is valid until the next libxml2 call in this thread.
211#[no_mangle]
212pub extern "C" fn xmlGetLastError() -> *mut _xmlError {
213    crate::xml::errors::get_last_error()
214}
215
216/// Get a copy of the last error for the current thread.
217///
218/// # UPSTREAM-PARITY
219///
220/// ```c
221/// xmlErrorPtr xmlCopyError(xmlErrorPtr from, xmlErrorPtr to);
222/// ```
223///
224/// Copies `from` into `to`. Returns 0 on success, -1 on error.
225///
226/// # SAFETY
227///
228/// - `from` and `to` must be valid pointers to `_xmlError` structs, or NULL.
229#[no_mangle]
230pub unsafe extern "C" fn xmlCopyError(from: *const _xmlError, to: *mut _xmlError) -> c_int {
231    // SAFETY: Delegates to xml::errors with same safety contract.
232    unsafe { crate::xml::errors::copy_error(from, to) }
233}
234
235/// Reset an error structure.
236///
237/// # UPSTREAM-PARITY
238///
239/// ```c
240/// void xmlResetError(xmlErrorPtr err);
241/// ```
242///
243/// # SAFETY
244///
245/// - `err` must be a valid pointer to `_xmlError`, or NULL.
246#[no_mangle]
247pub unsafe extern "C" fn xmlResetError(err: *mut _xmlError) {
248    // SAFETY: Delegates to xml::errors with same safety contract.
249    unsafe { crate::xml::errors::reset_error(err) };
250}
251
252/// Raise a structured error.
253///
254/// This is called internally when an error occurs. It updates the last error
255/// and invokes the structured error handler if one is set.
256///
257/// # SAFETY
258///
259/// - `ctxt` may be NULL (context of the error).
260/// - `domain`, `code`, `level`: valid error codes.
261/// - `msg` must be a valid C string or NULL.
262/// - `file` must be a valid C string or NULL.
263/// - `str1`, `str2`, `str3`: error-related strings (may be NULL).
264#[no_mangle]
265pub unsafe extern "C" fn xmlRaiseError(
266    ctxt: *mut c_void,
267    ctxt2: *mut c_void,
268    ctxt3: *mut c_void,
269    ctxt4: *mut c_void,
270    ctxt5: *mut c_void,
271    domain: c_int,
272    code: c_int,
273    level: c_int,
274    file: *const c_char,
275    line: c_int,
276    str1: *const c_char,
277    str2: *const c_char,
278    str3: *const c_char,
279    int1: c_int,
280    int2: c_int,
281    msg: *const c_char,
282) {
283    // SAFETY: Delegates to xml::errors with same safety contract.
284    unsafe {
285        crate::xml::errors::raise_error(
286            ctxt, ctxt2, ctxt3, ctxt4, ctxt5, domain, code, level, file, line, str1, str2, str3,
287            int1, int2, msg,
288        );
289    }
290}
291
292/// Remove any error from the last error stack.
293///
294/// # UPSTREAM-PARITY
295///
296/// ```c
297/// void xmlResetLastError(void);
298/// ```
299#[no_mangle]
300pub extern "C" fn xmlResetLastError() {
301    crate::xml::errors::reset_last_error();
302}
303
304// ═══════════════════════════════════════════════════════════════════════════════
305// 5. String Utilities
306// ═══════════════════════════════════════════════════════════════════════════════
307
308/// Duplicate a string using xmlChar.
309///
310/// # UPSTREAM-PARITY
311///
312/// ```c
313/// xmlChar *xmlStrdup(const xmlChar *cur);
314/// ```
315///
316/// # SAFETY
317///
318/// - `cur` must be a valid null-terminated xmlChar string or NULL.
319#[no_mangle]
320pub unsafe extern "C" fn xmlStrdup(cur: *const xmlChar) -> *mut xmlChar {
321    if cur.is_null() {
322        return ptr::null_mut();
323    }
324    let len = unsafe { xmlStrlen(cur) };
325    let size = len + 1;
326    let new_ptr = unsafe { xmlMalloc(size as usize) };
327    if new_ptr.is_null() {
328        return ptr::null_mut();
329    }
330    unsafe {
331        ptr::copy_nonoverlapping(cur as *const u8, new_ptr as *mut u8, size as usize);
332    }
333    new_ptr as *mut xmlChar
334}
335
336/// Duplicate a substring.
337///
338/// # UPSTREAM-PARITY
339///
340/// ```c
341/// xmlChar *xmlStrndup(const xmlChar *cur, int len);
342/// ```
343///
344/// # SAFETY
345///
346/// - `cur` must be a valid pointer or NULL.
347#[no_mangle]
348pub unsafe extern "C" fn xmlStrndup(cur: *const xmlChar, len: c_int) -> *mut xmlChar {
349    if cur.is_null() || len <= 0 {
350        return ptr::null_mut();
351    }
352    let size = len as usize + 1;
353    let new_ptr = unsafe { xmlMalloc(size) };
354    if new_ptr.is_null() {
355        return ptr::null_mut();
356    }
357    unsafe {
358        ptr::copy_nonoverlapping(cur as *const u8, new_ptr as *mut u8, len as usize);
359        *(new_ptr.add(len as usize) as *mut u8) = 0;
360    }
361    new_ptr as *mut xmlChar
362}
363
364/// Get the length of an xmlChar string.
365///
366/// # UPSTREAM-PARITY
367///
368/// ```c
369/// int xmlStrlen(const xmlChar *str);
370/// ```
371///
372/// # SAFETY
373///
374/// - `str` must be a valid null-terminated string or NULL (returns 0).
375#[no_mangle]
376pub unsafe extern "C" fn xmlStrlen(str: *const xmlChar) -> c_int {
377    if str.is_null() {
378        return 0;
379    }
380    unsafe { libc::strlen(str as *const c_char) as c_int }
381}
382
383/// Compare two xmlChar strings.
384///
385/// # UPSTREAM-PARITY
386///
387/// ```c
388/// int xmlStrcmp(const xmlChar *str1, const xmlChar *str2);
389/// ```
390///
391/// Returns 0 if equal, <0 if str1 < str2, >0 if str1 > str2.
392/// NULL-safe: NULL sorts before any non-NULL string.
393#[no_mangle]
394pub unsafe extern "C" fn xmlStrcmp(str1: *const xmlChar, str2: *const xmlChar) -> c_int {
395    if str1.is_null() && str2.is_null() {
396        return 0;
397    }
398    if str1.is_null() {
399        return -1;
400    }
401    if str2.is_null() {
402        return 1;
403    }
404    unsafe { libc::strcmp(str1 as *const c_char, str2 as *const c_char) as c_int }
405}
406
407/// Compare two xmlChar strings up to a given length.
408///
409/// # UPSTREAM-PARITY
410///
411/// ```c
412/// int xmlStrncmp(const xmlChar *str1, const xmlChar *str2, int len);
413/// ```
414#[no_mangle]
415pub unsafe extern "C" fn xmlStrncmp(
416    str1: *const xmlChar,
417    str2: *const xmlChar,
418    len: c_int,
419) -> c_int {
420    if len <= 0 {
421        return 0;
422    }
423    if str1.is_null() && str2.is_null() {
424        return 0;
425    }
426    if str1.is_null() {
427        return -1;
428    }
429    if str2.is_null() {
430        return 1;
431    }
432    unsafe { libc::strncmp(str1 as *const c_char, str2 as *const c_char, len as usize) as c_int }
433}
434
435/// Case-insensitive comparison of two xmlChar strings.
436///
437/// # UPSTREAM-PARITY
438///
439/// ```c
440/// int xmlStrcasecmp(const xmlChar *str1, const xmlChar *str2);
441/// ```
442#[no_mangle]
443pub unsafe extern "C" fn xmlStrcasecmp(str1: *const xmlChar, str2: *const xmlChar) -> c_int {
444    if str1.is_null() && str2.is_null() {
445        return 0;
446    }
447    if str1.is_null() {
448        return -1;
449    }
450    if str2.is_null() {
451        return 1;
452    }
453    unsafe { libc::strcasecmp(str1 as *const c_char, str2 as *const c_char) as c_int }
454}
455
456/// Case-insensitive comparison with length limit.
457///
458/// # UPSTREAM-PARITY
459///
460/// ```c
461/// int xmlStrncasecmp(const xmlChar *str1, const xmlChar *str2, int len);
462/// ```
463#[no_mangle]
464pub unsafe extern "C" fn xmlStrncasecmp(
465    str1: *const xmlChar,
466    str2: *const xmlChar,
467    len: c_int,
468) -> c_int {
469    if len <= 0 {
470        return 0;
471    }
472    if str1.is_null() && str2.is_null() {
473        return 0;
474    }
475    if str1.is_null() {
476        return -1;
477    }
478    if str2.is_null() {
479        return 1;
480    }
481    unsafe {
482        libc::strncasecmp(str1 as *const c_char, str2 as *const c_char, len as usize) as c_int
483    }
484}
485
486/// Check if two xmlChar strings are equal.
487///
488/// # UPSTREAM-PARITY
489///
490/// ```c
491/// int xmlStrEqual(const xmlChar *str1, const xmlChar *str2);
492/// ```
493///
494/// Returns 1 if equal, 0 if not. NULL-safe.
495#[no_mangle]
496pub unsafe extern "C" fn xmlStrEqual(str1: *const xmlChar, str2: *const xmlChar) -> c_int {
497    if str1.is_null() && str2.is_null() {
498        return 1;
499    }
500    if str1.is_null() || str2.is_null() {
501        return 0;
502    }
503    unsafe { (libc::strcmp(str1 as *const c_char, str2 as *const c_char) == 0) as c_int }
504}
505
506/// Check if an xmlChar string equals a qualified name.
507///
508/// # UPSTREAM-PARITY
509///
510/// ```c
511/// int xmlStrQEqual(const xmlChar *pref, const xmlChar *name, const xmlChar *str);
512/// ```
513///
514/// Returns 1 if `pref:name` equals `str`, 0 otherwise.
515/// `pref` may be NULL (compares only name).
516#[no_mangle]
517pub unsafe extern "C" fn xmlStrQEqual(
518    pref: *const xmlChar,
519    name: *const xmlChar,
520    str: *const xmlChar,
521) -> c_int {
522    if name.is_null() || str.is_null() {
523        return 0;
524    }
525    if pref.is_null() {
526        return unsafe { xmlStrEqual(name, str) };
527    }
528    // Compare "pref:name" with str
529    let pref_len = unsafe { xmlStrlen(pref) };
530    let name_len = unsafe { xmlStrlen(name) };
531    let total_len = pref_len + 1 + name_len;
532    let str_len = unsafe { xmlStrlen(str) };
533    if total_len != str_len {
534        return 0;
535    }
536    // Compare prefix part
537    if unsafe {
538        libc::strncmp(
539            pref as *const c_char,
540            str as *const c_char,
541            pref_len as usize,
542        )
543    } != 0
544    {
545        return 0;
546    }
547    // Check colon
548    if unsafe { *str.add(pref_len as usize) } != b':' as xmlChar {
549        return 0;
550    }
551    // Compare name part
552    (unsafe {
553        libc::strncmp(
554            name as *const c_char,
555            str.add((pref_len + 1) as usize) as *const c_char,
556            name_len as usize,
557        ) == 0
558    }) as c_int
559}
560
561/// Concatenate two strings.
562///
563/// # UPSTREAM-PARITY
564///
565/// ```c
566/// xmlChar *xmlStrcat(xmlChar *cur, const xmlChar *add);
567/// ```
568///
569/// # SAFETY
570///
571/// - `cur` must be a valid xmlMalloc'd string or NULL.
572/// - `add` must be a valid string or NULL.
573/// - If `cur` is NULL, behaves like xmlStrdup(add).
574#[no_mangle]
575pub unsafe extern "C" fn xmlStrcat(cur: *mut xmlChar, add: *const xmlChar) -> *mut xmlChar {
576    if add.is_null() {
577        return cur;
578    }
579    if cur.is_null() {
580        return unsafe { xmlStrdup(add) };
581    }
582    let cur_len = unsafe { xmlStrlen(cur) } as usize;
583    let add_len = unsafe { xmlStrlen(add) } as usize;
584    let new_size = cur_len + add_len + 1;
585    let new_ptr = unsafe { xmlRealloc(cur as *mut c_void, new_size) };
586    if new_ptr.is_null() {
587        return ptr::null_mut();
588    }
589    unsafe {
590        ptr::copy_nonoverlapping(add as *const u8, (new_ptr as *mut u8).add(cur_len), add_len);
591        *((new_ptr as *mut u8).add(cur_len + add_len)) = 0;
592    }
593    new_ptr as *mut xmlChar
594}
595
596/// Concatenate up to `len` characters.
597///
598/// # UPSTREAM-PARITY
599///
600/// ```c
601/// xmlChar *xmlStrncat(xmlChar *cur, const xmlChar *add, int len);
602/// ```
603///
604/// # SAFETY
605///
606/// Same as xmlStrcat, but only copies up to `len` characters from `add`.
607#[no_mangle]
608pub unsafe extern "C" fn xmlStrncat(
609    cur: *mut xmlChar,
610    add: *const xmlChar,
611    len: c_int,
612) -> *mut xmlChar {
613    if add.is_null() || len <= 0 {
614        return cur;
615    }
616    let len = len as usize;
617    if cur.is_null() {
618        return unsafe { xmlStrndup(add, len as c_int) };
619    }
620    let cur_len = unsafe { xmlStrlen(cur) } as usize;
621    let new_size = cur_len + len + 1;
622    let new_ptr = unsafe { xmlRealloc(cur as *mut c_void, new_size) };
623    if new_ptr.is_null() {
624        return ptr::null_mut();
625    }
626    unsafe {
627        ptr::copy_nonoverlapping(add as *const u8, (new_ptr as *mut u8).add(cur_len), len);
628        *((new_ptr as *mut u8).add(cur_len + len)) = 0;
629    }
630    new_ptr as *mut xmlChar
631}
632
633/// Create a new string by concatenating up to `len` characters.
634///
635/// # UPSTREAM-PARITY
636///
637/// ```c
638/// xmlChar *xmlStrncatNew(const xmlChar *str1, const xmlChar *str2, int len);
639/// ```
640#[no_mangle]
641pub unsafe extern "C" fn xmlStrncatNew(
642    str1: *const xmlChar,
643    str2: *const xmlChar,
644    len: c_int,
645) -> *mut xmlChar {
646    let mut result: *mut xmlChar = ptr::null_mut();
647    if !str1.is_null() {
648        result = unsafe { xmlStrdup(str1) };
649    }
650    if !str2.is_null() && len > 0 {
651        result = unsafe { xmlStrncat(result, str2, len) };
652    }
653    result
654}
655
656/// Copy a string.
657///
658/// # UPSTREAM-PARITY
659///
660/// ```c
661/// xmlChar *xmlStrcpy(xmlChar *dst, const xmlChar *src);
662/// ```
663///
664/// # SAFETY
665///
666/// - `dst` must be a valid xmlMalloc'd buffer large enough to hold `src`.
667/// - `src` must be a valid string.
668#[no_mangle]
669pub unsafe extern "C" fn xmlStrcpy(dst: *mut xmlChar, src: *const xmlChar) -> *mut xmlChar {
670    if dst.is_null() || src.is_null() {
671        return dst;
672    }
673    let len = unsafe { xmlStrlen(src) } as usize + 1;
674    unsafe {
675        ptr::copy_nonoverlapping(src as *const u8, dst as *mut u8, len);
676    }
677    dst
678}
679
680/// Copy up to `len` characters.
681///
682/// # UPSTREAM-PARITY
683///
684/// ```c
685/// xmlChar *xmlStrncpy(xmlChar *dst, const xmlChar *src, int len);
686/// ```
687#[no_mangle]
688pub unsafe extern "C" fn xmlStrncpy(
689    dst: *mut xmlChar,
690    src: *const xmlChar,
691    len: c_int,
692) -> *mut xmlChar {
693    if dst.is_null() || src.is_null() || len <= 0 {
694        return dst;
695    }
696    let len = len as usize;
697    let src_len = unsafe { xmlStrlen(src) } as usize;
698    let copy_len = if src_len < len { src_len } else { len - 1 };
699    unsafe {
700        ptr::copy_nonoverlapping(src as *const u8, dst as *mut u8, copy_len);
701        *dst.add(copy_len) = 0;
702    }
703    dst
704}
705
706/// Extract a substring.
707///
708/// # UPSTREAM-PARITY
709///
710/// ```c
711/// xmlChar *xmlStrsub(const xmlChar *str, int start, int len);
712/// ```
713///
714/// Returns a newly allocated substring, or NULL on error.
715#[no_mangle]
716pub unsafe extern "C" fn xmlStrsub(str: *const xmlChar, start: c_int, len: c_int) -> *mut xmlChar {
717    if str.is_null() || start < 0 || len < 0 {
718        return ptr::null_mut();
719    }
720    let str_len = unsafe { xmlStrlen(str) };
721    if start >= str_len {
722        return unsafe { xmlStrdup(b"\0" as *const u8 as *const xmlChar) };
723    }
724    let actual_len = if start + len > str_len {
725        str_len - start
726    } else {
727        len
728    };
729    unsafe { xmlStrndup(str.add(start as usize), actual_len) }
730}
731
732// ═══════════════════════════════════════════════════════════════════════════════
733// 6. Tree — Document, Node, Attribute, Namespace, DTD, Entity
734// ═══════════════════════════════════════════════════════════════════════════════
735
736/// Create a new document.
737///
738/// # UPSTREAM-PARITY
739///
740/// ```c
741/// xmlDocPtr xmlNewDoc(const xmlChar *version);
742/// ```
743///
744/// # SAFETY
745///
746/// - `version` must be a valid string or NULL (defaults to "1.0").
747/// - Returns a newly allocated document. Caller must free with `xmlFreeDoc`.
748#[no_mangle]
749pub unsafe extern "C" fn xmlNewDoc(version: *const xmlChar) -> *mut _xmlDoc {
750    crate::xml::tree::new_doc(version)
751}
752
753/// Free a document.
754///
755/// # UPSTREAM-PARITY
756///
757/// ```c
758/// void xmlFreeDoc(xmlDocPtr doc);
759/// ```
760///
761/// # SAFETY
762///
763/// - `doc` must be a valid document pointer or NULL.
764#[no_mangle]
765pub unsafe extern "C" fn xmlFreeDoc(doc: *mut _xmlDoc) {
766    crate::xml::tree::free_doc(doc);
767}
768
769/// Create a new node.
770///
771/// # UPSTREAM-PARITY
772///
773/// ```c
774/// xmlNodePtr xmlNewNode(xmlNsPtr ns, const xmlChar *name);
775/// ```
776///
777/// # SAFETY
778///
779/// - `ns` may be NULL.
780/// - `name` must be a valid string.
781/// - Returns a newly allocated node. Caller must free with `xmlFreeNode`.
782#[no_mangle]
783pub unsafe extern "C" fn xmlNewNode(ns: *mut _xmlNs, name: *const xmlChar) -> *mut _xmlNode {
784    crate::xml::tree::new_node(ns, name)
785}
786
787/// Free a node.
788///
789/// # UPSTREAM-PARITY
790///
791/// ```c
792/// void xmlFreeNode(xmlNodePtr node);
793/// ```
794///
795/// # SAFETY
796///
797/// - `node` must be a valid node pointer or NULL.
798/// - The node must NOT be part of a document tree (must be unlinked first).
799#[no_mangle]
800pub unsafe extern "C" fn xmlFreeNode(node: *mut _xmlNode) {
801    crate::xml::tree::free_node(node);
802}
803
804/// Unlink a node from its tree.
805///
806/// # UPSTREAM-PARITY
807///
808/// ```c
809/// void xmlUnlinkNode(xmlNodePtr node);
810/// ```
811///
812/// # SAFETY
813///
814/// - `node` must be a valid node pointer or NULL.
815#[no_mangle]
816pub unsafe extern "C" fn xmlUnlinkNode(node: *mut _xmlNode) {
817    crate::xml::tree::unlink_node(node);
818}
819
820/// Add a child node.
821///
822/// # UPSTREAM-PARITY
823///
824/// ```c
825/// xmlNodePtr xmlAddChild(xmlNodePtr parent, xmlNodePtr cur);
826/// ```
827///
828/// # SAFETY
829///
830/// - `parent` must be a valid node.
831/// - `cur` must be a valid node (ownership transfers to parent).
832/// - Returns pointer to the added child (borrowed).
833#[no_mangle]
834pub unsafe extern "C" fn xmlAddChild(parent: *mut _xmlNode, cur: *mut _xmlNode) -> *mut _xmlNode {
835    crate::xml::tree::add_child(parent, cur)
836}
837
838/// Add a sibling node.
839///
840/// # UPSTREAM-PARITY
841///
842/// ```c
843/// xmlNodePtr xmlAddSibling(xmlNodePtr cur, xmlNodePtr sibling);
844/// ```
845///
846/// # SAFETY
847///
848/// Same as xmlAddChild, but adds after `cur` instead of as a child.
849#[no_mangle]
850pub unsafe extern "C" fn xmlAddSibling(
851    cur: *mut _xmlNode,
852    sibling: *mut _xmlNode,
853) -> *mut _xmlNode {
854    crate::xml::tree::add_sibling(cur, sibling)
855}
856
857/// Create a new child element.
858///
859/// # UPSTREAM-PARITY
860///
861/// ```c
862/// xmlNodePtr xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
863///                        const xmlChar *name, const xmlChar *content);
864/// ```
865///
866/// Creates a new element node, adds it as a child of `parent`, and
867/// sets its content if `content` is non-NULL.
868///
869/// # SAFETY
870///
871/// - `parent` must be a valid node (may be NULL).
872/// - `ns` may be NULL.
873/// - `name` must be a valid string.
874/// - Returns a newly allocated node (owned by parent).
875#[no_mangle]
876pub unsafe extern "C" fn xmlNewChild(
877    parent: *mut _xmlNode,
878    ns: *mut _xmlNs,
879    name: *const xmlChar,
880    content: *const xmlChar,
881) -> *mut _xmlNode {
882    crate::xml::tree::new_child(parent, ns, name)
883}
884
885/// Set the root element of a document.
886///
887/// # UPSTREAM-PARITY
888///
889/// ```c
890/// xmlNodePtr xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root);
891/// ```
892///
893/// Returns the old root element (if any), which the caller must free.
894///
895/// # SAFETY
896///
897/// - `doc` must be a valid document.
898/// - `root` must be a valid node (ownership transfers to doc).
899#[no_mangle]
900pub unsafe extern "C" fn xmlDocSetRootElement(
901    doc: *mut _xmlDoc,
902    root: *mut _xmlNode,
903) -> *mut _xmlNode {
904    crate::xml::tree::doc_set_root_element(doc, root)
905}
906
907/// Get the root element of a document.
908///
909/// # UPSTREAM-PARITY
910///
911/// ```c
912/// xmlNodePtr xmlDocGetRootElement(const xmlDoc *doc);
913/// ```
914///
915/// Returns a borrowed pointer (do not free).
916#[no_mangle]
917pub extern "C" fn xmlDocGetRootElement(doc: *const _xmlDoc) -> *mut _xmlNode {
918    crate::xml::tree::doc_get_root_element(doc as *mut _xmlDoc)
919}
920
921/// Copy a node.
922///
923/// # UPSTREAM-PARITY
924///
925/// ```c
926/// xmlNodePtr xmlCopyNode(const xmlNodePtr node, int extended);
927/// ```
928///
929/// If `extended` is 1, copies recursively (deep copy).
930/// If `extended` is 0, copies only the node itself (shallow copy).
931///
932/// Returns a newly allocated copy. Caller must free with `xmlFreeNode`.
933#[no_mangle]
934pub unsafe extern "C" fn xmlCopyNode(node: *const _xmlNode, extended: c_int) -> *mut _xmlNode {
935    crate::xml::tree::copy_node(node, extended)
936}
937
938/// Copy a document.
939///
940/// # UPSTREAM-PARITY
941///
942/// ```c
943/// xmlDocPtr xmlCopyDoc(const xmlDocPtr doc, int recursive);
944/// ```
945///
946/// Returns a newly allocated copy. Caller must free with `xmlFreeDoc`.
947#[no_mangle]
948pub unsafe extern "C" fn xmlCopyDoc(doc: *const _xmlDoc, recursive: c_int) -> *mut _xmlDoc {
949    crate::xml::tree::copy_doc(doc, recursive)
950}
951
952/// Create a text node.
953///
954/// # UPSTREAM-PARITY
955///
956/// ```c
957/// xmlNodePtr xmlNewText(const xmlChar *content);
958/// ```
959///
960/// Creates a new text node with the given content.
961/// If `content` is NULL, creates an empty text node.
962#[no_mangle]
963pub unsafe extern "C" fn xmlNewText(content: *const xmlChar) -> *mut _xmlNode {
964    crate::xml::tree::new_text(content)
965}
966
967/// Create a new comment node.
968///
969/// # UPSTREAM-PARITY
970///
971/// ```c
972/// xmlNodePtr xmlNewComment(const xmlChar *content);
973/// ```
974#[no_mangle]
975pub unsafe extern "C" fn xmlNewComment(content: *const xmlChar) -> *mut _xmlNode {
976    crate::xml::tree::new_comment(content)
977}
978
979/// Create a new PI node.
980///
981/// # UPSTREAM-PARITY
982///
983/// ```c
984/// xmlNodePtr xmlNewPI(const xmlChar *name, const xmlChar *content);
985/// ```
986#[no_mangle]
987pub unsafe extern "C" fn xmlNewPI(name: *const xmlChar, content: *const xmlChar) -> *mut _xmlNode {
988    crate::xml::tree::new_pi(name, content)
989}
990
991/// Create a new CDATA node.
992///
993/// # UPSTREAM-PARITY
994///
995/// ```c
996/// xmlNodePtr xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len);
997/// ```
998#[no_mangle]
999pub unsafe extern "C" fn xmlNewCDataBlock(
1000    doc: *mut _xmlDoc,
1001    content: *const xmlChar,
1002    len: c_int,
1003) -> *mut _xmlNode {
1004    crate::xml::tree::new_cdata_block(doc, content, len)
1005}
1006
1007/// Create a new namespace definition.
1008///
1009/// # UPSTREAM-PARITY
1010///
1011/// ```c
1012/// xmlNsPtr xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix);
1013/// ```
1014///
1015/// # SAFETY
1016///
1017/// - `node` may be NULL.
1018/// - `href` and `prefix` are copied.
1019/// - Returns a borrowed pointer (namespace is owned by the node).
1020#[no_mangle]
1021pub unsafe extern "C" fn xmlNewNs(
1022    node: *mut _xmlNode,
1023    href: *const xmlChar,
1024    prefix: *const xmlChar,
1025) -> *mut _xmlNs {
1026    crate::xml::tree::new_ns(node, href, prefix)
1027}
1028
1029/// Set the namespace of a node.
1030///
1031/// # UPSTREAM-PARITY
1032///
1033/// ```c
1034/// void xmlSetNs(xmlNodePtr node, xmlNsPtr ns);
1035/// ```
1036#[no_mangle]
1037pub unsafe extern "C" fn xmlSetNs(node: *mut _xmlNode, ns: *mut _xmlNs) {
1038    crate::xml::tree::set_ns(node, ns);
1039}
1040
1041/// Get the namespace of a node.
1042///
1043/// # UPSTREAM-PARITY
1044///
1045/// ```c
1046/// xmlNsPtr xmlGetNsList(xmlDocPtr doc, const xmlNode *node);
1047/// ```
1048#[no_mangle]
1049pub unsafe extern "C" fn xmlGetNsList(
1050    doc: *mut _xmlDoc,
1051    node: *const _xmlNode,
1052) -> *mut *mut _xmlNs {
1053    crate::xml::tree::get_ns_list(doc, node as *mut _xmlNode)
1054}
1055
1056/// Search for a namespace by href.
1057///
1058/// # UPSTREAM-PARITY
1059///
1060/// ```c
1061/// xmlNsPtr xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace);
1062/// ```
1063#[no_mangle]
1064pub unsafe extern "C" fn xmlSearchNs(
1065    doc: *mut _xmlDoc,
1066    node: *mut _xmlNode,
1067    nameSpace: *const xmlChar,
1068) -> *mut _xmlNs {
1069    crate::xml::tree::search_ns(doc, node, nameSpace)
1070}
1071
1072/// Search for a namespace by href, using the full in-scope chain.
1073///
1074/// # UPSTREAM-PARITY
1075///
1076/// ```c
1077/// xmlNsPtr xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar *href);
1078/// ```
1079#[no_mangle]
1080pub unsafe extern "C" fn xmlSearchNsByHref(
1081    doc: *mut _xmlDoc,
1082    node: *mut _xmlNode,
1083    href: *const xmlChar,
1084) -> *mut _xmlNs {
1085    crate::xml::tree::search_ns_by_href(doc, node, href)
1086}
1087
1088/// Set a property (attribute) on a node.
1089///
1090/// # UPSTREAM-PARITY
1091///
1092/// ```c
1093/// xmlAttrPtr xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value);
1094/// ```
1095///
1096/// If the attribute already exists, its value is updated.
1097/// Returns a borrowed pointer to the attribute.
1098///
1099/// # SAFETY
1100///
1101/// - `node` must be a valid element node.
1102/// - `name` must be a valid string.
1103/// - `value` may be NULL.
1104#[no_mangle]
1105pub unsafe extern "C" fn xmlSetProp(
1106    node: *mut _xmlNode,
1107    name: *const xmlChar,
1108    value: *const xmlChar,
1109) -> *mut _xmlAttr {
1110    crate::xml::tree::set_prop(node, name, value)
1111}
1112
1113/// Get a property value by name.
1114///
1115/// # UPSTREAM-PARITY
1116///
1117/// ```c
1118/// xmlChar *xmlGetProp(const xmlNode *node, const xmlChar *name);
1119/// ```
1120///
1121/// Returns a newly allocated string. Caller must free with `xmlFree`.
1122#[no_mangle]
1123pub unsafe extern "C" fn xmlGetProp(node: *const _xmlNode, name: *const xmlChar) -> *mut xmlChar {
1124    crate::xml::tree::get_prop(node as *mut _xmlNode, name)
1125}
1126
1127/// Get a namespaced property value.
1128///
1129/// # UPSTREAM-PARITY
1130///
1131/// ```c
1132/// xmlChar *xmlGetNsProp(const xmlNode *node, const xmlChar *name, const xmlChar *nameSpace);
1133/// ```
1134#[no_mangle]
1135pub unsafe extern "C" fn xmlGetNsProp(
1136    node: *const _xmlNode,
1137    name: *const xmlChar,
1138    nameSpace: *const xmlChar,
1139) -> *mut xmlChar {
1140    crate::xml::tree::get_ns_prop(node as *mut _xmlNode, name, nameSpace)
1141}
1142
1143/// Set a namespaced property.
1144///
1145/// # UPSTREAM-PARITY
1146///
1147/// ```c
1148/// xmlAttrPtr xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns,
1149///                         const xmlChar *name, const xmlChar *value);
1150/// ```
1151#[no_mangle]
1152pub unsafe extern "C" fn xmlSetNsProp(
1153    node: *mut _xmlNode,
1154    ns: *mut _xmlNs,
1155    name: *const xmlChar,
1156    value: *const xmlChar,
1157) -> *mut _xmlAttr {
1158    crate::xml::tree::set_ns_prop(node, ns, name, value)
1159}
1160
1161/// Remove a property by name.
1162///
1163/// # UPSTREAM-PARITY
1164///
1165/// ```c
1166/// int xmlRemoveProp(xmlAttrPtr attr);
1167/// ```
1168///
1169/// Returns 0 on success, -1 on error.
1170#[no_mangle]
1171pub unsafe extern "C" fn xmlRemoveProp(attr: *mut _xmlAttr) -> c_int {
1172    crate::xml::tree::remove_prop(attr)
1173}
1174
1175/// Get a DTD from a document, creating one if needed.
1176///
1177/// # UPSTREAM-PARITY
1178///
1179/// ```c
1180/// xmlDtdPtr xmlGetIntSubset(const xmlDoc *doc);
1181/// ```
1182#[no_mangle]
1183pub extern "C" fn xmlGetIntSubset(doc: *const _xmlDoc) -> *mut _xmlDtd {
1184    crate::xml::tree::get_int_subset(doc)
1185}
1186
1187/// Create a new DTD.
1188///
1189/// # UPSTREAM-PARITY
1190///
1191/// ```c
1192/// xmlDtdPtr xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
1193///                     const xmlChar *ExternalID, const xmlChar *SystemID);
1194/// ```
1195#[no_mangle]
1196pub unsafe extern "C" fn xmlNewDtd(
1197    doc: *mut _xmlDoc,
1198    name: *const xmlChar,
1199    ExternalID: *const xmlChar,
1200    SystemID: *const xmlChar,
1201) -> *mut _xmlDtd {
1202    crate::xml::tree::new_dtd(doc, name, ExternalID, SystemID)
1203}
1204
1205/// Create a new entity.
1206///
1207/// # UPSTREAM-PARITY
1208///
1209/// ```c
1210/// xmlEntityPtr xmlNewEntity(xmlDocPtr doc, const xmlChar *name, int type,
1211///                           const xmlChar *ExternalID, const xmlChar *SystemID,
1212///                           const xmlChar *content);
1213/// ```
1214#[no_mangle]
1215pub unsafe extern "C" fn xmlNewEntity(
1216    doc: *mut _xmlDoc,
1217    name: *const xmlChar,
1218    type_: c_int,
1219    ExternalID: *const xmlChar,
1220    SystemID: *const xmlChar,
1221    content: *const xmlChar,
1222) -> *mut _xmlEntity {
1223    crate::xml::tree::new_entity(doc, name, type_, ExternalID, SystemID, content)
1224}
1225
1226/// Get an entity by name.
1227///
1228/// # UPSTREAM-PARITY
1229///
1230/// ```c
1231/// xmlEntityPtr xmlGetDocEntity(const xmlDoc *doc, const xmlChar *name);
1232/// ```
1233#[no_mangle]
1234pub unsafe extern "C" fn xmlGetDocEntity(
1235    doc: *const _xmlDoc,
1236    name: *const xmlChar,
1237) -> *mut _xmlEntity {
1238    crate::xml::tree::get_doc_entity(doc, name)
1239}
1240
1241/// Get a parameter entity by name.
1242///
1243/// # UPSTREAM-PARITY
1244///
1245/// ```c
1246/// xmlEntityPtr xmlGetParameterEntity(const xmlDoc *doc, const xmlChar *name);
1247/// ```
1248#[no_mangle]
1249pub unsafe extern "C" fn xmlGetParameterEntity(
1250    doc: *const _xmlDoc,
1251    name: *const xmlChar,
1252) -> *mut _xmlEntity {
1253    crate::xml::tree::get_parameter_entity(doc, name)
1254}
1255
1256/// Get the line number of a node.
1257///
1258/// # UPSTREAM-PARITY
1259///
1260/// ```c
1261/// long xmlGetLineNo(const xmlNode *node);
1262/// ```
1263#[no_mangle]
1264pub extern "C" fn xmlGetLineNo(node: *const _xmlNode) -> c_int {
1265    crate::xml::tree::get_line_no(node)
1266}
1267
1268// ═══════════════════════════════════════════════════════════════════════════════
1269// 7. Parser — SAX, DOM, Push, Reader
1270// ═══════════════════════════════════════════════════════════════════════════════
1271
1272/// Read an XML document from a string.
1273///
1274/// # UPSTREAM-PARITY
1275///
1276/// ```c
1277/// xmlDocPtr xmlReadDoc(const xmlChar *cur, const char *URL,
1278///                      const char *encoding, int options);
1279/// ```
1280///
1281/// Returns a parsed document. Caller must free with `xmlFreeDoc`.
1282#[no_mangle]
1283pub unsafe extern "C" fn xmlReadDoc(
1284    cur: *const xmlChar,
1285    URL: *const c_char,
1286    encoding: *const c_char,
1287    options: c_int,
1288) -> *mut _xmlDoc {
1289    // SAFETY: cur must be a valid null-terminated xmlChar string if non-null.
1290    if cur.is_null() {
1291        return ptr::null_mut();
1292    }
1293    let ctxt = crate::xml::parser::helpers::create_parser_ctxt();
1294    if ctxt.is_null() {
1295        return ptr::null_mut();
1296    }
1297    let len = crate::xml::string::xml_strlen(cur);
1298    let input = crate::xml::parser::helpers::input_from_memory(cur as *const c_char, len as c_int);
1299    crate::xml::parser::helpers::setup_parser_input(ctxt, input);
1300    (*ctxt).options = options;
1301    if crate::xml::parser::helpers::parse_document(ctxt) != 0 {
1302        let doc = (*ctxt).myDoc;
1303        crate::xml::parser::helpers::free_parser_ctxt(ctxt);
1304        return doc;
1305    }
1306    let doc = (*ctxt).myDoc;
1307    if !doc.is_null() {
1308        (*doc).URL = crate::xml::string::xml_strdup(URL as *const xmlChar);
1309    }
1310    crate::xml::parser::helpers::free_parser_ctxt(ctxt);
1311    doc
1312}
1313
1314/// Read an XML document from a file.
1315///
1316/// # UPSTREAM-PARITY
1317///
1318/// ```c
1319/// xmlDocPtr xmlReadFile(const char *URL, const char *encoding, int options);
1320/// ```
1321#[no_mangle]
1322pub unsafe extern "C" fn xmlReadFile(
1323    URL: *const c_char,
1324    encoding: *const c_char,
1325    options: c_int,
1326) -> *mut _xmlDoc {
1327    // SAFETY: URL must be a valid C string or NULL.
1328    if URL.is_null() {
1329        return ptr::null_mut();
1330    }
1331    let ctxt = crate::xml::parser::helpers::create_parser_ctxt();
1332    if ctxt.is_null() {
1333        return ptr::null_mut();
1334    }
1335    let input = match crate::xml::parser::helpers::input_from_file(URL) {
1336        Ok(input) => input,
1337        Err(_) => {
1338            crate::xml::parser::helpers::free_parser_ctxt(ctxt);
1339            return ptr::null_mut();
1340        }
1341    };
1342    crate::xml::parser::helpers::setup_parser_input(ctxt, input);
1343    (*ctxt).options = options;
1344    if crate::xml::parser::helpers::parse_document(ctxt) != 0 {
1345        let doc = (*ctxt).myDoc;
1346        crate::xml::parser::helpers::free_parser_ctxt(ctxt);
1347        return doc;
1348    }
1349    let doc = (*ctxt).myDoc;
1350    crate::xml::parser::helpers::free_parser_ctxt(ctxt);
1351    doc
1352}
1353
1354/// Read an XML document from memory.
1355///
1356/// # UPSTREAM-PARITY
1357///
1358/// ```c
1359/// xmlDocPtr xmlReadMemory(const char *buffer, int size,
1360///                         const char *URL, const char *encoding, int options);
1361/// ```
1362#[no_mangle]
1363pub unsafe extern "C" fn xmlReadMemory(
1364    buffer: *const c_char,
1365    size: c_int,
1366    URL: *const c_char,
1367    encoding: *const c_char,
1368    options: c_int,
1369) -> *mut _xmlDoc {
1370    // SAFETY: buffer must be a valid pointer with at least `size` readable bytes.
1371    if buffer.is_null() || size <= 0 {
1372        return ptr::null_mut();
1373    }
1374    let ctxt = crate::xml::parser::helpers::create_parser_ctxt();
1375    if ctxt.is_null() {
1376        return ptr::null_mut();
1377    }
1378    let input = crate::xml::parser::helpers::input_from_memory(buffer, size);
1379    crate::xml::parser::helpers::setup_parser_input(ctxt, input);
1380    (*ctxt).options = options;
1381    if crate::xml::parser::helpers::parse_document(ctxt) != 0 {
1382        let doc = (*ctxt).myDoc;
1383        crate::xml::parser::helpers::free_parser_ctxt(ctxt);
1384        return doc;
1385    }
1386    let doc = (*ctxt).myDoc;
1387    if !doc.is_null() && !URL.is_null() {
1388        (*doc).URL = crate::xml::string::xml_strdup(URL as *const xmlChar);
1389    }
1390    crate::xml::parser::helpers::free_parser_ctxt(ctxt);
1391    doc
1392}
1393
1394/// Read an XML document from a file descriptor.
1395///
1396/// # UPSTREAM-PARITY
1397///
1398/// ```c
1399/// xmlDocPtr xmlReadFd(int fd, const char *URL, const char *encoding, int options);
1400/// ```
1401#[no_mangle]
1402pub unsafe extern "C" fn xmlReadFd(
1403    fd: c_int,
1404    URL: *const c_char,
1405    encoding: *const c_char,
1406    options: c_int,
1407) -> *mut _xmlDoc {
1408    // SAFETY: fd must be a valid open file descriptor.
1409    let ctxt = crate::xml::parser::helpers::create_parser_ctxt();
1410    if ctxt.is_null() {
1411        return ptr::null_mut();
1412    }
1413    // Read all data from the fd
1414    let mut buf = Vec::new();
1415    let mut tmp = [0u8; 4096];
1416    loop {
1417        let n = libc::read(fd, tmp.as_mut_ptr() as *mut c_void, tmp.len());
1418        if n <= 0 {
1419            break;
1420        }
1421        buf.extend_from_slice(&tmp[..n as usize]);
1422    }
1423    let input = crate::xml::parser::helpers::input_from_memory(
1424        buf.as_ptr() as *const c_char,
1425        buf.len() as c_int,
1426    );
1427    crate::xml::parser::helpers::setup_parser_input(ctxt, input);
1428    (*ctxt).options = options;
1429    if crate::xml::parser::helpers::parse_document(ctxt) != 0 {
1430        let doc = (*ctxt).myDoc;
1431        crate::xml::parser::helpers::free_parser_ctxt(ctxt);
1432        return doc;
1433    }
1434    let doc = (*ctxt).myDoc;
1435    if !doc.is_null() && !URL.is_null() {
1436        (*doc).URL = crate::xml::string::xml_strdup(URL as *const xmlChar);
1437    }
1438    crate::xml::parser::helpers::free_parser_ctxt(ctxt);
1439    doc
1440}
1441
1442/// Read an XML document from I/O callbacks.
1443///
1444/// # UPSTREAM-PARITY
1445///
1446/// ```c
1447/// xmlDocPtr xmlReadIO(xmlInputReadCallback ioread, xmlInputCloseCallback ioclose,
1448///                     void *ioctx, const char *URL, const char *encoding, int options);
1449/// ```
1450#[no_mangle]
1451pub unsafe extern "C" fn xmlReadIO(
1452    ioread: Option<xmlInputReadCallback>,
1453    ioclose: Option<xmlInputCloseCallback>,
1454    ioctx: *mut c_void,
1455    URL: *const c_char,
1456    encoding: *const c_char,
1457    options: c_int,
1458) -> *mut _xmlDoc {
1459    // SAFETY: callbacks must be valid function pointers if non-NULL.
1460    let ctxt = crate::xml::parser::helpers::create_parser_ctxt();
1461    if ctxt.is_null() {
1462        return ptr::null_mut();
1463    }
1464    let input = crate::xml::parser::helpers::input_from_io(ioread, ioclose, ioctx);
1465    crate::xml::parser::helpers::setup_parser_input(ctxt, input);
1466    (*ctxt).options = options;
1467    if crate::xml::parser::helpers::parse_document(ctxt) != 0 {
1468        let doc = (*ctxt).myDoc;
1469        crate::xml::parser::helpers::free_parser_ctxt(ctxt);
1470        return doc;
1471    }
1472    let doc = (*ctxt).myDoc;
1473    if !doc.is_null() && !URL.is_null() {
1474        (*doc).URL = crate::xml::string::xml_strdup(URL as *const xmlChar);
1475    }
1476    crate::xml::parser::helpers::free_parser_ctxt(ctxt);
1477    doc
1478}
1479
1480/// Parse an XML document (SAX1).
1481///
1482/// # UPSTREAM-PARITY
1483///
1484/// ```c
1485/// xmlDocPtr xmlSAXParseDoc(xmlSAXHandlerPtr sax, const xmlChar *cur, int recovery);
1486/// ```
1487#[no_mangle]
1488pub unsafe extern "C" fn xmlSAXParseDoc(
1489    sax: *mut _xmlSAXHandler,
1490    cur: *const xmlChar,
1491    recovery: c_int,
1492) -> *mut _xmlDoc {
1493    // SAFETY: cur must be a valid null-terminated xmlChar string.
1494    if cur.is_null() {
1495        return ptr::null_mut();
1496    }
1497    let ctxt = crate::xml::parser::helpers::create_parser_ctxt();
1498    if ctxt.is_null() {
1499        return ptr::null_mut();
1500    }
1501    if !sax.is_null() {
1502        (*ctxt).sax = sax;
1503        (*ctxt).userData = (*ctxt).sax as *mut c_void;
1504    }
1505    if recovery != 0 {
1506        (*ctxt).recovery = 1;
1507        (*ctxt).options |= 1; // XML_PARSE_RECOVER
1508    }
1509    let len = crate::xml::string::xml_strlen(cur);
1510    let input = crate::xml::parser::helpers::input_from_memory(cur as *const c_char, len as c_int);
1511    crate::xml::parser::helpers::setup_parser_input(ctxt, input);
1512    crate::xml::parser::helpers::parse_document(ctxt);
1513    let doc = (*ctxt).myDoc;
1514    crate::xml::parser::helpers::free_parser_ctxt(ctxt);
1515    doc
1516}
1517
1518/// Parse an XML file (SAX1).
1519///
1520/// # UPSTREAM-PARITY
1521///
1522/// ```c
1523/// xmlDocPtr xmlSAXParseFile(xmlSAXHandlerPtr sax, const char *filename, int recovery);
1524/// ```
1525#[no_mangle]
1526pub unsafe extern "C" fn xmlSAXParseFile(
1527    sax: *mut _xmlSAXHandler,
1528    filename: *const c_char,
1529    recovery: c_int,
1530) -> *mut _xmlDoc {
1531    // SAFETY: filename must be a valid C string.
1532    if filename.is_null() {
1533        return ptr::null_mut();
1534    }
1535    let ctxt = crate::xml::parser::helpers::create_parser_ctxt();
1536    if ctxt.is_null() {
1537        return ptr::null_mut();
1538    }
1539    if !sax.is_null() {
1540        (*ctxt).sax = sax;
1541        (*ctxt).userData = (*ctxt).sax as *mut c_void;
1542    }
1543    if recovery != 0 {
1544        (*ctxt).recovery = 1;
1545        (*ctxt).options |= 1;
1546    }
1547    let input = match crate::xml::parser::helpers::input_from_file(filename) {
1548        Ok(input) => input,
1549        Err(_) => {
1550            crate::xml::parser::helpers::free_parser_ctxt(ctxt);
1551            return ptr::null_mut();
1552        }
1553    };
1554    crate::xml::parser::helpers::setup_parser_input(ctxt, input);
1555    crate::xml::parser::helpers::parse_document(ctxt);
1556    let doc = (*ctxt).myDoc;
1557    crate::xml::parser::helpers::free_parser_ctxt(ctxt);
1558    doc
1559}
1560
1561/// Parse an XML document from memory (SAX1).
1562///
1563/// # UPSTREAM-PARITY
1564///
1565/// ```c
1566/// xmlDocPtr xmlSAXParseMemory(xmlSAXHandlerPtr sax,
1567///                             const char *buffer, int size, int recovery);
1568/// ```
1569#[no_mangle]
1570pub unsafe extern "C" fn xmlSAXParseMemory(
1571    sax: *mut _xmlSAXHandler,
1572    buffer: *const c_char,
1573    size: c_int,
1574    recovery: c_int,
1575) -> *mut _xmlDoc {
1576    // SAFETY: buffer must be valid with at least `size` bytes.
1577    if buffer.is_null() || size <= 0 {
1578        return ptr::null_mut();
1579    }
1580    let ctxt = crate::xml::parser::helpers::create_parser_ctxt();
1581    if ctxt.is_null() {
1582        return ptr::null_mut();
1583    }
1584    if !sax.is_null() {
1585        (*ctxt).sax = sax;
1586        (*ctxt).userData = (*ctxt).sax as *mut c_void;
1587    }
1588    if recovery != 0 {
1589        (*ctxt).recovery = 1;
1590        (*ctxt).options |= 1;
1591    }
1592    let input = crate::xml::parser::helpers::input_from_memory(buffer, size);
1593    crate::xml::parser::helpers::setup_parser_input(ctxt, input);
1594    crate::xml::parser::helpers::parse_document(ctxt);
1595    let doc = (*ctxt).myDoc;
1596    crate::xml::parser::helpers::free_parser_ctxt(ctxt);
1597    doc
1598}
1599
1600/// SAX user parse file.
1601///
1602/// # UPSTREAM-PARITY
1603///
1604/// ```c
1605/// int xmlSAXUserParseFile(xmlSAXHandlerPtr sax, void *user_data,
1606///                         const char *filename);
1607/// ```
1608#[no_mangle]
1609pub unsafe extern "C" fn xmlSAXUserParseFile(
1610    sax: *mut _xmlSAXHandler,
1611    user_data: *mut c_void,
1612    filename: *const c_char,
1613) -> c_int {
1614    // SAFETY: filename must be a valid C string. sax and user_data may be NULL.
1615    if filename.is_null() {
1616        return -1;
1617    }
1618    let ctxt = crate::xml::parser::helpers::create_parser_ctxt();
1619    if ctxt.is_null() {
1620        return -1;
1621    }
1622    if !sax.is_null() {
1623        (*ctxt).sax = sax;
1624    }
1625    (*ctxt).userData = if !user_data.is_null() {
1626        user_data
1627    } else {
1628        ctxt as *mut c_void
1629    };
1630    let input = match crate::xml::parser::helpers::input_from_file(filename) {
1631        Ok(input) => input,
1632        Err(_) => {
1633            crate::xml::parser::helpers::free_parser_ctxt(ctxt);
1634            return -1;
1635        }
1636    };
1637    crate::xml::parser::helpers::setup_parser_input(ctxt, input);
1638    let ret = crate::xml::parser::helpers::parse_document(ctxt);
1639    crate::xml::parser::helpers::free_parser_ctxt(ctxt);
1640    ret
1641}
1642
1643/// SAX user parse memory.
1644///
1645/// # UPSTREAM-PARITY
1646///
1647/// ```c
1648/// int xmlSAXUserParseMemory(xmlSAXHandlerPtr sax, void *user_data,
1649///                           const char *buffer, int size);
1650/// ```
1651#[no_mangle]
1652pub unsafe extern "C" fn xmlSAXUserParseMemory(
1653    sax: *mut _xmlSAXHandler,
1654    user_data: *mut c_void,
1655    buffer: *const c_char,
1656    size: c_int,
1657) -> c_int {
1658    // SAFETY: buffer must be valid with at least `size` bytes.
1659    if buffer.is_null() || size <= 0 {
1660        return -1;
1661    }
1662    let ctxt = crate::xml::parser::helpers::create_parser_ctxt();
1663    if ctxt.is_null() {
1664        return -1;
1665    }
1666    if !sax.is_null() {
1667        (*ctxt).sax = sax;
1668    }
1669    (*ctxt).userData = if !user_data.is_null() {
1670        user_data
1671    } else {
1672        ctxt as *mut c_void
1673    };
1674    let input = crate::xml::parser::helpers::input_from_memory(buffer, size);
1675    crate::xml::parser::helpers::setup_parser_input(ctxt, input);
1676    let ret = crate::xml::parser::helpers::parse_document(ctxt);
1677    crate::xml::parser::helpers::free_parser_ctxt(ctxt);
1678    ret
1679}
1680
1681/// Parse an XML document from a string (DOM).
1682///
1683/// # UPSTREAM-PARITY
1684///
1685/// ```c
1686/// xmlDocPtr xmlParseDoc(const xmlChar *cur);
1687/// ```
1688#[no_mangle]
1689pub unsafe extern "C" fn xmlParseDoc(cur: *const xmlChar) -> *mut _xmlDoc {
1690    // SAFETY: cur must be a valid null-terminated xmlChar string.
1691    if cur.is_null() {
1692        return ptr::null_mut();
1693    }
1694    xmlReadDoc(cur, ptr::null(), ptr::null(), 0)
1695}
1696
1697/// Parse an XML file (DOM).
1698///
1699/// # UPSTREAM-PARITY
1700///
1701/// ```c
1702/// xmlDocPtr xmlParseFile(const char *filename);
1703/// ```
1704#[no_mangle]
1705pub unsafe extern "C" fn xmlParseFile(filename: *const c_char) -> *mut _xmlDoc {
1706    // SAFETY: filename must be a valid C string.
1707    if filename.is_null() {
1708        return ptr::null_mut();
1709    }
1710    xmlReadFile(filename, ptr::null(), 0)
1711}
1712
1713/// Parse an XML document from memory (DOM).
1714///
1715/// # UPSTREAM-PARITY
1716///
1717/// ```c
1718/// xmlDocPtr xmlParseMemory(const char *buffer, int size);
1719/// ```
1720#[no_mangle]
1721pub unsafe extern "C" fn xmlParseMemory(buffer: *const c_char, size: c_int) -> *mut _xmlDoc {
1722    // SAFETY: buffer must be valid with at least `size` bytes.
1723    if buffer.is_null() || size <= 0 {
1724        return ptr::null_mut();
1725    }
1726    xmlReadMemory(buffer, size, ptr::null(), ptr::null(), 0)
1727}
1728
1729/// Create a file parser context.
1730///
1731/// # UPSTREAM-PARITY
1732///
1733/// ```c
1734/// xmlParserCtxtPtr xmlCreateFileParserCtxt(const char *filename);
1735/// ```
1736#[no_mangle]
1737pub unsafe extern "C" fn xmlCreateFileParserCtxt(filename: *const c_char) -> *mut _xmlParserCtxt {
1738    // SAFETY: filename must be a valid C string.
1739    if filename.is_null() {
1740        return ptr::null_mut();
1741    }
1742    let ctxt = crate::xml::parser::helpers::create_parser_ctxt();
1743    if ctxt.is_null() {
1744        return ptr::null_mut();
1745    }
1746    let input = match crate::xml::parser::helpers::input_from_file(filename) {
1747        Ok(input) => input,
1748        Err(_) => {
1749            crate::xml::parser::helpers::free_parser_ctxt(ctxt);
1750            return ptr::null_mut();
1751        }
1752    };
1753    crate::xml::parser::helpers::setup_parser_input(ctxt, input);
1754    ctxt
1755}
1756
1757/// Create a document parser context.
1758///
1759/// # UPSTREAM-PARITY
1760///
1761/// ```c
1762/// xmlParserCtxtPtr xmlCreateDocParserCtxt(const xmlChar *cur);
1763/// ```
1764#[no_mangle]
1765pub unsafe extern "C" fn xmlCreateDocParserCtxt(cur: *const xmlChar) -> *mut _xmlParserCtxt {
1766    // SAFETY: cur must be a valid null-terminated xmlChar string.
1767    if cur.is_null() {
1768        return ptr::null_mut();
1769    }
1770    let ctxt = crate::xml::parser::helpers::create_parser_ctxt();
1771    if ctxt.is_null() {
1772        return ptr::null_mut();
1773    }
1774    let len = crate::xml::string::xml_strlen(cur);
1775    let input = crate::xml::parser::helpers::input_from_memory(cur as *const c_char, len as c_int);
1776    crate::xml::parser::helpers::setup_parser_input(ctxt, input);
1777    ctxt
1778}
1779
1780/// Parse a document using an existing parser context.
1781///
1782/// # UPSTREAM-PARITY
1783///
1784/// ```c
1785/// int xmlParseDocument(xmlParserCtxtPtr ctxt);
1786/// ```
1787#[no_mangle]
1788pub unsafe extern "C" fn xmlParseDocument(ctxt: *mut _xmlParserCtxt) -> c_int {
1789    // SAFETY: ctxt must be a valid parser context.
1790    if ctxt.is_null() {
1791        return -1;
1792    }
1793    crate::xml::parser::helpers::parse_document(ctxt)
1794}
1795
1796/// Free a parser context.
1797///
1798/// # UPSTREAM-PARITY
1799///
1800/// ```c
1801/// void xmlFreeParserCtxt(xmlParserCtxtPtr ctxt);
1802/// ```
1803#[no_mangle]
1804pub unsafe extern "C" fn xmlFreeParserCtxt(ctxt: *mut _xmlParserCtxt) {
1805    if ctxt.is_null() {
1806        return;
1807    }
1808    crate::xml::parser::helpers::free_parser_ctxt(ctxt);
1809}
1810
1811/// Set parser options.
1812///
1813/// # UPSTREAM-PARITY
1814///
1815/// ```c
1816/// int xmlCtxtUseOptions(xmlParserCtxtPtr ctxt, int options);
1817/// ```
1818#[no_mangle]
1819pub unsafe extern "C" fn xmlCtxtUseOptions(ctxt: *mut _xmlParserCtxt, options: c_int) -> c_int {
1820    if ctxt.is_null() {
1821        return -1;
1822    }
1823    // Phase 1: STUB
1824    unsafe {
1825        (*ctxt).options = options;
1826    }
1827    0
1828}
1829
1830/// Parse a well-balanced chunk (for push parsing).
1831///
1832/// # UPSTREAM-PARITY
1833///
1834/// ```c
1835/// xmlParserErrors xmlParseChunk(xmlParserCtxtPtr ctxt,
1836///                               const char *chunk, int size, int terminate);
1837/// ```
1838#[no_mangle]
1839pub unsafe extern "C" fn xmlParseChunk(
1840    ctxt: *mut _xmlParserCtxt,
1841    chunk: *const c_char,
1842    size: c_int,
1843    terminate: c_int,
1844) -> c_int {
1845    // SAFETY: ctxt must be a valid parser context.
1846    // chunk may be NULL if terminate is set (finalize without data).
1847    if ctxt.is_null() {
1848        return -1;
1849    }
1850    crate::xml::parser::helpers::parse_chunk(ctxt, chunk, size, terminate)
1851}
1852
1853/// Create a memory parser input buffer.
1854///
1855/// # UPSTREAM-PARITY
1856///
1857/// ```c
1858/// xmlParserInputBufferPtr xmlParserInputBufferCreateMem(const char *buffer, int size, int enc);
1859/// ```
1860#[no_mangle]
1861pub unsafe extern "C" fn xmlParserInputBufferCreateMem(
1862    buffer: *const c_char,
1863    size: c_int,
1864    enc: c_int,
1865) -> *mut _xmlParserInputBuffer {
1866    // SAFETY: buffer must be valid with at least `size` bytes.
1867    if buffer.is_null() || size <= 0 {
1868        return ptr::null_mut();
1869    }
1870    crate::xml::parser::helpers::alloc_parser_input_buffer()
1871}
1872
1873/// Create a file parser input buffer.
1874///
1875/// # UPSTREAM-PARITY
1876///
1877/// ```c
1878/// xmlParserInputBufferPtr xmlParserInputBufferCreateFilename(const char *URI, int enc);
1879/// ```
1880#[no_mangle]
1881pub unsafe extern "C" fn xmlParserInputBufferCreateFilename(
1882    URI: *const c_char,
1883    enc: c_int,
1884) -> *mut _xmlParserInputBuffer {
1885    // SAFETY: URI must be a valid C string or NULL.
1886    if URI.is_null() {
1887        return ptr::null_mut();
1888    }
1889    crate::xml::parser::helpers::alloc_parser_input_buffer()
1890}
1891
1892/// Create an I/O parser input buffer.
1893///
1894/// # UPSTREAM-PARITY
1895///
1896/// ```c
1897/// xmlParserInputBufferPtr xmlParserInputBufferCreateIO(
1898///     xmlInputReadCallback ioread, xmlInputCloseCallback ioclose,
1899///     void *ioctx, int enc);
1900/// ```
1901#[no_mangle]
1902pub unsafe extern "C" fn xmlParserInputBufferCreateIO(
1903    ioread: Option<xmlInputReadCallback>,
1904    ioclose: Option<xmlInputCloseCallback>,
1905    ioctx: *mut c_void,
1906    enc: c_int,
1907) -> *mut _xmlParserInputBuffer {
1908    // SAFETY: ioread must be a valid callback if Some. ioctx may be NULL.
1909    let buf = crate::xml::parser::helpers::alloc_parser_input_buffer();
1910    if !buf.is_null() {
1911        (*buf).readcallback = ioread;
1912        (*buf).closecallback = ioclose;
1913        (*buf).context = ioctx;
1914    }
1915    buf
1916}
1917
1918/// Free a parser input buffer.
1919///
1920/// # UPSTREAM-PARITY
1921///
1922/// ```c
1923/// void xmlFreeParserInputBuffer(xmlParserInputBufferPtr buf);
1924/// ```
1925#[no_mangle]
1926pub unsafe extern "C" fn xmlFreeParserInputBuffer(buf: *mut _xmlParserInputBuffer) {
1927    if buf.is_null() {
1928        return;
1929    }
1930    crate::xml::parser::helpers::free_parser_input_buffer(buf);
1931}
1932
1933/// Create a new parser input.
1934///
1935/// # UPSTREAM-PARITY
1936///
1937/// ```c
1938/// xmlParserInputPtr xmlNewInputFromFile(xmlParserCtxtPtr ctxt, const char *filename);
1939/// ```
1940#[no_mangle]
1941pub unsafe extern "C" fn xmlNewInputFromFile(
1942    ctxt: *mut _xmlParserCtxt,
1943    filename: *const c_char,
1944) -> *mut _xmlParserInput {
1945    // SAFETY: filename must be a valid C string. ctxt may be NULL.
1946    // This function allocates a _xmlParserInput. The caller owns it.
1947    // Note: The InputBuffer backing data is NOT leaked here (no ctxt._private
1948    // to store it). Use xmlCreateFileParserCtxt + xmlParseDocument instead.
1949    if filename.is_null() {
1950        return ptr::null_mut();
1951    }
1952    crate::xml::parser::helpers::alloc_parser_input_buffer() as *mut _xmlParserInput
1953}
1954
1955/// Free a parser input.
1956///
1957/// # UPSTREAM-PARITY
1958///
1959/// ```c
1960/// void xmlFreeInputStream(xmlParserInputPtr input);
1961/// ```
1962#[no_mangle]
1963pub unsafe extern "C" fn xmlFreeInputStream(input: *mut _xmlParserInput) {
1964    if input.is_null() {
1965        return;
1966    }
1967    crate::xml::parser::helpers::free_parser_input(input);
1968}
1969
1970// ═══════════════════════════════════════════════════════════════════════════════
1971// 8. I/O
1972// ═══════════════════════════════════════════════════════════════════════════════
1973
1974/// Create an output buffer for a file.
1975///
1976/// # UPSTREAM-PARITY
1977///
1978/// ```c
1979/// xmlOutputBufferPtr xmlOutputBufferCreateFilename(const char *URI,
1980///                                                  xmlCharEncodingHandlerPtr encoder,
1981///                                                  int compression);
1982/// ```
1983#[no_mangle]
1984pub unsafe extern "C" fn xmlOutputBufferCreateFilename(
1985    URI: *const c_char,
1986    encoder: *mut c_void,
1987    compression: c_int,
1988) -> *mut _xmlOutputBuffer {
1989    // Phase 1: STUB
1990    ptr::null_mut()
1991}
1992
1993/// Create an output buffer for a file descriptor.
1994///
1995/// # UPSTREAM-PARITY
1996///
1997/// ```c
1998/// xmlOutputBufferPtr xmlOutputBufferCreateFd(int fd,
1999///                                            xmlCharEncodingHandlerPtr encoder);
2000/// ```
2001#[no_mangle]
2002pub unsafe extern "C" fn xmlOutputBufferCreateFd(
2003    fd: c_int,
2004    encoder: *mut c_void,
2005) -> *mut _xmlOutputBuffer {
2006    // Phase 1: STUB
2007    ptr::null_mut()
2008}
2009
2010/// Create an output buffer from I/O callbacks.
2011///
2012/// # UPSTREAM-PARITY
2013///
2014/// ```c
2015/// xmlOutputBufferPtr xmlOutputBufferCreateIO(
2016///     xmlOutputWriteCallback iowrite, xmlOutputCloseCallback ioclose,
2017///     void *ioctx, xmlCharEncodingHandlerPtr encoder);
2018/// ```
2019#[no_mangle]
2020pub unsafe extern "C" fn xmlOutputBufferCreateIO(
2021    iowrite: Option<xmlOutputWriteCallback>,
2022    ioclose: Option<xmlOutputCloseCallback>,
2023    ioctx: *mut c_void,
2024    encoder: *mut c_void,
2025) -> *mut _xmlOutputBuffer {
2026    // Phase 1: STUB
2027    ptr::null_mut()
2028}
2029
2030/// Free an output buffer.
2031///
2032/// # UPSTREAM-PARITY
2033///
2034/// ```c
2035/// void xmlOutputBufferClose(xmlOutputBufferPtr out);
2036/// ```
2037#[no_mangle]
2038pub unsafe extern "C" fn xmlOutputBufferClose(out: *mut _xmlOutputBuffer) -> c_int {
2039    if out.is_null() {
2040        return 0;
2041    }
2042    // Phase 1: STUB
2043    unsafe {
2044        xmlFree(out as *mut c_void);
2045    }
2046    0
2047}
2048
2049/// Flush an output buffer.
2050///
2051/// # UPSTREAM-PARITY
2052///
2053/// ```c
2054/// int xmlOutputBufferFlush(xmlOutputBufferPtr out);
2055/// ```
2056#[no_mangle]
2057pub unsafe extern "C" fn xmlOutputBufferFlush(out: *mut _xmlOutputBuffer) -> c_int {
2058    // Phase 1: STUB
2059    0
2060}
2061
2062/// Write to an output buffer.
2063///
2064/// # UPSTREAM-PARITY
2065///
2066/// ```c
2067/// int xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *data);
2068/// ```
2069#[no_mangle]
2070pub unsafe extern "C" fn xmlOutputBufferWrite(
2071    out: *mut _xmlOutputBuffer,
2072    len: c_int,
2073    data: *const c_char,
2074) -> c_int {
2075    // Phase 1: STUB
2076    0
2077}
2078
2079/// Write a string to an output buffer.
2080///
2081/// # UPSTREAM-PARITY
2082///
2083/// ```c
2084/// int xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str);
2085/// ```
2086#[no_mangle]
2087pub unsafe extern "C" fn xmlOutputBufferWriteString(
2088    out: *mut _xmlOutputBuffer,
2089    str: *const c_char,
2090) -> c_int {
2091    if str.is_null() {
2092        return 0;
2093    }
2094    unsafe { xmlOutputBufferWrite(out, xmlStrlen(str as *const xmlChar), str) }
2095}
2096
2097// ═══════════════════════════════════════════════════════════════════════════════
2098// 9. Dictionary
2099// ═══════════════════════════════════════════════════════════════════════════════
2100
2101/// Create a new dictionary.
2102///
2103/// # UPSTREAM-PARITY
2104///
2105/// ```c
2106/// xmlDictPtr xmlDictCreate(void);
2107/// ```
2108#[no_mangle]
2109pub extern "C" fn xmlDictCreate() -> *mut c_void {
2110    // Phase 1: STUB — will be implemented in xml/dictionary module.
2111    ptr::null_mut()
2112}
2113
2114/// Create a sub-dictionary.
2115///
2116/// # UPSTREAM-PARITY
2117///
2118/// ```c
2119/// xmlDictPtr xmlDictCreateSub(xmlDictPtr sub);
2120/// ```
2121#[no_mangle]
2122pub extern "C" fn xmlDictCreateSub(_sub: *mut c_void) -> *mut c_void {
2123    // Phase 1: STUB
2124    ptr::null_mut()
2125}
2126
2127/// Look up a string in the dictionary.
2128///
2129/// # UPSTREAM-PARITY
2130///
2131/// ```c
2132/// const xmlChar *xmlDictLookup(xmlDictPtr dict, const xmlChar *name, int len);
2133/// ```
2134///
2135/// Returns an interned string pointer (valid as long as the dictionary exists).
2136/// - If `len` < 0, `name` must be null-terminated.
2137/// - If `len` >= 0, exactly `len` bytes are used.
2138#[no_mangle]
2139pub unsafe extern "C" fn xmlDictLookup(
2140    dict: *mut c_void,
2141    name: *const xmlChar,
2142    len: c_int,
2143) -> *const xmlChar {
2144    // Phase 1: STUB
2145    name
2146}
2147
2148/// Check if a string exists in the dictionary.
2149///
2150/// # UPSTREAM-PARITY
2151///
2152/// ```c
2153/// const xmlChar *xmlDictExists(xmlDictPtr dict, const xmlChar *name, int len);
2154/// ```
2155#[no_mangle]
2156pub unsafe extern "C" fn xmlDictExists(
2157    dict: *mut c_void,
2158    name: *const xmlChar,
2159    len: c_int,
2160) -> *const xmlChar {
2161    // Phase 1: STUB
2162    ptr::null()
2163}
2164
2165/// Query dictionary size.
2166///
2167/// # UPSTREAM-PARITY
2168///
2169/// ```c
2170/// unsigned int xmlDictSize(const xmlDictPtr dict);
2171/// ```
2172#[no_mangle]
2173pub extern "C" fn xmlDictSize(dict: *const c_void) -> c_uint {
2174    // Phase 1: STUB
2175    0
2176}
2177
2178/// Free a dictionary.
2179///
2180/// # UPSTREAM-PARITY
2181///
2182/// ```c
2183/// void xmlDictFree(xmlDictPtr dict);
2184/// ```
2185#[no_mangle]
2186pub extern "C" fn xmlDictFree(_dict: *mut c_void) {
2187    // Phase 1: STUB
2188}
2189
2190/// Set the dictionary size limit.
2191///
2192/// # UPSTREAM-PARITY
2193///
2194/// ```c
2195/// unsigned int xmlDictSetLimit(xmlDictPtr dict, unsigned int limit);
2196/// ```
2197#[no_mangle]
2198pub extern "C" fn xmlDictSetLimit(_dict: *mut c_void, _limit: c_uint) -> c_uint {
2199    // Phase 1: STUB
2200    0
2201}
2202
2203/// Get current dictionary usage.
2204///
2205/// # UPSTREAM-PARITY
2206///
2207/// ```c
2208/// unsigned int xmlDictGetUsage(const xmlDictPtr dict);
2209/// ```
2210#[no_mangle]
2211pub extern "C" fn xmlDictGetUsage(_dict: *const c_void) -> c_uint {
2212    // Phase 1: STUB
2213    0
2214}
2215
2216// ═══════════════════════════════════════════════════════════════════════════════
2217// 10. Hash Table
2218// ═══════════════════════════════════════════════════════════════════════════════
2219
2220/// Create a new hash table.
2221///
2222/// # UPSTREAM-PARITY
2223///
2224/// ```c
2225/// xmlHashTablePtr xmlHashCreate(int size);
2226/// ```
2227#[no_mangle]
2228pub extern "C" fn xmlHashCreate(_size: c_int) -> *mut c_void {
2229    // Phase 1: STUB
2230    ptr::null_mut()
2231}
2232
2233/// Create a new hash table with a dictionary.
2234///
2235/// # UPSTREAM-PARITY
2236///
2237/// ```c
2238/// xmlHashTablePtr xmlHashCreateDict(int size, xmlDictPtr dict);
2239/// ```
2240#[no_mangle]
2241pub extern "C" fn xmlHashCreateDict(_size: c_int, _dict: *mut c_void) -> *mut c_void {
2242    // Phase 1: STUB
2243    ptr::null_mut()
2244}
2245
2246/// Free a hash table.
2247///
2248/// # UPSTREAM-PARITY
2249///
2250/// ```c
2251/// void xmlHashFree(xmlHashTablePtr table, xmlHashDeallocator f);
2252/// ```
2253#[no_mangle]
2254pub extern "C" fn xmlHashFree(
2255    _table: *mut c_void,
2256    _f: Option<unsafe extern "C" fn(*mut c_void, *mut xmlChar)>,
2257) {
2258    // Phase 1: STUB
2259}
2260
2261/// Add an entry to a hash table.
2262///
2263/// # UPSTREAM-PARITY
2264///
2265/// ```c
2266/// int xmlHashAddEntry(xmlHashTablePtr table, const xmlChar *name, void *userdata);
2267/// ```
2268#[no_mangle]
2269pub unsafe extern "C" fn xmlHashAddEntry(
2270    _table: *mut c_void,
2271    _name: *const xmlChar,
2272    _userdata: *mut c_void,
2273) -> c_int {
2274    // Phase 1: STUB
2275    0
2276}
2277
2278/// Add a 2-key entry.
2279///
2280/// # UPSTREAM-PARITY
2281///
2282/// ```c
2283/// int xmlHashAddEntry2(xmlHashTablePtr table, const xmlChar *name,
2284///                      const xmlChar *name2, void *userdata);
2285/// ```
2286#[no_mangle]
2287pub unsafe extern "C" fn xmlHashAddEntry2(
2288    _table: *mut c_void,
2289    _name: *const xmlChar,
2290    _name2: *const xmlChar,
2291    _userdata: *mut c_void,
2292) -> c_int {
2293    // Phase 1: STUB
2294    0
2295}
2296
2297/// Add a 3-key entry.
2298///
2299/// # UPSTREAM-PARITY
2300///
2301/// ```c
2302/// int xmlHashAddEntry3(xmlHashTablePtr table, const xmlChar *name,
2303///                      const xmlChar *name2, const xmlChar *name3, void *userdata);
2304/// ```
2305#[no_mangle]
2306pub unsafe extern "C" fn xmlHashAddEntry3(
2307    _table: *mut c_void,
2308    _name: *const xmlChar,
2309    _name2: *const xmlChar,
2310    _name3: *const xmlChar,
2311    _userdata: *mut c_void,
2312) -> c_int {
2313    // Phase 1: STUB
2314    0
2315}
2316
2317/// Update or add an entry.
2318///
2319/// # UPSTREAM-PARITY
2320///
2321/// ```c
2322/// int xmlHashUpdateEntry(xmlHashTablePtr table, const xmlChar *name,
2323///                        void *userdata, xmlHashDeallocator f);
2324/// ```
2325#[no_mangle]
2326pub unsafe extern "C" fn xmlHashUpdateEntry(
2327    _table: *mut c_void,
2328    _name: *const xmlChar,
2329    _userdata: *mut c_void,
2330    _f: Option<unsafe extern "C" fn(*mut c_void, *mut xmlChar)>,
2331) -> c_int {
2332    // Phase 1: STUB
2333    0
2334}
2335
2336/// Update or add a 2-key entry.
2337#[no_mangle]
2338pub unsafe extern "C" fn xmlHashUpdateEntry2(
2339    _table: *mut c_void,
2340    _name: *const xmlChar,
2341    _name2: *const xmlChar,
2342    _userdata: *mut c_void,
2343    _f: Option<unsafe extern "C" fn(*mut c_void, *mut xmlChar)>,
2344) -> c_int {
2345    // Phase 1: STUB
2346    0
2347}
2348
2349/// Update or add a 3-key entry.
2350#[no_mangle]
2351pub unsafe extern "C" fn xmlHashUpdateEntry3(
2352    _table: *mut c_void,
2353    _name: *const xmlChar,
2354    _name2: *const xmlChar,
2355    _name3: *const xmlChar,
2356    _userdata: *mut c_void,
2357    _f: Option<unsafe extern "C" fn(*mut c_void, *mut xmlChar)>,
2358) -> c_int {
2359    // Phase 1: STUB
2360    0
2361}
2362
2363/// Look up an entry.
2364///
2365/// # UPSTREAM-PARITY
2366///
2367/// ```c
2368/// void *xmlHashLookup(xmlHashTablePtr table, const xmlChar *name);
2369/// ```
2370#[no_mangle]
2371pub unsafe extern "C" fn xmlHashLookup(_table: *mut c_void, _name: *const xmlChar) -> *mut c_void {
2372    // Phase 1: STUB
2373    ptr::null_mut()
2374}
2375
2376/// Look up a 2-key entry.
2377#[no_mangle]
2378pub unsafe extern "C" fn xmlHashLookup2(
2379    _table: *mut c_void,
2380    _name: *const xmlChar,
2381    _name2: *const xmlChar,
2382) -> *mut c_void {
2383    // Phase 1: STUB
2384    ptr::null_mut()
2385}
2386
2387/// Look up a 3-key entry.
2388#[no_mangle]
2389pub unsafe extern "C" fn xmlHashLookup3(
2390    _table: *mut c_void,
2391    _name: *const xmlChar,
2392    _name2: *const xmlChar,
2393    _name3: *const xmlChar,
2394) -> *mut c_void {
2395    // Phase 1: STUB
2396    ptr::null_mut()
2397}
2398
2399/// Get the size of a hash table.
2400///
2401/// # UPSTREAM-PARITY
2402///
2403/// ```c
2404/// int xmlHashSize(xmlHashTablePtr table);
2405/// ```
2406#[no_mangle]
2407pub extern "C" fn xmlHashSize(_table: *mut c_void) -> c_int {
2408    // Phase 1: STUB
2409    0
2410}
2411
2412/// Remove an entry.
2413///
2414/// # UPSTREAM-PARITY
2415///
2416/// ```c
2417/// int xmlHashRemoveEntry(xmlHashTablePtr table, const xmlChar *name,
2418///                        xmlHashDeallocator f);
2419/// ```
2420#[no_mangle]
2421pub unsafe extern "C" fn xmlHashRemoveEntry(
2422    _table: *mut c_void,
2423    _name: *const xmlChar,
2424    _f: Option<unsafe extern "C" fn(*mut c_void, *mut xmlChar)>,
2425) -> c_int {
2426    // Phase 1: STUB
2427    0
2428}
2429
2430/// Remove a 2-key entry.
2431#[no_mangle]
2432pub unsafe extern "C" fn xmlHashRemoveEntry2(
2433    _table: *mut c_void,
2434    _name: *const xmlChar,
2435    _name2: *const xmlChar,
2436    _f: Option<unsafe extern "C" fn(*mut c_void, *mut xmlChar)>,
2437) -> c_int {
2438    // Phase 1: STUB
2439    0
2440}
2441
2442/// Remove a 3-key entry.
2443#[no_mangle]
2444pub unsafe extern "C" fn xmlHashRemoveEntry3(
2445    _table: *mut c_void,
2446    _name: *const xmlChar,
2447    _name2: *const xmlChar,
2448    _name3: *const xmlChar,
2449    _f: Option<unsafe extern "C" fn(*mut c_void, *mut xmlChar)>,
2450) -> c_int {
2451    // Phase 1: STUB
2452    0
2453}
2454
2455/// Scan a hash table with a scanner function.
2456///
2457/// # UPSTREAM-PARITY
2458///
2459/// ```c
2460/// void xmlHashScan(xmlHashTablePtr table, xmlHashScanner f, void *data);
2461/// ```
2462#[no_mangle]
2463pub extern "C" fn xmlHashScan(
2464    _table: *mut c_void,
2465    _f: Option<unsafe extern "C" fn(*mut c_void, *const xmlChar, *mut c_void)>,
2466    _data: *mut c_void,
2467) {
2468    // Phase 1: STUB
2469}
2470
2471/// Scan a hash table with a full scanner function.
2472#[no_mangle]
2473pub extern "C" fn xmlHashScanFull(
2474    _table: *mut c_void,
2475    _f: Option<unsafe extern "C" fn(*mut c_void, *const xmlChar, *mut c_void, *mut c_void)>,
2476    _data: *mut c_void,
2477) {
2478    // Phase 1: STUB
2479}
2480
2481/// Copy a hash table.
2482///
2483/// # UPSTREAM-PARITY
2484///
2485/// ```c
2486/// xmlHashTablePtr xmlHashCopy(xmlHashTablePtr table, xmlHashCopier f);
2487/// ```
2488#[no_mangle]
2489pub extern "C" fn xmlHashCopy(
2490    _table: *mut c_void,
2491    _f: Option<unsafe extern "C" fn(*mut c_void, *const xmlChar) -> *mut c_void>,
2492) -> *mut c_void {
2493    // Phase 1: STUB
2494    ptr::null_mut()
2495}
2496
2497// ═══════════════════════════════════════════════════════════════════════════════
2498// 11. List
2499// ═══════════════════════════════════════════════════════════════════════════════
2500
2501/// Create a new list.
2502///
2503/// # UPSTREAM-PARITY
2504///
2505/// ```c
2506/// xmlListPtr xmlListCreate(xmlListDeallocator deallocator,
2507///                          xmlListDataCompare compare);
2508/// ```
2509#[no_mangle]
2510pub extern "C" fn xmlListCreate(
2511    _deallocator: Option<unsafe extern "C" fn(*mut c_void)>,
2512    _compare: Option<unsafe extern "C" fn(*const c_void, *const c_void) -> c_int>,
2513) -> *mut c_void {
2514    // Phase 1: STUB
2515    ptr::null_mut()
2516}
2517
2518/// Delete a list.
2519///
2520/// # UPSTREAM-PARITY
2521///
2522/// ```c
2523/// void xmlListDelete(xmlListPtr list);
2524/// ```
2525#[no_mangle]
2526pub extern "C" fn xmlListDelete(_list: *mut c_void) {
2527    // Phase 1: STUB
2528}
2529
2530/// Search a list.
2531///
2532/// # UPSTREAM-PARITY
2533///
2534/// ```c
2535/// void *xmlListSearch(xmlListPtr list, void *data);
2536/// ```
2537#[no_mangle]
2538pub extern "C" fn xmlListSearch(_list: *mut c_void, _data: *mut c_void) -> *mut c_void {
2539    // Phase 1: STUB
2540    ptr::null_mut()
2541}
2542
2543/// Walk a list.
2544///
2545/// # UPSTREAM-PARITY
2546///
2547/// ```c
2548/// void xmlListWalk(xmlListPtr list, xmlListWalker walker, void *data);
2549/// ```
2550#[no_mangle]
2551pub extern "C" fn xmlListWalk(
2552    _list: *mut c_void,
2553    _walker: Option<unsafe extern "C" fn(*mut c_void, *mut c_void) -> c_int>,
2554    _data: *mut c_void,
2555) {
2556    // Phase 1: STUB
2557}
2558
2559/// Push to back.
2560///
2561/// # UPSTREAM-PARITY
2562///
2563/// ```c
2564/// int xmlListPushBack(xmlListPtr list, void *data);
2565/// ```
2566#[no_mangle]
2567pub extern "C" fn xmlListPushBack(_list: *mut c_void, _data: *mut c_void) -> c_int {
2568    // Phase 1: STUB
2569    0
2570}
2571
2572/// Push to front.
2573///
2574/// # UPSTREAM-PARITY
2575///
2576/// ```c
2577/// int xmlListPushFront(xmlListPtr list, void *data);
2578/// ```
2579#[no_mangle]
2580pub extern "C" fn xmlListPushFront(_list: *mut c_void, _data: *mut c_void) -> c_int {
2581    // Phase 1: STUB
2582    0
2583}
2584
2585/// Pop from back.
2586#[no_mangle]
2587pub extern "C" fn xmlListPopBack(_list: *mut c_void) {
2588    // Phase 1: STUB
2589}
2590
2591/// Pop from front.
2592#[no_mangle]
2593pub extern "C" fn xmlListPopFront(_list: *mut c_void) {
2594    // Phase 1: STUB
2595}
2596
2597/// Insert into sorted list.
2598///
2599/// # UPSTREAM-PARITY
2600///
2601/// ```c
2602/// int xmlListInsert(xmlListPtr list, void *data);
2603/// ```
2604#[no_mangle]
2605pub extern "C" fn xmlListInsert(_list: *mut c_void, _data: *mut c_void) -> c_int {
2606    // Phase 1: STUB
2607    0
2608}
2609
2610/// Append to list.
2611#[no_mangle]
2612pub extern "C" fn xmlListAppend(_list: *mut c_void, _data: *mut c_void) -> c_int {
2613    // Phase 1: STUB
2614    0
2615}
2616
2617/// Remove first matching element.
2618#[no_mangle]
2619pub extern "C" fn xmlListRemoveFirst(_list: *mut c_void, _data: *mut c_void) -> c_int {
2620    // Phase 1: STUB
2621    0
2622}
2623
2624/// Remove last matching element.
2625#[no_mangle]
2626pub extern "C" fn xmlListRemoveLast(_list: *mut c_void, _data: *mut c_void) -> c_int {
2627    // Phase 1: STUB
2628    0
2629}
2630
2631/// Remove all matching elements.
2632#[no_mangle]
2633pub extern "C" fn xmlListRemoveAll(_list: *mut c_void, _data: *mut c_void) -> c_int {
2634    // Phase 1: STUB
2635    0
2636}
2637
2638/// Clear a list.
2639#[no_mangle]
2640pub extern "C" fn xmlListClear(_list: *mut c_void) {
2641    // Phase 1: STUB
2642}
2643
2644/// Check if list is empty.
2645///
2646/// # UPSTREAM-PARITY
2647///
2648/// ```c
2649/// int xmlListEmpty(xmlListPtr list);
2650/// ```
2651#[no_mangle]
2652pub extern "C" fn xmlListEmpty(_list: *mut c_void) -> c_int {
2653    // Phase 1: STUB
2654    1
2655}
2656
2657/// Get front element.
2658///
2659/// # UPSTREAM-PARITY
2660///
2661/// ```c
2662/// void *xmlListFront(xmlListPtr list);
2663/// ```
2664#[no_mangle]
2665pub extern "C" fn xmlListFront(_list: *mut c_void) -> *mut c_void {
2666    // Phase 1: STUB
2667    ptr::null_mut()
2668}
2669
2670/// Get back element.
2671///
2672/// # UPSTREAM-PARITY
2673///
2674/// ```c
2675/// void *xmlListBack(xmlListPtr list);
2676/// ```
2677#[no_mangle]
2678pub extern "C" fn xmlListBack(_list: *mut c_void) -> *mut c_void {
2679    // Phase 1: STUB
2680    ptr::null_mut()
2681}
2682
2683/// Get list size.
2684///
2685/// # UPSTREAM-PARITY
2686///
2687/// ```c
2688/// int xmlListSize(xmlListPtr list);
2689/// ```
2690#[no_mangle]
2691pub extern "C" fn xmlListSize(_list: *mut c_void) -> c_int {
2692    // Phase 1: STUB
2693    0
2694}
2695
2696/// Sort a list.
2697#[no_mangle]
2698pub extern "C" fn xmlListSort(_list: *mut c_void) {
2699    // Phase 1: STUB
2700}
2701
2702/// Reverse a list.
2703#[no_mangle]
2704pub extern "C" fn xmlListReverse(_list: *mut c_void) {
2705    // Phase 1: STUB
2706}
2707
2708/// Reverse a list in-place.
2709#[no_mangle]
2710pub extern "C" fn xmlListReverseSplice(_list: *mut c_void, _list2: *mut c_void) {
2711    // Phase 1: STUB
2712}
2713
2714/// Merge two sorted lists.
2715#[no_mangle]
2716pub extern "C" fn xmlListMerge(_list: *mut c_void, _list2: *mut c_void) {
2717    // Phase 1: STUB
2718}
2719
2720// ═══════════════════════════════════════════════════════════════════════════════
2721// 12. Buffer
2722// ═══════════════════════════════════════════════════════════════════════════════
2723
2724/// Create a new buffer.
2725///
2726/// # UPSTREAM-PARITY
2727///
2728/// ```c
2729/// xmlBufferPtr xmlBufferCreate(void);
2730/// ```
2731#[no_mangle]
2732pub extern "C" fn xmlBufferCreate() -> *mut _xmlBuffer {
2733    // Phase 1: STUB
2734    ptr::null_mut()
2735}
2736
2737/// Create a new buffer of a given size.
2738///
2739/// # UPSTREAM-PARITY
2740///
2741/// ```c
2742/// xmlBufferPtr xmlBufferCreateSize(size_t size);
2743/// ```
2744#[no_mangle]
2745pub extern "C" fn xmlBufferCreateSize(_size: usize) -> *mut _xmlBuffer {
2746    // Phase 1: STUB
2747    ptr::null_mut()
2748}
2749
2750/// Create a buffer from a static string.
2751///
2752/// # UPSTREAM-PARITY
2753///
2754/// ```c
2755/// xmlBufferPtr xmlBufferCreateStatic(void *mem, size_t size);
2756/// ```
2757#[no_mangle]
2758pub extern "C" fn xmlBufferCreateStatic(_mem: *mut c_void, _size: usize) -> *mut _xmlBuffer {
2759    // Phase 1: STUB
2760    ptr::null_mut()
2761}
2762
2763/// Free a buffer.
2764///
2765/// # UPSTREAM-PARITY
2766///
2767/// ```c
2768/// void xmlBufferFree(xmlBufferPtr buf);
2769/// ```
2770#[no_mangle]
2771pub extern "C" fn xmlBufferFree(_buf: *mut _xmlBuffer) {
2772    // Phase 1: STUB
2773}
2774
2775/// Empty a buffer.
2776///
2777/// # UPSTREAM-PARITY
2778///
2779/// ```c
2780/// void xmlBufferEmpty(xmlBufferPtr buf);
2781/// ```
2782#[no_mangle]
2783pub extern "C" fn xmlBufferEmpty(_buf: *mut _xmlBuffer) {
2784    // Phase 1: STUB
2785}
2786
2787/// Get buffer content.
2788///
2789/// # UPSTREAM-PARITY
2790///
2791/// ```c
2792/// xmlChar *xmlBufferContent(const xmlBuffer *buf);
2793/// ```
2794#[no_mangle]
2795pub extern "C" fn xmlBufferContent(_buf: *const _xmlBuffer) -> *mut xmlChar {
2796    // Phase 1: STUB
2797    ptr::null_mut()
2798}
2799
2800/// Get buffer length.
2801///
2802/// # UPSTREAM-PARITY
2803///
2804/// ```c
2805/// int xmlBufferLength(const xmlBuffer *buf);
2806/// ```
2807#[no_mangle]
2808pub extern "C" fn xmlBufferLength(_buf: *const _xmlBuffer) -> c_int {
2809    // Phase 1: STUB
2810    0
2811}
2812
2813/// Write to a buffer.
2814///
2815/// # UPSTREAM-PARITY
2816///
2817/// ```c
2818/// int xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len);
2819/// ```
2820#[no_mangle]
2821pub unsafe extern "C" fn xmlBufferAdd(
2822    _buf: *mut _xmlBuffer,
2823    _str: *const xmlChar,
2824    _len: c_int,
2825) -> c_int {
2826    // Phase 1: STUB
2827    0
2828}
2829
2830/// Write to a buffer at a position.
2831///
2832/// # UPSTREAM-PARITY
2833///
2834/// ```c
2835/// int xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len);
2836/// ```
2837#[no_mangle]
2838pub unsafe extern "C" fn xmlBufferAddHead(
2839    _buf: *mut _xmlBuffer,
2840    _str: *const xmlChar,
2841    _len: c_int,
2842) -> c_int {
2843    // Phase 1: STUB
2844    0
2845}
2846
2847/// Set buffer allocation scheme.
2848///
2849/// # UPSTREAM-PARITY
2850///
2851/// ```c
2852/// void xmlBufferSetAllocationScheme(xmlBufferPtr buf,
2853///                                    xmlBufferAllocationScheme scheme);
2854/// ```
2855#[no_mangle]
2856pub extern "C" fn xmlBufferSetAllocationScheme(_buf: *mut _xmlBuffer, _scheme: c_int) {
2857    // Phase 1: STUB
2858}
2859
2860/// Shrink buffer.
2861///
2862/// # UPSTREAM-PARITY
2863///
2864/// ```c
2865/// int xmlBufferShrink(xmlBufferPtr buf, int len);
2866/// ```
2867#[no_mangle]
2868pub extern "C" fn xmlBufferShrink(_buf: *mut _xmlBuffer, _len: c_int) -> c_int {
2869    // Phase 1: STUB
2870    0
2871}
2872
2873/// Grow buffer.
2874///
2875/// # UPSTREAM-PARITY
2876///
2877/// ```c
2878/// int xmlBufferGrow(xmlBufferPtr buf, int len);
2879/// ```
2880#[no_mangle]
2881pub extern "C" fn xmlBufferGrow(_buf: *mut _xmlBuffer, _len: c_int) -> c_int {
2882    // Phase 1: STUB
2883    0
2884}
2885
2886/// Reserve buffer space.
2887///
2888/// # UPSTREAM-PARITY
2889///
2890/// ```c
2891/// int xmlBufferReserve(xmlBufferPtr buf, int len);
2892/// ```
2893#[no_mangle]
2894pub extern "C" fn xmlBufferReserve(_buf: *mut _xmlBuffer, _len: c_int) -> c_int {
2895    // Phase 1: STUB
2896    0
2897}
2898
2899/// Detach buffer content.
2900///
2901/// # UPSTREAM-PARITY
2902///
2903/// ```c
2904/// xmlChar *xmlBufferDetach(xmlBufferPtr buf);
2905/// ```
2906#[no_mangle]
2907pub extern "C" fn xmlBufferDetach(_buf: *mut _xmlBuffer) -> *mut xmlChar {
2908    // Phase 1: STUB
2909    ptr::null_mut()
2910}
2911
2912// ═══════════════════════════════════════════════════════════════════════════════
2913// 13. Encoding
2914// ═══════════════════════════════════════════════════════════════════════════════
2915
2916/// Get encoding from a name string.
2917///
2918/// # UPSTREAM-PARITY
2919///
2920/// ```c
2921/// xmlCharEncoding xmlGetCharEncoding(const char *name);
2922/// ```
2923#[no_mangle]
2924pub extern "C" fn xmlGetCharEncoding(_name: *const c_char) -> c_int {
2925    // Phase 1: STUB
2926    // Return XML_CHAR_ENCODING_NONE = 0
2927    0
2928}
2929
2930/// Find an encoding handler.
2931///
2932/// # UPSTREAM-PARITY
2933///
2934/// ```c
2935/// xmlCharEncodingHandlerPtr xmlFindCharEncodingHandler(const char *name);
2936/// ```
2937#[no_mangle]
2938pub extern "C" fn xmlFindCharEncodingHandler(_name: *const c_char) -> *mut c_void {
2939    // Phase 1: STUB
2940    ptr::null_mut()
2941}
2942
2943/// Close an encoding handler.
2944///
2945/// # UPSTREAM-PARITY
2946///
2947/// ```c
2948/// int xmlCharEncCloseFunc(xmlCharEncodingHandlerPtr handler);
2949/// ```
2950#[no_mangle]
2951pub extern "C" fn xmlCharEncCloseFunc(_handler: *mut c_void) -> c_int {
2952    // Phase 1: STUB
2953    0
2954}
2955
2956/// Convert an input buffer's encoding.
2957///
2958/// # UPSTREAM-PARITY
2959///
2960/// ```c
2961/// int xmlCharEncInput(xmlParserInputBufferPtr input, int to);
2962/// ```
2963#[no_mangle]
2964pub extern "C" fn xmlCharEncInput(_input: *mut _xmlParserInputBuffer, _to: c_int) -> c_int {
2965    // Phase 1: STUB
2966    0
2967}
2968
2969/// Convert an output buffer's encoding.
2970///
2971/// # UPSTREAM-PARITY
2972///
2973/// ```c
2974/// int xmlCharEncOutput(xmlOutputBufferPtr output, int to);
2975/// ```
2976#[no_mangle]
2977pub extern "C" fn xmlCharEncOutput(_output: *mut _xmlOutputBuffer, _to: c_int) -> c_int {
2978    // Phase 1: STUB
2979    0
2980}
2981
2982// ═══════════════════════════════════════════════════════════════════════════════
2983// 14. XPath
2984// ═══════════════════════════════════════════════════════════════════════════════
2985
2986/// Create a new XPath context.
2987///
2988/// # UPSTREAM-PARITY
2989///
2990/// ```c
2991/// xmlXPathContextPtr xmlXPathNewContext(xmlDocPtr doc);
2992/// ```
2993#[no_mangle]
2994pub unsafe extern "C" fn xmlXPathNewContext(_doc: *mut _xmlDoc) -> *mut _xmlXPathContext {
2995    // Phase 1: STUB
2996    ptr::null_mut()
2997}
2998
2999/// Free an XPath context.
3000///
3001/// # UPSTREAM-PARITY
3002///
3003/// ```c
3004/// void xmlXPathFreeContext(xmlXPathContextPtr ctxt);
3005/// ```
3006#[no_mangle]
3007pub extern "C" fn xmlXPathFreeContext(_ctxt: *mut _xmlXPathContext) {
3008    // Phase 1: STUB
3009}
3010
3011/// Evaluate an XPath expression.
3012///
3013/// # UPSTREAM-PARITY
3014///
3015/// ```c
3016/// xmlXPathObjectPtr xmlXPathEvalExpression(const xmlChar *str,
3017///                                          xmlXPathContextPtr ctxt);
3018/// ```
3019#[no_mangle]
3020pub unsafe extern "C" fn xmlXPathEvalExpression(
3021    _str: *const xmlChar,
3022    _ctxt: *mut _xmlXPathContext,
3023) -> *mut _xmlXPathObject {
3024    // Phase 1: STUB
3025    ptr::null_mut()
3026}
3027
3028/// Evaluate an XPath expression (simplified).
3029///
3030/// # UPSTREAM-PARITY
3031///
3032/// ```c
3033/// xmlXPathObjectPtr xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctxt);
3034/// ```
3035#[no_mangle]
3036pub unsafe extern "C" fn xmlXPathEval(
3037    _str: *const xmlChar,
3038    _ctxt: *mut _xmlXPathContext,
3039) -> *mut _xmlXPathObject {
3040    // Phase 1: STUB
3041    ptr::null_mut()
3042}
3043
3044/// Free an XPath object.
3045///
3046/// # UPSTREAM-PARITY
3047///
3048/// ```c
3049/// void xmlXPathFreeObject(xmlXPathObjectPtr obj);
3050/// ```
3051#[no_mangle]
3052pub extern "C" fn xmlXPathFreeObject(_obj: *mut _xmlXPathObject) {
3053    // Phase 1: STUB
3054}
3055
3056/// Compile an XPath expression.
3057///
3058/// # UPSTREAM-PARITY
3059///
3060/// ```c
3061/// xmlXPathCompExprPtr xmlXPathCompile(const xmlChar *str);
3062/// ```
3063#[no_mangle]
3064pub unsafe extern "C" fn xmlXPathCompile(_str: *const xmlChar) -> *mut c_void {
3065    // Phase 1: STUB
3066    ptr::null_mut()
3067}
3068
3069/// Free a compiled XPath expression.
3070///
3071/// # UPSTREAM-PARITY
3072///
3073/// ```c
3074/// void xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp);
3075/// ```
3076#[no_mangle]
3077pub extern "C" fn xmlXPathFreeCompExpr(_comp: *mut c_void) {
3078    // Phase 1: STUB
3079}
3080
3081/// Register an XPath namespace.
3082///
3083/// # UPSTREAM-PARITY
3084///
3085/// ```c
3086/// int xmlXPathRegisterNs(xmlXPathContextPtr ctxt,
3087///                        const xmlChar *prefix, const xmlChar *ns_uri);
3088/// ```
3089#[no_mangle]
3090pub unsafe extern "C" fn xmlXPathRegisterNs(
3091    _ctxt: *mut _xmlXPathContext,
3092    _prefix: *const xmlChar,
3093    _ns_uri: *const xmlChar,
3094) -> c_int {
3095    // Phase 1: STUB
3096    0
3097}
3098
3099/// Register an XPath function.
3100///
3101/// # UPSTREAM-PARITY
3102///
3103/// ```c
3104/// int xmlXPathRegisterFunc(xmlXPathContextPtr ctxt,
3105///                          const xmlChar *name, xmlXPathFunction f);
3106/// ```
3107#[no_mangle]
3108pub unsafe extern "C" fn xmlXPathRegisterFunc(
3109    _ctxt: *mut _xmlXPathContext,
3110    _name: *const xmlChar,
3111    _f: Option<unsafe extern "C" fn(*mut c_void, c_int)>,
3112) -> c_int {
3113    // Phase 1: STUB
3114    0
3115}
3116
3117/// Register an XPath function with namespace.
3118///
3119/// # UPSTREAM-PARITY
3120///
3121/// ```c
3122/// int xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt,
3123///                            const xmlChar *name, const xmlChar *ns_uri,
3124///                            xmlXPathFunction f);
3125/// ```
3126#[no_mangle]
3127pub unsafe extern "C" fn xmlXPathRegisterFuncNS(
3128    _ctxt: *mut _xmlXPathContext,
3129    _name: *const xmlChar,
3130    _ns_uri: *const xmlChar,
3131    _f: Option<unsafe extern "C" fn(*mut c_void, c_int)>,
3132) -> c_int {
3133    // Phase 1: STUB
3134    0
3135}
3136
3137/// Register an XPath variable.
3138///
3139/// # UPSTREAM-PARITY
3140///
3141/// ```c
3142/// int xmlXPathRegisterVariable(xmlXPathContextPtr ctxt,
3143///                              const xmlChar *name, xmlXPathObjectPtr value);
3144/// ```
3145#[no_mangle]
3146pub unsafe extern "C" fn xmlXPathRegisterVariable(
3147    _ctxt: *mut _xmlXPathContext,
3148    _name: *const xmlChar,
3149    _value: *mut _xmlXPathObject,
3150) -> c_int {
3151    // Phase 1: STUB
3152    0
3153}
3154
3155/// Create an XPath object from a node set.
3156///
3157/// # UPSTREAM-PARITY
3158///
3159/// ```c
3160/// xmlXPathObjectPtr xmlXPathNewNodeSet(xmlNodePtr val);
3161/// ```
3162#[no_mangle]
3163pub unsafe extern "C" fn xmlXPathNewNodeSet(_val: *mut _xmlNode) -> *mut _xmlXPathObject {
3164    // Phase 1: STUB
3165    ptr::null_mut()
3166}
3167
3168/// Create an XPath object from a value.
3169///
3170/// # UPSTREAM-PARITY
3171///
3172/// ```c
3173/// xmlXPathObjectPtr xmlXPathNewCString(const xmlChar *val);
3174/// ```
3175#[no_mangle]
3176pub unsafe extern "C" fn xmlXPathNewCString(_val: *const xmlChar) -> *mut _xmlXPathObject {
3177    // Phase 1: STUB
3178    ptr::null_mut()
3179}
3180
3181/// Create an XPath number object.
3182///
3183/// # UPSTREAM-PARITY
3184///
3185/// ```c
3186/// xmlXPathObjectPtr xmlXPathNewFloat(double val);
3187/// ```
3188#[no_mangle]
3189pub extern "C" fn xmlXPathNewFloat(_val: f64) -> *mut _xmlXPathObject {
3190    // Phase 1: STUB
3191    ptr::null_mut()
3192}
3193
3194/// Create an XPath boolean object.
3195///
3196/// # UPSTREAM-PARITY
3197///
3198/// ```c
3199/// xmlXPathObjectPtr xmlXPathNewBoolean(int val);
3200/// ```
3201#[no_mangle]
3202pub extern "C" fn xmlXPathNewBoolean(_val: c_int) -> *mut _xmlXPathObject {
3203    // Phase 1: STUB
3204    ptr::null_mut()
3205}
3206
3207// ═══════════════════════════════════════════════════════════════════════════════
3208// 15. XInclude
3209// ═══════════════════════════════════════════════════════════════════════════════
3210
3211/// Process XInclude nodes in a document.
3212///
3213/// # UPSTREAM-PARITY
3214///
3215/// ```c
3216/// int xmlXIncludeProcess(xmlDocPtr doc);
3217/// ```
3218#[no_mangle]
3219pub extern "C" fn xmlXIncludeProcess(_doc: *mut _xmlDoc) -> c_int {
3220    // Phase 1: STUB
3221    -1
3222}
3223
3224/// Process XInclude nodes with flags.
3225///
3226/// # UPSTREAM-PARITY
3227///
3228/// ```c
3229/// int xmlXIncludeProcessFlags(xmlDocPtr doc, int flags);
3230/// ```
3231#[no_mangle]
3232pub extern "C" fn xmlXIncludeProcessFlags(_doc: *mut _xmlDoc, _flags: c_int) -> c_int {
3233    // Phase 1: STUB
3234    -1
3235}
3236
3237// ═══════════════════════════════════════════════════════════════════════════════
3238// 16. Catalog
3239// ═══════════════════════════════════════════════════════════════════════════════
3240
3241/// Load a catalog.
3242///
3243/// # UPSTREAM-PARITY
3244///
3245/// ```c
3246/// xmlCatalogPtr xmlCatalogLoad(const char *catalogs);
3247/// ```
3248#[no_mangle]
3249pub extern "C" fn xmlCatalogLoad(_catalogs: *const c_char) -> *mut c_void {
3250    // Phase 1: STUB
3251    ptr::null_mut()
3252}
3253
3254/// Resolve a public ID.
3255///
3256/// # UPSTREAM-PARITY
3257///
3258/// ```c
3259/// xmlCharPtr xmlCatalogResolvePublic(const xmlChar *pubID);
3260/// ```
3261#[no_mangle]
3262pub unsafe extern "C" fn xmlCatalogResolvePublic(_pubID: *const xmlChar) -> *mut xmlChar {
3263    // Phase 1: STUB
3264    ptr::null_mut()
3265}
3266
3267/// Resolve a system ID.
3268///
3269/// # UPSTREAM-PARITY
3270///
3271/// ```c
3272/// xmlCharPtr xmlCatalogResolveSystem(const xmlChar *sysID);
3273/// ```
3274#[no_mangle]
3275pub unsafe extern "C" fn xmlCatalogResolveSystem(_sysID: *const xmlChar) -> *mut xmlChar {
3276    // Phase 1: STUB
3277    ptr::null_mut()
3278}
3279
3280/// Resolve a URI.
3281///
3282/// # UPSTREAM-PARITY
3283///
3284/// ```c
3285/// xmlCharPtr xmlCatalogResolveURI(const xmlChar *URI);
3286/// ```
3287#[no_mangle]
3288pub unsafe extern "C" fn xmlCatalogResolveURI(_URI: *const xmlChar) -> *mut xmlChar {
3289    // Phase 1: STUB
3290    ptr::null_mut()
3291}
3292
3293/// Set catalog defaults.
3294///
3295/// # UPSTREAM-PARITY
3296///
3297/// ```c
3298/// void xmlCatalogSetDefaults(xmlCatalogAllowValue allow);
3299/// ```
3300#[no_mangle]
3301pub extern "C" fn xmlCatalogSetDefaults(_allow: c_int) {
3302    // Phase 1: STUB
3303}
3304
3305/// Get catalog defaults.
3306///
3307/// # UPSTREAM-PARITY
3308///
3309/// ```c
3310/// xmlCatalogAllowValue xmlCatalogGetDefaults(void);
3311/// ```
3312#[no_mangle]
3313pub extern "C" fn xmlCatalogGetDefaults() -> c_int {
3314    // Phase 1: STUB
3315    0
3316}
3317
3318/// Add a catalog.
3319///
3320/// # UPSTREAM-PARITY
3321///
3322/// ```c
3323/// int xmlCatalogAdd(const xmlChar *type, const xmlChar *orig, const xmlChar *replace);
3324/// ```
3325#[no_mangle]
3326pub unsafe extern "C" fn xmlCatalogAdd(
3327    _type: *const xmlChar,
3328    _orig: *const xmlChar,
3329    _replace: *const xmlChar,
3330) -> c_int {
3331    // Phase 1: STUB
3332    0
3333}
3334
3335/// Remove a catalog entry.
3336///
3337/// # UPSTREAM-PARITY
3338///
3339/// ```c
3340/// int xmlCatalogRemove(const xmlChar *value);
3341/// ```
3342#[no_mangle]
3343pub unsafe extern "C" fn xmlCatalogRemove(_value: *const xmlChar) -> c_int {
3344    // Phase 1: STUB
3345    0
3346}
3347
3348/// Clean up the catalog subsystem.
3349///
3350/// # UPSTREAM-PARITY
3351///
3352/// ```c
3353/// void xmlCatalogCleanup(void);
3354/// ```
3355#[no_mangle]
3356pub extern "C" fn xmlCatalogCleanup() {
3357    // Phase 1: STUB
3358}
3359
3360/// Convert an SGML catalog to XML.
3361///
3362/// # UPSTREAM-PARITY
3363///
3364/// ```c
3365/// xmlDocPtr xmlCatalogConvert(void);
3366/// ```
3367#[no_mangle]
3368pub extern "C" fn xmlCatalogConvert() -> *mut _xmlDoc {
3369    // Phase 1: STUB
3370    ptr::null_mut()
3371}
3372
3373// ═══════════════════════════════════════════════════════════════════════════════
3374// 17. HTML
3375// ═══════════════════════════════════════════════════════════════════════════════
3376
3377/// Parse an HTML document from a file.
3378///
3379/// # UPSTREAM-PARITY
3380///
3381/// ```c
3382/// htmlDocPtr htmlParseFile(const char *filename, const char *encoding);
3383/// ```
3384#[no_mangle]
3385pub unsafe extern "C" fn htmlParseFile(
3386    _filename: *const c_char,
3387    _encoding: *const c_char,
3388) -> *mut _xmlDoc {
3389    // Phase 1: STUB
3390    ptr::null_mut()
3391}
3392
3393/// Parse an HTML document from memory.
3394///
3395/// # UPSTREAM-PARITY
3396///
3397/// ```c
3398/// htmlDocPtr htmlParseMemory(const char *buffer, int size);
3399/// ```
3400#[no_mangle]
3401pub unsafe extern "C" fn htmlParseMemory(_buffer: *const c_char, _size: c_int) -> *mut _xmlDoc {
3402    // Phase 1: STUB
3403    ptr::null_mut()
3404}
3405
3406/// Parse an HTML document from a document string.
3407///
3408/// # UPSTREAM-PARITY
3409///
3410/// ```c
3411/// htmlDocPtr htmlParseDoc(const xmlChar *cur, const char *encoding);
3412/// ```
3413#[no_mangle]
3414pub unsafe extern "C" fn htmlParseDoc(
3415    _cur: *const xmlChar,
3416    _encoding: *const c_char,
3417) -> *mut _xmlDoc {
3418    // Phase 1: STUB
3419    ptr::null_mut()
3420}
3421
3422/// Create an HTML parser context.
3423///
3424/// # UPSTREAM-PARITY
3425///
3426/// ```c
3427/// htmlParserCtxtPtr htmlCreateFileParserCtxt(const char *filename,
3428///                                            const char *encoding);
3429/// ```
3430#[no_mangle]
3431pub unsafe extern "C" fn htmlCreateFileParserCtxt(
3432    _filename: *const c_char,
3433    _encoding: *const c_char,
3434) -> *mut c_void {
3435    // Phase 1: STUB
3436    ptr::null_mut()
3437}
3438
3439/// Free an HTML parser context.
3440///
3441/// # UPSTREAM-PARITY
3442///
3443/// ```c
3444/// void htmlFreeParserCtxt(htmlParserCtxtPtr ctxt);
3445/// ```
3446#[no_mangle]
3447pub extern "C" fn htmlFreeParserCtxt(_ctxt: *mut c_void) {
3448    // Phase 1: STUB
3449}
3450
3451/// Initialize the HTML parser.
3452///
3453/// # UPSTREAM-PARITY
3454///
3455/// ```c
3456/// void htmlInitParser(void);
3457/// ```
3458#[no_mangle]
3459pub extern "C" fn htmlInitParser() {
3460    // Phase 1: STUB
3461}
3462
3463/// Clean up the HTML parser.
3464///
3465/// # UPSTREAM-PARITY
3466///
3467/// ```c
3468/// void htmlCleanupParser(void);
3469/// ```
3470#[no_mangle]
3471pub extern "C" fn htmlCleanupParser() {
3472    // Phase 1: STUB
3473}
3474
3475// ═══════════════════════════════════════════════════════════════════════════════
3476// 18. Debug / Miscellaneous
3477// ═══════════════════════════════════════════════════════════════════════════════
3478
3479/// Dump a document to a file for debugging.
3480///
3481/// # UPSTREAM-PARITY
3482///
3483/// ```c
3484/// void xmlDebugDumpDocument(FILE *output, xmlDocPtr doc);
3485/// ```
3486#[no_mangle]
3487pub unsafe extern "C" fn xmlDebugDumpDocument(_output: *mut c_void, _doc: *mut _xmlDoc) {
3488    // Phase 1: STUB
3489}
3490
3491/// Dump a node for debugging.
3492///
3493/// # UPSTREAM-PARITY
3494///
3495/// ```c
3496/// void xmlDebugDumpNode(FILE *output, xmlNodePtr node);
3497/// ```
3498#[no_mangle]
3499pub unsafe extern "C" fn xmlDebugDumpNode(_output: *mut c_void, _node: *mut _xmlNode) {
3500    // Phase 1: STUB
3501}
3502
3503/// Dump a node for debugging (recursive).
3504///
3505/// # UPSTREAM-PARITY
3506///
3507/// ```c
3508/// void xmlDebugDumpNodeList(FILE *output, xmlNodePtr node);
3509/// ```
3510#[no_mangle]
3511pub unsafe extern "C" fn xmlDebugDumpNodeList(_output: *mut c_void, _node: *mut _xmlNode) {
3512    // Phase 1: STUB
3513}
3514
3515/// Get the path to the current executable.
3516///
3517/// # UPSTREAM-PARITY
3518///
3519/// ```c
3520/// char *xmlGetBinaryPath(void);
3521/// ```
3522#[no_mangle]
3523pub extern "C" fn xmlGetBinaryPath() -> *mut c_char {
3524    // Phase 1: STUB
3525    ptr::null_mut()
3526}
3527
3528/// Get the path to the current executable's home directory.
3529///
3530/// # UPSTREAM-PARITY
3531///
3532/// ```c
3533/// char *xmlGetHomeOfBinary(void);
3534/// ```
3535#[no_mangle]
3536pub extern "C" fn xmlGetHomeOfBinary() -> *mut c_char {
3537    // Phase 1: STUB
3538    ptr::null_mut()
3539}