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// Serialization — xmlNodeDump, xmlDocDump, xmlSaveFile, etc.
1270// ═══════════════════════════════════════════════════════════════════════════════
1271
1272/// Dump a node to a buffer.
1273///
1274/// # UPSTREAM-PARITY
1275///
1276/// ```c
1277/// int xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level, int format);
1278/// ```
1279#[no_mangle]
1280pub unsafe extern "C" fn xmlNodeDump(
1281    buf: *mut _xmlBuffer,
1282    doc: *mut _xmlDoc,
1283    cur: *mut _xmlNode,
1284    level: c_int,
1285    format: c_int,
1286) -> c_int {
1287    if buf.is_null() || cur.is_null() {
1288        return -1;
1289    }
1290    crate::xml::tree::xmlNodeDump(buf, doc, cur, level, format)
1291}
1292
1293/// Dump a document to a file pointer.
1294///
1295/// # UPSTREAM-PARITY
1296///
1297/// ```c
1298/// int xmlDocDump(FILE *f, xmlDocPtr doc);
1299/// ```
1300#[no_mangle]
1301pub unsafe extern "C" fn xmlDocDump(fp: *mut c_void, doc: *mut _xmlDoc) -> c_int {
1302    if fp.is_null() || doc.is_null() {
1303        return -1;
1304    }
1305    crate::xml::tree::xmlDocDump(fp, doc)
1306}
1307
1308/// Dump a document to memory with format.
1309///
1310/// # UPSTREAM-PARITY
1311///
1312/// ```c
1313/// void xmlDocDumpFormatMemory(xmlDocPtr doc, xmlChar **mem, int *size, int format);
1314/// ```
1315#[no_mangle]
1316pub unsafe extern "C" fn xmlDocDumpFormatMemory(
1317    doc: *mut _xmlDoc,
1318    mem: *mut *mut xmlChar,
1319    size: *mut c_int,
1320    format: c_int,
1321) {
1322    if doc.is_null() || mem.is_null() || size.is_null() {
1323        return;
1324    }
1325    crate::xml::tree::xmlDocDumpFormatMemory(doc, mem, size, format)
1326}
1327
1328/// Dump a document to memory (unformatted).
1329///
1330/// # UPSTREAM-PARITY
1331///
1332/// ```c
1333/// void xmlDocDumpMemory(xmlDocPtr doc, xmlChar **mem, int *size);
1334/// ```
1335#[no_mangle]
1336pub unsafe extern "C" fn xmlDocDumpMemory(
1337    doc: *mut _xmlDoc,
1338    mem: *mut *mut xmlChar,
1339    size: *mut c_int,
1340) {
1341    if doc.is_null() || mem.is_null() || size.is_null() {
1342        return;
1343    }
1344    crate::xml::tree::xmlDocDumpMemory(doc, mem, size)
1345}
1346
1347/// Save a document to a file.
1348///
1349/// # UPSTREAM-PARITY
1350///
1351/// ```c
1352/// int xmlSaveFile(const char *filename, xmlDocPtr cur);
1353/// ```
1354#[no_mangle]
1355pub unsafe extern "C" fn xmlSaveFile(filename: *const c_char, cur: *mut _xmlDoc) -> c_int {
1356    if filename.is_null() || cur.is_null() {
1357        return -1;
1358    }
1359    crate::xml::tree::xmlSaveFile(filename, cur)
1360}
1361
1362/// Save a document to a file with encoding.
1363///
1364/// # UPSTREAM-PARITY
1365///
1366/// ```c
1367/// int xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding);
1368/// ```
1369#[no_mangle]
1370pub unsafe extern "C" fn xmlSaveFileEnc(
1371    filename: *const c_char,
1372    cur: *mut _xmlDoc,
1373    encoding: *const c_char,
1374) -> c_int {
1375    if filename.is_null() || cur.is_null() {
1376        return -1;
1377    }
1378    crate::xml::tree::xmlSaveFileEnc(filename, cur, encoding)
1379}
1380
1381/// Save a document to a file with format.
1382///
1383/// # UPSTREAM-PARITY
1384///
1385/// ```c
1386/// int xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format);
1387/// ```
1388#[no_mangle]
1389pub unsafe extern "C" fn xmlSaveFormatFile(
1390    filename: *const c_char,
1391    cur: *mut _xmlDoc,
1392    format: c_int,
1393) -> c_int {
1394    if filename.is_null() || cur.is_null() {
1395        return -1;
1396    }
1397    crate::xml::tree::xmlSaveFormatFile(filename, cur, format)
1398}
1399
1400/// Save a document to a file with encoding and format.
1401///
1402/// # UPSTREAM-PARITY
1403///
1404/// ```c
1405/// int xmlSaveFormatFileEnc(const char *filename, xmlDocPtr cur, const char *encoding, int format);
1406/// ```
1407#[no_mangle]
1408pub unsafe extern "C" fn xmlSaveFormatFileEnc(
1409    filename: *const c_char,
1410    cur: *mut _xmlDoc,
1411    encoding: *const c_char,
1412    format: c_int,
1413) -> c_int {
1414    if filename.is_null() || cur.is_null() {
1415        return -1;
1416    }
1417    crate::xml::tree::xmlSaveFormatFileEnc(filename, cur, encoding, format)
1418}
1419
1420// ═══════════════════════════════════════════════════════════════════════════════
1421// 7. Parser — SAX, DOM, Push, Reader
1422// ═══════════════════════════════════════════════════════════════════════════════
1423
1424/// Read an XML document from a string.
1425///
1426/// # UPSTREAM-PARITY
1427///
1428/// ```c
1429/// xmlDocPtr xmlReadDoc(const xmlChar *cur, const char *URL,
1430///                      const char *encoding, int options);
1431/// ```
1432///
1433/// Returns a parsed document. Caller must free with `xmlFreeDoc`.
1434#[no_mangle]
1435pub unsafe extern "C" fn xmlReadDoc(
1436    cur: *const xmlChar,
1437    URL: *const c_char,
1438    encoding: *const c_char,
1439    options: c_int,
1440) -> *mut _xmlDoc {
1441    // SAFETY: cur must be a valid null-terminated xmlChar string if non-null.
1442    if cur.is_null() {
1443        return ptr::null_mut();
1444    }
1445    let ctxt = crate::xml::parser::helpers::create_parser_ctxt();
1446    if ctxt.is_null() {
1447        return ptr::null_mut();
1448    }
1449    let len = crate::xml::string::xml_strlen(cur);
1450    let input = crate::xml::parser::helpers::input_from_memory(cur as *const c_char, len as c_int);
1451    crate::xml::parser::helpers::setup_parser_input(ctxt, input);
1452    (*ctxt).options = options;
1453    if crate::xml::parser::helpers::parse_document(ctxt) != 0 {
1454        let doc = (*ctxt).myDoc;
1455        crate::xml::parser::helpers::free_parser_ctxt(ctxt);
1456        return doc;
1457    }
1458    let doc = (*ctxt).myDoc;
1459    if !doc.is_null() {
1460        (*doc).URL = crate::xml::string::xml_strdup(URL as *const xmlChar);
1461    }
1462    crate::xml::parser::helpers::free_parser_ctxt(ctxt);
1463    doc
1464}
1465
1466/// Read an XML document from a file.
1467///
1468/// # UPSTREAM-PARITY
1469///
1470/// ```c
1471/// xmlDocPtr xmlReadFile(const char *URL, const char *encoding, int options);
1472/// ```
1473#[no_mangle]
1474pub unsafe extern "C" fn xmlReadFile(
1475    URL: *const c_char,
1476    encoding: *const c_char,
1477    options: c_int,
1478) -> *mut _xmlDoc {
1479    // SAFETY: URL must be a valid C string or NULL.
1480    if URL.is_null() {
1481        return ptr::null_mut();
1482    }
1483    let ctxt = crate::xml::parser::helpers::create_parser_ctxt();
1484    if ctxt.is_null() {
1485        return ptr::null_mut();
1486    }
1487    let input = match crate::xml::parser::helpers::input_from_file(URL) {
1488        Ok(input) => input,
1489        Err(_) => {
1490            crate::xml::parser::helpers::free_parser_ctxt(ctxt);
1491            return ptr::null_mut();
1492        }
1493    };
1494    crate::xml::parser::helpers::setup_parser_input(ctxt, input);
1495    (*ctxt).options = options;
1496    if crate::xml::parser::helpers::parse_document(ctxt) != 0 {
1497        let doc = (*ctxt).myDoc;
1498        crate::xml::parser::helpers::free_parser_ctxt(ctxt);
1499        return doc;
1500    }
1501    let doc = (*ctxt).myDoc;
1502    crate::xml::parser::helpers::free_parser_ctxt(ctxt);
1503    doc
1504}
1505
1506/// Read an XML document from memory.
1507///
1508/// # UPSTREAM-PARITY
1509///
1510/// ```c
1511/// xmlDocPtr xmlReadMemory(const char *buffer, int size,
1512///                         const char *URL, const char *encoding, int options);
1513/// ```
1514#[no_mangle]
1515pub unsafe extern "C" fn xmlReadMemory(
1516    buffer: *const c_char,
1517    size: c_int,
1518    URL: *const c_char,
1519    encoding: *const c_char,
1520    options: c_int,
1521) -> *mut _xmlDoc {
1522    // SAFETY: buffer must be a valid pointer with at least `size` readable bytes.
1523    if buffer.is_null() || size <= 0 {
1524        return ptr::null_mut();
1525    }
1526    let ctxt = crate::xml::parser::helpers::create_parser_ctxt();
1527    if ctxt.is_null() {
1528        return ptr::null_mut();
1529    }
1530    let input = crate::xml::parser::helpers::input_from_memory(buffer, size);
1531    crate::xml::parser::helpers::setup_parser_input(ctxt, input);
1532    (*ctxt).options = options;
1533    if crate::xml::parser::helpers::parse_document(ctxt) != 0 {
1534        let doc = (*ctxt).myDoc;
1535        crate::xml::parser::helpers::free_parser_ctxt(ctxt);
1536        return doc;
1537    }
1538    let doc = (*ctxt).myDoc;
1539    if !doc.is_null() && !URL.is_null() {
1540        (*doc).URL = crate::xml::string::xml_strdup(URL as *const xmlChar);
1541    }
1542    crate::xml::parser::helpers::free_parser_ctxt(ctxt);
1543    doc
1544}
1545
1546/// Read an XML document from a file descriptor.
1547///
1548/// # UPSTREAM-PARITY
1549///
1550/// ```c
1551/// xmlDocPtr xmlReadFd(int fd, const char *URL, const char *encoding, int options);
1552/// ```
1553#[no_mangle]
1554pub unsafe extern "C" fn xmlReadFd(
1555    fd: c_int,
1556    URL: *const c_char,
1557    encoding: *const c_char,
1558    options: c_int,
1559) -> *mut _xmlDoc {
1560    // SAFETY: fd must be a valid open file descriptor.
1561    let ctxt = crate::xml::parser::helpers::create_parser_ctxt();
1562    if ctxt.is_null() {
1563        return ptr::null_mut();
1564    }
1565    // Read all data from the fd
1566    let mut buf = Vec::new();
1567    let mut tmp = [0u8; 4096];
1568    loop {
1569        let n = libc::read(fd, tmp.as_mut_ptr() as *mut c_void, tmp.len());
1570        if n <= 0 {
1571            break;
1572        }
1573        buf.extend_from_slice(&tmp[..n as usize]);
1574    }
1575    let input = crate::xml::parser::helpers::input_from_memory(
1576        buf.as_ptr() as *const c_char,
1577        buf.len() as c_int,
1578    );
1579    crate::xml::parser::helpers::setup_parser_input(ctxt, input);
1580    (*ctxt).options = options;
1581    if crate::xml::parser::helpers::parse_document(ctxt) != 0 {
1582        let doc = (*ctxt).myDoc;
1583        crate::xml::parser::helpers::free_parser_ctxt(ctxt);
1584        return doc;
1585    }
1586    let doc = (*ctxt).myDoc;
1587    if !doc.is_null() && !URL.is_null() {
1588        (*doc).URL = crate::xml::string::xml_strdup(URL as *const xmlChar);
1589    }
1590    crate::xml::parser::helpers::free_parser_ctxt(ctxt);
1591    doc
1592}
1593
1594/// Read an XML document from I/O callbacks.
1595///
1596/// # UPSTREAM-PARITY
1597///
1598/// ```c
1599/// xmlDocPtr xmlReadIO(xmlInputReadCallback ioread, xmlInputCloseCallback ioclose,
1600///                     void *ioctx, const char *URL, const char *encoding, int options);
1601/// ```
1602#[no_mangle]
1603pub unsafe extern "C" fn xmlReadIO(
1604    ioread: Option<xmlInputReadCallback>,
1605    ioclose: Option<xmlInputCloseCallback>,
1606    ioctx: *mut c_void,
1607    URL: *const c_char,
1608    encoding: *const c_char,
1609    options: c_int,
1610) -> *mut _xmlDoc {
1611    // SAFETY: callbacks must be valid function pointers if non-NULL.
1612    let ctxt = crate::xml::parser::helpers::create_parser_ctxt();
1613    if ctxt.is_null() {
1614        return ptr::null_mut();
1615    }
1616    let input = crate::xml::parser::helpers::input_from_io(ioread, ioclose, ioctx);
1617    crate::xml::parser::helpers::setup_parser_input(ctxt, input);
1618    (*ctxt).options = options;
1619    if crate::xml::parser::helpers::parse_document(ctxt) != 0 {
1620        let doc = (*ctxt).myDoc;
1621        crate::xml::parser::helpers::free_parser_ctxt(ctxt);
1622        return doc;
1623    }
1624    let doc = (*ctxt).myDoc;
1625    if !doc.is_null() && !URL.is_null() {
1626        (*doc).URL = crate::xml::string::xml_strdup(URL as *const xmlChar);
1627    }
1628    crate::xml::parser::helpers::free_parser_ctxt(ctxt);
1629    doc
1630}
1631
1632/// Parse an XML document (SAX1).
1633///
1634/// # UPSTREAM-PARITY
1635///
1636/// ```c
1637/// xmlDocPtr xmlSAXParseDoc(xmlSAXHandlerPtr sax, const xmlChar *cur, int recovery);
1638/// ```
1639#[no_mangle]
1640pub unsafe extern "C" fn xmlSAXParseDoc(
1641    sax: *mut _xmlSAXHandler,
1642    cur: *const xmlChar,
1643    recovery: c_int,
1644) -> *mut _xmlDoc {
1645    // SAFETY: cur must be a valid null-terminated xmlChar string.
1646    if cur.is_null() {
1647        return ptr::null_mut();
1648    }
1649    let ctxt = crate::xml::parser::helpers::create_parser_ctxt();
1650    if ctxt.is_null() {
1651        return ptr::null_mut();
1652    }
1653    if !sax.is_null() {
1654        (*ctxt).sax = sax;
1655        (*ctxt).userData = (*ctxt).sax as *mut c_void;
1656    }
1657    if recovery != 0 {
1658        (*ctxt).recovery = 1;
1659        (*ctxt).options |= 1; // XML_PARSE_RECOVER
1660    }
1661    let len = crate::xml::string::xml_strlen(cur);
1662    let input = crate::xml::parser::helpers::input_from_memory(cur as *const c_char, len as c_int);
1663    crate::xml::parser::helpers::setup_parser_input(ctxt, input);
1664    crate::xml::parser::helpers::parse_document(ctxt);
1665    let doc = (*ctxt).myDoc;
1666    crate::xml::parser::helpers::free_parser_ctxt(ctxt);
1667    doc
1668}
1669
1670/// Parse an XML file (SAX1).
1671///
1672/// # UPSTREAM-PARITY
1673///
1674/// ```c
1675/// xmlDocPtr xmlSAXParseFile(xmlSAXHandlerPtr sax, const char *filename, int recovery);
1676/// ```
1677#[no_mangle]
1678pub unsafe extern "C" fn xmlSAXParseFile(
1679    sax: *mut _xmlSAXHandler,
1680    filename: *const c_char,
1681    recovery: c_int,
1682) -> *mut _xmlDoc {
1683    // SAFETY: filename must be a valid C string.
1684    if filename.is_null() {
1685        return ptr::null_mut();
1686    }
1687    let ctxt = crate::xml::parser::helpers::create_parser_ctxt();
1688    if ctxt.is_null() {
1689        return ptr::null_mut();
1690    }
1691    if !sax.is_null() {
1692        (*ctxt).sax = sax;
1693        (*ctxt).userData = (*ctxt).sax as *mut c_void;
1694    }
1695    if recovery != 0 {
1696        (*ctxt).recovery = 1;
1697        (*ctxt).options |= 1;
1698    }
1699    let input = match crate::xml::parser::helpers::input_from_file(filename) {
1700        Ok(input) => input,
1701        Err(_) => {
1702            crate::xml::parser::helpers::free_parser_ctxt(ctxt);
1703            return ptr::null_mut();
1704        }
1705    };
1706    crate::xml::parser::helpers::setup_parser_input(ctxt, input);
1707    crate::xml::parser::helpers::parse_document(ctxt);
1708    let doc = (*ctxt).myDoc;
1709    crate::xml::parser::helpers::free_parser_ctxt(ctxt);
1710    doc
1711}
1712
1713/// Parse an XML document from memory (SAX1).
1714///
1715/// # UPSTREAM-PARITY
1716///
1717/// ```c
1718/// xmlDocPtr xmlSAXParseMemory(xmlSAXHandlerPtr sax,
1719///                             const char *buffer, int size, int recovery);
1720/// ```
1721#[no_mangle]
1722pub unsafe extern "C" fn xmlSAXParseMemory(
1723    sax: *mut _xmlSAXHandler,
1724    buffer: *const c_char,
1725    size: c_int,
1726    recovery: c_int,
1727) -> *mut _xmlDoc {
1728    // SAFETY: buffer must be valid with at least `size` bytes.
1729    if buffer.is_null() || size <= 0 {
1730        return ptr::null_mut();
1731    }
1732    let ctxt = crate::xml::parser::helpers::create_parser_ctxt();
1733    if ctxt.is_null() {
1734        return ptr::null_mut();
1735    }
1736    if !sax.is_null() {
1737        (*ctxt).sax = sax;
1738        (*ctxt).userData = (*ctxt).sax as *mut c_void;
1739    }
1740    if recovery != 0 {
1741        (*ctxt).recovery = 1;
1742        (*ctxt).options |= 1;
1743    }
1744    let input = crate::xml::parser::helpers::input_from_memory(buffer, size);
1745    crate::xml::parser::helpers::setup_parser_input(ctxt, input);
1746    crate::xml::parser::helpers::parse_document(ctxt);
1747    let doc = (*ctxt).myDoc;
1748    crate::xml::parser::helpers::free_parser_ctxt(ctxt);
1749    doc
1750}
1751
1752/// SAX user parse file.
1753///
1754/// # UPSTREAM-PARITY
1755///
1756/// ```c
1757/// int xmlSAXUserParseFile(xmlSAXHandlerPtr sax, void *user_data,
1758///                         const char *filename);
1759/// ```
1760#[no_mangle]
1761pub unsafe extern "C" fn xmlSAXUserParseFile(
1762    sax: *mut _xmlSAXHandler,
1763    user_data: *mut c_void,
1764    filename: *const c_char,
1765) -> c_int {
1766    // SAFETY: filename must be a valid C string. sax and user_data may be NULL.
1767    if filename.is_null() {
1768        return -1;
1769    }
1770    let ctxt = crate::xml::parser::helpers::create_parser_ctxt();
1771    if ctxt.is_null() {
1772        return -1;
1773    }
1774    if !sax.is_null() {
1775        (*ctxt).sax = sax;
1776    }
1777    (*ctxt).userData = if !user_data.is_null() {
1778        user_data
1779    } else {
1780        ctxt as *mut c_void
1781    };
1782    let input = match crate::xml::parser::helpers::input_from_file(filename) {
1783        Ok(input) => input,
1784        Err(_) => {
1785            crate::xml::parser::helpers::free_parser_ctxt(ctxt);
1786            return -1;
1787        }
1788    };
1789    crate::xml::parser::helpers::setup_parser_input(ctxt, input);
1790    let ret = crate::xml::parser::helpers::parse_document(ctxt);
1791    crate::xml::parser::helpers::free_parser_ctxt(ctxt);
1792    ret
1793}
1794
1795/// SAX user parse memory.
1796///
1797/// # UPSTREAM-PARITY
1798///
1799/// ```c
1800/// int xmlSAXUserParseMemory(xmlSAXHandlerPtr sax, void *user_data,
1801///                           const char *buffer, int size);
1802/// ```
1803#[no_mangle]
1804pub unsafe extern "C" fn xmlSAXUserParseMemory(
1805    sax: *mut _xmlSAXHandler,
1806    user_data: *mut c_void,
1807    buffer: *const c_char,
1808    size: c_int,
1809) -> c_int {
1810    // SAFETY: buffer must be valid with at least `size` bytes.
1811    if buffer.is_null() || size <= 0 {
1812        return -1;
1813    }
1814    let ctxt = crate::xml::parser::helpers::create_parser_ctxt();
1815    if ctxt.is_null() {
1816        return -1;
1817    }
1818    if !sax.is_null() {
1819        (*ctxt).sax = sax;
1820    }
1821    (*ctxt).userData = if !user_data.is_null() {
1822        user_data
1823    } else {
1824        ctxt as *mut c_void
1825    };
1826    let input = crate::xml::parser::helpers::input_from_memory(buffer, size);
1827    crate::xml::parser::helpers::setup_parser_input(ctxt, input);
1828    let ret = crate::xml::parser::helpers::parse_document(ctxt);
1829    crate::xml::parser::helpers::free_parser_ctxt(ctxt);
1830    ret
1831}
1832
1833/// Parse an XML document from a string (DOM).
1834///
1835/// # UPSTREAM-PARITY
1836///
1837/// ```c
1838/// xmlDocPtr xmlParseDoc(const xmlChar *cur);
1839/// ```
1840#[no_mangle]
1841pub unsafe extern "C" fn xmlParseDoc(cur: *const xmlChar) -> *mut _xmlDoc {
1842    // SAFETY: cur must be a valid null-terminated xmlChar string.
1843    if cur.is_null() {
1844        return ptr::null_mut();
1845    }
1846    xmlReadDoc(cur, ptr::null(), ptr::null(), 0)
1847}
1848
1849/// Parse an XML file (DOM).
1850///
1851/// # UPSTREAM-PARITY
1852///
1853/// ```c
1854/// xmlDocPtr xmlParseFile(const char *filename);
1855/// ```
1856#[no_mangle]
1857pub unsafe extern "C" fn xmlParseFile(filename: *const c_char) -> *mut _xmlDoc {
1858    // SAFETY: filename must be a valid C string.
1859    if filename.is_null() {
1860        return ptr::null_mut();
1861    }
1862    xmlReadFile(filename, ptr::null(), 0)
1863}
1864
1865/// Parse an XML document from memory (DOM).
1866///
1867/// # UPSTREAM-PARITY
1868///
1869/// ```c
1870/// xmlDocPtr xmlParseMemory(const char *buffer, int size);
1871/// ```
1872#[no_mangle]
1873pub unsafe extern "C" fn xmlParseMemory(buffer: *const c_char, size: c_int) -> *mut _xmlDoc {
1874    // SAFETY: buffer must be valid with at least `size` bytes.
1875    if buffer.is_null() || size <= 0 {
1876        return ptr::null_mut();
1877    }
1878    xmlReadMemory(buffer, size, ptr::null(), ptr::null(), 0)
1879}
1880
1881/// Create a file parser context.
1882///
1883/// # UPSTREAM-PARITY
1884///
1885/// ```c
1886/// xmlParserCtxtPtr xmlCreateFileParserCtxt(const char *filename);
1887/// ```
1888#[no_mangle]
1889pub unsafe extern "C" fn xmlCreateFileParserCtxt(filename: *const c_char) -> *mut _xmlParserCtxt {
1890    // SAFETY: filename must be a valid C string.
1891    if filename.is_null() {
1892        return ptr::null_mut();
1893    }
1894    let ctxt = crate::xml::parser::helpers::create_parser_ctxt();
1895    if ctxt.is_null() {
1896        return ptr::null_mut();
1897    }
1898    let input = match crate::xml::parser::helpers::input_from_file(filename) {
1899        Ok(input) => input,
1900        Err(_) => {
1901            crate::xml::parser::helpers::free_parser_ctxt(ctxt);
1902            return ptr::null_mut();
1903        }
1904    };
1905    crate::xml::parser::helpers::setup_parser_input(ctxt, input);
1906    ctxt
1907}
1908
1909/// Create a document parser context.
1910///
1911/// # UPSTREAM-PARITY
1912///
1913/// ```c
1914/// xmlParserCtxtPtr xmlCreateDocParserCtxt(const xmlChar *cur);
1915/// ```
1916#[no_mangle]
1917pub unsafe extern "C" fn xmlCreateDocParserCtxt(cur: *const xmlChar) -> *mut _xmlParserCtxt {
1918    // SAFETY: cur must be a valid null-terminated xmlChar string.
1919    if cur.is_null() {
1920        return ptr::null_mut();
1921    }
1922    let ctxt = crate::xml::parser::helpers::create_parser_ctxt();
1923    if ctxt.is_null() {
1924        return ptr::null_mut();
1925    }
1926    let len = crate::xml::string::xml_strlen(cur);
1927    let input = crate::xml::parser::helpers::input_from_memory(cur as *const c_char, len as c_int);
1928    crate::xml::parser::helpers::setup_parser_input(ctxt, input);
1929    ctxt
1930}
1931
1932/// Parse a document using an existing parser context.
1933///
1934/// # UPSTREAM-PARITY
1935///
1936/// ```c
1937/// int xmlParseDocument(xmlParserCtxtPtr ctxt);
1938/// ```
1939#[no_mangle]
1940pub unsafe extern "C" fn xmlParseDocument(ctxt: *mut _xmlParserCtxt) -> c_int {
1941    // SAFETY: ctxt must be a valid parser context.
1942    if ctxt.is_null() {
1943        return -1;
1944    }
1945    crate::xml::parser::helpers::parse_document(ctxt)
1946}
1947
1948/// Free a parser context.
1949///
1950/// # UPSTREAM-PARITY
1951///
1952/// ```c
1953/// void xmlFreeParserCtxt(xmlParserCtxtPtr ctxt);
1954/// ```
1955#[no_mangle]
1956pub unsafe extern "C" fn xmlFreeParserCtxt(ctxt: *mut _xmlParserCtxt) {
1957    if ctxt.is_null() {
1958        return;
1959    }
1960    crate::xml::parser::helpers::free_parser_ctxt(ctxt);
1961}
1962
1963/// Set parser options.
1964///
1965/// # UPSTREAM-PARITY
1966///
1967/// ```c
1968/// int xmlCtxtUseOptions(xmlParserCtxtPtr ctxt, int options);
1969/// ```
1970#[no_mangle]
1971pub unsafe extern "C" fn xmlCtxtUseOptions(ctxt: *mut _xmlParserCtxt, options: c_int) -> c_int {
1972    if ctxt.is_null() {
1973        return -1;
1974    }
1975    // Phase 1: STUB
1976    unsafe {
1977        (*ctxt).options = options;
1978    }
1979    0
1980}
1981
1982/// Parse a well-balanced chunk (for push parsing).
1983///
1984/// # UPSTREAM-PARITY
1985///
1986/// ```c
1987/// xmlParserErrors xmlParseChunk(xmlParserCtxtPtr ctxt,
1988///                               const char *chunk, int size, int terminate);
1989/// ```
1990#[no_mangle]
1991pub unsafe extern "C" fn xmlParseChunk(
1992    ctxt: *mut _xmlParserCtxt,
1993    chunk: *const c_char,
1994    size: c_int,
1995    terminate: c_int,
1996) -> c_int {
1997    // SAFETY: ctxt must be a valid parser context.
1998    // chunk may be NULL if terminate is set (finalize without data).
1999    if ctxt.is_null() {
2000        return -1;
2001    }
2002    crate::xml::parser::helpers::parse_chunk(ctxt, chunk, size, terminate)
2003}
2004
2005/// Create a memory parser input buffer.
2006///
2007/// # UPSTREAM-PARITY
2008///
2009/// ```c
2010/// xmlParserInputBufferPtr xmlParserInputBufferCreateMem(const char *buffer, int size, int enc);
2011/// ```
2012#[no_mangle]
2013pub unsafe extern "C" fn xmlParserInputBufferCreateMem(
2014    buffer: *const c_char,
2015    size: c_int,
2016    enc: c_int,
2017) -> *mut _xmlParserInputBuffer {
2018    // SAFETY: buffer must be valid with at least `size` bytes.
2019    if buffer.is_null() || size <= 0 {
2020        return ptr::null_mut();
2021    }
2022    crate::xml::parser::helpers::alloc_parser_input_buffer()
2023}
2024
2025/// Create a file parser input buffer.
2026///
2027/// # UPSTREAM-PARITY
2028///
2029/// ```c
2030/// xmlParserInputBufferPtr xmlParserInputBufferCreateFilename(const char *URI, int enc);
2031/// ```
2032#[no_mangle]
2033pub unsafe extern "C" fn xmlParserInputBufferCreateFilename(
2034    URI: *const c_char,
2035    enc: c_int,
2036) -> *mut _xmlParserInputBuffer {
2037    // SAFETY: URI must be a valid C string or NULL.
2038    if URI.is_null() {
2039        return ptr::null_mut();
2040    }
2041    crate::xml::parser::helpers::alloc_parser_input_buffer()
2042}
2043
2044/// Create an I/O parser input buffer.
2045///
2046/// # UPSTREAM-PARITY
2047///
2048/// ```c
2049/// xmlParserInputBufferPtr xmlParserInputBufferCreateIO(
2050///     xmlInputReadCallback ioread, xmlInputCloseCallback ioclose,
2051///     void *ioctx, int enc);
2052/// ```
2053#[no_mangle]
2054pub unsafe extern "C" fn xmlParserInputBufferCreateIO(
2055    ioread: Option<xmlInputReadCallback>,
2056    ioclose: Option<xmlInputCloseCallback>,
2057    ioctx: *mut c_void,
2058    enc: c_int,
2059) -> *mut _xmlParserInputBuffer {
2060    // SAFETY: ioread must be a valid callback if Some. ioctx may be NULL.
2061    let buf = crate::xml::parser::helpers::alloc_parser_input_buffer();
2062    if !buf.is_null() {
2063        (*buf).readcallback = ioread;
2064        (*buf).closecallback = ioclose;
2065        (*buf).context = ioctx;
2066    }
2067    buf
2068}
2069
2070/// Free a parser input buffer.
2071///
2072/// # UPSTREAM-PARITY
2073///
2074/// ```c
2075/// void xmlFreeParserInputBuffer(xmlParserInputBufferPtr buf);
2076/// ```
2077#[no_mangle]
2078pub unsafe extern "C" fn xmlFreeParserInputBuffer(buf: *mut _xmlParserInputBuffer) {
2079    if buf.is_null() {
2080        return;
2081    }
2082    crate::xml::parser::helpers::free_parser_input_buffer(buf);
2083}
2084
2085/// Create a new parser input.
2086///
2087/// # UPSTREAM-PARITY
2088///
2089/// ```c
2090/// xmlParserInputPtr xmlNewInputFromFile(xmlParserCtxtPtr ctxt, const char *filename);
2091/// ```
2092#[no_mangle]
2093pub unsafe extern "C" fn xmlNewInputFromFile(
2094    ctxt: *mut _xmlParserCtxt,
2095    filename: *const c_char,
2096) -> *mut _xmlParserInput {
2097    // SAFETY: filename must be a valid C string. ctxt may be NULL.
2098    // This function allocates a _xmlParserInput. The caller owns it.
2099    // Note: The InputBuffer backing data is NOT leaked here (no ctxt._private
2100    // to store it). Use xmlCreateFileParserCtxt + xmlParseDocument instead.
2101    if filename.is_null() {
2102        return ptr::null_mut();
2103    }
2104    crate::xml::parser::helpers::alloc_parser_input_buffer() as *mut _xmlParserInput
2105}
2106
2107/// Free a parser input.
2108///
2109/// # UPSTREAM-PARITY
2110///
2111/// ```c
2112/// void xmlFreeInputStream(xmlParserInputPtr input);
2113/// ```
2114#[no_mangle]
2115pub unsafe extern "C" fn xmlFreeInputStream(input: *mut _xmlParserInput) {
2116    if input.is_null() {
2117        return;
2118    }
2119    crate::xml::parser::helpers::free_parser_input(input);
2120}
2121
2122// ═══════════════════════════════════════════════════════════════════════════════
2123// 8. I/O
2124// ═══════════════════════════════════════════════════════════════════════════════
2125
2126/// Create an output buffer for a file.
2127///
2128/// # UPSTREAM-PARITY
2129///
2130/// ```c
2131/// xmlOutputBufferPtr xmlOutputBufferCreateFilename(const char *URI,
2132///                                                  xmlCharEncodingHandlerPtr encoder,
2133///                                                  int compression);
2134/// ```
2135#[no_mangle]
2136pub unsafe extern "C" fn xmlOutputBufferCreateFilename(
2137    URI: *const c_char,
2138    encoder: *mut c_void,
2139    compression: c_int,
2140) -> *mut _xmlOutputBuffer {
2141    let _ = compression;
2142    if URI.is_null() {
2143        return ptr::null_mut();
2144    }
2145    crate::xml::io::output_buffer_create_filename(
2146        URI,
2147        encoder as *mut crate::abi::structs::_xmlCharEncodingHandler,
2148        0,
2149    )
2150}
2151
2152/// Create an output buffer for a file descriptor.
2153///
2154/// # UPSTREAM-PARITY
2155///
2156/// ```c
2157/// xmlOutputBufferPtr xmlOutputBufferCreateFd(int fd,
2158///                                            xmlCharEncodingHandlerPtr encoder);
2159/// ```
2160#[no_mangle]
2161pub unsafe extern "C" fn xmlOutputBufferCreateFd(
2162    fd: c_int,
2163    encoder: *mut c_void,
2164) -> *mut _xmlOutputBuffer {
2165    if fd < 0 {
2166        return ptr::null_mut();
2167    }
2168    crate::xml::io::output_buffer_create_fd(
2169        fd,
2170        encoder as *mut crate::abi::structs::_xmlCharEncodingHandler,
2171    )
2172}
2173
2174/// Create an output buffer from I/O callbacks.
2175///
2176/// # UPSTREAM-PARITY
2177///
2178/// ```c
2179/// xmlOutputBufferPtr xmlOutputBufferCreateIO(
2180///     xmlOutputWriteCallback iowrite, xmlOutputCloseCallback ioclose,
2181///     void *ioctx, xmlCharEncodingHandlerPtr encoder);
2182/// ```
2183#[no_mangle]
2184pub unsafe extern "C" fn xmlOutputBufferCreateIO(
2185    iowrite: Option<xmlOutputWriteCallback>,
2186    ioclose: Option<xmlOutputCloseCallback>,
2187    ioctx: *mut c_void,
2188    encoder: *mut c_void,
2189) -> *mut _xmlOutputBuffer {
2190    crate::xml::io::output_buffer_create_io(
2191        iowrite,
2192        ioclose,
2193        ioctx,
2194        encoder as *mut crate::abi::structs::_xmlCharEncodingHandler,
2195    )
2196}
2197
2198/// Free an output buffer.
2199///
2200/// # UPSTREAM-PARITY
2201///
2202/// ```c
2203/// void xmlOutputBufferClose(xmlOutputBufferPtr out);
2204/// ```
2205#[no_mangle]
2206pub unsafe extern "C" fn xmlOutputBufferClose(out: *mut _xmlOutputBuffer) -> c_int {
2207    if out.is_null() {
2208        return -1;
2209    }
2210    crate::xml::io::output_buffer_close(out)
2211}
2212
2213/// Flush an output buffer.
2214///
2215/// # UPSTREAM-PARITY
2216///
2217/// ```c
2218/// int xmlOutputBufferFlush(xmlOutputBufferPtr out);
2219/// ```
2220#[no_mangle]
2221pub unsafe extern "C" fn xmlOutputBufferFlush(out: *mut _xmlOutputBuffer) -> c_int {
2222    if out.is_null() {
2223        return -1;
2224    }
2225    crate::xml::io::output_buffer_flush(out)
2226}
2227
2228/// Write to an output buffer.
2229///
2230/// # UPSTREAM-PARITY
2231///
2232/// ```c
2233/// int xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *data);
2234/// ```
2235#[no_mangle]
2236pub unsafe extern "C" fn xmlOutputBufferWrite(
2237    out: *mut _xmlOutputBuffer,
2238    len: c_int,
2239    data: *const c_char,
2240) -> c_int {
2241    if out.is_null() || data.is_null() || len <= 0 {
2242        return -1;
2243    }
2244    crate::xml::io::output_buffer_write(out, len, data)
2245}
2246
2247/// Write a string to an output buffer.
2248///
2249/// # UPSTREAM-PARITY
2250///
2251/// ```c
2252/// int xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str);
2253/// ```
2254#[no_mangle]
2255pub unsafe extern "C" fn xmlOutputBufferWriteString(
2256    out: *mut _xmlOutputBuffer,
2257    str: *const c_char,
2258) -> c_int {
2259    if str.is_null() {
2260        return 0;
2261    }
2262    unsafe { xmlOutputBufferWrite(out, xmlStrlen(str as *const xmlChar), str) }
2263}
2264
2265// ═══════════════════════════════════════════════════════════════════════════════
2266// 9. Dictionary
2267// ═══════════════════════════════════════════════════════════════════════════════
2268
2269/// Create a new dictionary.
2270///
2271/// # UPSTREAM-PARITY
2272///
2273/// ```c
2274/// xmlDictPtr xmlDictCreate(void);
2275/// ```
2276#[no_mangle]
2277pub extern "C" fn xmlDictCreate() -> *mut c_void {
2278    // Phase 1: STUB — will be implemented in xml/dictionary module.
2279    ptr::null_mut()
2280}
2281
2282/// Create a sub-dictionary.
2283///
2284/// # UPSTREAM-PARITY
2285///
2286/// ```c
2287/// xmlDictPtr xmlDictCreateSub(xmlDictPtr sub);
2288/// ```
2289#[no_mangle]
2290pub extern "C" fn xmlDictCreateSub(_sub: *mut c_void) -> *mut c_void {
2291    // Phase 1: STUB
2292    ptr::null_mut()
2293}
2294
2295/// Look up a string in the dictionary.
2296///
2297/// # UPSTREAM-PARITY
2298///
2299/// ```c
2300/// const xmlChar *xmlDictLookup(xmlDictPtr dict, const xmlChar *name, int len);
2301/// ```
2302///
2303/// Returns an interned string pointer (valid as long as the dictionary exists).
2304/// - If `len` < 0, `name` must be null-terminated.
2305/// - If `len` >= 0, exactly `len` bytes are used.
2306#[no_mangle]
2307pub unsafe extern "C" fn xmlDictLookup(
2308    dict: *mut c_void,
2309    name: *const xmlChar,
2310    len: c_int,
2311) -> *const xmlChar {
2312    // Phase 1: STUB
2313    name
2314}
2315
2316/// Check if a string exists in the dictionary.
2317///
2318/// # UPSTREAM-PARITY
2319///
2320/// ```c
2321/// const xmlChar *xmlDictExists(xmlDictPtr dict, const xmlChar *name, int len);
2322/// ```
2323#[no_mangle]
2324pub unsafe extern "C" fn xmlDictExists(
2325    dict: *mut c_void,
2326    name: *const xmlChar,
2327    len: c_int,
2328) -> *const xmlChar {
2329    // Phase 1: STUB
2330    ptr::null()
2331}
2332
2333/// Query dictionary size.
2334///
2335/// # UPSTREAM-PARITY
2336///
2337/// ```c
2338/// unsigned int xmlDictSize(const xmlDictPtr dict);
2339/// ```
2340#[no_mangle]
2341pub extern "C" fn xmlDictSize(dict: *const c_void) -> c_uint {
2342    // Phase 1: STUB
2343    0
2344}
2345
2346/// Free a dictionary.
2347///
2348/// # UPSTREAM-PARITY
2349///
2350/// ```c
2351/// void xmlDictFree(xmlDictPtr dict);
2352/// ```
2353#[no_mangle]
2354pub extern "C" fn xmlDictFree(_dict: *mut c_void) {
2355    // Phase 1: STUB
2356}
2357
2358/// Set the dictionary size limit.
2359///
2360/// # UPSTREAM-PARITY
2361///
2362/// ```c
2363/// unsigned int xmlDictSetLimit(xmlDictPtr dict, unsigned int limit);
2364/// ```
2365#[no_mangle]
2366pub extern "C" fn xmlDictSetLimit(_dict: *mut c_void, _limit: c_uint) -> c_uint {
2367    // Phase 1: STUB
2368    0
2369}
2370
2371/// Get current dictionary usage.
2372///
2373/// # UPSTREAM-PARITY
2374///
2375/// ```c
2376/// unsigned int xmlDictGetUsage(const xmlDictPtr dict);
2377/// ```
2378#[no_mangle]
2379pub extern "C" fn xmlDictGetUsage(_dict: *const c_void) -> c_uint {
2380    // Phase 1: STUB
2381    0
2382}
2383
2384// ═══════════════════════════════════════════════════════════════════════════════
2385// 10. Hash Table
2386// ═══════════════════════════════════════════════════════════════════════════════
2387
2388/// Create a new hash table.
2389///
2390/// # UPSTREAM-PARITY
2391///
2392/// ```c
2393/// xmlHashTablePtr xmlHashCreate(int size);
2394/// ```
2395#[no_mangle]
2396pub extern "C" fn xmlHashCreate(_size: c_int) -> *mut c_void {
2397    // Phase 1: STUB
2398    ptr::null_mut()
2399}
2400
2401/// Create a new hash table with a dictionary.
2402///
2403/// # UPSTREAM-PARITY
2404///
2405/// ```c
2406/// xmlHashTablePtr xmlHashCreateDict(int size, xmlDictPtr dict);
2407/// ```
2408#[no_mangle]
2409pub extern "C" fn xmlHashCreateDict(_size: c_int, _dict: *mut c_void) -> *mut c_void {
2410    // Phase 1: STUB
2411    ptr::null_mut()
2412}
2413
2414/// Free a hash table.
2415///
2416/// # UPSTREAM-PARITY
2417///
2418/// ```c
2419/// void xmlHashFree(xmlHashTablePtr table, xmlHashDeallocator f);
2420/// ```
2421#[no_mangle]
2422pub extern "C" fn xmlHashFree(
2423    _table: *mut c_void,
2424    _f: Option<unsafe extern "C" fn(*mut c_void, *mut xmlChar)>,
2425) {
2426    // Phase 1: STUB
2427}
2428
2429/// Add an entry to a hash table.
2430///
2431/// # UPSTREAM-PARITY
2432///
2433/// ```c
2434/// int xmlHashAddEntry(xmlHashTablePtr table, const xmlChar *name, void *userdata);
2435/// ```
2436#[no_mangle]
2437pub unsafe extern "C" fn xmlHashAddEntry(
2438    _table: *mut c_void,
2439    _name: *const xmlChar,
2440    _userdata: *mut c_void,
2441) -> c_int {
2442    // Phase 1: STUB
2443    0
2444}
2445
2446/// Add a 2-key entry.
2447///
2448/// # UPSTREAM-PARITY
2449///
2450/// ```c
2451/// int xmlHashAddEntry2(xmlHashTablePtr table, const xmlChar *name,
2452///                      const xmlChar *name2, void *userdata);
2453/// ```
2454#[no_mangle]
2455pub unsafe extern "C" fn xmlHashAddEntry2(
2456    _table: *mut c_void,
2457    _name: *const xmlChar,
2458    _name2: *const xmlChar,
2459    _userdata: *mut c_void,
2460) -> c_int {
2461    // Phase 1: STUB
2462    0
2463}
2464
2465/// Add a 3-key entry.
2466///
2467/// # UPSTREAM-PARITY
2468///
2469/// ```c
2470/// int xmlHashAddEntry3(xmlHashTablePtr table, const xmlChar *name,
2471///                      const xmlChar *name2, const xmlChar *name3, void *userdata);
2472/// ```
2473#[no_mangle]
2474pub unsafe extern "C" fn xmlHashAddEntry3(
2475    _table: *mut c_void,
2476    _name: *const xmlChar,
2477    _name2: *const xmlChar,
2478    _name3: *const xmlChar,
2479    _userdata: *mut c_void,
2480) -> c_int {
2481    // Phase 1: STUB
2482    0
2483}
2484
2485/// Update or add an entry.
2486///
2487/// # UPSTREAM-PARITY
2488///
2489/// ```c
2490/// int xmlHashUpdateEntry(xmlHashTablePtr table, const xmlChar *name,
2491///                        void *userdata, xmlHashDeallocator f);
2492/// ```
2493#[no_mangle]
2494pub unsafe extern "C" fn xmlHashUpdateEntry(
2495    _table: *mut c_void,
2496    _name: *const xmlChar,
2497    _userdata: *mut c_void,
2498    _f: Option<unsafe extern "C" fn(*mut c_void, *mut xmlChar)>,
2499) -> c_int {
2500    // Phase 1: STUB
2501    0
2502}
2503
2504/// Update or add a 2-key entry.
2505#[no_mangle]
2506pub unsafe extern "C" fn xmlHashUpdateEntry2(
2507    _table: *mut c_void,
2508    _name: *const xmlChar,
2509    _name2: *const xmlChar,
2510    _userdata: *mut c_void,
2511    _f: Option<unsafe extern "C" fn(*mut c_void, *mut xmlChar)>,
2512) -> c_int {
2513    // Phase 1: STUB
2514    0
2515}
2516
2517/// Update or add a 3-key entry.
2518#[no_mangle]
2519pub unsafe extern "C" fn xmlHashUpdateEntry3(
2520    _table: *mut c_void,
2521    _name: *const xmlChar,
2522    _name2: *const xmlChar,
2523    _name3: *const xmlChar,
2524    _userdata: *mut c_void,
2525    _f: Option<unsafe extern "C" fn(*mut c_void, *mut xmlChar)>,
2526) -> c_int {
2527    // Phase 1: STUB
2528    0
2529}
2530
2531/// Look up an entry.
2532///
2533/// # UPSTREAM-PARITY
2534///
2535/// ```c
2536/// void *xmlHashLookup(xmlHashTablePtr table, const xmlChar *name);
2537/// ```
2538#[no_mangle]
2539pub unsafe extern "C" fn xmlHashLookup(_table: *mut c_void, _name: *const xmlChar) -> *mut c_void {
2540    // Phase 1: STUB
2541    ptr::null_mut()
2542}
2543
2544/// Look up a 2-key entry.
2545#[no_mangle]
2546pub unsafe extern "C" fn xmlHashLookup2(
2547    _table: *mut c_void,
2548    _name: *const xmlChar,
2549    _name2: *const xmlChar,
2550) -> *mut c_void {
2551    // Phase 1: STUB
2552    ptr::null_mut()
2553}
2554
2555/// Look up a 3-key entry.
2556#[no_mangle]
2557pub unsafe extern "C" fn xmlHashLookup3(
2558    _table: *mut c_void,
2559    _name: *const xmlChar,
2560    _name2: *const xmlChar,
2561    _name3: *const xmlChar,
2562) -> *mut c_void {
2563    // Phase 1: STUB
2564    ptr::null_mut()
2565}
2566
2567/// Get the size of a hash table.
2568///
2569/// # UPSTREAM-PARITY
2570///
2571/// ```c
2572/// int xmlHashSize(xmlHashTablePtr table);
2573/// ```
2574#[no_mangle]
2575pub extern "C" fn xmlHashSize(_table: *mut c_void) -> c_int {
2576    // Phase 1: STUB
2577    0
2578}
2579
2580/// Remove an entry.
2581///
2582/// # UPSTREAM-PARITY
2583///
2584/// ```c
2585/// int xmlHashRemoveEntry(xmlHashTablePtr table, const xmlChar *name,
2586///                        xmlHashDeallocator f);
2587/// ```
2588#[no_mangle]
2589pub unsafe extern "C" fn xmlHashRemoveEntry(
2590    _table: *mut c_void,
2591    _name: *const xmlChar,
2592    _f: Option<unsafe extern "C" fn(*mut c_void, *mut xmlChar)>,
2593) -> c_int {
2594    // Phase 1: STUB
2595    0
2596}
2597
2598/// Remove a 2-key entry.
2599#[no_mangle]
2600pub unsafe extern "C" fn xmlHashRemoveEntry2(
2601    _table: *mut c_void,
2602    _name: *const xmlChar,
2603    _name2: *const xmlChar,
2604    _f: Option<unsafe extern "C" fn(*mut c_void, *mut xmlChar)>,
2605) -> c_int {
2606    // Phase 1: STUB
2607    0
2608}
2609
2610/// Remove a 3-key entry.
2611#[no_mangle]
2612pub unsafe extern "C" fn xmlHashRemoveEntry3(
2613    _table: *mut c_void,
2614    _name: *const xmlChar,
2615    _name2: *const xmlChar,
2616    _name3: *const xmlChar,
2617    _f: Option<unsafe extern "C" fn(*mut c_void, *mut xmlChar)>,
2618) -> c_int {
2619    // Phase 1: STUB
2620    0
2621}
2622
2623/// Scan a hash table with a scanner function.
2624///
2625/// # UPSTREAM-PARITY
2626///
2627/// ```c
2628/// void xmlHashScan(xmlHashTablePtr table, xmlHashScanner f, void *data);
2629/// ```
2630#[no_mangle]
2631pub extern "C" fn xmlHashScan(
2632    _table: *mut c_void,
2633    _f: Option<unsafe extern "C" fn(*mut c_void, *const xmlChar, *mut c_void)>,
2634    _data: *mut c_void,
2635) {
2636    // Phase 1: STUB
2637}
2638
2639/// Scan a hash table with a full scanner function.
2640#[no_mangle]
2641pub extern "C" fn xmlHashScanFull(
2642    _table: *mut c_void,
2643    _f: Option<unsafe extern "C" fn(*mut c_void, *const xmlChar, *mut c_void, *mut c_void)>,
2644    _data: *mut c_void,
2645) {
2646    // Phase 1: STUB
2647}
2648
2649/// Copy a hash table.
2650///
2651/// # UPSTREAM-PARITY
2652///
2653/// ```c
2654/// xmlHashTablePtr xmlHashCopy(xmlHashTablePtr table, xmlHashCopier f);
2655/// ```
2656#[no_mangle]
2657pub extern "C" fn xmlHashCopy(
2658    _table: *mut c_void,
2659    _f: Option<unsafe extern "C" fn(*mut c_void, *const xmlChar) -> *mut c_void>,
2660) -> *mut c_void {
2661    // Phase 1: STUB
2662    ptr::null_mut()
2663}
2664
2665// ═══════════════════════════════════════════════════════════════════════════════
2666// 11. List
2667// ═══════════════════════════════════════════════════════════════════════════════
2668
2669/// Create a new list.
2670///
2671/// # UPSTREAM-PARITY
2672///
2673/// ```c
2674/// xmlListPtr xmlListCreate(xmlListDeallocator deallocator,
2675///                          xmlListDataCompare compare);
2676/// ```
2677#[no_mangle]
2678pub extern "C" fn xmlListCreate(
2679    _deallocator: Option<unsafe extern "C" fn(*mut c_void)>,
2680    _compare: Option<unsafe extern "C" fn(*const c_void, *const c_void) -> c_int>,
2681) -> *mut c_void {
2682    // Phase 1: STUB
2683    ptr::null_mut()
2684}
2685
2686/// Delete a list.
2687///
2688/// # UPSTREAM-PARITY
2689///
2690/// ```c
2691/// void xmlListDelete(xmlListPtr list);
2692/// ```
2693#[no_mangle]
2694pub extern "C" fn xmlListDelete(_list: *mut c_void) {
2695    // Phase 1: STUB
2696}
2697
2698/// Search a list.
2699///
2700/// # UPSTREAM-PARITY
2701///
2702/// ```c
2703/// void *xmlListSearch(xmlListPtr list, void *data);
2704/// ```
2705#[no_mangle]
2706pub extern "C" fn xmlListSearch(_list: *mut c_void, _data: *mut c_void) -> *mut c_void {
2707    // Phase 1: STUB
2708    ptr::null_mut()
2709}
2710
2711/// Walk a list.
2712///
2713/// # UPSTREAM-PARITY
2714///
2715/// ```c
2716/// void xmlListWalk(xmlListPtr list, xmlListWalker walker, void *data);
2717/// ```
2718#[no_mangle]
2719pub extern "C" fn xmlListWalk(
2720    _list: *mut c_void,
2721    _walker: Option<unsafe extern "C" fn(*mut c_void, *mut c_void) -> c_int>,
2722    _data: *mut c_void,
2723) {
2724    // Phase 1: STUB
2725}
2726
2727/// Push to back.
2728///
2729/// # UPSTREAM-PARITY
2730///
2731/// ```c
2732/// int xmlListPushBack(xmlListPtr list, void *data);
2733/// ```
2734#[no_mangle]
2735pub extern "C" fn xmlListPushBack(_list: *mut c_void, _data: *mut c_void) -> c_int {
2736    // Phase 1: STUB
2737    0
2738}
2739
2740/// Push to front.
2741///
2742/// # UPSTREAM-PARITY
2743///
2744/// ```c
2745/// int xmlListPushFront(xmlListPtr list, void *data);
2746/// ```
2747#[no_mangle]
2748pub extern "C" fn xmlListPushFront(_list: *mut c_void, _data: *mut c_void) -> c_int {
2749    // Phase 1: STUB
2750    0
2751}
2752
2753/// Pop from back.
2754#[no_mangle]
2755pub extern "C" fn xmlListPopBack(_list: *mut c_void) {
2756    // Phase 1: STUB
2757}
2758
2759/// Pop from front.
2760#[no_mangle]
2761pub extern "C" fn xmlListPopFront(_list: *mut c_void) {
2762    // Phase 1: STUB
2763}
2764
2765/// Insert into sorted list.
2766///
2767/// # UPSTREAM-PARITY
2768///
2769/// ```c
2770/// int xmlListInsert(xmlListPtr list, void *data);
2771/// ```
2772#[no_mangle]
2773pub extern "C" fn xmlListInsert(_list: *mut c_void, _data: *mut c_void) -> c_int {
2774    // Phase 1: STUB
2775    0
2776}
2777
2778/// Append to list.
2779#[no_mangle]
2780pub extern "C" fn xmlListAppend(_list: *mut c_void, _data: *mut c_void) -> c_int {
2781    // Phase 1: STUB
2782    0
2783}
2784
2785/// Remove first matching element.
2786#[no_mangle]
2787pub extern "C" fn xmlListRemoveFirst(_list: *mut c_void, _data: *mut c_void) -> c_int {
2788    // Phase 1: STUB
2789    0
2790}
2791
2792/// Remove last matching element.
2793#[no_mangle]
2794pub extern "C" fn xmlListRemoveLast(_list: *mut c_void, _data: *mut c_void) -> c_int {
2795    // Phase 1: STUB
2796    0
2797}
2798
2799/// Remove all matching elements.
2800#[no_mangle]
2801pub extern "C" fn xmlListRemoveAll(_list: *mut c_void, _data: *mut c_void) -> c_int {
2802    // Phase 1: STUB
2803    0
2804}
2805
2806/// Clear a list.
2807#[no_mangle]
2808pub extern "C" fn xmlListClear(_list: *mut c_void) {
2809    // Phase 1: STUB
2810}
2811
2812/// Check if list is empty.
2813///
2814/// # UPSTREAM-PARITY
2815///
2816/// ```c
2817/// int xmlListEmpty(xmlListPtr list);
2818/// ```
2819#[no_mangle]
2820pub extern "C" fn xmlListEmpty(_list: *mut c_void) -> c_int {
2821    // Phase 1: STUB
2822    1
2823}
2824
2825/// Get front element.
2826///
2827/// # UPSTREAM-PARITY
2828///
2829/// ```c
2830/// void *xmlListFront(xmlListPtr list);
2831/// ```
2832#[no_mangle]
2833pub extern "C" fn xmlListFront(_list: *mut c_void) -> *mut c_void {
2834    // Phase 1: STUB
2835    ptr::null_mut()
2836}
2837
2838/// Get back element.
2839///
2840/// # UPSTREAM-PARITY
2841///
2842/// ```c
2843/// void *xmlListBack(xmlListPtr list);
2844/// ```
2845#[no_mangle]
2846pub extern "C" fn xmlListBack(_list: *mut c_void) -> *mut c_void {
2847    // Phase 1: STUB
2848    ptr::null_mut()
2849}
2850
2851/// Get list size.
2852///
2853/// # UPSTREAM-PARITY
2854///
2855/// ```c
2856/// int xmlListSize(xmlListPtr list);
2857/// ```
2858#[no_mangle]
2859pub extern "C" fn xmlListSize(_list: *mut c_void) -> c_int {
2860    // Phase 1: STUB
2861    0
2862}
2863
2864/// Sort a list.
2865#[no_mangle]
2866pub extern "C" fn xmlListSort(_list: *mut c_void) {
2867    // Phase 1: STUB
2868}
2869
2870/// Reverse a list.
2871#[no_mangle]
2872pub extern "C" fn xmlListReverse(_list: *mut c_void) {
2873    // Phase 1: STUB
2874}
2875
2876/// Reverse a list in-place.
2877#[no_mangle]
2878pub extern "C" fn xmlListReverseSplice(_list: *mut c_void, _list2: *mut c_void) {
2879    // Phase 1: STUB
2880}
2881
2882/// Merge two sorted lists.
2883#[no_mangle]
2884pub extern "C" fn xmlListMerge(_list: *mut c_void, _list2: *mut c_void) {
2885    // Phase 1: STUB
2886}
2887
2888// ═══════════════════════════════════════════════════════════════════════════════
2889// 12. Buffer
2890// ═══════════════════════════════════════════════════════════════════════════════
2891
2892/// Create a new buffer.
2893///
2894/// # UPSTREAM-PARITY
2895///
2896/// ```c
2897/// xmlBufferPtr xmlBufferCreate(void);
2898/// ```
2899#[no_mangle]
2900pub extern "C" fn xmlBufferCreate() -> *mut _xmlBuffer {
2901    crate::xml::io::buf_create(-1)
2902}
2903
2904/// Create a new buffer of a given size.
2905///
2906/// # UPSTREAM-PARITY
2907///
2908/// ```c
2909/// xmlBufferPtr xmlBufferCreateSize(size_t size);
2910/// ```
2911#[no_mangle]
2912pub extern "C" fn xmlBufferCreateSize(size: usize) -> *mut _xmlBuffer {
2913    crate::xml::io::buf_create(size as c_int)
2914}
2915
2916/// Create a buffer from a static string.
2917///
2918/// # UPSTREAM-PARITY
2919///
2920/// ```c
2921/// xmlBufferPtr xmlBufferCreateStatic(void *mem, size_t size);
2922/// ```
2923#[no_mangle]
2924pub extern "C" fn xmlBufferCreateStatic(mem: *mut c_void, size: usize) -> *mut _xmlBuffer {
2925    if mem.is_null() || size == 0 {
2926        return ptr::null_mut();
2927    }
2928    crate::xml::io::buf_create_static(mem as *const xmlChar, size as c_int)
2929}
2930
2931/// Free a buffer.
2932///
2933/// # UPSTREAM-PARITY
2934///
2935/// ```c
2936/// void xmlBufferFree(xmlBufferPtr buf);
2937/// ```
2938#[no_mangle]
2939pub extern "C" fn xmlBufferFree(buf: *mut _xmlBuffer) {
2940    crate::xml::io::buf_free(buf)
2941}
2942
2943/// Empty a buffer.
2944///
2945/// # UPSTREAM-PARITY
2946///
2947/// ```c
2948/// void xmlBufferEmpty(xmlBufferPtr buf);
2949/// ```
2950#[no_mangle]
2951pub extern "C" fn xmlBufferEmpty(buf: *mut _xmlBuffer) {
2952    if buf.is_null() {
2953        return;
2954    }
2955    unsafe {
2956        if !(*buf).content.is_null() {
2957            *(*buf).content = 0;
2958        }
2959        (*buf).use_ = 0;
2960    }
2961}
2962
2963/// Get buffer content.
2964///
2965/// # UPSTREAM-PARITY
2966///
2967/// ```c
2968/// xmlChar *xmlBufferContent(const xmlBuffer *buf);
2969/// ```
2970#[no_mangle]
2971pub extern "C" fn xmlBufferContent(buf: *const _xmlBuffer) -> *mut xmlChar {
2972    crate::xml::io::buf_content(buf as *mut _xmlBuffer)
2973}
2974
2975/// Get buffer length.
2976///
2977/// # UPSTREAM-PARITY
2978///
2979/// ```c
2980/// int xmlBufferLength(const xmlBuffer *buf);
2981/// ```
2982#[no_mangle]
2983pub extern "C" fn xmlBufferLength(buf: *const _xmlBuffer) -> c_int {
2984    crate::xml::io::buf_length(buf as *mut _xmlBuffer)
2985}
2986
2987/// Write to a buffer.
2988///
2989/// # UPSTREAM-PARITY
2990///
2991/// ```c
2992/// int xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len);
2993/// ```
2994#[no_mangle]
2995pub unsafe extern "C" fn xmlBufferAdd(
2996    buf: *mut _xmlBuffer,
2997    str: *const xmlChar,
2998    len: c_int,
2999) -> c_int {
3000    crate::xml::io::buf_add(buf, str, len)
3001}
3002
3003/// Write to a buffer at a position.
3004///
3005/// # UPSTREAM-PARITY
3006///
3007/// ```c
3008/// int xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len);
3009/// ```
3010#[no_mangle]
3011pub unsafe extern "C" fn xmlBufferAddHead(
3012    buf: *mut _xmlBuffer,
3013    str: *const xmlChar,
3014    len: c_int,
3015) -> c_int {
3016    crate::xml::io::buf_add_head(buf, str, len)
3017}
3018
3019/// Write a C string to a buffer.
3020///
3021/// # UPSTREAM-PARITY
3022///
3023/// ```c
3024/// int xmlBufferCat(xmlBufferPtr buf, const xmlChar *str);
3025/// ```
3026#[no_mangle]
3027pub unsafe extern "C" fn xmlBufferCat(buf: *mut _xmlBuffer, str: *const xmlChar) -> c_int {
3028    if str.is_null() {
3029        return -1;
3030    }
3031    let len = crate::xml::string::xml_strlen(str) as c_int;
3032    crate::xml::io::buf_add(buf, str, len)
3033}
3034
3035/// Set buffer allocation scheme.
3036///
3037/// # UPSTREAM-PARITY
3038///
3039/// ```c
3040/// void xmlBufferSetAllocationScheme(xmlBufferPtr buf,
3041///                                    xmlBufferAllocationScheme scheme);
3042/// ```
3043#[no_mangle]
3044pub extern "C" fn xmlBufferSetAllocationScheme(buf: *mut _xmlBuffer, scheme: c_int) {
3045    if buf.is_null() {
3046        return;
3047    }
3048    unsafe {
3049        (*buf).alloc = scheme;
3050    }
3051}
3052
3053/// Shrink buffer.
3054///
3055/// # UPSTREAM-PARITY
3056///
3057/// ```c
3058/// int xmlBufferShrink(xmlBufferPtr buf, int len);
3059/// ```
3060#[no_mangle]
3061pub extern "C" fn xmlBufferShrink(buf: *mut _xmlBuffer, len: c_int) -> c_int {
3062    if buf.is_null() || len <= 0 {
3063        return 0;
3064    }
3065    unsafe {
3066        let b = &mut *buf;
3067        let shrink_len = (len as c_uint).min(b.use_);
3068        if shrink_len > 0 {
3069            let remaining = b.use_ - shrink_len;
3070            if remaining > 0 {
3071                core::ptr::copy(
3072                    b.content.add(shrink_len as usize),
3073                    b.content,
3074                    remaining as usize,
3075                );
3076            }
3077            *b.content.add(remaining as usize) = 0;
3078            b.use_ = remaining;
3079        }
3080    }
3081    len
3082}
3083
3084/// Grow buffer.
3085///
3086/// # UPSTREAM-PARITY
3087///
3088/// ```c
3089/// int xmlBufferGrow(xmlBufferPtr buf, int len);
3090/// ```
3091#[no_mangle]
3092pub extern "C" fn xmlBufferGrow(buf: *mut _xmlBuffer, len: c_int) -> c_int {
3093    if buf.is_null() || len <= 0 {
3094        return 0;
3095    }
3096    let cur_use = unsafe { (*buf).use_ };
3097    let new_size = cur_use + len as c_uint + 1;
3098    crate::xml::io::buf_grow(buf, new_size)
3099}
3100
3101/// Reserve buffer space.
3102///
3103/// # UPSTREAM-PARITY
3104///
3105/// ```c
3106/// int xmlBufferReserve(xmlBufferPtr buf, int len);
3107/// ```
3108#[no_mangle]
3109pub extern "C" fn xmlBufferReserve(buf: *mut _xmlBuffer, len: c_int) -> c_int {
3110    xmlBufferGrow(buf, len)
3111}
3112
3113/// Detach buffer content.
3114///
3115/// # UPSTREAM-PARITY
3116///
3117/// ```c
3118/// xmlChar *xmlBufferDetach(xmlBufferPtr buf);
3119/// ```
3120#[no_mangle]
3121pub extern "C" fn xmlBufferDetach(buf: *mut _xmlBuffer) -> *mut xmlChar {
3122    if buf.is_null() {
3123        return ptr::null_mut();
3124    }
3125    unsafe {
3126        let content = (*buf).content;
3127        (*buf).content = ptr::null_mut();
3128        (*buf).use_ = 0;
3129        (*buf).size = 0;
3130        content
3131    }
3132}
3133
3134// ═══════════════════════════════════════════════════════════════════════════════
3135// 13. Encoding
3136// ═══════════════════════════════════════════════════════════════════════════════
3137
3138/// Get encoding from a name string.
3139///
3140/// # UPSTREAM-PARITY
3141///
3142/// ```c
3143/// xmlCharEncoding xmlGetCharEncoding(const char *name);
3144/// ```
3145#[no_mangle]
3146pub extern "C" fn xmlGetCharEncoding(name: *const c_char) -> c_int {
3147    if name.is_null() {
3148        return 0; // XML_CHAR_ENCODING_NONE
3149    }
3150    let name_bytes = unsafe {
3151        let len = libc::strlen(name);
3152        core::slice::from_raw_parts(name as *const u8, len)
3153    };
3154    crate::xml::encoding::encoding_from_name(name_bytes) as c_int
3155}
3156
3157/// Find an encoding handler.
3158///
3159/// # UPSTREAM-PARITY
3160///
3161/// ```c
3162/// xmlCharEncodingHandlerPtr xmlFindCharEncodingHandler(const char *name);
3163/// ```
3164#[no_mangle]
3165pub extern "C" fn xmlFindCharEncodingHandler(name: *const c_char) -> *mut c_void {
3166    if name.is_null() {
3167        return ptr::null_mut();
3168    }
3169    crate::xml::encoding::find_encoding_handler(name as *const xmlChar) as *mut c_void
3170}
3171
3172/// Close an encoding handler.
3173///
3174/// # UPSTREAM-PARITY
3175///
3176/// ```c
3177/// int xmlCharEncCloseFunc(xmlCharEncodingHandlerPtr handler);
3178/// ```
3179#[no_mangle]
3180pub extern "C" fn xmlCharEncCloseFunc(handler: *mut c_void) -> c_int {
3181    if handler.is_null() {
3182        return -1;
3183    }
3184    // Free the encoding handler
3185    unsafe {
3186        let h = handler as *mut crate::abi::structs::_xmlCharEncodingHandler;
3187        if !(*h).name.is_null() {
3188            crate::abi::allocator::xmlFree((*h).name as *mut c_void);
3189        }
3190        crate::abi::allocator::xmlFree(handler);
3191    }
3192    0
3193}
3194
3195/// Convert an input buffer's encoding.
3196///
3197/// # UPSTREAM-PARITY
3198///
3199/// ```c
3200/// int xmlCharEncInput(xmlParserInputBufferPtr input, int to);
3201/// ```
3202#[no_mangle]
3203pub unsafe extern "C" fn xmlCharEncInput(input: *mut _xmlParserInputBuffer, _to: c_int) -> c_int {
3204    if input.is_null() {
3205        return -1;
3206    }
3207    let handler = (*input).encoder as *mut crate::abi::structs::_xmlCharEncodingHandler;
3208    if handler.is_null() {
3209        return -1;
3210    }
3211    let raw = (*input).raw as *mut crate::abi::structs::_xmlBuffer;
3212    let buf = (*input).buffer as *mut crate::abi::structs::_xmlBuffer;
3213    if raw.is_null() || buf.is_null() {
3214        return -1;
3215    }
3216    crate::xml::encoding::char_enc_in(handler, buf, raw)
3217}
3218
3219/// Convert an output buffer's encoding.
3220///
3221/// # UPSTREAM-PARITY
3222///
3223/// ```c
3224/// int xmlCharEncOutput(xmlOutputBufferPtr output, int to);
3225/// ```
3226#[no_mangle]
3227pub unsafe extern "C" fn xmlCharEncOutput(output: *mut _xmlOutputBuffer, _to: c_int) -> c_int {
3228    if output.is_null() {
3229        return -1;
3230    }
3231    let handler = (*output).encoder as *mut crate::abi::structs::_xmlCharEncodingHandler;
3232    if handler.is_null() {
3233        return -1;
3234    }
3235    let buf = (*output).buffer as *mut crate::abi::structs::_xmlBuffer;
3236    let conv = (*output).conv as *mut crate::abi::structs::_xmlBuffer;
3237    if buf.is_null() || conv.is_null() {
3238        return -1;
3239    }
3240    crate::xml::encoding::char_enc_out(handler, conv, buf)
3241}
3242
3243// ═══════════════════════════════════════════════════════════════════════════════
3244// URI
3245// ═══════════════════════════════════════════════════════════════════════════════
3246
3247/// Parse a URI string.
3248///
3249/// # UPSTREAM-PARITY
3250///
3251/// ```c
3252/// xmlURIPtr xmlParseURI(const char *str);
3253/// ```
3254#[no_mangle]
3255pub unsafe extern "C" fn xmlParseURI(str: *const c_char) -> *mut c_void {
3256    crate::xml::uri::xmlParseURI(str)
3257}
3258
3259/// Parse a URI string (raw version).
3260///
3261/// # UPSTREAM-PARITY
3262///
3263/// ```c
3264/// xmlURIPtr xmlParseURIRaw(const char *str, int raw);
3265/// ```
3266#[no_mangle]
3267pub unsafe extern "C" fn xmlParseURIRaw(str: *const c_char, raw: c_int) -> *mut c_void {
3268    let _ = raw;
3269    crate::xml::uri::xmlParseURI(str)
3270}
3271
3272/// Free a URI structure.
3273///
3274/// # UPSTREAM-PARITY
3275///
3276/// ```c
3277/// void xmlFreeURI(xmlURIPtr uri);
3278/// ```
3279#[no_mangle]
3280pub unsafe extern "C" fn xmlFreeURI(uri: *mut c_void) {
3281    crate::xml::uri::xmlFreeURI(uri)
3282}
3283
3284/// Create an empty URI.
3285///
3286/// # UPSTREAM-PARITY
3287///
3288/// ```c
3289/// xmlURIPtr xmlCreateURI(void);
3290/// ```
3291#[no_mangle]
3292pub extern "C" fn xmlCreateURI() -> *mut c_void {
3293    crate::xml::uri::xmlCreateURI()
3294}
3295
3296/// Save a URI structure to a string.
3297///
3298/// # UPSTREAM-PARITY
3299///
3300/// ```c
3301/// xmlChar *xmlSaveUri(xmlURIPtr uri);
3302/// ```
3303#[no_mangle]
3304pub unsafe extern "C" fn xmlSaveUri(uri: *mut c_void) -> *mut xmlChar {
3305    crate::xml::uri::xmlSaveUri(uri)
3306}
3307
3308/// Escape a URI string.
3309///
3310/// # UPSTREAM-PARITY
3311///
3312/// ```c
3313/// xmlChar *xmlURIEscapeStr(const xmlChar *str, const xmlChar *list);
3314/// ```
3315#[no_mangle]
3316pub unsafe extern "C" fn xmlURIEscapeStr(
3317    str: *const xmlChar,
3318    list: *const xmlChar,
3319) -> *mut xmlChar {
3320    crate::xml::uri::xmlURIEscapeStr(str, list)
3321}
3322
3323/// Unescape a URI string.
3324///
3325/// # UPSTREAM-PARITY
3326///
3327/// ```c
3328/// char *xmlURIUnescapeString(const char *str, int len, char *target);
3329/// ```
3330#[no_mangle]
3331pub unsafe extern "C" fn xmlURIUnescapeString(
3332    str: *const c_char,
3333    len: c_int,
3334    target: *mut c_char,
3335) -> *mut c_char {
3336    crate::xml::uri::xmlURIUnescapeString(str, len, target)
3337}
3338
3339// ═══════════════════════════════════════════════════════════════════════════════
3340// 14. XPath
3341// ═══════════════════════════════════════════════════════════════════════════════
3342
3343/// Create a new XPath context.
3344///
3345/// # UPSTREAM-PARITY
3346///
3347/// ```c
3348/// xmlXPathContextPtr xmlXPathNewContext(xmlDocPtr doc);
3349/// ```
3350#[no_mangle]
3351pub unsafe extern "C" fn xmlXPathNewContext(_doc: *mut _xmlDoc) -> *mut _xmlXPathContext {
3352    // Phase 1: STUB
3353    ptr::null_mut()
3354}
3355
3356/// Free an XPath context.
3357///
3358/// # UPSTREAM-PARITY
3359///
3360/// ```c
3361/// void xmlXPathFreeContext(xmlXPathContextPtr ctxt);
3362/// ```
3363#[no_mangle]
3364pub extern "C" fn xmlXPathFreeContext(_ctxt: *mut _xmlXPathContext) {
3365    // Phase 1: STUB
3366}
3367
3368/// Evaluate an XPath expression.
3369///
3370/// # UPSTREAM-PARITY
3371///
3372/// ```c
3373/// xmlXPathObjectPtr xmlXPathEvalExpression(const xmlChar *str,
3374///                                          xmlXPathContextPtr ctxt);
3375/// ```
3376#[no_mangle]
3377pub unsafe extern "C" fn xmlXPathEvalExpression(
3378    _str: *const xmlChar,
3379    _ctxt: *mut _xmlXPathContext,
3380) -> *mut _xmlXPathObject {
3381    // Phase 1: STUB
3382    ptr::null_mut()
3383}
3384
3385/// Evaluate an XPath expression (simplified).
3386///
3387/// # UPSTREAM-PARITY
3388///
3389/// ```c
3390/// xmlXPathObjectPtr xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctxt);
3391/// ```
3392#[no_mangle]
3393pub unsafe extern "C" fn xmlXPathEval(
3394    _str: *const xmlChar,
3395    _ctxt: *mut _xmlXPathContext,
3396) -> *mut _xmlXPathObject {
3397    // Phase 1: STUB
3398    ptr::null_mut()
3399}
3400
3401/// Free an XPath object.
3402///
3403/// # UPSTREAM-PARITY
3404///
3405/// ```c
3406/// void xmlXPathFreeObject(xmlXPathObjectPtr obj);
3407/// ```
3408#[no_mangle]
3409pub extern "C" fn xmlXPathFreeObject(_obj: *mut _xmlXPathObject) {
3410    // Phase 1: STUB
3411}
3412
3413/// Compile an XPath expression.
3414///
3415/// # UPSTREAM-PARITY
3416///
3417/// ```c
3418/// xmlXPathCompExprPtr xmlXPathCompile(const xmlChar *str);
3419/// ```
3420#[no_mangle]
3421pub unsafe extern "C" fn xmlXPathCompile(_str: *const xmlChar) -> *mut c_void {
3422    // Phase 1: STUB
3423    ptr::null_mut()
3424}
3425
3426/// Free a compiled XPath expression.
3427///
3428/// # UPSTREAM-PARITY
3429///
3430/// ```c
3431/// void xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp);
3432/// ```
3433#[no_mangle]
3434pub extern "C" fn xmlXPathFreeCompExpr(_comp: *mut c_void) {
3435    // Phase 1: STUB
3436}
3437
3438/// Register an XPath namespace.
3439///
3440/// # UPSTREAM-PARITY
3441///
3442/// ```c
3443/// int xmlXPathRegisterNs(xmlXPathContextPtr ctxt,
3444///                        const xmlChar *prefix, const xmlChar *ns_uri);
3445/// ```
3446#[no_mangle]
3447pub unsafe extern "C" fn xmlXPathRegisterNs(
3448    _ctxt: *mut _xmlXPathContext,
3449    _prefix: *const xmlChar,
3450    _ns_uri: *const xmlChar,
3451) -> c_int {
3452    // Phase 1: STUB
3453    0
3454}
3455
3456/// Register an XPath function.
3457///
3458/// # UPSTREAM-PARITY
3459///
3460/// ```c
3461/// int xmlXPathRegisterFunc(xmlXPathContextPtr ctxt,
3462///                          const xmlChar *name, xmlXPathFunction f);
3463/// ```
3464#[no_mangle]
3465pub unsafe extern "C" fn xmlXPathRegisterFunc(
3466    _ctxt: *mut _xmlXPathContext,
3467    _name: *const xmlChar,
3468    _f: Option<unsafe extern "C" fn(*mut c_void, c_int)>,
3469) -> c_int {
3470    // Phase 1: STUB
3471    0
3472}
3473
3474/// Register an XPath function with namespace.
3475///
3476/// # UPSTREAM-PARITY
3477///
3478/// ```c
3479/// int xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt,
3480///                            const xmlChar *name, const xmlChar *ns_uri,
3481///                            xmlXPathFunction f);
3482/// ```
3483#[no_mangle]
3484pub unsafe extern "C" fn xmlXPathRegisterFuncNS(
3485    _ctxt: *mut _xmlXPathContext,
3486    _name: *const xmlChar,
3487    _ns_uri: *const xmlChar,
3488    _f: Option<unsafe extern "C" fn(*mut c_void, c_int)>,
3489) -> c_int {
3490    // Phase 1: STUB
3491    0
3492}
3493
3494/// Register an XPath variable.
3495///
3496/// # UPSTREAM-PARITY
3497///
3498/// ```c
3499/// int xmlXPathRegisterVariable(xmlXPathContextPtr ctxt,
3500///                              const xmlChar *name, xmlXPathObjectPtr value);
3501/// ```
3502#[no_mangle]
3503pub unsafe extern "C" fn xmlXPathRegisterVariable(
3504    _ctxt: *mut _xmlXPathContext,
3505    _name: *const xmlChar,
3506    _value: *mut _xmlXPathObject,
3507) -> c_int {
3508    // Phase 1: STUB
3509    0
3510}
3511
3512/// Create an XPath object from a node set.
3513///
3514/// # UPSTREAM-PARITY
3515///
3516/// ```c
3517/// xmlXPathObjectPtr xmlXPathNewNodeSet(xmlNodePtr val);
3518/// ```
3519#[no_mangle]
3520pub unsafe extern "C" fn xmlXPathNewNodeSet(_val: *mut _xmlNode) -> *mut _xmlXPathObject {
3521    // Phase 1: STUB
3522    ptr::null_mut()
3523}
3524
3525/// Create an XPath object from a value.
3526///
3527/// # UPSTREAM-PARITY
3528///
3529/// ```c
3530/// xmlXPathObjectPtr xmlXPathNewCString(const xmlChar *val);
3531/// ```
3532#[no_mangle]
3533pub unsafe extern "C" fn xmlXPathNewCString(_val: *const xmlChar) -> *mut _xmlXPathObject {
3534    // Phase 1: STUB
3535    ptr::null_mut()
3536}
3537
3538/// Create an XPath number object.
3539///
3540/// # UPSTREAM-PARITY
3541///
3542/// ```c
3543/// xmlXPathObjectPtr xmlXPathNewFloat(double val);
3544/// ```
3545#[no_mangle]
3546pub extern "C" fn xmlXPathNewFloat(_val: f64) -> *mut _xmlXPathObject {
3547    // Phase 1: STUB
3548    ptr::null_mut()
3549}
3550
3551/// Create an XPath boolean object.
3552///
3553/// # UPSTREAM-PARITY
3554///
3555/// ```c
3556/// xmlXPathObjectPtr xmlXPathNewBoolean(int val);
3557/// ```
3558#[no_mangle]
3559pub extern "C" fn xmlXPathNewBoolean(_val: c_int) -> *mut _xmlXPathObject {
3560    // Phase 1: STUB
3561    ptr::null_mut()
3562}
3563
3564// ═══════════════════════════════════════════════════════════════════════════════
3565// 15. XInclude
3566// ═══════════════════════════════════════════════════════════════════════════════
3567
3568/// Process XInclude nodes in a document.
3569///
3570/// # UPSTREAM-PARITY
3571///
3572/// ```c
3573/// int xmlXIncludeProcess(xmlDocPtr doc);
3574/// ```
3575#[no_mangle]
3576pub extern "C" fn xmlXIncludeProcess(_doc: *mut _xmlDoc) -> c_int {
3577    // Phase 1: STUB
3578    -1
3579}
3580
3581/// Process XInclude nodes with flags.
3582///
3583/// # UPSTREAM-PARITY
3584///
3585/// ```c
3586/// int xmlXIncludeProcessFlags(xmlDocPtr doc, int flags);
3587/// ```
3588#[no_mangle]
3589pub extern "C" fn xmlXIncludeProcessFlags(_doc: *mut _xmlDoc, _flags: c_int) -> c_int {
3590    // Phase 1: STUB
3591    -1
3592}
3593
3594// ═══════════════════════════════════════════════════════════════════════════════
3595// 16. Catalog
3596// ═══════════════════════════════════════════════════════════════════════════════
3597
3598/// Load a catalog.
3599///
3600/// # UPSTREAM-PARITY
3601///
3602/// ```c
3603/// xmlCatalogPtr xmlCatalogLoad(const char *catalogs);
3604/// ```
3605#[no_mangle]
3606pub extern "C" fn xmlCatalogLoad(catalogs: *const c_char) -> *mut c_void {
3607    if catalogs.is_null() {
3608        return ptr::null_mut();
3609    }
3610    crate::xml::catalog::load_catalog(catalogs)
3611}
3612
3613/// Resolve a public ID.
3614///
3615/// # UPSTREAM-PARITY
3616///
3617/// ```c
3618/// xmlCharPtr xmlCatalogResolvePublic(const xmlChar *pubID);
3619/// ```
3620#[no_mangle]
3621pub unsafe extern "C" fn xmlCatalogResolvePublic(pubID: *const xmlChar) -> *mut xmlChar {
3622    if pubID.is_null() {
3623        return ptr::null_mut();
3624    }
3625    crate::xml::catalog::resolve_public(pubID)
3626}
3627
3628/// Resolve a system ID.
3629///
3630/// # UPSTREAM-PARITY
3631///
3632/// ```c
3633/// xmlCharPtr xmlCatalogResolveSystem(const xmlChar *sysID);
3634/// ```
3635#[no_mangle]
3636pub unsafe extern "C" fn xmlCatalogResolveSystem(sysID: *const xmlChar) -> *mut xmlChar {
3637    if sysID.is_null() {
3638        return ptr::null_mut();
3639    }
3640    crate::xml::catalog::resolve_system(sysID)
3641}
3642
3643/// Resolve a URI.
3644///
3645/// # UPSTREAM-PARITY
3646///
3647/// ```c
3648/// xmlCharPtr xmlCatalogResolveURI(const xmlChar *URI);
3649/// ```
3650#[no_mangle]
3651pub unsafe extern "C" fn xmlCatalogResolveURI(URI: *const xmlChar) -> *mut xmlChar {
3652    if URI.is_null() {
3653        return ptr::null_mut();
3654    }
3655    crate::xml::catalog::resolve_uri(URI)
3656}
3657
3658/// Set catalog defaults.
3659///
3660/// # UPSTREAM-PARITY
3661///
3662/// ```c
3663/// void xmlCatalogSetDefaults(xmlCatalogAllowValue allow);
3664/// ```
3665#[no_mangle]
3666pub extern "C" fn xmlCatalogSetDefaults(allow: c_int) {
3667    crate::xml::catalog::set_defaults(allow)
3668}
3669
3670/// Get catalog defaults.
3671///
3672/// # UPSTREAM-PARITY
3673///
3674/// ```c
3675/// xmlCatalogAllowValue xmlCatalogGetDefaults(void);
3676/// ```
3677#[no_mangle]
3678pub extern "C" fn xmlCatalogGetDefaults() -> c_int {
3679    crate::xml::catalog::get_defaults()
3680}
3681
3682/// Add a catalog.
3683///
3684/// # UPSTREAM-PARITY
3685///
3686/// ```c
3687/// int xmlCatalogAdd(const xmlChar *type, const xmlChar *orig, const xmlChar *replace);
3688/// ```
3689#[no_mangle]
3690pub unsafe extern "C" fn xmlCatalogAdd(
3691    type_: *const xmlChar,
3692    orig: *const xmlChar,
3693    replace: *const xmlChar,
3694) -> c_int {
3695    if type_.is_null() || orig.is_null() || replace.is_null() {
3696        return -1;
3697    }
3698    crate::xml::catalog::add(type_, orig, replace)
3699}
3700
3701/// Remove a catalog entry.
3702///
3703/// # UPSTREAM-PARITY
3704///
3705/// ```c
3706/// int xmlCatalogRemove(const xmlChar *value);
3707/// ```
3708#[no_mangle]
3709pub unsafe extern "C" fn xmlCatalogRemove(value: *const xmlChar) -> c_int {
3710    if value.is_null() {
3711        return 0;
3712    }
3713    crate::xml::catalog::remove(value)
3714}
3715
3716/// Clean up the catalog subsystem.
3717///
3718/// # UPSTREAM-PARITY
3719///
3720/// ```c
3721/// void xmlCatalogCleanup(void);
3722/// ```
3723#[no_mangle]
3724pub extern "C" fn xmlCatalogCleanup() {
3725    crate::xml::catalog::cleanup();
3726}
3727
3728/// Convert an SGML catalog to XML.
3729///
3730/// # UPSTREAM-PARITY
3731///
3732/// ```c
3733/// xmlDocPtr xmlCatalogConvert(void);
3734/// ```
3735#[no_mangle]
3736pub extern "C" fn xmlCatalogConvert() -> *mut _xmlDoc {
3737    // SAFETY: catalog::convert() allocates and builds an XML document tree.
3738    unsafe { crate::xml::catalog::convert() }
3739}
3740
3741// ═══════════════════════════════════════════════════════════════════════════════
3742// 17. HTML
3743// ═══════════════════════════════════════════════════════════════════════════════
3744
3745/// Parse an HTML document from a file.
3746///
3747/// # UPSTREAM-PARITY
3748///
3749/// ```c
3750/// htmlDocPtr htmlParseFile(const char *filename, const char *encoding);
3751/// ```
3752#[no_mangle]
3753pub unsafe extern "C" fn htmlParseFile(
3754    _filename: *const c_char,
3755    _encoding: *const c_char,
3756) -> *mut _xmlDoc {
3757    // Phase 1: STUB
3758    ptr::null_mut()
3759}
3760
3761/// Parse an HTML document from memory.
3762///
3763/// # UPSTREAM-PARITY
3764///
3765/// ```c
3766/// htmlDocPtr htmlParseMemory(const char *buffer, int size);
3767/// ```
3768#[no_mangle]
3769pub unsafe extern "C" fn htmlParseMemory(_buffer: *const c_char, _size: c_int) -> *mut _xmlDoc {
3770    // Phase 1: STUB
3771    ptr::null_mut()
3772}
3773
3774/// Parse an HTML document from a document string.
3775///
3776/// # UPSTREAM-PARITY
3777///
3778/// ```c
3779/// htmlDocPtr htmlParseDoc(const xmlChar *cur, const char *encoding);
3780/// ```
3781#[no_mangle]
3782pub unsafe extern "C" fn htmlParseDoc(
3783    _cur: *const xmlChar,
3784    _encoding: *const c_char,
3785) -> *mut _xmlDoc {
3786    // Phase 1: STUB
3787    ptr::null_mut()
3788}
3789
3790/// Create an HTML parser context.
3791///
3792/// # UPSTREAM-PARITY
3793///
3794/// ```c
3795/// htmlParserCtxtPtr htmlCreateFileParserCtxt(const char *filename,
3796///                                            const char *encoding);
3797/// ```
3798#[no_mangle]
3799pub unsafe extern "C" fn htmlCreateFileParserCtxt(
3800    _filename: *const c_char,
3801    _encoding: *const c_char,
3802) -> *mut c_void {
3803    // Phase 1: STUB
3804    ptr::null_mut()
3805}
3806
3807/// Free an HTML parser context.
3808///
3809/// # UPSTREAM-PARITY
3810///
3811/// ```c
3812/// void htmlFreeParserCtxt(htmlParserCtxtPtr ctxt);
3813/// ```
3814#[no_mangle]
3815pub extern "C" fn htmlFreeParserCtxt(_ctxt: *mut c_void) {
3816    // Phase 1: STUB
3817}
3818
3819/// Initialize the HTML parser.
3820///
3821/// # UPSTREAM-PARITY
3822///
3823/// ```c
3824/// void htmlInitParser(void);
3825/// ```
3826#[no_mangle]
3827pub extern "C" fn htmlInitParser() {
3828    // Phase 1: STUB
3829}
3830
3831/// Clean up the HTML parser.
3832///
3833/// # UPSTREAM-PARITY
3834///
3835/// ```c
3836/// void htmlCleanupParser(void);
3837/// ```
3838#[no_mangle]
3839pub extern "C" fn htmlCleanupParser() {
3840    // Phase 1: STUB
3841}
3842
3843// ═══════════════════════════════════════════════════════════════════════════════
3844// 18. Debug / Miscellaneous
3845// ═══════════════════════════════════════════════════════════════════════════════
3846
3847/// Dump a document to a file for debugging.
3848///
3849/// # UPSTREAM-PARITY
3850///
3851/// ```c
3852/// void xmlDebugDumpDocument(FILE *output, xmlDocPtr doc);
3853/// ```
3854#[no_mangle]
3855pub unsafe extern "C" fn xmlDebugDumpDocument(_output: *mut c_void, _doc: *mut _xmlDoc) {
3856    // Phase 1: STUB
3857}
3858
3859/// Dump a node for debugging.
3860///
3861/// # UPSTREAM-PARITY
3862///
3863/// ```c
3864/// void xmlDebugDumpNode(FILE *output, xmlNodePtr node);
3865/// ```
3866#[no_mangle]
3867pub unsafe extern "C" fn xmlDebugDumpNode(_output: *mut c_void, _node: *mut _xmlNode) {
3868    // Phase 1: STUB
3869}
3870
3871/// Dump a node for debugging (recursive).
3872///
3873/// # UPSTREAM-PARITY
3874///
3875/// ```c
3876/// void xmlDebugDumpNodeList(FILE *output, xmlNodePtr node);
3877/// ```
3878#[no_mangle]
3879pub unsafe extern "C" fn xmlDebugDumpNodeList(_output: *mut c_void, _node: *mut _xmlNode) {
3880    // Phase 1: STUB
3881}
3882
3883/// Get the path to the current executable.
3884///
3885/// # UPSTREAM-PARITY
3886///
3887/// ```c
3888/// char *xmlGetBinaryPath(void);
3889/// ```
3890#[no_mangle]
3891pub extern "C" fn xmlGetBinaryPath() -> *mut c_char {
3892    // Phase 1: STUB
3893    ptr::null_mut()
3894}
3895
3896/// Get the path to the current executable's home directory.
3897///
3898/// # UPSTREAM-PARITY
3899///
3900/// ```c
3901/// char *xmlGetHomeOfBinary(void);
3902/// ```
3903#[no_mangle]
3904pub extern "C" fn xmlGetHomeOfBinary() -> *mut c_char {
3905    // Phase 1: STUB
3906    ptr::null_mut()
3907}