1#![allow(missing_docs)]
16#![allow(non_snake_case)]
17#![allow(non_camel_case_types)]
18#![allow(non_upper_case_globals)]
19
20use core::ffi::CStr;
21use core::ptr;
22use std::os::raw::{c_char, c_int, c_long, c_uchar, c_uint, c_ulong, c_void};
23
24use parking_lot::Mutex;
25
26use crate::abi::allocator::{
27 xmlFreeImpl, xmlMallocImpl, xmlMallocZero, xmlMemStrdupImpl, xmlReallocImpl,
28};
29use crate::abi::callbacks::{
30 xmlGenericErrorFunc, xmlInputCloseCallback, xmlInputReadCallback, xmlOutputCloseCallback,
31 xmlOutputWriteCallback, xmlStructuredErrorFunc,
32};
33use crate::abi::structs::*;
34use crate::abi::types::*;
35use crate::xml::parser::helpers;
36use crate::xml::parser::input::InputBuffer;
37use crate::xml::{dtd, encoding, entities, errors, globals, io, string, tree};
38
39type xmlInputMatchCallback = unsafe extern "C" fn(filename: *const c_char) -> c_int;
46
47type xmlInputOpenCallback = unsafe extern "C" fn(filename: *const c_char) -> *mut c_void;
49
50type xmlOutputMatchCallback = unsafe extern "C" fn(filename: *const c_char) -> c_int;
53
54type xmlOutputOpenCallback = unsafe extern "C" fn(filename: *const c_char) -> *mut c_void;
56
57type xmlExternalEntityLoader = unsafe extern "C" fn(
59 URL: *const c_char,
60 ID: *const c_char,
61 ctxt: *mut _xmlParserCtxt,
62) -> *mut _xmlParserInput;
63
64#[derive(Clone, Copy)]
65struct InputCallbackEntry {
66 matchcb: Option<xmlInputMatchCallback>,
67 opencb: Option<xmlInputOpenCallback>,
68 readcb: Option<xmlInputReadCallback>,
69 closecb: Option<xmlInputCloseCallback>,
70}
71
72#[derive(Clone, Copy)]
73struct OutputCallbackEntry {
74 matchcb: Option<xmlOutputMatchCallback>,
75 opencb: Option<xmlOutputOpenCallback>,
76 writecb: Option<xmlOutputWriteCallback>,
77 closecb: Option<xmlOutputCloseCallback>,
78}
79
80static INPUT_CALLBACKS: Mutex<Vec<InputCallbackEntry>> = Mutex::new(Vec::new());
81static OUTPUT_CALLBACKS: Mutex<Vec<OutputCallbackEntry>> = Mutex::new(Vec::new());
82
83static EXTERNAL_ENTITY_LOADER: Mutex<Option<xmlExternalEntityLoader>> =
84 Mutex::new(Some(default_external_entity_loader));
85
86const XML_ERR_USER_STOP: c_int = 111;
88const XML_ERR_RESOURCE_LIMIT: c_int = 114;
89
90const XML_SCAN_NC: c_int = 1;
92const XML_SCAN_NMTOKEN: c_int = 2;
93const XML_SCAN_OLD10: c_int = 4;
94
95const XML_DETECT_IDS: c_int = 1 << 0;
97const XML_COMPLETE_ATTRS: c_int = 1 << 1;
98
99const LINE_LEN: usize = 80;
101
102const INPUT_CHUNK: usize = 100;
104
105const XML_INVALID_CHAR: c_int = -1;
106
107unsafe fn init_sax_parser_ctxt(
118 ctxt: *mut _xmlParserCtxt,
119 sax: *const _xmlSAXHandler,
120 userData: *mut c_void,
121) -> c_int {
122 unsafe {
123 ptr::write_bytes(ctxt as *mut u8, 0, core::mem::size_of::<_xmlParserCtxt>());
124
125 let c = &mut *ctxt;
126
127 if c.sax.is_null() {
129 let new_sax =
130 xmlMallocZero(core::mem::size_of::<_xmlSAXHandler>()) as *mut _xmlSAXHandler;
131 if new_sax.is_null() {
132 return -1;
133 }
134 c.sax = new_sax;
135 }
136 if sax.is_null() {
137 crate::xml::sax::xmlSAX2InitDefaultSAXHandler(c.sax);
138 c.userData = ctxt as *mut c_void;
139 } else if (*sax).initialized == XML_SAX2_MAGIC as c_uint {
140 ptr::copy_nonoverlapping(sax, c.sax, 1);
142 c.userData = if userData.is_null() {
143 ctxt as *mut c_void
144 } else {
145 userData
146 };
147 } else {
148 ptr::write_bytes(c.sax as *mut u8, 0, core::mem::size_of::<_xmlSAXHandler>());
150 ptr::copy_nonoverlapping(
151 sax as *const u8,
152 c.sax as *mut u8,
153 core::mem::size_of::<_xmlSAXHandlerV1>(),
154 );
155 c.userData = if userData.is_null() {
156 ctxt as *mut c_void
157 } else {
158 userData
159 };
160 }
161
162 c.wellFormed = 1;
163 c.standalone = -1;
164 c.errNo = XML_ERR_OK;
165 c.valid = 1;
166 c.nsWellFormed = 1;
167 c.instate = xmlParserInputState::XML_PARSER_START as c_int;
168 c.keepBlanks = globals::get_keep_blanks_default();
169 c.replaceEntities = globals::get_substitute_entities_default();
170 c.linenumbers = 1;
171 c.charset = xmlCharEncoding::XML_CHAR_ENCODING_UTF8 as c_int;
172 c.pedantic = globals::get_pedantic_parser_default();
173 c.loadsubset = globals::get_load_ext_dtd_default();
174 c.docdict = 1;
175 c.options = 0;
176
177 c.vctxt.userData = ctxt as *mut c_void;
178 c.vctxt.valid = 1;
179 }
180 0
181}
182
183pub(crate) unsafe fn apply_options(ctxt: *mut _xmlParserCtxt, options: c_int) {
190 unsafe {
191 let c = &mut *ctxt;
192 c.options = options;
193 c.recovery = (options & XML_PARSE_RECOVER != 0) as c_int;
194 c.replaceEntities = (options & XML_PARSE_NOENT != 0) as c_int;
195 c.loadsubset = ((options & XML_PARSE_DTDLOAD != 0) as c_int)
196 | if options & XML_PARSE_DTDATTR != 0 {
197 XML_COMPLETE_ATTRS
198 } else {
199 0
200 };
201 c.validate = (options & XML_PARSE_DTDVALID != 0) as c_int;
202 c.pedantic = (options & XML_PARSE_PEDANTIC != 0) as c_int;
203 c.keepBlanks = if options & XML_PARSE_NOBLANKS != 0 {
204 0
205 } else {
206 1
207 };
208 c.dictNames = if options & XML_PARSE_NODICT != 0 {
209 0
210 } else {
211 1
212 };
213 }
214}
215
216unsafe fn encoding_handler_for(enc: c_int) -> *mut _xmlCharEncodingHandler {
218 let e: xmlCharEncoding = unsafe { core::mem::transmute(enc) };
219 match encoding::encoding_name(e) {
220 Some(name) => {
221 let mut nul = name.to_vec();
222 nul.push(0);
223 encoding::find_encoding_handler(nul.as_ptr() as *const xmlChar)
224 }
225 None => ptr::null_mut(),
226 }
227}
228
229unsafe fn parser_input_from_buf(buf: *mut _xmlParserInputBuffer) -> *mut _xmlParserInput {
238 let input =
239 unsafe { xmlMallocZero(core::mem::size_of::<_xmlParserInput>()) } as *mut _xmlParserInput;
240 if input.is_null() {
241 return ptr::null_mut();
242 }
243 unsafe {
244 (*input).buf = buf;
245 (*input).line = 1;
246 (*input).col = 1;
247 if !buf.is_null() {
248 let b = &*buf;
249 if !b.buffer.is_null() {
250 let xbuf = &*(b.buffer as *mut _xmlBuffer);
251 if !xbuf.content.is_null() {
252 (*input).base = xbuf.content;
253 (*input).cur = xbuf.content;
254 (*input).end = xbuf.content.add(xbuf.use_ as usize);
255 (*input).length = xbuf.use_ as c_int;
256 }
257 }
258 }
259 }
260 input
261}
262
263pub(crate) unsafe fn parser_input_from_buf_pub(
266 buf: *mut _xmlParserInputBuffer,
267) -> *mut _xmlParserInput {
268 unsafe { parser_input_from_buf(buf) }
269}
270
271unsafe fn input_buffer_from_parser_input(input: *mut _xmlParserInput) -> InputBuffer {
278 unsafe {
279 let pi = &*input;
280 if !pi.buf.is_null() {
281 let b = &*pi.buf;
282 if let Some(read) = b.readcallback {
283 return helpers::input_from_io(Some(read), b.closecallback, b.context);
284 }
285 }
286 if !pi.base.is_null() && !pi.end.is_null() && pi.end >= pi.base {
287 let len = (pi.end as usize).saturating_sub(pi.base as usize);
288 let slice = core::slice::from_raw_parts(pi.base, len);
289 return InputBuffer::from_memory(slice, None);
290 }
291 InputBuffer::from_memory(&[], None)
292 }
293}
294
295unsafe fn ctxt_read_doc(
302 ctxt: *mut _xmlParserCtxt,
303 input: InputBuffer,
304 url: *const c_char,
305 options: c_int,
306) -> *mut _xmlDoc {
307 unsafe {
308 xmlCtxtReset(ctxt);
309 apply_options(ctxt, options);
310 helpers::setup_parser_input(ctxt, input);
311 if helpers::parse_document(ctxt) != 0 {
312 let doc = (*ctxt).myDoc;
313 (*ctxt).myDoc = ptr::null_mut();
314 if options & XML_PARSE_RECOVER != 0 {
315 return doc;
316 }
317 if !doc.is_null() {
318 tree::free_doc(doc);
319 }
320 return ptr::null_mut();
321 }
322 let doc = (*ctxt).myDoc;
323 if !doc.is_null() && !url.is_null() {
324 (*doc).URL = string::xml_strdup(url as *const xmlChar);
325 }
326 doc
327 }
328}
329
330unsafe fn parse_dtd_text(
341 ctxt: *mut _xmlParserCtxt,
342 data: &[u8],
343 public_id: *const xmlChar,
344 system_id: *const xmlChar,
345) -> *mut _xmlDtd {
346 unsafe {
347 let has_doctype = data
350 .windows(9)
351 .any(|w| w.eq_ignore_ascii_case(b"<!DOCTYPE"));
352 let mut wrapped: Vec<u8>;
353 let parse_data: &[u8] = if has_doctype {
354 data
355 } else {
356 wrapped = Vec::with_capacity(data.len() + 32);
357 wrapped.extend_from_slice(b"<!DOCTYPE none [");
358 wrapped.extend_from_slice(data);
359 wrapped.extend_from_slice(b"]><none/>");
360 &wrapped
361 };
362
363 let input = InputBuffer::from_memory(parse_data, None);
364 helpers::setup_parser_input(ctxt, input);
365 let rc = helpers::parse_document(ctxt);
366 let doc = (*ctxt).myDoc;
367 (*ctxt).myDoc = ptr::null_mut();
368
369 if rc == 0 && !doc.is_null() && !(*doc).intSubset.is_null() {
370 let dtd = (*doc).intSubset;
371 (*doc).intSubset = ptr::null_mut();
372 (*dtd).parent = ptr::null_mut();
373 (*dtd).doc = ptr::null_mut();
374 if !public_id.is_null() {
375 (*dtd).ExternalID = string::xml_strdup(public_id);
376 }
377 if !system_id.is_null() {
378 (*dtd).SystemID = string::xml_strdup(system_id);
379 }
380 tree::free_doc(doc);
381 return dtd;
382 }
383
384 if !doc.is_null() {
385 tree::free_doc(doc);
386 }
387 let dtd = dtd::new_dtd(ptr::null_mut(), b"none\0".as_ptr(), public_id, system_id);
389 dtd
390 }
391}
392
393#[no_mangle]
405pub unsafe extern "C" fn xmlNewParserCtxt() -> *mut _xmlParserCtxt {
406 unsafe {
407 globals::init_parser();
408 let ctxt = xmlMallocZero(core::mem::size_of::<_xmlParserCtxt>()) as *mut _xmlParserCtxt;
409 if ctxt.is_null() {
410 return ptr::null_mut();
411 }
412 if init_sax_parser_ctxt(ctxt, ptr::null(), ptr::null_mut()) < 0 {
413 helpers::free_parser_ctxt(ctxt);
414 return ptr::null_mut();
415 }
416 ctxt
417 }
418}
419
420#[no_mangle]
429pub unsafe extern "C" fn xmlNewSAXParserCtxt(
430 sax: *const _xmlSAXHandler,
431 userData: *mut c_void,
432) -> *mut _xmlParserCtxt {
433 unsafe {
434 globals::init_parser();
435 let ctxt = xmlMallocZero(core::mem::size_of::<_xmlParserCtxt>()) as *mut _xmlParserCtxt;
436 if ctxt.is_null() {
437 return ptr::null_mut();
438 }
439 if init_sax_parser_ctxt(ctxt, sax, userData) < 0 {
440 helpers::free_parser_ctxt(ctxt);
441 return ptr::null_mut();
442 }
443 ctxt
444 }
445}
446
447#[no_mangle]
456pub unsafe extern "C" fn xmlInitParserCtxt(ctxt: *mut _xmlParserCtxt) -> c_int {
457 unsafe { init_sax_parser_ctxt(ctxt, ptr::null(), ptr::null_mut()) }
458}
459
460#[no_mangle]
468pub unsafe extern "C" fn xmlClearParserCtxt(ctxt: *mut _xmlParserCtxt) {
469 unsafe { xmlCtxtReset(ctxt) }
470}
471
472#[no_mangle]
481pub unsafe extern "C" fn xmlCtxtReset(ctxt: *mut _xmlParserCtxt) {
482 if ctxt.is_null() {
483 return;
484 }
485 unsafe {
486 let c = &mut *ctxt;
487
488 let input_nr = c.inputNr;
490 let input_tab = c.inputTab;
491 if !input_tab.is_null() {
492 for i in 0..input_nr {
493 let input = *input_tab.add(i as usize);
494 if !input.is_null() {
495 helpers::free_parser_input(input);
496 }
497 }
498 xmlFreeImpl(input_tab as *mut c_void);
499 }
500 c.inputTab = ptr::null_mut();
501 c.inputMax = 0;
502 c.inputNr = 0;
503 c.input = ptr::null_mut();
504
505 helpers::free_stashed_input_buffer(ctxt);
508
509 if !c.nodeTab.is_null() {
511 xmlFreeImpl(c.nodeTab as *mut c_void);
512 }
513 c.nodeTab = ptr::null_mut();
514 c.nodeMax = 0;
515 c.nodeNr = 0;
516 c.node = ptr::null_mut();
517
518 if !c.nameTab.is_null() {
520 xmlFreeImpl(c.nameTab as *mut c_void);
521 }
522 c.nameTab = ptr::null_mut();
523 c.nameMax = 0;
524 c.nameNr = 0;
525 c.name = ptr::null();
526
527 c.spaceNr = 0;
529 c.space = ptr::null_mut();
530
531 c.nsNr = 0;
533
534 if !c.version.is_null() {
536 xmlFreeImpl(c.version as *mut c_void);
537 c.version = ptr::null_mut();
538 }
539 if !c.encoding.is_null() {
540 xmlFreeImpl(c.encoding as *mut c_void);
541 c.encoding = ptr::null_mut();
542 }
543 if !c.extSubURI.is_null() {
544 xmlFreeImpl(c.extSubURI as *mut c_void);
545 c.extSubURI = ptr::null_mut();
546 }
547 if !c.extSubSystem.is_null() {
548 xmlFreeImpl(c.extSubSystem as *mut c_void);
549 c.extSubSystem = ptr::null_mut();
550 }
551 if !c.directory.is_null() {
552 xmlFreeImpl(c.directory as *mut c_void);
553 c.directory = ptr::null_mut();
554 }
555
556 if !c.myDoc.is_null() {
558 tree::free_doc(c.myDoc);
559 }
560 c.myDoc = ptr::null_mut();
561
562 c.standalone = -1;
564 c.hasExternalSubset = 0;
565 c.hasPErefs = 0;
566 c.instate = xmlParserInputState::XML_PARSER_START as c_int;
567 c.wellFormed = 1;
568 c.nsWellFormed = 1;
569 c.disableSAX = 0;
570 c.valid = 1;
571 c.record_info = 0;
572 c.checkIndex = 0;
573 c.inSubset = 0;
574 c.errNo = XML_ERR_OK;
575 c.depth = 0;
576 c.nbentities = 0;
577 c.sizeentities = 0;
578 c.nbErrors = 0;
579 c.nbWarnings = 0;
580
581 xmlInitNodeInfoSeq(&mut c.node_seq);
582
583 if c.lastError.code != XML_ERR_OK {
584 errors::reset_error(&mut c.lastError);
585 }
586 }
587}
588
589#[no_mangle]
598pub unsafe extern "C" fn xmlCtxtResetPush(
599 ctxt: *mut _xmlParserCtxt,
600 chunk: *const c_char,
601 size: c_int,
602 filename: *const c_char,
603 encoding: *const c_char,
604) -> c_int {
605 if ctxt.is_null() {
606 return 1;
607 }
608 unsafe {
609 xmlCtxtReset(ctxt);
610
611 let slice = if size > 0 && !chunk.is_null() {
612 core::slice::from_raw_parts(chunk as *const u8, size as usize)
613 } else {
614 &[]
615 };
616 let uri = if filename.is_null() {
617 None
618 } else {
619 CStr::from_ptr(filename).to_str().ok()
620 };
621 let input = InputBuffer::from_memory(slice, uri);
622 helpers::setup_parser_input(ctxt, input);
623
624 if !encoding.is_null() {
625 let handler = encoding::find_encoding_handler(encoding as *const xmlChar);
626 if !handler.is_null() {
627 xmlSwitchToEncoding(ctxt, handler);
628 }
629 }
630 }
631 0
632}
633
634#[no_mangle]
642pub unsafe extern "C" fn xmlCtxtSetOptions(ctxt: *mut _xmlParserCtxt, options: c_int) -> c_int {
643 if ctxt.is_null() {
644 return -1;
645 }
646 const ALL_MASK: c_int = XML_PARSE_RECOVER
647 | XML_PARSE_NOENT
648 | XML_PARSE_DTDLOAD
649 | XML_PARSE_DTDATTR
650 | XML_PARSE_DTDVALID
651 | XML_PARSE_NOERROR
652 | XML_PARSE_NOWARNING
653 | XML_PARSE_PEDANTIC
654 | XML_PARSE_NOBLANKS
655 | XML_PARSE_SAX1
656 | XML_PARSE_NONET
657 | XML_PARSE_NODICT
658 | XML_PARSE_NSCLEAN
659 | XML_PARSE_NOCDATA
660 | XML_PARSE_COMPACT
661 | XML_PARSE_OLD10
662 | XML_PARSE_HUGE
663 | XML_PARSE_OLDSAX
664 | XML_PARSE_IGNORE_ENC
665 | XML_PARSE_BIG_LINES;
666
667 unsafe {
668 apply_options(ctxt, options & ALL_MASK);
669 }
670 options & !ALL_MASK
671}
672
673#[no_mangle]
682pub unsafe extern "C" fn xmlCtxtSetErrorHandler(
683 ctxt: *mut _xmlParserCtxt,
684 handler: Option<xmlStructuredErrorFunc>,
685 data: *mut c_void,
686) {
687 if ctxt.is_null() {
688 return;
689 }
690 unsafe {
691 (*ctxt).errorHandler = handler;
692 (*ctxt).errorCtxt = data;
693 }
694}
695
696#[no_mangle]
704pub unsafe extern "C" fn xmlCtxtSetMaxAmplification(ctxt: *mut _xmlParserCtxt, maxAmpl: c_uint) {
705 if ctxt.is_null() || maxAmpl == 0 {
706 return;
707 }
708 unsafe {
709 (*ctxt).maxAmpl = maxAmpl;
710 }
711}
712
713#[no_mangle]
721pub unsafe extern "C" fn xmlCtxtGetLastError(ctx: *mut c_void) -> *const _xmlError {
722 if ctx.is_null() {
723 return ptr::null();
724 }
725 let ctxt = ctx as *mut _xmlParserCtxt;
726 unsafe {
727 if (*ctxt).lastError.code == XML_ERR_OK {
728 return ptr::null();
729 }
730 &(*ctxt).lastError
731 }
732}
733
734#[no_mangle]
742pub unsafe extern "C" fn xmlCtxtResetLastError(ctx: *mut c_void) {
743 if ctx.is_null() {
744 return;
745 }
746 let ctxt = ctx as *mut _xmlParserCtxt;
747 unsafe {
748 (*ctxt).errNo = XML_ERR_OK;
749 if (*ctxt).lastError.code != XML_ERR_OK {
750 errors::reset_error(&mut (*ctxt).lastError);
751 }
752 }
753}
754
755#[no_mangle]
763pub unsafe extern "C" fn xmlCtxtErrMemory(ctxt: *mut _xmlParserCtxt) {
764 if ctxt.is_null() {
765 return;
766 }
767 unsafe {
768 let c = &mut *ctxt;
769 c.errNo = XML_ERR_NO_MEMORY;
770 c.instate = xmlParserInputState::XML_PARSER_EOF as c_int;
771 c.wellFormed = 0;
772 c.disableSAX = 2;
773
774 c.lastError.domain = XML_FROM_PARSER;
775 c.lastError.code = XML_ERR_NO_MEMORY;
776 c.lastError.level = xmlErrorLevel::XML_ERR_FATAL as c_int;
777 c.lastError.message = b"out of memory\n\0".as_ptr() as *mut c_char;
778
779 if let Some(handler) = c.errorHandler {
780 handler(c.errorCtxt, &c.lastError);
781 } else if !c.sax.is_null() {
782 if let Some(serror) = (*c.sax).serror {
783 serror(c.userData, &c.lastError);
784 }
785 }
786 }
787}
788
789#[no_mangle]
797pub unsafe extern "C" fn xmlStopParser(ctxt: *mut _xmlParserCtxt) {
798 if ctxt.is_null() {
799 return;
800 }
801 unsafe {
802 (*ctxt).disableSAX = 2;
803 if (*ctxt).errNo == XML_ERR_OK {
804 (*ctxt).errNo = XML_ERR_USER_STOP;
805 (*ctxt).lastError.code = XML_ERR_USER_STOP;
806 (*ctxt).wellFormed = 0;
807 }
808 }
809}
810
811#[no_mangle]
820pub unsafe extern "C" fn xmlByteConsumed(ctxt: *mut _xmlParserCtxt) -> c_long {
821 if ctxt.is_null() {
822 return -1;
823 }
824 unsafe {
825 let input = (*ctxt).input;
826 if input.is_null() {
827 return -1;
828 }
829 if !(*input).buf.is_null() && !(*(*input).buf).encoder.is_null() {
830 return (*(*input).buf).rawconsumed as c_long;
833 }
834 let consumed = (*input).consumed;
835 if (*input).base.is_null() {
836 return consumed as c_long;
837 }
838 (consumed + ((*input).cur as usize).saturating_sub((*input).base as usize) as c_ulong)
839 as c_long
840 }
841}
842
843#[no_mangle]
851pub unsafe extern "C" fn xmlParserGetDirectory(filename: *const c_char) -> *mut c_char {
852 if filename.is_null() {
853 return ptr::null_mut();
854 }
855 unsafe {
856 let len = libc::strlen(filename);
857 let mut last_sep: Option<usize> = None;
858 for i in 0..len {
859 if *filename.add(i) == b'/' as c_char {
860 last_sep = Some(i);
861 }
862 }
863 match last_sep {
864 Some(0) => xmlMemStrdupImpl(b"/\0".as_ptr() as *const c_char) as *mut c_char,
865 Some(pos) => {
866 let slice = core::slice::from_raw_parts(filename as *const u8, pos);
867 let mut v = slice.to_vec();
868 v.push(0);
869 xmlMemStrdupImpl(v.as_ptr() as *const c_char) as *mut c_char
870 }
871 None => xmlMemStrdupImpl(b".\0".as_ptr() as *const c_char) as *mut c_char,
872 }
873 }
874}
875
876#[no_mangle]
885pub unsafe extern "C" fn xmlCheckFilename(path: *const c_char) -> c_int {
886 if path.is_null() {
887 return 0;
888 }
889 unsafe {
890 let mut st: libc::stat = core::mem::zeroed();
891 if libc::stat(path, &mut st) != 0 {
892 return 0;
893 }
894 if st.st_mode & libc::S_IFMT == libc::S_IFDIR {
895 2
896 } else {
897 1
898 }
899 }
900}
901
902#[no_mangle]
910pub unsafe extern "C" fn xmlIsXHTML(systemID: *const xmlChar, publicID: *const xmlChar) -> c_int {
911 const XHTML_STRICT_PUBLIC_ID: &[u8] = b"-//W3C//DTD XHTML 1.0 Strict//EN\0";
912 const XHTML_STRICT_SYSTEM_ID: &[u8] = b"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\0";
913 const XHTML_FRAME_PUBLIC_ID: &[u8] = b"-//W3C//DTD XHTML 1.0 Frameset//EN\0";
914 const XHTML_FRAME_SYSTEM_ID: &[u8] = b"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd\0";
915 const XHTML_TRANS_PUBLIC_ID: &[u8] = b"-//W3C//DTD XHTML 1.0 Transitional//EN\0";
916 const XHTML_TRANS_SYSTEM_ID: &[u8] =
917 b"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\0";
918
919 if systemID.is_null() && publicID.is_null() {
920 return -1;
921 }
922 unsafe {
923 if !publicID.is_null() {
924 if string::xml_strcmp(publicID, XHTML_STRICT_PUBLIC_ID.as_ptr() as *const xmlChar) == 0
925 || string::xml_strcmp(publicID, XHTML_FRAME_PUBLIC_ID.as_ptr() as *const xmlChar)
926 == 0
927 || string::xml_strcmp(publicID, XHTML_TRANS_PUBLIC_ID.as_ptr() as *const xmlChar)
928 == 0
929 {
930 return 1;
931 }
932 }
933 if !systemID.is_null() {
934 if string::xml_strcmp(systemID, XHTML_STRICT_SYSTEM_ID.as_ptr() as *const xmlChar) == 0
935 || string::xml_strcmp(systemID, XHTML_FRAME_SYSTEM_ID.as_ptr() as *const xmlChar)
936 == 0
937 || string::xml_strcmp(systemID, XHTML_TRANS_SYSTEM_ID.as_ptr() as *const xmlChar)
938 == 0
939 {
940 return 1;
941 }
942 }
943 }
944 0
945}
946
947#[no_mangle]
959pub unsafe extern "C" fn xmlCreateMemoryParserCtxt(
960 buffer: *const c_char,
961 size: c_int,
962) -> *mut _xmlParserCtxt {
963 if buffer.is_null() || size < 0 {
964 return ptr::null_mut();
965 }
966 unsafe {
967 let ctxt = xmlNewParserCtxt();
968 if ctxt.is_null() {
969 return ptr::null_mut();
970 }
971 let input = helpers::input_from_memory(buffer, size);
972 helpers::setup_parser_input(ctxt, input);
973 ctxt
974 }
975}
976
977#[no_mangle]
987pub unsafe extern "C" fn xmlCreatePushParserCtxt(
988 sax: *mut _xmlSAXHandler,
989 user_data: *mut c_void,
990 chunk: *const c_char,
991 size: c_int,
992 filename: *const c_char,
993) -> *mut _xmlParserCtxt {
994 unsafe {
995 let ctxt = xmlNewSAXParserCtxt(sax, user_data);
996 if ctxt.is_null() {
997 return ptr::null_mut();
998 }
999 let slice = if size > 0 && !chunk.is_null() {
1000 core::slice::from_raw_parts(chunk as *const u8, size as usize)
1001 } else {
1002 &[]
1003 };
1004 let uri = if filename.is_null() {
1005 None
1006 } else {
1007 CStr::from_ptr(filename).to_str().ok()
1008 };
1009 let input = InputBuffer::from_memory(slice, uri);
1010 helpers::setup_parser_input(ctxt, input);
1011 ctxt
1012 }
1013}
1014
1015#[no_mangle]
1026pub unsafe extern "C" fn xmlCreateIOParserCtxt(
1027 sax: *mut _xmlSAXHandler,
1028 user_data: *mut c_void,
1029 ioread: Option<xmlInputReadCallback>,
1030 ioclose: Option<xmlInputCloseCallback>,
1031 ioctx: *mut c_void,
1032 enc: c_int,
1033) -> *mut _xmlParserCtxt {
1034 unsafe {
1035 let ctxt = xmlNewSAXParserCtxt(sax, user_data);
1036 if ctxt.is_null() {
1037 return ptr::null_mut();
1038 }
1039 let input = helpers::input_from_io(ioread, ioclose, ioctx);
1040 helpers::setup_parser_input(ctxt, input);
1041 if enc != xmlCharEncoding::XML_CHAR_ENCODING_NONE as c_int {
1042 xmlSwitchEncoding(ctxt, enc);
1043 }
1044 ctxt
1045 }
1046}
1047
1048#[no_mangle]
1056pub unsafe extern "C" fn xmlCreateURLParserCtxt(
1057 filename: *const c_char,
1058 options: c_int,
1059) -> *mut _xmlParserCtxt {
1060 if filename.is_null() {
1061 return ptr::null_mut();
1062 }
1063 unsafe {
1064 let ctxt = xmlNewParserCtxt();
1065 if ctxt.is_null() {
1066 return ptr::null_mut();
1067 }
1068 apply_options(ctxt, options);
1069 let input = match helpers::input_from_file(filename) {
1070 Ok(i) => i,
1071 Err(_) => {
1072 helpers::free_parser_ctxt(ctxt);
1073 return ptr::null_mut();
1074 }
1075 };
1076 helpers::setup_parser_input(ctxt, input);
1077 ctxt
1078 }
1079}
1080
1081#[no_mangle]
1091pub unsafe extern "C" fn xmlCreateEntityParserCtxt(
1092 URL: *const xmlChar,
1093 ID: *const xmlChar,
1094 base: *const xmlChar,
1095) -> *mut _xmlParserCtxt {
1096 let _ = base; unsafe {
1098 let ctxt = xmlNewParserCtxt();
1099 if ctxt.is_null() {
1100 return ptr::null_mut();
1101 }
1102 let input = xmlLoadExternalEntity(URL as *const c_char, ID as *const c_char, ctxt);
1103 if input.is_null() {
1104 helpers::free_parser_ctxt(ctxt);
1105 return ptr::null_mut();
1106 }
1107 if xmlPushInput(ctxt, input) < 0 {
1108 helpers::free_parser_input(input);
1109 helpers::free_parser_ctxt(ctxt);
1110 return ptr::null_mut();
1111 }
1112 ctxt
1113 }
1114}
1115
1116#[no_mangle]
1129pub unsafe extern "C" fn xmlCtxtReadDoc(
1130 ctxt: *mut _xmlParserCtxt,
1131 cur: *const xmlChar,
1132 URL: *const c_char,
1133 _encoding: *const c_char,
1134 options: c_int,
1135) -> *mut _xmlDoc {
1136 if ctxt.is_null() || cur.is_null() {
1137 return ptr::null_mut();
1138 }
1139 unsafe {
1140 let len = string::xml_strlen(cur);
1141 let input = helpers::input_from_memory(cur as *const c_char, len as c_int);
1142 ctxt_read_doc(ctxt, input, URL, options)
1143 }
1144}
1145
1146#[no_mangle]
1155pub unsafe extern "C" fn xmlCtxtReadFile(
1156 ctxt: *mut _xmlParserCtxt,
1157 filename: *const c_char,
1158 _encoding: *const c_char,
1159 options: c_int,
1160) -> *mut _xmlDoc {
1161 if ctxt.is_null() || filename.is_null() {
1162 return ptr::null_mut();
1163 }
1164 unsafe {
1165 match helpers::input_from_file(filename) {
1166 Ok(input) => ctxt_read_doc(ctxt, input, filename, options),
1167 Err(_) => ptr::null_mut(),
1168 }
1169 }
1170}
1171
1172#[no_mangle]
1182pub unsafe extern "C" fn xmlCtxtReadMemory(
1183 ctxt: *mut _xmlParserCtxt,
1184 buffer: *const c_char,
1185 size: c_int,
1186 URL: *const c_char,
1187 _encoding: *const c_char,
1188 options: c_int,
1189) -> *mut _xmlDoc {
1190 if ctxt.is_null() || buffer.is_null() || size < 0 {
1191 return ptr::null_mut();
1192 }
1193 unsafe {
1194 let input = helpers::input_from_memory(buffer, size);
1195 ctxt_read_doc(ctxt, input, URL, options)
1196 }
1197}
1198
1199#[no_mangle]
1208pub unsafe extern "C" fn xmlCtxtReadFd(
1209 ctxt: *mut _xmlParserCtxt,
1210 fd: c_int,
1211 URL: *const c_char,
1212 _encoding: *const c_char,
1213 options: c_int,
1214) -> *mut _xmlDoc {
1215 if ctxt.is_null() || fd < 0 {
1216 return ptr::null_mut();
1217 }
1218 unsafe {
1219 let mut buf = Vec::new();
1220 let mut tmp = [0u8; 4096];
1221 loop {
1222 let n = libc::read(fd, tmp.as_mut_ptr() as *mut c_void, tmp.len());
1223 if n <= 0 {
1224 break;
1225 }
1226 buf.extend_from_slice(&tmp[..n as usize]);
1227 }
1228 let input = helpers::input_from_memory(buf.as_ptr() as *const c_char, buf.len() as c_int);
1229 ctxt_read_doc(ctxt, input, URL, options)
1230 }
1231}
1232
1233#[no_mangle]
1243pub unsafe extern "C" fn xmlCtxtReadIO(
1244 ctxt: *mut _xmlParserCtxt,
1245 ioread: Option<xmlInputReadCallback>,
1246 ioclose: Option<xmlInputCloseCallback>,
1247 ioctx: *mut c_void,
1248 URL: *const c_char,
1249 _encoding: *const c_char,
1250 options: c_int,
1251) -> *mut _xmlDoc {
1252 if ctxt.is_null() {
1253 return ptr::null_mut();
1254 }
1255 unsafe {
1256 let input = helpers::input_from_io(ioread, ioclose, ioctx);
1257 ctxt_read_doc(ctxt, input, URL, options)
1258 }
1259}
1260
1261#[no_mangle]
1269pub unsafe extern "C" fn xmlCtxtParseDocument(
1270 ctxt: *mut _xmlParserCtxt,
1271 input: *mut _xmlParserInput,
1272) -> *mut _xmlDoc {
1273 if ctxt.is_null() || input.is_null() {
1274 return ptr::null_mut();
1275 }
1276 unsafe {
1277 let mut owned = false;
1280 let nr = (*ctxt).inputNr;
1281 let tab = (*ctxt).inputTab;
1282 if !tab.is_null() {
1283 for i in 0..nr {
1284 if *tab.add(i as usize) == input {
1285 owned = true;
1286 break;
1287 }
1288 }
1289 }
1290 if (*ctxt).input == input {
1291 owned = true;
1292 }
1293
1294 let ib = input_buffer_from_parser_input(input);
1296
1297 xmlCtxtReset(ctxt);
1298 helpers::setup_parser_input(ctxt, ib);
1299 helpers::parse_document(ctxt);
1300
1301 if !owned {
1302 helpers::free_parser_input(input);
1303 }
1304
1305 (*ctxt).myDoc
1306 }
1307}
1308
1309#[no_mangle]
1321pub unsafe extern "C" fn xmlAllocParserInputBuffer(enc: c_int) -> *mut _xmlParserInputBuffer {
1322 unsafe {
1323 let buf = xmlMallocZero(core::mem::size_of::<_xmlParserInputBuffer>())
1324 as *mut _xmlParserInputBuffer;
1325 if buf.is_null() {
1326 return ptr::null_mut();
1327 }
1328 let b = &mut *buf;
1329 b.buffer = io::buf_create(crate::abi::data_globals::xmlDefaultBufferSize) as *mut c_void;
1330 b.raw = io::buf_create(crate::abi::data_globals::xmlDefaultBufferSize) as *mut c_void;
1331 if b.buffer.is_null() || b.raw.is_null() {
1332 io::buf_free(b.buffer as *mut _xmlBuffer);
1333 io::buf_free(b.raw as *mut _xmlBuffer);
1334 xmlFreeImpl(buf as *mut c_void);
1335 return ptr::null_mut();
1336 }
1337 b.compressed = -1;
1338
1339 if enc != xmlCharEncoding::XML_CHAR_ENCODING_NONE as c_int
1340 && enc != xmlCharEncoding::XML_CHAR_ENCODING_ERROR as c_int
1341 {
1342 let handler = encoding_handler_for(enc);
1343 if !handler.is_null() {
1344 b.encoder = handler as *mut c_void;
1345 }
1346 }
1347 buf
1348 }
1349}
1350
1351#[no_mangle]
1359pub unsafe extern "C" fn xmlParserInputBufferGrow(
1360 in_: *mut _xmlParserInputBuffer,
1361 len: c_int,
1362) -> c_int {
1363 if in_.is_null() || len <= 0 {
1364 return 0;
1365 }
1366 unsafe {
1367 let b = &mut *in_;
1368 if b.error != 0 {
1369 return -1;
1370 }
1371 let Some(read_cb) = b.readcallback else {
1372 return 0;
1374 };
1375 let mut tmp = vec![0u8; len as usize];
1376 let n = read_cb(b.context, tmp.as_mut_ptr() as *mut c_char, len);
1377 if n < 0 {
1378 b.error = 1;
1379 return -1;
1380 }
1381 if n == 0 {
1382 return 0;
1383 }
1384 io::input_buffer_push(in_, tmp.as_ptr() as *const c_char, n);
1385 n
1386 }
1387}
1388
1389#[no_mangle]
1397pub unsafe extern "C" fn xmlParserInputBufferPush(
1398 in_: *mut _xmlParserInputBuffer,
1399 len: c_int,
1400 buf: *const c_char,
1401) -> c_int {
1402 if in_.is_null() {
1403 return -1;
1404 }
1405 if len < 0 || (len > 0 && buf.is_null()) {
1406 return -1;
1407 }
1408 if len == 0 {
1409 return 0;
1410 }
1411 io::input_buffer_push(in_, buf, len)
1412}
1413
1414#[no_mangle]
1422pub unsafe extern "C" fn xmlParserInputBufferRead(
1423 in_: *mut _xmlParserInputBuffer,
1424 len: c_int,
1425) -> c_int {
1426 xmlParserInputBufferGrow(in_, len)
1427}
1428
1429#[no_mangle]
1437pub unsafe extern "C" fn xmlParserInputRead(_in_: *mut _xmlParserInput, _len: c_int) -> c_int {
1438 -1
1439}
1440
1441#[no_mangle]
1449pub unsafe extern "C" fn xmlParserInputGrow(in_: *mut _xmlParserInput, len: c_int) -> c_int {
1450 if in_.is_null() || len < 0 {
1451 return -1;
1452 }
1453 unsafe {
1454 let pi = &*in_;
1455 if pi.base.is_null() || pi.cur.is_null() {
1456 return -1;
1457 }
1458 if pi.buf.is_null() {
1459 return 0;
1461 }
1462 let b = &*pi.buf;
1463 if b.readcallback.is_none() && b.encoder.is_null() {
1465 return 0;
1466 }
1467 xmlParserInputBufferGrow(pi.buf, len)
1468 }
1469}
1470
1471#[no_mangle]
1479pub unsafe extern "C" fn xmlParserInputShrink(in_: *mut _xmlParserInput) {
1480 if in_.is_null() {
1481 return;
1482 }
1483 unsafe {
1484 let pi = &mut *in_;
1485 if pi.buf.is_null() || pi.base.is_null() || pi.cur.is_null() {
1486 return;
1487 }
1488 let used = (pi.cur as usize).saturating_sub(pi.base as usize);
1489 if used > LINE_LEN {
1490 pi.consumed = pi.consumed.saturating_add((used - LINE_LEN) as c_ulong);
1493 }
1494 }
1495}
1496
1497#[no_mangle]
1505pub unsafe extern "C" fn xmlNewInputStream(ctxt: *mut _xmlParserCtxt) -> *mut _xmlParserInput {
1506 unsafe {
1507 let input = xmlMallocZero(core::mem::size_of::<_xmlParserInput>()) as *mut _xmlParserInput;
1508 if input.is_null() {
1509 if !ctxt.is_null() {
1510 xmlCtxtErrMemory(ctxt);
1511 }
1512 return ptr::null_mut();
1513 }
1514 (*input).line = 1;
1515 (*input).col = 1;
1516 input
1517 }
1518}
1519
1520#[no_mangle]
1530pub unsafe extern "C" fn xmlNewIOInputStream(
1531 ctxt: *mut _xmlParserCtxt,
1532 input: *mut _xmlParserInputBuffer,
1533 enc: c_int,
1534) -> *mut _xmlParserInput {
1535 if ctxt.is_null() || input.is_null() {
1536 return ptr::null_mut();
1537 }
1538 unsafe {
1539 let pi = xmlNewInputStream(ctxt);
1540 if pi.is_null() {
1541 return ptr::null_mut();
1542 }
1543 (*pi).buf = input;
1544 if enc != xmlCharEncoding::XML_CHAR_ENCODING_NONE as c_int
1545 && enc != xmlCharEncoding::XML_CHAR_ENCODING_ERROR as c_int
1546 {
1547 let handler = encoding_handler_for(enc);
1548 if !handler.is_null() {
1549 io::input_buffer_set_encoder(input, handler);
1550 }
1551 }
1552 pi
1553 }
1554}
1555
1556#[no_mangle]
1566pub unsafe extern "C" fn xmlNewStringInputStream(
1567 ctxt: *mut _xmlParserCtxt,
1568 buffer: *const xmlChar,
1569) -> *mut _xmlParserInput {
1570 if ctxt.is_null() || buffer.is_null() {
1571 return ptr::null_mut();
1572 }
1573 unsafe {
1574 let input = xmlNewInputStream(ctxt);
1575 if input.is_null() {
1576 return ptr::null_mut();
1577 }
1578 let len = string::xml_strlen(buffer);
1579 (*input).base = buffer;
1580 (*input).cur = buffer;
1581 (*input).end = buffer.add(len);
1582 (*input).length = len as c_int;
1583 input
1584 }
1585}
1586
1587#[no_mangle]
1596pub unsafe extern "C" fn xmlSetupParserForBuffer(
1597 ctxt: *mut _xmlParserCtxt,
1598 buffer: *const xmlChar,
1599 filename: *const c_char,
1600) {
1601 if ctxt.is_null() || buffer.is_null() {
1602 return;
1603 }
1604 unsafe {
1605 xmlCtxtReset(ctxt);
1606 let len = string::xml_strlen(buffer);
1607 let uri = if filename.is_null() {
1608 None
1609 } else {
1610 CStr::from_ptr(filename).to_str().ok()
1611 };
1612 let input = InputBuffer::from_memory(core::slice::from_raw_parts(buffer, len), uri);
1613 helpers::setup_parser_input(ctxt, input);
1614 }
1615}
1616
1617#[no_mangle]
1625pub unsafe extern "C" fn xmlPushInput(
1626 ctxt: *mut _xmlParserCtxt,
1627 input: *mut _xmlParserInput,
1628) -> c_int {
1629 if ctxt.is_null() || input.is_null() {
1630 return -1;
1631 }
1632 unsafe {
1633 let c = &mut *ctxt;
1634 if c.inputNr >= c.inputMax {
1635 let new_max = if c.inputMax == 0 { 5 } else { c.inputMax * 2 };
1636 let new_tab = xmlReallocImpl(
1637 c.inputTab as *mut c_void,
1638 (new_max as usize) * core::mem::size_of::<*mut _xmlParserInput>(),
1639 ) as *mut *mut _xmlParserInput;
1640 if new_tab.is_null() {
1641 return -1;
1642 }
1643 c.inputTab = new_tab;
1644 c.inputMax = new_max;
1645 }
1646 *c.inputTab.add(c.inputNr as usize) = input;
1647 c.input = input;
1648 (*input).id = c.input_id;
1649 c.input_id += 1;
1650 let idx = c.inputNr;
1651 c.inputNr += 1;
1652 idx
1653 }
1654}
1655
1656#[no_mangle]
1665pub unsafe extern "C" fn xmlPopInput(ctxt: *mut _xmlParserCtxt) -> xmlChar {
1666 if ctxt.is_null() || (*ctxt).inputNr <= 1 {
1667 return 0;
1668 }
1669 unsafe {
1670 let c = &mut *ctxt;
1671 c.inputNr -= 1;
1672 let popped = *c.inputTab.add(c.inputNr as usize);
1673 *c.inputTab.add(c.inputNr as usize) = ptr::null_mut();
1674 if c.inputNr > 0 {
1675 c.input = *c.inputTab.add((c.inputNr - 1) as usize);
1676 } else {
1677 c.input = ptr::null_mut();
1678 }
1679 if !popped.is_null() {
1680 helpers::free_parser_input(popped);
1681 }
1682 if c.input.is_null() {
1683 return 0;
1684 }
1685 let cur = (*c.input).cur;
1686 let end = (*c.input).end;
1687 if cur.is_null() || cur >= end {
1688 0
1689 } else {
1690 *cur
1691 }
1692 }
1693}
1694
1695#[no_mangle]
1707pub unsafe extern "C" fn xmlSwitchEncoding(ctxt: *mut _xmlParserCtxt, enc: c_int) -> c_int {
1708 if ctxt.is_null() || (*ctxt).input.is_null() {
1709 return -1;
1710 }
1711 if enc == xmlCharEncoding::XML_CHAR_ENCODING_NONE as c_int {
1712 return 0;
1713 }
1714 unsafe {
1715 let handler = encoding_handler_for(enc);
1716 if handler.is_null() {
1717 return -1;
1718 }
1719 xmlSwitchToEncoding(ctxt, handler)
1720 }
1721}
1722
1723#[no_mangle]
1731pub unsafe extern "C" fn xmlSwitchEncodingName(
1732 ctxt: *mut _xmlParserCtxt,
1733 encoding: *const c_char,
1734) -> c_int {
1735 if ctxt.is_null() || encoding.is_null() {
1736 return -1;
1737 }
1738 unsafe {
1739 let handler = encoding::find_encoding_handler(encoding as *const xmlChar);
1740 if handler.is_null() {
1741 return -1;
1742 }
1743 xmlSwitchToEncoding(ctxt, handler)
1744 }
1745}
1746
1747#[no_mangle]
1756pub unsafe extern "C" fn xmlSwitchInputEncoding(
1757 ctxt: *mut _xmlParserCtxt,
1758 input: *mut _xmlParserInput,
1759 handler: *mut _xmlCharEncodingHandler,
1760) -> c_int {
1761 let _ = ctxt;
1762 if input.is_null() {
1763 return -1;
1764 }
1765 unsafe {
1766 if (*input).buf.is_null() {
1767 return -1;
1768 }
1769 io::input_buffer_set_encoder((*input).buf, handler);
1770 }
1771 0
1772}
1773
1774#[no_mangle]
1783pub unsafe extern "C" fn xmlSwitchToEncoding(
1784 ctxt: *mut _xmlParserCtxt,
1785 handler: *mut _xmlCharEncodingHandler,
1786) -> c_int {
1787 if ctxt.is_null() {
1788 return -1;
1789 }
1790 unsafe {
1791 let input = (*ctxt).input;
1792 if input.is_null() || (*input).buf.is_null() {
1793 return -1;
1794 }
1795 io::input_buffer_set_encoder((*input).buf, handler);
1796 }
1797 0
1798}
1799
1800#[no_mangle]
1812pub unsafe extern "C" fn xmlInitNodeInfoSeq(seq: *mut _xmlParserNodeInfoSeq) {
1813 if seq.is_null() {
1814 return;
1815 }
1816 unsafe {
1817 (*seq).block = ptr::null_mut();
1818 (*seq).index = ptr::null_mut();
1819 (*seq).block_max = 0;
1820 (*seq).size = 0;
1821 }
1822}
1823
1824#[no_mangle]
1832pub unsafe extern "C" fn xmlClearNodeInfoSeq(seq: *mut _xmlParserNodeInfoSeq) {
1833 if seq.is_null() {
1834 return;
1835 }
1836 unsafe {
1837 if !(*seq).block.is_null() {
1838 xmlFreeImpl((*seq).block as *mut c_void);
1839 }
1840 if !(*seq).index.is_null() {
1841 xmlFreeImpl((*seq).index as *mut c_void);
1842 }
1843 xmlInitNodeInfoSeq(seq);
1844 }
1845}
1846
1847#[no_mangle]
1857pub unsafe extern "C" fn xmlParserFindNodeInfoIndex(
1858 seq: *mut _xmlParserNodeInfoSeq,
1859 node: *mut _xmlNode,
1860) -> c_ulong {
1861 if seq.is_null() || node.is_null() {
1862 return c_ulong::MAX;
1863 }
1864 unsafe {
1865 let s = &*seq;
1866 if s.block.is_null() || s.size == 0 {
1867 return 0;
1868 }
1869 let mut lower: usize = 0;
1870 let mut upper: usize = s.size as usize;
1871 while lower < upper {
1872 let middle = lower + (upper - lower) / 2;
1873 let cur_node = (*s.block.add(middle)).node;
1874 if cur_node == node {
1875 return middle as c_ulong;
1876 }
1877 if (cur_node as usize) < (node as usize) {
1878 lower = middle + 1;
1879 } else {
1880 upper = middle;
1881 }
1882 }
1883 lower as c_ulong
1884 }
1885}
1886
1887#[no_mangle]
1896pub unsafe extern "C" fn xmlParserFindNodeInfo(
1897 ctxt: *mut _xmlParserCtxt,
1898 node: *mut _xmlNode,
1899) -> *const _xmlParserNodeInfo {
1900 if ctxt.is_null() || node.is_null() {
1901 return ptr::null();
1902 }
1903 unsafe {
1904 let seq = &(*ctxt).node_seq;
1905 let seq_mut = seq as *const _ as *mut _xmlParserNodeInfoSeq;
1906 let pos = xmlParserFindNodeInfoIndex(seq_mut, node);
1907 if !seq.block.is_null() && (pos as usize) < (seq.size as usize) {
1908 let info = &*seq.block.add(pos as usize);
1909 if info.node == node {
1910 return info;
1911 }
1912 }
1913 ptr::null()
1914 }
1915}
1916
1917#[no_mangle]
1925pub unsafe extern "C" fn xmlParserAddNodeInfo(
1926 ctxt: *mut _xmlParserCtxt,
1927 info: *mut _xmlParserNodeInfo,
1928) {
1929 if ctxt.is_null() || info.is_null() {
1930 return;
1931 }
1932 unsafe {
1933 let seq = &mut (*ctxt).node_seq;
1934 let node = (*info).node;
1935 let pos = xmlParserFindNodeInfoIndex(seq, node as *mut _xmlNode) as usize;
1936
1937 if !seq.block.is_null() && pos < seq.size as usize && (*seq.block.add(pos)).node == node {
1938 ptr::copy_nonoverlapping(info, seq.block.add(pos), 1);
1939 return;
1940 }
1941
1942 if seq.size + 1 > seq.block_max {
1944 let new_max = if seq.block_max == 0 {
1945 4
1946 } else {
1947 seq.block_max * 2
1948 };
1949 let new_block = xmlReallocImpl(
1950 seq.block as *mut c_void,
1951 (new_max as usize) * core::mem::size_of::<_xmlParserNodeInfo>(),
1952 ) as *mut _xmlParserNodeInfo;
1953 if new_block.is_null() {
1954 xmlCtxtErrMemory(ctxt);
1955 return;
1956 }
1957 seq.block = new_block;
1958 seq.block_max = new_max;
1959 }
1960
1961 let size = seq.size as usize;
1963 for i in (pos + 1..=size).rev() {
1964 ptr::copy_nonoverlapping(seq.block.add(i - 1), seq.block.add(i), 1);
1965 }
1966 ptr::copy_nonoverlapping(info, seq.block.add(pos), 1);
1967 seq.size += 1;
1968 }
1969}
1970
1971#[no_mangle]
1986pub unsafe extern "C" fn xmlRegisterInputCallbacks(
1987 matchFunc: Option<xmlInputMatchCallback>,
1988 openFunc: Option<xmlInputOpenCallback>,
1989 readFunc: Option<xmlInputReadCallback>,
1990 closeFunc: Option<xmlInputCloseCallback>,
1991) -> c_int {
1992 unsafe {
1993 globals::init_parser();
1994 }
1995 let mut table = INPUT_CALLBACKS.lock();
1996 if table.len() >= 10 {
1997 return -1;
1998 }
1999 table.push(InputCallbackEntry {
2000 matchcb: matchFunc,
2001 opencb: openFunc,
2002 readcb: readFunc,
2003 closecb: closeFunc,
2004 });
2005 (table.len() - 1) as c_int
2006}
2007
2008#[no_mangle]
2016pub unsafe extern "C" fn xmlRegisterDefaultInputCallbacks() {
2017 unsafe {
2018 xmlRegisterInputCallbacks(
2019 Some(xmlFileMatch),
2020 Some(xmlFileOpen),
2021 Some(xmlFileRead),
2022 Some(xmlFileClose),
2023 );
2024 }
2025}
2026
2027#[no_mangle]
2035pub unsafe extern "C" fn xmlPopInputCallbacks() -> c_int {
2036 unsafe {
2037 globals::init_parser();
2038 }
2039 let mut table = INPUT_CALLBACKS.lock();
2040 if table.is_empty() {
2041 return -1;
2042 }
2043 table.pop();
2044 table.len() as c_int
2045}
2046
2047#[no_mangle]
2055pub unsafe extern "C" fn xmlCleanupInputCallbacks() {
2056 unsafe {
2057 globals::init_parser();
2058 }
2059 INPUT_CALLBACKS.lock().clear();
2060}
2061
2062#[no_mangle]
2073pub unsafe extern "C" fn xmlRegisterOutputCallbacks(
2074 matchFunc: Option<xmlOutputMatchCallback>,
2075 openFunc: Option<xmlOutputOpenCallback>,
2076 writeFunc: Option<xmlOutputWriteCallback>,
2077 closeFunc: Option<xmlOutputCloseCallback>,
2078) -> c_int {
2079 unsafe {
2080 globals::init_parser();
2081 }
2082 let mut table = OUTPUT_CALLBACKS.lock();
2083 if table.len() >= 10 {
2084 return -1;
2085 }
2086 table.push(OutputCallbackEntry {
2087 matchcb: matchFunc,
2088 opencb: openFunc,
2089 writecb: writeFunc,
2090 closecb: closeFunc,
2091 });
2092 (table.len() - 1) as c_int
2093}
2094
2095#[no_mangle]
2103pub unsafe extern "C" fn xmlRegisterDefaultOutputCallbacks() {
2104 unsafe {
2105 xmlRegisterOutputCallbacks(Some(xmlFileMatch), None, None, None);
2106 }
2107}
2108
2109#[no_mangle]
2117pub unsafe extern "C" fn xmlRegisterHTTPPostCallbacks() {
2118 unsafe { xmlRegisterDefaultOutputCallbacks() }
2119}
2120
2121#[no_mangle]
2129pub unsafe extern "C" fn xmlPopOutputCallbacks() -> c_int {
2130 unsafe {
2131 globals::init_parser();
2132 }
2133 let mut table = OUTPUT_CALLBACKS.lock();
2134 if table.is_empty() {
2135 return -1;
2136 }
2137 table.pop();
2138 table.len() as c_int
2139}
2140
2141#[no_mangle]
2149pub unsafe extern "C" fn xmlCleanupOutputCallbacks() {
2150 unsafe {
2151 globals::init_parser();
2152 }
2153 OUTPUT_CALLBACKS.lock().clear();
2154}
2155
2156unsafe extern "C" fn default_external_entity_loader(
2167 url: *const c_char,
2168 public_id: *const c_char,
2169 ctxt: *mut _xmlParserCtxt,
2170) -> *mut _xmlParserInput {
2171 let _ = public_id;
2172 if url.is_null() {
2173 return ptr::null_mut();
2174 }
2175 unsafe {
2176 if !ctxt.is_null() && (*ctxt).options & XML_PARSE_NONET != 0 {
2178 let len = libc::strlen(url);
2179 if len >= 7 && libc::strncasecmp(url, b"http://\0".as_ptr() as *const c_char, 7) == 0 {
2180 return ptr::null_mut();
2181 }
2182 }
2183 let table = INPUT_CALLBACKS.lock();
2185 for entry in table.iter() {
2186 if let (Some(match_cb), Some(open_cb)) = (entry.matchcb, entry.opencb) {
2187 if match_cb(url) != 0 {
2188 let ctx = open_cb(url);
2189 if !ctx.is_null() {
2190 let buf = helpers::alloc_parser_input_buffer();
2191 if buf.is_null() {
2192 if let Some(close_cb) = entry.closecb {
2193 close_cb(ctx);
2194 }
2195 return ptr::null_mut();
2196 }
2197 (*buf).context = ctx;
2198 (*buf).readcallback = entry.readcb;
2199 (*buf).closecallback = entry.closecb;
2200 return parser_input_from_buf(buf);
2201 }
2202 }
2203 }
2204 }
2205
2206 let buf =
2208 io::input_buffer_create_file(url, xmlCharEncoding::XML_CHAR_ENCODING_NONE as c_int);
2209 if buf.is_null() {
2210 return ptr::null_mut();
2211 }
2212 parser_input_from_buf(buf)
2213 }
2214}
2215
2216#[no_mangle]
2224pub unsafe extern "C" fn xmlSetExternalEntityLoader(f: Option<xmlExternalEntityLoader>) {
2225 *EXTERNAL_ENTITY_LOADER.lock() = f;
2226}
2227
2228#[no_mangle]
2236pub unsafe extern "C" fn xmlGetExternalEntityLoader() -> Option<xmlExternalEntityLoader> {
2237 *EXTERNAL_ENTITY_LOADER.lock()
2238}
2239
2240#[no_mangle]
2250pub unsafe extern "C" fn xmlNoNetExternalEntityLoader(
2251 URL: *const c_char,
2252 ID: *const c_char,
2253 ctxt: *mut _xmlParserCtxt,
2254) -> *mut _xmlParserInput {
2255 unsafe {
2256 let old_options = if ctxt.is_null() { 0 } else { (*ctxt).options };
2257 if !ctxt.is_null() {
2258 (*ctxt).options |= XML_PARSE_NONET;
2259 }
2260 let input = default_external_entity_loader(URL, ID, ctxt);
2261 if !ctxt.is_null() {
2262 (*ctxt).options = old_options;
2263 }
2264 input
2265 }
2266}
2267
2268#[no_mangle]
2277pub unsafe extern "C" fn xmlLoadExternalEntity(
2278 URL: *const c_char,
2279 ID: *const c_char,
2280 ctxt: *mut _xmlParserCtxt,
2281) -> *mut _xmlParserInput {
2282 let loader = *EXTERNAL_ENTITY_LOADER.lock();
2283 match loader {
2284 Some(f) => unsafe { f(URL, ID, ctxt) },
2285 None => unsafe { default_external_entity_loader(URL, ID, ctxt) },
2286 }
2287}
2288
2289#[no_mangle]
2299pub unsafe extern "C" fn xmlCheckHTTPInput(
2300 ctxt: *mut _xmlParserCtxt,
2301 ret: *mut _xmlParserInput,
2302) -> *mut _xmlParserInput {
2303 if ret.is_null() {
2304 return ptr::null_mut();
2305 }
2306 unsafe {
2307 if !ctxt.is_null() && (*ctxt).options & XML_PARSE_NONET != 0 {
2308 let filename = (*ret).filename;
2309 if !filename.is_null() {
2310 let len = libc::strlen(filename);
2311 if len >= 7
2312 && libc::strncasecmp(filename, b"http://\0".as_ptr() as *const c_char, 7) == 0
2313 {
2314 helpers::free_parser_input(ret);
2317 return ptr::null_mut();
2318 }
2319 }
2320 }
2321 ret
2322 }
2323}
2324
2325#[no_mangle]
2337pub unsafe extern "C" fn xmlFileMatch(_filename: *const c_char) -> c_int {
2338 1
2339}
2340
2341#[no_mangle]
2349pub unsafe extern "C" fn xmlFileOpen(filename: *const c_char) -> *mut c_void {
2350 if filename.is_null() {
2351 return ptr::null_mut();
2352 }
2353 unsafe { libc::fopen(filename, b"rb\0".as_ptr() as *const c_char) as *mut c_void }
2354}
2355
2356#[no_mangle]
2364pub unsafe extern "C" fn xmlFileRead(
2365 context: *mut c_void,
2366 buffer: *mut c_char,
2367 len: c_int,
2368) -> c_int {
2369 if context.is_null() || buffer.is_null() || len <= 0 {
2370 return -1;
2371 }
2372 unsafe {
2373 let n = libc::fread(
2374 buffer as *mut c_void,
2375 1,
2376 len as usize,
2377 context as *mut libc::FILE,
2378 );
2379 if n < len as usize && libc::ferror(context as *mut libc::FILE) != 0 {
2380 return -1;
2381 }
2382 n as c_int
2383 }
2384}
2385
2386#[no_mangle]
2394pub unsafe extern "C" fn xmlFileClose(context: *mut c_void) -> c_int {
2395 if context.is_null() {
2396 return -1;
2397 }
2398 unsafe {
2399 let file = context as *mut libc::FILE;
2400 let fd = libc::fileno(file);
2401 if fd == 0 {
2402 return 0;
2404 }
2405 if fd == 1 || fd == 2 {
2406 return if libc::fflush(file) == 0 { 0 } else { -1 };
2408 }
2409 libc::fclose(file)
2410 }
2411}
2412
2413#[no_mangle]
2426pub unsafe extern "C" fn xmlCurrentChar(ctxt: *mut _xmlParserCtxt, len: *mut c_int) -> c_int {
2427 if ctxt.is_null() || len.is_null() || (*ctxt).input.is_null() {
2428 return 0;
2429 }
2430 unsafe {
2431 let pi = &*((*ctxt).input);
2432 let cur = pi.cur;
2433 if cur.is_null() {
2434 *len = 0;
2435 return 0;
2436 }
2437 let avail = (pi.end as usize).saturating_sub(cur as usize);
2438 let c = *cur;
2439
2440 if c < 0x80 {
2441 if c == b'\r' {
2442 if avail >= 2 && *cur.add(1) == b'\n' {
2444 (*(*ctxt).input).cur = cur.add(1);
2445 }
2446 *len = 1;
2447 return b'\n' as c_int;
2448 }
2449 if c == 0 {
2450 if avail == 0 {
2451 *len = 0;
2452 } else {
2453 *len = 1;
2454 }
2455 return 0;
2456 }
2457 *len = 1;
2458 return c as c_int;
2459 }
2460
2461 if avail < 2 || (*cur.add(1) & 0xc0) != 0x80 {
2463 *len = 1;
2464 return XML_INVALID_CHAR;
2465 }
2466 if c < 0xe0 {
2467 if c < 0xc2 {
2468 *len = 1;
2469 return XML_INVALID_CHAR;
2470 }
2471 let val = (((c & 0x1f) as c_int) << 6) | ((*cur.add(1) & 0x3f) as c_int);
2472 *len = 2;
2473 return val;
2474 }
2475 if avail < 3 || (*cur.add(2) & 0xc0) != 0x80 {
2476 *len = 1;
2477 return XML_INVALID_CHAR;
2478 }
2479 if c < 0xf0 {
2480 let val = (((c & 0x0f) as c_int) << 12)
2481 | (((*cur.add(1) & 0x3f) as c_int) << 6)
2482 | ((*cur.add(2) & 0x3f) as c_int);
2483 if val < 0x800 || (val >= 0xd800 && val < 0xe000) {
2484 *len = 1;
2485 return XML_INVALID_CHAR;
2486 }
2487 *len = 3;
2488 return val;
2489 }
2490 if avail < 4 || (*cur.add(3) & 0xc0) != 0x80 {
2491 *len = 1;
2492 return XML_INVALID_CHAR;
2493 }
2494 let val = (((c & 0x07) as c_int) << 18)
2495 | (((*cur.add(1) & 0x3f) as c_int) << 12)
2496 | (((*cur.add(2) & 0x3f) as c_int) << 6)
2497 | ((*cur.add(3) & 0x3f) as c_int);
2498 if val < 0x10000 || val >= 0x110000 {
2499 *len = 1;
2500 return XML_INVALID_CHAR;
2501 }
2502 *len = 4;
2503 val
2504 }
2505}
2506
2507#[no_mangle]
2515pub unsafe extern "C" fn xmlNextChar(ctxt: *mut _xmlParserCtxt) {
2516 if ctxt.is_null() || (*ctxt).input.is_null() {
2517 return;
2518 }
2519 unsafe {
2520 let pi = &mut *((*ctxt).input);
2521 let cur = pi.cur;
2522 if cur.is_null() {
2523 return;
2524 }
2525 let avail = (pi.end as usize).saturating_sub(cur as usize);
2526 if avail == 0 {
2527 return;
2528 }
2529 let c = *cur;
2530
2531 if c < 0x80 {
2532 if c == b'\n' {
2533 pi.cur = cur.add(1);
2534 pi.line += 1;
2535 pi.col = 1;
2536 } else if c == b'\r' {
2537 pi.cur = cur.add(if avail >= 2 && *cur.add(1) == b'\n' {
2539 2
2540 } else {
2541 1
2542 });
2543 pi.line += 1;
2544 pi.col = 1;
2545 } else {
2546 pi.cur = cur.add(1);
2547 pi.col += 1;
2548 }
2549 return;
2550 }
2551
2552 pi.col += 1;
2553
2554 if avail < 2 || (*cur.add(1) & 0xc0) != 0x80 {
2555 pi.cur = cur.add(1);
2556 return;
2557 }
2558 if c < 0xe0 {
2559 if c < 0xc2 {
2560 pi.cur = cur.add(1);
2561 return;
2562 }
2563 pi.cur = cur.add(2);
2564 return;
2565 }
2566 if avail < 3 || (*cur.add(2) & 0xc0) != 0x80 {
2567 pi.cur = cur.add(1);
2568 return;
2569 }
2570 if c < 0xf0 {
2571 let val = (((c as c_int) << 8) as u32) | (*cur.add(1) as u32);
2572 if (val < 0xe0a0) || (val >= 0xeda0 && val < 0xee00) {
2573 pi.cur = cur.add(1);
2574 return;
2575 }
2576 pi.cur = cur.add(3);
2577 return;
2578 }
2579 if avail < 4 || (*cur.add(3) & 0xc0) != 0x80 {
2580 pi.cur = cur.add(1);
2581 return;
2582 }
2583 let val = (((c as c_int) << 8) as u32) | (*cur.add(1) as u32);
2584 if val < 0xf090 || val >= 0xf490 {
2585 pi.cur = cur.add(1);
2586 return;
2587 }
2588 pi.cur = cur.add(4);
2589 }
2590}
2591
2592#[no_mangle]
2601pub unsafe extern "C" fn xmlSkipBlankChars(ctxt: *mut _xmlParserCtxt) -> c_int {
2602 if ctxt.is_null() || (*ctxt).input.is_null() {
2603 return 0;
2604 }
2605 unsafe {
2606 let pi = &mut *((*ctxt).input);
2607 let mut cur = pi.cur;
2608 if cur.is_null() {
2609 return 0;
2610 }
2611 let end = pi.end;
2612 let mut res = 0;
2613 while cur < end && (*cur == 0x20 || *cur == 0x09 || *cur == 0x0a || *cur == 0x0d) {
2614 if *cur == b'\n' {
2615 pi.line += 1;
2616 pi.col = 1;
2617 } else {
2618 pi.col += 1;
2619 }
2620 cur = cur.add(1);
2621 res += 1;
2622 }
2623 pi.cur = cur;
2624 res
2625 }
2626}
2627
2628fn is_name_start_char_new(c: c_int) -> bool {
2630 if c == b' ' as c_int || c == b'>' as c_int || c == b'/' as c_int {
2631 return false;
2632 }
2633 (c >= b'a' as c_int && c <= b'z' as c_int)
2634 || (c >= b'A' as c_int && c <= b'Z' as c_int)
2635 || c == b'_' as c_int
2636 || c == b':' as c_int
2637 || (c >= 0xC0 && c <= 0xD6)
2638 || (c >= 0xD8 && c <= 0xF6)
2639 || (c >= 0xF8 && c <= 0x2FF)
2640 || (c >= 0x370 && c <= 0x37D)
2641 || (c >= 0x37F && c <= 0x1FFF)
2642 || (c >= 0x200C && c <= 0x200D)
2643 || (c >= 0x2070 && c <= 0x218F)
2644 || (c >= 0x2C00 && c <= 0x2FEF)
2645 || (c >= 0x3001 && c <= 0xD7FF)
2646 || (c >= 0xF900 && c <= 0xFDCF)
2647 || (c >= 0xFDF0 && c <= 0xFFFD)
2648 || (c >= 0x10000 && c <= 0xEFFFF)
2649}
2650
2651fn is_name_char_new(c: c_int) -> bool {
2653 if c == b' ' as c_int || c == b'>' as c_int || c == b'/' as c_int {
2654 return false;
2655 }
2656 (c >= b'a' as c_int && c <= b'z' as c_int)
2657 || (c >= b'A' as c_int && c <= b'Z' as c_int)
2658 || (c >= b'0' as c_int && c <= b'9' as c_int)
2659 || c == b'_' as c_int
2660 || c == b':' as c_int
2661 || c == b'-' as c_int
2662 || c == b'.' as c_int
2663 || c == 0xB7
2664 || (c >= 0xC0 && c <= 0xD6)
2665 || (c >= 0xD8 && c <= 0xF6)
2666 || (c >= 0xF8 && c <= 0x2FF)
2667 || (c >= 0x300 && c <= 0x36F)
2668 || (c >= 0x370 && c <= 0x37D)
2669 || (c >= 0x37F && c <= 0x1FFF)
2670 || (c >= 0x200C && c <= 0x200D)
2671 || (c >= 0x203F && c <= 0x2040)
2672 || (c >= 0x2070 && c <= 0x218F)
2673 || (c >= 0x2C00 && c <= 0x2FEF)
2674 || (c >= 0x3001 && c <= 0xD7FF)
2675 || (c >= 0xF900 && c <= 0xFDCF)
2676 || (c >= 0xFDF0 && c <= 0xFFFD)
2677 || (c >= 0x10000 && c <= 0xEFFFF)
2678}
2679
2680#[no_mangle]
2690pub unsafe extern "C" fn xmlScanName(
2691 ctxt: *mut _xmlParserCtxt,
2692 max: c_int,
2693 flags: c_int,
2694) -> *const xmlChar {
2695 if ctxt.is_null() || (*ctxt).input.is_null() || max <= 0 {
2696 return ptr::null();
2697 }
2698 unsafe {
2699 let pi = &mut *((*ctxt).input);
2700 let mut ptr = pi.cur;
2701 if ptr.is_null() {
2702 return ptr::null();
2703 }
2704 let end = pi.end;
2705 let mut remaining = max as usize;
2706 let stop: u8 = if flags & XML_SCAN_NC != 0 { b':' } else { 0 };
2707 let old10 = flags & XML_SCAN_OLD10 != 0;
2708 let mut f = flags;
2709
2710 loop {
2711 if ptr >= end {
2712 break;
2713 }
2714 let c = *ptr;
2715 let (cp, len) = if c < 0x80 {
2716 if stop != 0 && c == stop {
2717 break;
2718 }
2719 (c as c_int, 1usize)
2720 } else {
2721 let avail = (end as usize).saturating_sub(ptr as usize);
2723 let mut l = 4usize;
2724 let cp = decode_utf8_char(ptr, avail, &mut l);
2725 if cp < 0 {
2726 break;
2727 }
2728 (cp, l)
2729 };
2730
2731 let ok = if f & XML_SCAN_NMTOKEN != 0 {
2732 if old10 {
2733 is_name_char_old10(cp)
2734 } else {
2735 is_name_char_new(cp)
2736 }
2737 } else if old10 {
2738 is_name_start_char_old10(cp)
2739 } else {
2740 is_name_start_char_new(cp)
2741 };
2742 if !ok {
2743 break;
2744 }
2745 if len > remaining {
2746 return ptr::null();
2747 }
2748 ptr = ptr.add(len);
2749 remaining -= len;
2750 f |= XML_SCAN_NMTOKEN;
2751 }
2752
2753 pi.cur = ptr;
2754 ptr
2755 }
2756}
2757
2758unsafe fn decode_utf8_char(ptr: *const u8, avail: usize, len: &mut usize) -> c_int {
2761 unsafe {
2762 let c = *ptr;
2763 if avail < 2 || (*ptr.add(1) & 0xc0) != 0x80 {
2764 return -1;
2765 }
2766 if c < 0xe0 {
2767 if c < 0xc2 {
2768 return -1;
2769 }
2770 *len = 2;
2771 return (((c & 0x1f) as c_int) << 6) | ((*ptr.add(1) & 0x3f) as c_int);
2772 }
2773 if avail < 3 || (*ptr.add(2) & 0xc0) != 0x80 {
2774 return -1;
2775 }
2776 if c < 0xf0 {
2777 let val = (((c & 0x0f) as c_int) << 12)
2778 | (((*ptr.add(1) & 0x3f) as c_int) << 6)
2779 | ((*ptr.add(2) & 0x3f) as c_int);
2780 if val < 0x800 || (val >= 0xd800 && val < 0xe000) {
2781 return -1;
2782 }
2783 *len = 3;
2784 return val;
2785 }
2786 if avail < 4 || (*ptr.add(3) & 0xc0) != 0x80 {
2787 return -1;
2788 }
2789 let val = (((c & 0x07) as c_int) << 18)
2790 | (((*ptr.add(1) & 0x3f) as c_int) << 12)
2791 | (((*ptr.add(2) & 0x3f) as c_int) << 6)
2792 | ((*ptr.add(3) & 0x3f) as c_int);
2793 if val < 0x10000 || val >= 0x110000 {
2794 return -1;
2795 }
2796 *len = 4;
2797 val
2798 }
2799}
2800
2801fn is_name_start_char_old10(c: c_int) -> bool {
2803 (c >= b'a' as c_int && c <= b'z' as c_int)
2804 || (c >= b'A' as c_int && c <= b'Z' as c_int)
2805 || c == b'_' as c_int
2806 || c == b':' as c_int
2807 || (c >= 0xC0 && c <= 0xD6)
2808 || (c >= 0xD8 && c <= 0xF6)
2809 || (c >= 0xF8 && c <= 0x2FF)
2810 || (c >= 0x370 && c <= 0x37D)
2811 || (c >= 0x37F && c <= 0x1FFF)
2812 || (c >= 0x200C && c <= 0x200D)
2813 || (c >= 0x2070 && c <= 0x218F)
2814 || (c >= 0x2C00 && c <= 0x2FEF)
2815 || (c >= 0x3001 && c <= 0xD7FF)
2816 || (c >= 0xF900 && c <= 0xFDCF)
2817 || (c >= 0xFDF0 && c <= 0xFFFD)
2818 || (c >= 0x10000 && c <= 0xEFFFF)
2819}
2820
2821fn is_name_char_old10(c: c_int) -> bool {
2824 is_name_start_char_old10(c)
2825 || (c >= b'0' as c_int && c <= b'9' as c_int)
2826 || c == b'.' as c_int
2827 || c == b'-' as c_int
2828 || c == 0xB7
2829 || (c >= 0x300 && c <= 0x36F)
2830 || c == 0x02D0
2831 || c == 0x02D1
2832 || c == 0x0387
2833 || c == 0x0640
2834 || c == 0x0E46
2835 || c == 0x0EC6
2836 || c == 0x3005
2837 || (c >= 0x3031 && c <= 0x3035)
2838 || (c >= 0x309D && c <= 0x309E)
2839 || (c >= 0x30FC && c <= 0x30FE)
2840}
2841
2842#[no_mangle]
2853pub unsafe extern "C" fn xmlDecodeEntities(
2854 ctxt: *mut _xmlParserCtxt,
2855 len: c_int,
2856 end: xmlChar,
2857 end2: xmlChar,
2858 end3: xmlChar,
2859) -> *mut xmlChar {
2860 if ctxt.is_null() || (*ctxt).input.is_null() {
2861 return ptr::null_mut();
2862 }
2863 unsafe {
2864 let pi = &*((*ctxt).input);
2865 let cur = pi.cur;
2866 if cur.is_null() {
2867 return ptr::null_mut();
2868 }
2869 let avail = (pi.end as usize).saturating_sub(cur as usize);
2870 let n = if len < 0 {
2871 avail
2872 } else {
2873 (len as usize).min(avail)
2874 };
2875
2876 let mut out: Vec<u8> = Vec::new();
2877 let mut i = 0usize;
2878
2879 while i < n {
2880 let c = *cur.add(i);
2881 if c == end || c == end2 || c == end3 {
2882 break;
2883 }
2884 if c != b'&' {
2885 out.push(c);
2886 i += 1;
2887 continue;
2888 }
2889
2890 if i + 1 < n && *cur.add(i + 1) == b'#' {
2892 let (value, consumed) = parse_char_ref(cur.add(i), n - i);
2893 if consumed == 0 {
2894 out.push(b'&');
2895 i += 1;
2896 continue;
2897 }
2898 let mut buf = [0u8; 4];
2899 let blen = copy_char_utf8(&mut buf, value);
2900 out.extend_from_slice(&buf[..blen]);
2901 i += consumed;
2902 continue;
2903 }
2904
2905 let mut j = i + 1;
2907 while j < n
2908 && ((*cur.add(j)).is_ascii_alphanumeric()
2909 || *cur.add(j) == b'_'
2910 || *cur.add(j) == b'-'
2911 || *cur.add(j) == b'.'
2912 || *cur.add(j) == b':')
2913 {
2914 j += 1;
2915 }
2916 if j < n && *cur.add(j) == b';' {
2917 let name = core::slice::from_raw_parts(cur.add(i + 1), j - i - 1);
2918 let mut replaced = false;
2919 let content: Option<&[u8]> = match name {
2921 b"amp" => Some(b"&"),
2922 b"lt" => Some(b"<"),
2923 b"gt" => Some(b">"),
2924 b"quot" => Some(b"\""),
2925 b"apos" => Some(b"'"),
2926 _ => None,
2927 };
2928 if let Some(c) = content {
2929 out.extend_from_slice(c);
2930 replaced = true;
2931 } else {
2932 let mut name_nul = name.to_vec();
2934 name_nul.push(0);
2935 let ent = entities::get_entity((*ctxt).myDoc, name_nul.as_ptr());
2936 if !ent.is_null() && !(*ent).content.is_null() {
2937 let clen = string::xml_strlen((*ent).content);
2938 out.extend_from_slice(core::slice::from_raw_parts((*ent).content, clen));
2939 replaced = true;
2940 }
2941 }
2942 if replaced {
2943 i = j + 1;
2944 continue;
2945 }
2946 }
2947 out.push(b'&');
2948 i += 1;
2949 }
2950
2951 out.push(0);
2952 let result = xmlMallocImpl(out.len()) as *mut xmlChar;
2953 if result.is_null() {
2954 return ptr::null_mut();
2955 }
2956 ptr::copy_nonoverlapping(out.as_ptr(), result, out.len());
2957 result
2958 }
2959}
2960
2961unsafe fn parse_char_ref(ptr: *const u8, avail: usize) -> (c_int, usize) {
2964 unsafe {
2965 if avail < 3 || *ptr != b'&' || *ptr.add(1) != b'#' {
2966 return (0, 0);
2967 }
2968 let mut i = 2usize;
2969 let hex = i < avail && (*ptr.add(i) == b'x' || *ptr.add(i) == b'X');
2970 if hex {
2971 i += 1;
2972 }
2973 let start = i;
2974 let mut value: u32 = 0;
2975 while i < avail && *ptr.add(i) != b';' {
2976 let d = (*ptr.add(i) as char).to_digit(if hex { 16 } else { 10 });
2977 match d {
2978 Some(d) => {
2979 value = value
2980 .saturating_mul(if hex { 16 } else { 10 })
2981 .saturating_add(d);
2982 i += 1;
2983 }
2984 None => return (0, 0),
2985 }
2986 }
2987 if i == start || i >= avail || *ptr.add(i) != b';' {
2988 return (0, 0);
2989 }
2990 (value as c_int, i + 1)
2991 }
2992}
2993
2994fn copy_char_utf8(out: &mut [u8; 4], val: c_int) -> usize {
2996 if val < 0x80 {
2997 out[0] = val as u8;
2998 1
2999 } else if val < 0x800 {
3000 out[0] = 0xC0 | ((val >> 6) as u8);
3001 out[1] = 0x80 | ((val & 0x3F) as u8);
3002 2
3003 } else if val < 0x10000 {
3004 out[0] = 0xE0 | ((val >> 12) as u8);
3005 out[1] = 0x80 | (((val >> 6) & 0x3F) as u8);
3006 out[2] = 0x80 | ((val & 0x3F) as u8);
3007 3
3008 } else if val < 0x110000 {
3009 out[0] = 0xF0 | ((val >> 18) as u8);
3010 out[1] = 0x80 | (((val >> 12) & 0x3F) as u8);
3011 out[2] = 0x80 | (((val >> 6) & 0x3F) as u8);
3012 out[3] = 0x80 | ((val & 0x3F) as u8);
3013 4
3014 } else {
3015 out[0] = 0;
3016 1
3017 }
3018}
3019
3020#[no_mangle]
3028pub unsafe extern "C" fn xmlDetectCharEncoding(in_: *const c_uchar, len: c_int) -> c_int {
3029 if in_.is_null() {
3030 return xmlCharEncoding::XML_CHAR_ENCODING_NONE as c_int;
3031 }
3032 unsafe {
3033 if len >= 4 {
3034 if *in_ == 0x00 && *in_.add(1) == 0x00 && *in_.add(2) == 0x00 && *in_.add(3) == 0x3C {
3035 return xmlCharEncoding::XML_CHAR_ENCODING_UCS4BE as c_int;
3036 }
3037 if *in_ == 0x3C && *in_.add(1) == 0x00 && *in_.add(2) == 0x00 && *in_.add(3) == 0x00 {
3038 return xmlCharEncoding::XML_CHAR_ENCODING_UCS4LE as c_int;
3039 }
3040 if *in_ == 0x4C && *in_.add(1) == 0x6F && *in_.add(2) == 0xA7 && *in_.add(3) == 0x94 {
3041 return xmlCharEncoding::XML_CHAR_ENCODING_EBCDIC as c_int;
3042 }
3043 if *in_ == 0x3C && *in_.add(1) == 0x3F && *in_.add(2) == 0x78 && *in_.add(3) == 0x6D {
3044 return xmlCharEncoding::XML_CHAR_ENCODING_UTF8 as c_int;
3045 }
3046 if *in_ == 0x3C && *in_.add(1) == 0x00 && *in_.add(2) == 0x3F && *in_.add(3) == 0x00 {
3047 return xmlCharEncoding::XML_CHAR_ENCODING_UTF16LE as c_int;
3048 }
3049 if *in_ == 0x00 && *in_.add(1) == 0x3C && *in_.add(2) == 0x00 && *in_.add(3) == 0x3F {
3050 return xmlCharEncoding::XML_CHAR_ENCODING_UTF16BE as c_int;
3051 }
3052 }
3053 if len >= 3 && *in_ == 0xEF && *in_.add(1) == 0xBB && *in_.add(2) == 0xBF {
3054 return xmlCharEncoding::XML_CHAR_ENCODING_UTF8 as c_int;
3055 }
3056 if len >= 2 {
3057 if *in_ == 0xFE && *in_.add(1) == 0xFF {
3058 return xmlCharEncoding::XML_CHAR_ENCODING_UTF16BE as c_int;
3059 }
3060 if *in_ == 0xFF && *in_.add(1) == 0xFE {
3061 return xmlCharEncoding::XML_CHAR_ENCODING_UTF16LE as c_int;
3062 }
3063 }
3064 }
3065 xmlCharEncoding::XML_CHAR_ENCODING_NONE as c_int
3066}
3067
3068#[no_mangle]
3078pub unsafe extern "C" fn xmlCharEncFirstLine(
3079 handler: *mut _xmlCharEncodingHandler,
3080 out: *mut _xmlBuffer,
3081 in_: *mut _xmlBuffer,
3082) -> c_int {
3083 encoding::xmlCharEncInFunc(handler, out, in_)
3084}
3085
3086#[no_mangle]
3094pub unsafe extern "C" fn xmlIsMainThread() -> c_int {
3095 1
3096}
3097
3098#[no_mangle]
3111pub unsafe extern "C" fn xmlParserPrintFileInfo(input: *mut _xmlParserInput) {
3112 if input.is_null() {
3113 return;
3114 }
3115 unsafe {
3116 let channel: Option<xmlGenericErrorFunc> = globals::get_generic_error_func();
3117 let data = globals::get_generic_error_ctx();
3118 let Some(ch) = channel else { return };
3119 let msg;
3120 if !(*input).filename.is_null() {
3121 let file = CStr::from_ptr((*input).filename);
3122 let s = format!("{}:{}: ", file.to_string_lossy(), (*input).line);
3123 msg = std::ffi::CString::new(s).unwrap_or_default();
3124 } else {
3125 let s = format!("Entity: line {}: ", (*input).line);
3126 msg = std::ffi::CString::new(s).unwrap_or_default();
3127 }
3128 ch(data, msg.as_ptr());
3129 }
3130}
3131
3132#[no_mangle]
3141pub unsafe extern "C" fn xmlParserPrintFileContext(input: *mut _xmlParserInput) {
3142 if input.is_null() || (*input).cur.is_null() {
3143 return;
3144 }
3145 unsafe {
3146 let channel: Option<xmlGenericErrorFunc> = globals::get_generic_error_func();
3147 let data = globals::get_generic_error_ctx();
3148 let Some(ch) = channel else { return };
3149
3150 let pi = &*input;
3151 let cur = pi.cur;
3152 let base = pi.base;
3153 let end = pi.end;
3154
3155 let before = if base.is_null() {
3157 0
3158 } else {
3159 (cur as usize).saturating_sub(base as usize)
3160 };
3161 let take = before.min(LINE_LEN);
3162 let start = cur.sub(take);
3163 let n = (end as usize).saturating_sub(start as usize).min(LINE_LEN);
3164
3165 let mut content = vec![0u8; n];
3166 if n > 0 {
3167 ptr::copy_nonoverlapping(start, content.as_mut_ptr(), n);
3168 }
3169 let line = std::ffi::CString::new(content.clone()).unwrap_or_default();
3170 ch(data, line.as_ptr());
3171
3172 let mut caret = vec![b' '; take];
3174 if take + 1 <= LINE_LEN + 1 {
3175 caret.push(b'^');
3176 }
3177 let caret_c = std::ffi::CString::new(caret).unwrap_or_default();
3178 ch(data, caret_c.as_ptr());
3179 }
3180}
3181
3182#[no_mangle]
3195pub unsafe extern "C" fn xmlHandleEntity(ctxt: *mut _xmlParserCtxt, entity: *mut c_void) {
3196 if ctxt.is_null() {
3197 return;
3198 }
3199 unsafe {
3200 let ent = entity as *mut _xmlEntity;
3201 if ent.is_null() {
3202 return;
3203 }
3204 if (*ent).etype == xmlEntityType::XML_EXTERNAL_GENERAL_UNPARSED_ENTITY as c_int {
3206 return;
3207 }
3208
3209 let mut input = ptr::null_mut();
3210 if !(*ent).content.is_null() {
3211 let content = (*ent).content;
3213 let pi = xmlNewInputStream(ctxt);
3214 if pi.is_null() {
3215 return;
3216 }
3217 let len = string::xml_strlen(content);
3218 (*pi).base = content;
3219 (*pi).cur = content;
3220 (*pi).end = content.add(len);
3221 (*pi).length = len as c_int;
3222 (*pi).entity = ent;
3223 input = pi;
3224 } else if !(*ent).URI.is_null() {
3225 input = xmlLoadExternalEntity(
3227 (*ent).URI as *const c_char,
3228 (*ent).ExternalID as *const c_char,
3229 ctxt,
3230 );
3231 if !input.is_null() {
3232 (*input).entity = ent;
3233 }
3234 }
3235
3236 if input.is_null() {
3237 return;
3238 }
3239 xmlPushInput(ctxt, input);
3240 }
3241}
3242
3243#[no_mangle]
3253pub unsafe extern "C" fn xmlSAXParseDTD(
3254 sax: *mut _xmlSAXHandler,
3255 publicId: *const xmlChar,
3256 systemId: *const xmlChar,
3257) -> *mut _xmlDtd {
3258 if publicId.is_null() && systemId.is_null() {
3259 return ptr::null_mut();
3260 }
3261 unsafe {
3262 let ctxt = xmlNewSAXParserCtxt(sax, ptr::null_mut());
3263 if ctxt.is_null() {
3264 return ptr::null_mut();
3265 }
3266 apply_options(ctxt, XML_PARSE_DTDLOAD);
3267
3268 let mut input = ptr::null_mut();
3271 if !sax.is_null() {
3272 if let Some(resolve) = (*sax).resolveEntity {
3273 input = resolve((*ctxt).userData, publicId, systemId);
3274 }
3275 }
3276 if input.is_null() {
3277 if systemId.is_null() {
3278 helpers::free_parser_ctxt(ctxt);
3279 return ptr::null_mut();
3280 }
3281 input = xmlLoadExternalEntity(systemId as *const c_char, ptr::null(), ctxt);
3282 }
3283 if input.is_null() {
3284 helpers::free_parser_ctxt(ctxt);
3285 return ptr::null_mut();
3286 }
3287
3288 let data: Vec<u8> = {
3290 let pi = &*input;
3291 if !pi.base.is_null() && !pi.end.is_null() && pi.end >= pi.base {
3292 let len = (pi.end as usize).saturating_sub(pi.base as usize);
3293 core::slice::from_raw_parts(pi.base, len).to_vec()
3294 } else if !pi.buf.is_null() {
3295 input_buffer_data(pi.buf)
3296 } else {
3297 Vec::new()
3298 }
3299 };
3300 helpers::free_parser_input(input);
3301
3302 let dtd = parse_dtd_text(ctxt, &data, publicId, systemId);
3303 helpers::free_parser_ctxt(ctxt);
3304 dtd
3305 }
3306}
3307
3308#[no_mangle]
3317pub unsafe extern "C" fn xmlIOParseDTD(
3318 sax: *mut _xmlSAXHandler,
3319 input: *mut _xmlParserInputBuffer,
3320 enc: c_int,
3321) -> *mut _xmlDtd {
3322 if input.is_null() {
3323 return ptr::null_mut();
3324 }
3325 unsafe {
3326 let ctxt = xmlNewSAXParserCtxt(sax, ptr::null_mut());
3327 if ctxt.is_null() {
3328 io::input_buffer_free(input);
3329 return ptr::null_mut();
3330 }
3331 apply_options(ctxt, XML_PARSE_DTDLOAD);
3332 if enc != xmlCharEncoding::XML_CHAR_ENCODING_NONE as c_int {
3333 (*ctxt).charset = enc;
3334 }
3335
3336 let data: Vec<u8> = input_buffer_data(input);
3338 io::input_buffer_free(input);
3339
3340 let dtd = parse_dtd_text(ctxt, &data, ptr::null(), ptr::null());
3341 helpers::free_parser_ctxt(ctxt);
3342 dtd
3343 }
3344}
3345
3346unsafe fn input_buffer_data(buf: *mut _xmlParserInputBuffer) -> Vec<u8> {
3348 unsafe {
3349 if buf.is_null() {
3350 return Vec::new();
3351 }
3352 let b = &*buf;
3353 if let Some(read) = b.readcallback {
3354 let mut out = Vec::new();
3355 let mut tmp = [0u8; 4096];
3356 loop {
3357 let n = read(
3358 b.context,
3359 tmp.as_mut_ptr() as *mut c_char,
3360 tmp.len() as c_int,
3361 );
3362 if n <= 0 {
3363 break;
3364 }
3365 out.extend_from_slice(&tmp[..n as usize]);
3366 }
3367 return out;
3368 }
3369 if !b.buffer.is_null() {
3370 let xbuf = &*(b.buffer as *mut _xmlBuffer);
3371 if !xbuf.content.is_null() && xbuf.use_ > 0 {
3372 return core::slice::from_raw_parts(xbuf.content, xbuf.use_ as usize).to_vec();
3373 }
3374 }
3375 Vec::new()
3376 }
3377}
3378
3379#[no_mangle]
3387pub unsafe extern "C" fn xmlSAXParseEntity(
3388 sax: *mut _xmlSAXHandler,
3389 filename: *const c_char,
3390) -> *mut _xmlDoc {
3391 if filename.is_null() {
3392 return ptr::null_mut();
3393 }
3394 unsafe {
3395 let ctxt = xmlNewSAXParserCtxt(sax, ptr::null_mut());
3396 if ctxt.is_null() {
3397 return ptr::null_mut();
3398 }
3399 let input = match helpers::input_from_file(filename) {
3400 Ok(i) => i,
3401 Err(_) => {
3402 helpers::free_parser_ctxt(ctxt);
3403 return ptr::null_mut();
3404 }
3405 };
3406 helpers::setup_parser_input(ctxt, input);
3407 let rc = helpers::parse_document(ctxt);
3408 let doc = (*ctxt).myDoc;
3409 (*ctxt).myDoc = ptr::null_mut();
3410 if rc != 0 || (*ctxt).wellFormed == 0 {
3411 if !doc.is_null() {
3412 tree::free_doc(doc);
3413 }
3414 helpers::free_parser_ctxt(ctxt);
3415 return ptr::null_mut();
3416 }
3417 helpers::free_parser_ctxt(ctxt);
3418 doc
3419 }
3420}
3421
3422#[no_mangle]
3436pub unsafe extern "C" fn xmlC14NDocSave(
3437 doc: *mut _xmlDoc,
3438 nodes: *mut _xmlNodeSet,
3439 mode: c_int,
3440 inclusive_ns_prefixes: *mut *mut xmlChar,
3441 with_comments: c_int,
3442 filename: *const c_char,
3443 compression: c_int,
3444) -> c_int {
3445 if filename.is_null() {
3446 return -1;
3447 }
3448 unsafe {
3449 let output = io::output_buffer_create_filename(filename, ptr::null_mut(), compression);
3450 if output.is_null() {
3451 return -1;
3452 }
3453 let ret = crate::xml::c14n::xmlC14NDocSaveTo(
3454 doc,
3455 nodes,
3456 mode,
3457 inclusive_ns_prefixes,
3458 with_comments,
3459 output,
3460 );
3461 if ret < 0 {
3462 io::output_buffer_close(output);
3463 return -1;
3464 }
3465 let close_ret = io::output_buffer_close(output);
3466 if close_ret < 0 {
3467 -1
3468 } else {
3469 ret
3470 }
3471 }
3472}