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
263unsafe fn input_buffer_from_parser_input(input: *mut _xmlParserInput) -> InputBuffer {
270 unsafe {
271 let pi = &*input;
272 if !pi.buf.is_null() {
273 let b = &*pi.buf;
274 if let Some(read) = b.readcallback {
275 return helpers::input_from_io(Some(read), b.closecallback, b.context);
276 }
277 }
278 if !pi.base.is_null() && !pi.end.is_null() && pi.end >= pi.base {
279 let len = (pi.end as usize).saturating_sub(pi.base as usize);
280 let slice = core::slice::from_raw_parts(pi.base, len);
281 return InputBuffer::from_memory(slice, None);
282 }
283 InputBuffer::from_memory(&[], None)
284 }
285}
286
287unsafe fn ctxt_read_doc(
294 ctxt: *mut _xmlParserCtxt,
295 input: InputBuffer,
296 url: *const c_char,
297 options: c_int,
298) -> *mut _xmlDoc {
299 unsafe {
300 xmlCtxtReset(ctxt);
301 apply_options(ctxt, options);
302 helpers::setup_parser_input(ctxt, input);
303 if helpers::parse_document(ctxt) != 0 {
304 let doc = (*ctxt).myDoc;
305 (*ctxt).myDoc = ptr::null_mut();
306 if options & XML_PARSE_RECOVER != 0 {
307 return doc;
308 }
309 if !doc.is_null() {
310 tree::free_doc(doc);
311 }
312 return ptr::null_mut();
313 }
314 let doc = (*ctxt).myDoc;
315 if !doc.is_null() && !url.is_null() {
316 (*doc).URL = string::xml_strdup(url as *const xmlChar);
317 }
318 doc
319 }
320}
321
322unsafe fn parse_dtd_text(
333 ctxt: *mut _xmlParserCtxt,
334 data: &[u8],
335 public_id: *const xmlChar,
336 system_id: *const xmlChar,
337) -> *mut _xmlDtd {
338 unsafe {
339 let has_doctype = data
342 .windows(9)
343 .any(|w| w.eq_ignore_ascii_case(b"<!DOCTYPE"));
344 let mut wrapped: Vec<u8>;
345 let parse_data: &[u8] = if has_doctype {
346 data
347 } else {
348 wrapped = Vec::with_capacity(data.len() + 32);
349 wrapped.extend_from_slice(b"<!DOCTYPE none [");
350 wrapped.extend_from_slice(data);
351 wrapped.extend_from_slice(b"]><none/>");
352 &wrapped
353 };
354
355 let input = InputBuffer::from_memory(parse_data, None);
356 helpers::setup_parser_input(ctxt, input);
357 let rc = helpers::parse_document(ctxt);
358 let doc = (*ctxt).myDoc;
359 (*ctxt).myDoc = ptr::null_mut();
360
361 if rc == 0 && !doc.is_null() && !(*doc).intSubset.is_null() {
362 let dtd = (*doc).intSubset;
363 (*doc).intSubset = ptr::null_mut();
364 (*dtd).parent = ptr::null_mut();
365 (*dtd).doc = ptr::null_mut();
366 if !public_id.is_null() {
367 (*dtd).ExternalID = string::xml_strdup(public_id);
368 }
369 if !system_id.is_null() {
370 (*dtd).SystemID = string::xml_strdup(system_id);
371 }
372 tree::free_doc(doc);
373 return dtd;
374 }
375
376 if !doc.is_null() {
377 tree::free_doc(doc);
378 }
379 let dtd = dtd::new_dtd(ptr::null_mut(), b"none\0".as_ptr(), public_id, system_id);
381 dtd
382 }
383}
384
385#[no_mangle]
397pub unsafe extern "C" fn xmlNewParserCtxt() -> *mut _xmlParserCtxt {
398 unsafe {
399 globals::init_parser();
400 let ctxt = xmlMallocZero(core::mem::size_of::<_xmlParserCtxt>()) as *mut _xmlParserCtxt;
401 if ctxt.is_null() {
402 return ptr::null_mut();
403 }
404 if init_sax_parser_ctxt(ctxt, ptr::null(), ptr::null_mut()) < 0 {
405 helpers::free_parser_ctxt(ctxt);
406 return ptr::null_mut();
407 }
408 ctxt
409 }
410}
411
412#[no_mangle]
421pub unsafe extern "C" fn xmlNewSAXParserCtxt(
422 sax: *const _xmlSAXHandler,
423 userData: *mut c_void,
424) -> *mut _xmlParserCtxt {
425 unsafe {
426 globals::init_parser();
427 let ctxt = xmlMallocZero(core::mem::size_of::<_xmlParserCtxt>()) as *mut _xmlParserCtxt;
428 if ctxt.is_null() {
429 return ptr::null_mut();
430 }
431 if init_sax_parser_ctxt(ctxt, sax, userData) < 0 {
432 helpers::free_parser_ctxt(ctxt);
433 return ptr::null_mut();
434 }
435 ctxt
436 }
437}
438
439#[no_mangle]
448pub unsafe extern "C" fn xmlInitParserCtxt(ctxt: *mut _xmlParserCtxt) -> c_int {
449 unsafe { init_sax_parser_ctxt(ctxt, ptr::null(), ptr::null_mut()) }
450}
451
452#[no_mangle]
460pub unsafe extern "C" fn xmlClearParserCtxt(ctxt: *mut _xmlParserCtxt) {
461 unsafe { xmlCtxtReset(ctxt) }
462}
463
464#[no_mangle]
473pub unsafe extern "C" fn xmlCtxtReset(ctxt: *mut _xmlParserCtxt) {
474 if ctxt.is_null() {
475 return;
476 }
477 unsafe {
478 let c = &mut *ctxt;
479
480 let input_nr = c.inputNr;
482 let input_tab = c.inputTab;
483 if !input_tab.is_null() {
484 for i in 0..input_nr {
485 let input = *input_tab.add(i as usize);
486 if !input.is_null() {
487 helpers::free_parser_input(input);
488 }
489 }
490 xmlFreeImpl(input_tab as *mut c_void);
491 }
492 c.inputTab = ptr::null_mut();
493 c.inputMax = 0;
494 c.inputNr = 0;
495 c.input = ptr::null_mut();
496
497 if !c._private.is_null() {
499 let _ = Box::from_raw(c._private as *mut InputBuffer);
500 c._private = ptr::null_mut();
501 }
502
503 if !c.nodeTab.is_null() {
505 xmlFreeImpl(c.nodeTab as *mut c_void);
506 }
507 c.nodeTab = ptr::null_mut();
508 c.nodeMax = 0;
509 c.nodeNr = 0;
510 c.node = ptr::null_mut();
511
512 if !c.nameTab.is_null() {
514 xmlFreeImpl(c.nameTab as *mut c_void);
515 }
516 c.nameTab = ptr::null_mut();
517 c.nameMax = 0;
518 c.nameNr = 0;
519 c.name = ptr::null();
520
521 c.spaceNr = 0;
523 c.space = ptr::null_mut();
524
525 c.nsNr = 0;
527
528 if !c.version.is_null() {
530 xmlFreeImpl(c.version as *mut c_void);
531 c.version = ptr::null_mut();
532 }
533 if !c.encoding.is_null() {
534 xmlFreeImpl(c.encoding as *mut c_void);
535 c.encoding = ptr::null_mut();
536 }
537 if !c.extSubURI.is_null() {
538 xmlFreeImpl(c.extSubURI as *mut c_void);
539 c.extSubURI = ptr::null_mut();
540 }
541 if !c.extSubSystem.is_null() {
542 xmlFreeImpl(c.extSubSystem as *mut c_void);
543 c.extSubSystem = ptr::null_mut();
544 }
545 if !c.directory.is_null() {
546 xmlFreeImpl(c.directory as *mut c_void);
547 c.directory = ptr::null_mut();
548 }
549
550 if !c.myDoc.is_null() {
552 tree::free_doc(c.myDoc);
553 }
554 c.myDoc = ptr::null_mut();
555
556 c.standalone = -1;
558 c.hasExternalSubset = 0;
559 c.hasPErefs = 0;
560 c.instate = xmlParserInputState::XML_PARSER_START as c_int;
561 c.wellFormed = 1;
562 c.nsWellFormed = 1;
563 c.disableSAX = 0;
564 c.valid = 1;
565 c.record_info = 0;
566 c.checkIndex = 0;
567 c.inSubset = 0;
568 c.errNo = XML_ERR_OK;
569 c.depth = 0;
570 c.nbentities = 0;
571 c.sizeentities = 0;
572 c.nbErrors = 0;
573 c.nbWarnings = 0;
574
575 xmlInitNodeInfoSeq(&mut c.node_seq);
576
577 if c.lastError.code != XML_ERR_OK {
578 errors::reset_error(&mut c.lastError);
579 }
580 }
581}
582
583#[no_mangle]
592pub unsafe extern "C" fn xmlCtxtResetPush(
593 ctxt: *mut _xmlParserCtxt,
594 chunk: *const c_char,
595 size: c_int,
596 filename: *const c_char,
597 encoding: *const c_char,
598) -> c_int {
599 if ctxt.is_null() {
600 return 1;
601 }
602 unsafe {
603 xmlCtxtReset(ctxt);
604
605 let slice = if size > 0 && !chunk.is_null() {
606 core::slice::from_raw_parts(chunk as *const u8, size as usize)
607 } else {
608 &[]
609 };
610 let uri = if filename.is_null() {
611 None
612 } else {
613 CStr::from_ptr(filename).to_str().ok()
614 };
615 let input = InputBuffer::from_memory(slice, uri);
616 helpers::setup_parser_input(ctxt, input);
617
618 if !encoding.is_null() {
619 let handler = encoding::find_encoding_handler(encoding as *const xmlChar);
620 if !handler.is_null() {
621 xmlSwitchToEncoding(ctxt, handler);
622 }
623 }
624 }
625 0
626}
627
628#[no_mangle]
636pub unsafe extern "C" fn xmlCtxtSetOptions(ctxt: *mut _xmlParserCtxt, options: c_int) -> c_int {
637 if ctxt.is_null() {
638 return -1;
639 }
640 const ALL_MASK: c_int = XML_PARSE_RECOVER
641 | XML_PARSE_NOENT
642 | XML_PARSE_DTDLOAD
643 | XML_PARSE_DTDATTR
644 | XML_PARSE_DTDVALID
645 | XML_PARSE_NOERROR
646 | XML_PARSE_NOWARNING
647 | XML_PARSE_PEDANTIC
648 | XML_PARSE_NOBLANKS
649 | XML_PARSE_SAX1
650 | XML_PARSE_NONET
651 | XML_PARSE_NODICT
652 | XML_PARSE_NSCLEAN
653 | XML_PARSE_NOCDATA
654 | XML_PARSE_COMPACT
655 | XML_PARSE_OLD10
656 | XML_PARSE_HUGE
657 | XML_PARSE_OLDSAX
658 | XML_PARSE_IGNORE_ENC
659 | XML_PARSE_BIG_LINES;
660
661 unsafe {
662 apply_options(ctxt, options & ALL_MASK);
663 }
664 options & !ALL_MASK
665}
666
667#[no_mangle]
676pub unsafe extern "C" fn xmlCtxtSetErrorHandler(
677 ctxt: *mut _xmlParserCtxt,
678 handler: Option<xmlStructuredErrorFunc>,
679 data: *mut c_void,
680) {
681 if ctxt.is_null() {
682 return;
683 }
684 unsafe {
685 (*ctxt).errorHandler = handler;
686 (*ctxt).errorCtxt = data;
687 }
688}
689
690#[no_mangle]
698pub unsafe extern "C" fn xmlCtxtSetMaxAmplification(ctxt: *mut _xmlParserCtxt, maxAmpl: c_uint) {
699 if ctxt.is_null() || maxAmpl == 0 {
700 return;
701 }
702 unsafe {
703 (*ctxt).maxAmpl = maxAmpl;
704 }
705}
706
707#[no_mangle]
715pub unsafe extern "C" fn xmlCtxtGetLastError(ctx: *mut c_void) -> *const _xmlError {
716 if ctx.is_null() {
717 return ptr::null();
718 }
719 let ctxt = ctx as *mut _xmlParserCtxt;
720 unsafe {
721 if (*ctxt).lastError.code == XML_ERR_OK {
722 return ptr::null();
723 }
724 &(*ctxt).lastError
725 }
726}
727
728#[no_mangle]
736pub unsafe extern "C" fn xmlCtxtResetLastError(ctx: *mut c_void) {
737 if ctx.is_null() {
738 return;
739 }
740 let ctxt = ctx as *mut _xmlParserCtxt;
741 unsafe {
742 (*ctxt).errNo = XML_ERR_OK;
743 if (*ctxt).lastError.code != XML_ERR_OK {
744 errors::reset_error(&mut (*ctxt).lastError);
745 }
746 }
747}
748
749#[no_mangle]
757pub unsafe extern "C" fn xmlCtxtErrMemory(ctxt: *mut _xmlParserCtxt) {
758 if ctxt.is_null() {
759 return;
760 }
761 unsafe {
762 let c = &mut *ctxt;
763 c.errNo = XML_ERR_NO_MEMORY;
764 c.instate = xmlParserInputState::XML_PARSER_EOF as c_int;
765 c.wellFormed = 0;
766 c.disableSAX = 2;
767
768 c.lastError.domain = XML_FROM_PARSER;
769 c.lastError.code = XML_ERR_NO_MEMORY;
770 c.lastError.level = xmlErrorLevel::XML_ERR_FATAL as c_int;
771 c.lastError.message = b"out of memory\n\0".as_ptr() as *mut c_char;
772
773 if let Some(handler) = c.errorHandler {
774 handler(c.errorCtxt, &c.lastError);
775 } else if !c.sax.is_null() {
776 if let Some(serror) = (*c.sax).serror {
777 serror(c.userData, &c.lastError);
778 }
779 }
780 }
781}
782
783#[no_mangle]
791pub unsafe extern "C" fn xmlStopParser(ctxt: *mut _xmlParserCtxt) {
792 if ctxt.is_null() {
793 return;
794 }
795 unsafe {
796 (*ctxt).disableSAX = 2;
797 if (*ctxt).errNo == XML_ERR_OK {
798 (*ctxt).errNo = XML_ERR_USER_STOP;
799 (*ctxt).lastError.code = XML_ERR_USER_STOP;
800 (*ctxt).wellFormed = 0;
801 }
802 }
803}
804
805#[no_mangle]
814pub unsafe extern "C" fn xmlByteConsumed(ctxt: *mut _xmlParserCtxt) -> c_long {
815 if ctxt.is_null() {
816 return -1;
817 }
818 unsafe {
819 let input = (*ctxt).input;
820 if input.is_null() {
821 return -1;
822 }
823 if !(*input).buf.is_null() && !(*(*input).buf).encoder.is_null() {
824 return (*(*input).buf).rawconsumed as c_long;
827 }
828 let consumed = (*input).consumed;
829 if (*input).base.is_null() {
830 return consumed as c_long;
831 }
832 (consumed + ((*input).cur as usize).saturating_sub((*input).base as usize) as c_ulong)
833 as c_long
834 }
835}
836
837#[no_mangle]
845pub unsafe extern "C" fn xmlParserGetDirectory(filename: *const c_char) -> *mut c_char {
846 if filename.is_null() {
847 return ptr::null_mut();
848 }
849 unsafe {
850 let len = libc::strlen(filename);
851 let mut last_sep: Option<usize> = None;
852 for i in 0..len {
853 if *filename.add(i) == b'/' as c_char {
854 last_sep = Some(i);
855 }
856 }
857 match last_sep {
858 Some(0) => xmlMemStrdupImpl(b"/\0".as_ptr() as *const c_char) as *mut c_char,
859 Some(pos) => {
860 let slice = core::slice::from_raw_parts(filename as *const u8, pos);
861 let mut v = slice.to_vec();
862 v.push(0);
863 xmlMemStrdupImpl(v.as_ptr() as *const c_char) as *mut c_char
864 }
865 None => xmlMemStrdupImpl(b".\0".as_ptr() as *const c_char) as *mut c_char,
866 }
867 }
868}
869
870#[no_mangle]
879pub unsafe extern "C" fn xmlCheckFilename(path: *const c_char) -> c_int {
880 if path.is_null() {
881 return 0;
882 }
883 unsafe {
884 let mut st: libc::stat = core::mem::zeroed();
885 if libc::stat(path, &mut st) != 0 {
886 return 0;
887 }
888 if st.st_mode & libc::S_IFMT == libc::S_IFDIR {
889 2
890 } else {
891 1
892 }
893 }
894}
895
896#[no_mangle]
904pub unsafe extern "C" fn xmlIsXHTML(systemID: *const xmlChar, publicID: *const xmlChar) -> c_int {
905 const XHTML_STRICT_PUBLIC_ID: &[u8] = b"-//W3C//DTD XHTML 1.0 Strict//EN\0";
906 const XHTML_STRICT_SYSTEM_ID: &[u8] = b"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\0";
907 const XHTML_FRAME_PUBLIC_ID: &[u8] = b"-//W3C//DTD XHTML 1.0 Frameset//EN\0";
908 const XHTML_FRAME_SYSTEM_ID: &[u8] = b"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd\0";
909 const XHTML_TRANS_PUBLIC_ID: &[u8] = b"-//W3C//DTD XHTML 1.0 Transitional//EN\0";
910 const XHTML_TRANS_SYSTEM_ID: &[u8] =
911 b"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\0";
912
913 if systemID.is_null() && publicID.is_null() {
914 return -1;
915 }
916 unsafe {
917 if !publicID.is_null() {
918 if string::xml_strcmp(publicID, XHTML_STRICT_PUBLIC_ID.as_ptr() as *const xmlChar) == 0
919 || string::xml_strcmp(publicID, XHTML_FRAME_PUBLIC_ID.as_ptr() as *const xmlChar)
920 == 0
921 || string::xml_strcmp(publicID, XHTML_TRANS_PUBLIC_ID.as_ptr() as *const xmlChar)
922 == 0
923 {
924 return 1;
925 }
926 }
927 if !systemID.is_null() {
928 if string::xml_strcmp(systemID, XHTML_STRICT_SYSTEM_ID.as_ptr() as *const xmlChar) == 0
929 || string::xml_strcmp(systemID, XHTML_FRAME_SYSTEM_ID.as_ptr() as *const xmlChar)
930 == 0
931 || string::xml_strcmp(systemID, XHTML_TRANS_SYSTEM_ID.as_ptr() as *const xmlChar)
932 == 0
933 {
934 return 1;
935 }
936 }
937 }
938 0
939}
940
941#[no_mangle]
953pub unsafe extern "C" fn xmlCreateMemoryParserCtxt(
954 buffer: *const c_char,
955 size: c_int,
956) -> *mut _xmlParserCtxt {
957 if buffer.is_null() || size < 0 {
958 return ptr::null_mut();
959 }
960 unsafe {
961 let ctxt = xmlNewParserCtxt();
962 if ctxt.is_null() {
963 return ptr::null_mut();
964 }
965 let input = helpers::input_from_memory(buffer, size);
966 helpers::setup_parser_input(ctxt, input);
967 ctxt
968 }
969}
970
971#[no_mangle]
981pub unsafe extern "C" fn xmlCreatePushParserCtxt(
982 sax: *mut _xmlSAXHandler,
983 user_data: *mut c_void,
984 chunk: *const c_char,
985 size: c_int,
986 filename: *const c_char,
987) -> *mut _xmlParserCtxt {
988 unsafe {
989 let ctxt = xmlNewSAXParserCtxt(sax, user_data);
990 if ctxt.is_null() {
991 return ptr::null_mut();
992 }
993 let slice = if size > 0 && !chunk.is_null() {
994 core::slice::from_raw_parts(chunk as *const u8, size as usize)
995 } else {
996 &[]
997 };
998 let uri = if filename.is_null() {
999 None
1000 } else {
1001 CStr::from_ptr(filename).to_str().ok()
1002 };
1003 let input = InputBuffer::from_memory(slice, uri);
1004 helpers::setup_parser_input(ctxt, input);
1005 ctxt
1006 }
1007}
1008
1009#[no_mangle]
1020pub unsafe extern "C" fn xmlCreateIOParserCtxt(
1021 sax: *mut _xmlSAXHandler,
1022 user_data: *mut c_void,
1023 ioread: Option<xmlInputReadCallback>,
1024 ioclose: Option<xmlInputCloseCallback>,
1025 ioctx: *mut c_void,
1026 enc: c_int,
1027) -> *mut _xmlParserCtxt {
1028 unsafe {
1029 let ctxt = xmlNewSAXParserCtxt(sax, user_data);
1030 if ctxt.is_null() {
1031 return ptr::null_mut();
1032 }
1033 let input = helpers::input_from_io(ioread, ioclose, ioctx);
1034 helpers::setup_parser_input(ctxt, input);
1035 if enc != xmlCharEncoding::XML_CHAR_ENCODING_NONE as c_int {
1036 xmlSwitchEncoding(ctxt, enc);
1037 }
1038 ctxt
1039 }
1040}
1041
1042#[no_mangle]
1050pub unsafe extern "C" fn xmlCreateURLParserCtxt(
1051 filename: *const c_char,
1052 options: c_int,
1053) -> *mut _xmlParserCtxt {
1054 if filename.is_null() {
1055 return ptr::null_mut();
1056 }
1057 unsafe {
1058 let ctxt = xmlNewParserCtxt();
1059 if ctxt.is_null() {
1060 return ptr::null_mut();
1061 }
1062 apply_options(ctxt, options);
1063 let input = match helpers::input_from_file(filename) {
1064 Ok(i) => i,
1065 Err(_) => {
1066 helpers::free_parser_ctxt(ctxt);
1067 return ptr::null_mut();
1068 }
1069 };
1070 helpers::setup_parser_input(ctxt, input);
1071 ctxt
1072 }
1073}
1074
1075#[no_mangle]
1085pub unsafe extern "C" fn xmlCreateEntityParserCtxt(
1086 URL: *const xmlChar,
1087 ID: *const xmlChar,
1088 base: *const xmlChar,
1089) -> *mut _xmlParserCtxt {
1090 let _ = base; unsafe {
1092 let ctxt = xmlNewParserCtxt();
1093 if ctxt.is_null() {
1094 return ptr::null_mut();
1095 }
1096 let input = xmlLoadExternalEntity(URL as *const c_char, ID as *const c_char, ctxt);
1097 if input.is_null() {
1098 helpers::free_parser_ctxt(ctxt);
1099 return ptr::null_mut();
1100 }
1101 if xmlPushInput(ctxt, input) < 0 {
1102 helpers::free_parser_input(input);
1103 helpers::free_parser_ctxt(ctxt);
1104 return ptr::null_mut();
1105 }
1106 ctxt
1107 }
1108}
1109
1110#[no_mangle]
1123pub unsafe extern "C" fn xmlCtxtReadDoc(
1124 ctxt: *mut _xmlParserCtxt,
1125 cur: *const xmlChar,
1126 URL: *const c_char,
1127 _encoding: *const c_char,
1128 options: c_int,
1129) -> *mut _xmlDoc {
1130 if ctxt.is_null() || cur.is_null() {
1131 return ptr::null_mut();
1132 }
1133 unsafe {
1134 let len = string::xml_strlen(cur);
1135 let input = helpers::input_from_memory(cur as *const c_char, len as c_int);
1136 ctxt_read_doc(ctxt, input, URL, options)
1137 }
1138}
1139
1140#[no_mangle]
1149pub unsafe extern "C" fn xmlCtxtReadFile(
1150 ctxt: *mut _xmlParserCtxt,
1151 filename: *const c_char,
1152 _encoding: *const c_char,
1153 options: c_int,
1154) -> *mut _xmlDoc {
1155 if ctxt.is_null() || filename.is_null() {
1156 return ptr::null_mut();
1157 }
1158 unsafe {
1159 match helpers::input_from_file(filename) {
1160 Ok(input) => ctxt_read_doc(ctxt, input, filename, options),
1161 Err(_) => ptr::null_mut(),
1162 }
1163 }
1164}
1165
1166#[no_mangle]
1176pub unsafe extern "C" fn xmlCtxtReadMemory(
1177 ctxt: *mut _xmlParserCtxt,
1178 buffer: *const c_char,
1179 size: c_int,
1180 URL: *const c_char,
1181 _encoding: *const c_char,
1182 options: c_int,
1183) -> *mut _xmlDoc {
1184 if ctxt.is_null() || buffer.is_null() || size < 0 {
1185 return ptr::null_mut();
1186 }
1187 unsafe {
1188 let input = helpers::input_from_memory(buffer, size);
1189 ctxt_read_doc(ctxt, input, URL, options)
1190 }
1191}
1192
1193#[no_mangle]
1202pub unsafe extern "C" fn xmlCtxtReadFd(
1203 ctxt: *mut _xmlParserCtxt,
1204 fd: c_int,
1205 URL: *const c_char,
1206 _encoding: *const c_char,
1207 options: c_int,
1208) -> *mut _xmlDoc {
1209 if ctxt.is_null() || fd < 0 {
1210 return ptr::null_mut();
1211 }
1212 unsafe {
1213 let mut buf = Vec::new();
1214 let mut tmp = [0u8; 4096];
1215 loop {
1216 let n = libc::read(fd, tmp.as_mut_ptr() as *mut c_void, tmp.len());
1217 if n <= 0 {
1218 break;
1219 }
1220 buf.extend_from_slice(&tmp[..n as usize]);
1221 }
1222 let input = helpers::input_from_memory(buf.as_ptr() as *const c_char, buf.len() as c_int);
1223 ctxt_read_doc(ctxt, input, URL, options)
1224 }
1225}
1226
1227#[no_mangle]
1237pub unsafe extern "C" fn xmlCtxtReadIO(
1238 ctxt: *mut _xmlParserCtxt,
1239 ioread: Option<xmlInputReadCallback>,
1240 ioclose: Option<xmlInputCloseCallback>,
1241 ioctx: *mut c_void,
1242 URL: *const c_char,
1243 _encoding: *const c_char,
1244 options: c_int,
1245) -> *mut _xmlDoc {
1246 if ctxt.is_null() {
1247 return ptr::null_mut();
1248 }
1249 unsafe {
1250 let input = helpers::input_from_io(ioread, ioclose, ioctx);
1251 ctxt_read_doc(ctxt, input, URL, options)
1252 }
1253}
1254
1255#[no_mangle]
1263pub unsafe extern "C" fn xmlCtxtParseDocument(
1264 ctxt: *mut _xmlParserCtxt,
1265 input: *mut _xmlParserInput,
1266) -> *mut _xmlDoc {
1267 if ctxt.is_null() || input.is_null() {
1268 return ptr::null_mut();
1269 }
1270 unsafe {
1271 let mut owned = false;
1274 let nr = (*ctxt).inputNr;
1275 let tab = (*ctxt).inputTab;
1276 if !tab.is_null() {
1277 for i in 0..nr {
1278 if *tab.add(i as usize) == input {
1279 owned = true;
1280 break;
1281 }
1282 }
1283 }
1284 if (*ctxt).input == input {
1285 owned = true;
1286 }
1287
1288 let ib = input_buffer_from_parser_input(input);
1290
1291 xmlCtxtReset(ctxt);
1292 helpers::setup_parser_input(ctxt, ib);
1293 helpers::parse_document(ctxt);
1294
1295 if !owned {
1296 helpers::free_parser_input(input);
1297 }
1298
1299 (*ctxt).myDoc
1300 }
1301}
1302
1303#[no_mangle]
1315pub unsafe extern "C" fn xmlAllocParserInputBuffer(enc: c_int) -> *mut _xmlParserInputBuffer {
1316 unsafe {
1317 let buf = xmlMallocZero(core::mem::size_of::<_xmlParserInputBuffer>())
1318 as *mut _xmlParserInputBuffer;
1319 if buf.is_null() {
1320 return ptr::null_mut();
1321 }
1322 let b = &mut *buf;
1323 b.buffer = io::buf_create(crate::abi::data_globals::xmlDefaultBufferSize) as *mut c_void;
1324 b.raw = io::buf_create(crate::abi::data_globals::xmlDefaultBufferSize) as *mut c_void;
1325 if b.buffer.is_null() || b.raw.is_null() {
1326 io::buf_free(b.buffer as *mut _xmlBuffer);
1327 io::buf_free(b.raw as *mut _xmlBuffer);
1328 xmlFreeImpl(buf as *mut c_void);
1329 return ptr::null_mut();
1330 }
1331 b.compressed = -1;
1332
1333 if enc != xmlCharEncoding::XML_CHAR_ENCODING_NONE as c_int
1334 && enc != xmlCharEncoding::XML_CHAR_ENCODING_ERROR as c_int
1335 {
1336 let handler = encoding_handler_for(enc);
1337 if !handler.is_null() {
1338 b.encoder = handler as *mut c_void;
1339 }
1340 }
1341 buf
1342 }
1343}
1344
1345#[no_mangle]
1353pub unsafe extern "C" fn xmlParserInputBufferGrow(
1354 in_: *mut _xmlParserInputBuffer,
1355 len: c_int,
1356) -> c_int {
1357 if in_.is_null() || len <= 0 {
1358 return 0;
1359 }
1360 unsafe {
1361 let b = &mut *in_;
1362 if b.error != 0 {
1363 return -1;
1364 }
1365 let Some(read_cb) = b.readcallback else {
1366 return 0;
1368 };
1369 let mut tmp = vec![0u8; len as usize];
1370 let n = read_cb(b.context, tmp.as_mut_ptr() as *mut c_char, len);
1371 if n < 0 {
1372 b.error = 1;
1373 return -1;
1374 }
1375 if n == 0 {
1376 return 0;
1377 }
1378 io::input_buffer_push(in_, tmp.as_ptr() as *const c_char, n);
1379 n
1380 }
1381}
1382
1383#[no_mangle]
1391pub unsafe extern "C" fn xmlParserInputBufferPush(
1392 in_: *mut _xmlParserInputBuffer,
1393 len: c_int,
1394 buf: *const c_char,
1395) -> c_int {
1396 if in_.is_null() {
1397 return -1;
1398 }
1399 if len < 0 || (len > 0 && buf.is_null()) {
1400 return -1;
1401 }
1402 if len == 0 {
1403 return 0;
1404 }
1405 io::input_buffer_push(in_, buf, len)
1406}
1407
1408#[no_mangle]
1416pub unsafe extern "C" fn xmlParserInputBufferRead(
1417 in_: *mut _xmlParserInputBuffer,
1418 len: c_int,
1419) -> c_int {
1420 xmlParserInputBufferGrow(in_, len)
1421}
1422
1423#[no_mangle]
1431pub unsafe extern "C" fn xmlParserInputRead(_in_: *mut _xmlParserInput, _len: c_int) -> c_int {
1432 -1
1433}
1434
1435#[no_mangle]
1443pub unsafe extern "C" fn xmlParserInputGrow(in_: *mut _xmlParserInput, len: c_int) -> c_int {
1444 if in_.is_null() || len < 0 {
1445 return -1;
1446 }
1447 unsafe {
1448 let pi = &*in_;
1449 if pi.base.is_null() || pi.cur.is_null() {
1450 return -1;
1451 }
1452 if pi.buf.is_null() {
1453 return 0;
1455 }
1456 let b = &*pi.buf;
1457 if b.readcallback.is_none() && b.encoder.is_null() {
1459 return 0;
1460 }
1461 xmlParserInputBufferGrow(pi.buf, len)
1462 }
1463}
1464
1465#[no_mangle]
1473pub unsafe extern "C" fn xmlParserInputShrink(in_: *mut _xmlParserInput) {
1474 if in_.is_null() {
1475 return;
1476 }
1477 unsafe {
1478 let pi = &mut *in_;
1479 if pi.buf.is_null() || pi.base.is_null() || pi.cur.is_null() {
1480 return;
1481 }
1482 let used = (pi.cur as usize).saturating_sub(pi.base as usize);
1483 if used > LINE_LEN {
1484 pi.consumed = pi.consumed.saturating_add((used - LINE_LEN) as c_ulong);
1487 }
1488 }
1489}
1490
1491#[no_mangle]
1499pub unsafe extern "C" fn xmlNewInputStream(ctxt: *mut _xmlParserCtxt) -> *mut _xmlParserInput {
1500 unsafe {
1501 let input = xmlMallocZero(core::mem::size_of::<_xmlParserInput>()) as *mut _xmlParserInput;
1502 if input.is_null() {
1503 if !ctxt.is_null() {
1504 xmlCtxtErrMemory(ctxt);
1505 }
1506 return ptr::null_mut();
1507 }
1508 (*input).line = 1;
1509 (*input).col = 1;
1510 input
1511 }
1512}
1513
1514#[no_mangle]
1524pub unsafe extern "C" fn xmlNewIOInputStream(
1525 ctxt: *mut _xmlParserCtxt,
1526 input: *mut _xmlParserInputBuffer,
1527 enc: c_int,
1528) -> *mut _xmlParserInput {
1529 if ctxt.is_null() || input.is_null() {
1530 return ptr::null_mut();
1531 }
1532 unsafe {
1533 let pi = xmlNewInputStream(ctxt);
1534 if pi.is_null() {
1535 return ptr::null_mut();
1536 }
1537 (*pi).buf = input;
1538 if enc != xmlCharEncoding::XML_CHAR_ENCODING_NONE as c_int
1539 && enc != xmlCharEncoding::XML_CHAR_ENCODING_ERROR as c_int
1540 {
1541 let handler = encoding_handler_for(enc);
1542 if !handler.is_null() {
1543 io::input_buffer_set_encoder(input, handler);
1544 }
1545 }
1546 pi
1547 }
1548}
1549
1550#[no_mangle]
1560pub unsafe extern "C" fn xmlNewStringInputStream(
1561 ctxt: *mut _xmlParserCtxt,
1562 buffer: *const xmlChar,
1563) -> *mut _xmlParserInput {
1564 if ctxt.is_null() || buffer.is_null() {
1565 return ptr::null_mut();
1566 }
1567 unsafe {
1568 let input = xmlNewInputStream(ctxt);
1569 if input.is_null() {
1570 return ptr::null_mut();
1571 }
1572 let len = string::xml_strlen(buffer);
1573 (*input).base = buffer;
1574 (*input).cur = buffer;
1575 (*input).end = buffer.add(len);
1576 (*input).length = len as c_int;
1577 input
1578 }
1579}
1580
1581#[no_mangle]
1590pub unsafe extern "C" fn xmlSetupParserForBuffer(
1591 ctxt: *mut _xmlParserCtxt,
1592 buffer: *const xmlChar,
1593 filename: *const c_char,
1594) {
1595 if ctxt.is_null() || buffer.is_null() {
1596 return;
1597 }
1598 unsafe {
1599 xmlCtxtReset(ctxt);
1600 let len = string::xml_strlen(buffer);
1601 let uri = if filename.is_null() {
1602 None
1603 } else {
1604 CStr::from_ptr(filename).to_str().ok()
1605 };
1606 let input = InputBuffer::from_memory(core::slice::from_raw_parts(buffer, len), uri);
1607 helpers::setup_parser_input(ctxt, input);
1608 }
1609}
1610
1611#[no_mangle]
1619pub unsafe extern "C" fn xmlPushInput(
1620 ctxt: *mut _xmlParserCtxt,
1621 input: *mut _xmlParserInput,
1622) -> c_int {
1623 if ctxt.is_null() || input.is_null() {
1624 return -1;
1625 }
1626 unsafe {
1627 let c = &mut *ctxt;
1628 if c.inputNr >= c.inputMax {
1629 let new_max = if c.inputMax == 0 { 5 } else { c.inputMax * 2 };
1630 let new_tab = xmlReallocImpl(
1631 c.inputTab as *mut c_void,
1632 (new_max as usize) * core::mem::size_of::<*mut _xmlParserInput>(),
1633 ) as *mut *mut _xmlParserInput;
1634 if new_tab.is_null() {
1635 return -1;
1636 }
1637 c.inputTab = new_tab;
1638 c.inputMax = new_max;
1639 }
1640 *c.inputTab.add(c.inputNr as usize) = input;
1641 c.input = input;
1642 (*input).id = c.input_id;
1643 c.input_id += 1;
1644 let idx = c.inputNr;
1645 c.inputNr += 1;
1646 idx
1647 }
1648}
1649
1650#[no_mangle]
1659pub unsafe extern "C" fn xmlPopInput(ctxt: *mut _xmlParserCtxt) -> xmlChar {
1660 if ctxt.is_null() || (*ctxt).inputNr <= 1 {
1661 return 0;
1662 }
1663 unsafe {
1664 let c = &mut *ctxt;
1665 c.inputNr -= 1;
1666 let popped = *c.inputTab.add(c.inputNr as usize);
1667 *c.inputTab.add(c.inputNr as usize) = ptr::null_mut();
1668 if c.inputNr > 0 {
1669 c.input = *c.inputTab.add((c.inputNr - 1) as usize);
1670 } else {
1671 c.input = ptr::null_mut();
1672 }
1673 if !popped.is_null() {
1674 helpers::free_parser_input(popped);
1675 }
1676 if c.input.is_null() {
1677 return 0;
1678 }
1679 let cur = (*c.input).cur;
1680 let end = (*c.input).end;
1681 if cur.is_null() || cur >= end {
1682 0
1683 } else {
1684 *cur
1685 }
1686 }
1687}
1688
1689#[no_mangle]
1701pub unsafe extern "C" fn xmlSwitchEncoding(ctxt: *mut _xmlParserCtxt, enc: c_int) -> c_int {
1702 if ctxt.is_null() || (*ctxt).input.is_null() {
1703 return -1;
1704 }
1705 if enc == xmlCharEncoding::XML_CHAR_ENCODING_NONE as c_int {
1706 return 0;
1707 }
1708 unsafe {
1709 let handler = encoding_handler_for(enc);
1710 if handler.is_null() {
1711 return -1;
1712 }
1713 xmlSwitchToEncoding(ctxt, handler)
1714 }
1715}
1716
1717#[no_mangle]
1725pub unsafe extern "C" fn xmlSwitchEncodingName(
1726 ctxt: *mut _xmlParserCtxt,
1727 encoding: *const c_char,
1728) -> c_int {
1729 if ctxt.is_null() || encoding.is_null() {
1730 return -1;
1731 }
1732 unsafe {
1733 let handler = encoding::find_encoding_handler(encoding as *const xmlChar);
1734 if handler.is_null() {
1735 return -1;
1736 }
1737 xmlSwitchToEncoding(ctxt, handler)
1738 }
1739}
1740
1741#[no_mangle]
1750pub unsafe extern "C" fn xmlSwitchInputEncoding(
1751 ctxt: *mut _xmlParserCtxt,
1752 input: *mut _xmlParserInput,
1753 handler: *mut _xmlCharEncodingHandler,
1754) -> c_int {
1755 let _ = ctxt;
1756 if input.is_null() {
1757 return -1;
1758 }
1759 unsafe {
1760 if (*input).buf.is_null() {
1761 return -1;
1762 }
1763 io::input_buffer_set_encoder((*input).buf, handler);
1764 }
1765 0
1766}
1767
1768#[no_mangle]
1777pub unsafe extern "C" fn xmlSwitchToEncoding(
1778 ctxt: *mut _xmlParserCtxt,
1779 handler: *mut _xmlCharEncodingHandler,
1780) -> c_int {
1781 if ctxt.is_null() {
1782 return -1;
1783 }
1784 unsafe {
1785 let input = (*ctxt).input;
1786 if input.is_null() || (*input).buf.is_null() {
1787 return -1;
1788 }
1789 io::input_buffer_set_encoder((*input).buf, handler);
1790 }
1791 0
1792}
1793
1794#[no_mangle]
1806pub unsafe extern "C" fn xmlInitNodeInfoSeq(seq: *mut _xmlParserNodeInfoSeq) {
1807 if seq.is_null() {
1808 return;
1809 }
1810 unsafe {
1811 (*seq).block = ptr::null_mut();
1812 (*seq).index = ptr::null_mut();
1813 (*seq).block_max = 0;
1814 (*seq).size = 0;
1815 }
1816}
1817
1818#[no_mangle]
1826pub unsafe extern "C" fn xmlClearNodeInfoSeq(seq: *mut _xmlParserNodeInfoSeq) {
1827 if seq.is_null() {
1828 return;
1829 }
1830 unsafe {
1831 if !(*seq).block.is_null() {
1832 xmlFreeImpl((*seq).block as *mut c_void);
1833 }
1834 if !(*seq).index.is_null() {
1835 xmlFreeImpl((*seq).index as *mut c_void);
1836 }
1837 xmlInitNodeInfoSeq(seq);
1838 }
1839}
1840
1841#[no_mangle]
1851pub unsafe extern "C" fn xmlParserFindNodeInfoIndex(
1852 seq: *mut _xmlParserNodeInfoSeq,
1853 node: *mut _xmlNode,
1854) -> c_ulong {
1855 if seq.is_null() || node.is_null() {
1856 return c_ulong::MAX;
1857 }
1858 unsafe {
1859 let s = &*seq;
1860 if s.block.is_null() || s.size == 0 {
1861 return 0;
1862 }
1863 let mut lower: usize = 0;
1864 let mut upper: usize = s.size as usize;
1865 while lower < upper {
1866 let middle = lower + (upper - lower) / 2;
1867 let cur_node = (*s.block.add(middle)).node;
1868 if cur_node == node {
1869 return middle as c_ulong;
1870 }
1871 if (cur_node as usize) < (node as usize) {
1872 lower = middle + 1;
1873 } else {
1874 upper = middle;
1875 }
1876 }
1877 lower as c_ulong
1878 }
1879}
1880
1881#[no_mangle]
1890pub unsafe extern "C" fn xmlParserFindNodeInfo(
1891 ctxt: *mut _xmlParserCtxt,
1892 node: *mut _xmlNode,
1893) -> *const _xmlParserNodeInfo {
1894 if ctxt.is_null() || node.is_null() {
1895 return ptr::null();
1896 }
1897 unsafe {
1898 let seq = &(*ctxt).node_seq;
1899 let seq_mut = seq as *const _ as *mut _xmlParserNodeInfoSeq;
1900 let pos = xmlParserFindNodeInfoIndex(seq_mut, node);
1901 if !seq.block.is_null() && (pos as usize) < (seq.size as usize) {
1902 let info = &*seq.block.add(pos as usize);
1903 if info.node == node {
1904 return info;
1905 }
1906 }
1907 ptr::null()
1908 }
1909}
1910
1911#[no_mangle]
1919pub unsafe extern "C" fn xmlParserAddNodeInfo(
1920 ctxt: *mut _xmlParserCtxt,
1921 info: *mut _xmlParserNodeInfo,
1922) {
1923 if ctxt.is_null() || info.is_null() {
1924 return;
1925 }
1926 unsafe {
1927 let seq = &mut (*ctxt).node_seq;
1928 let node = (*info).node;
1929 let pos = xmlParserFindNodeInfoIndex(seq, node as *mut _xmlNode) as usize;
1930
1931 if !seq.block.is_null() && pos < seq.size as usize && (*seq.block.add(pos)).node == node {
1932 ptr::copy_nonoverlapping(info, seq.block.add(pos), 1);
1933 return;
1934 }
1935
1936 if seq.size + 1 > seq.block_max {
1938 let new_max = if seq.block_max == 0 {
1939 4
1940 } else {
1941 seq.block_max * 2
1942 };
1943 let new_block = xmlReallocImpl(
1944 seq.block as *mut c_void,
1945 (new_max as usize) * core::mem::size_of::<_xmlParserNodeInfo>(),
1946 ) as *mut _xmlParserNodeInfo;
1947 if new_block.is_null() {
1948 xmlCtxtErrMemory(ctxt);
1949 return;
1950 }
1951 seq.block = new_block;
1952 seq.block_max = new_max;
1953 }
1954
1955 let size = seq.size as usize;
1957 for i in (pos + 1..=size).rev() {
1958 ptr::copy_nonoverlapping(seq.block.add(i - 1), seq.block.add(i), 1);
1959 }
1960 ptr::copy_nonoverlapping(info, seq.block.add(pos), 1);
1961 seq.size += 1;
1962 }
1963}
1964
1965#[no_mangle]
1980pub unsafe extern "C" fn xmlRegisterInputCallbacks(
1981 matchFunc: Option<xmlInputMatchCallback>,
1982 openFunc: Option<xmlInputOpenCallback>,
1983 readFunc: Option<xmlInputReadCallback>,
1984 closeFunc: Option<xmlInputCloseCallback>,
1985) -> c_int {
1986 unsafe {
1987 globals::init_parser();
1988 }
1989 let mut table = INPUT_CALLBACKS.lock();
1990 if table.len() >= 10 {
1991 return -1;
1992 }
1993 table.push(InputCallbackEntry {
1994 matchcb: matchFunc,
1995 opencb: openFunc,
1996 readcb: readFunc,
1997 closecb: closeFunc,
1998 });
1999 (table.len() - 1) as c_int
2000}
2001
2002#[no_mangle]
2010pub unsafe extern "C" fn xmlRegisterDefaultInputCallbacks() {
2011 unsafe {
2012 xmlRegisterInputCallbacks(
2013 Some(xmlFileMatch),
2014 Some(xmlFileOpen),
2015 Some(xmlFileRead),
2016 Some(xmlFileClose),
2017 );
2018 }
2019}
2020
2021#[no_mangle]
2029pub unsafe extern "C" fn xmlPopInputCallbacks() -> c_int {
2030 unsafe {
2031 globals::init_parser();
2032 }
2033 let mut table = INPUT_CALLBACKS.lock();
2034 if table.is_empty() {
2035 return -1;
2036 }
2037 table.pop();
2038 table.len() as c_int
2039}
2040
2041#[no_mangle]
2049pub unsafe extern "C" fn xmlCleanupInputCallbacks() {
2050 unsafe {
2051 globals::init_parser();
2052 }
2053 INPUT_CALLBACKS.lock().clear();
2054}
2055
2056#[no_mangle]
2067pub unsafe extern "C" fn xmlRegisterOutputCallbacks(
2068 matchFunc: Option<xmlOutputMatchCallback>,
2069 openFunc: Option<xmlOutputOpenCallback>,
2070 writeFunc: Option<xmlOutputWriteCallback>,
2071 closeFunc: Option<xmlOutputCloseCallback>,
2072) -> c_int {
2073 unsafe {
2074 globals::init_parser();
2075 }
2076 let mut table = OUTPUT_CALLBACKS.lock();
2077 if table.len() >= 10 {
2078 return -1;
2079 }
2080 table.push(OutputCallbackEntry {
2081 matchcb: matchFunc,
2082 opencb: openFunc,
2083 writecb: writeFunc,
2084 closecb: closeFunc,
2085 });
2086 (table.len() - 1) as c_int
2087}
2088
2089#[no_mangle]
2097pub unsafe extern "C" fn xmlRegisterDefaultOutputCallbacks() {
2098 unsafe {
2099 xmlRegisterOutputCallbacks(Some(xmlFileMatch), None, None, None);
2100 }
2101}
2102
2103#[no_mangle]
2111pub unsafe extern "C" fn xmlRegisterHTTPPostCallbacks() {
2112 unsafe { xmlRegisterDefaultOutputCallbacks() }
2113}
2114
2115#[no_mangle]
2123pub unsafe extern "C" fn xmlPopOutputCallbacks() -> c_int {
2124 unsafe {
2125 globals::init_parser();
2126 }
2127 let mut table = OUTPUT_CALLBACKS.lock();
2128 if table.is_empty() {
2129 return -1;
2130 }
2131 table.pop();
2132 table.len() as c_int
2133}
2134
2135#[no_mangle]
2143pub unsafe extern "C" fn xmlCleanupOutputCallbacks() {
2144 unsafe {
2145 globals::init_parser();
2146 }
2147 OUTPUT_CALLBACKS.lock().clear();
2148}
2149
2150unsafe extern "C" fn default_external_entity_loader(
2161 url: *const c_char,
2162 public_id: *const c_char,
2163 ctxt: *mut _xmlParserCtxt,
2164) -> *mut _xmlParserInput {
2165 let _ = public_id;
2166 if url.is_null() {
2167 return ptr::null_mut();
2168 }
2169 unsafe {
2170 if !ctxt.is_null() && (*ctxt).options & XML_PARSE_NONET != 0 {
2172 let len = libc::strlen(url);
2173 if len >= 7 && libc::strncasecmp(url, b"http://\0".as_ptr() as *const c_char, 7) == 0 {
2174 return ptr::null_mut();
2175 }
2176 }
2177 let table = INPUT_CALLBACKS.lock();
2179 for entry in table.iter() {
2180 if let (Some(match_cb), Some(open_cb)) = (entry.matchcb, entry.opencb) {
2181 if match_cb(url) != 0 {
2182 let ctx = open_cb(url);
2183 if !ctx.is_null() {
2184 let buf = helpers::alloc_parser_input_buffer();
2185 if buf.is_null() {
2186 if let Some(close_cb) = entry.closecb {
2187 close_cb(ctx);
2188 }
2189 return ptr::null_mut();
2190 }
2191 (*buf).context = ctx;
2192 (*buf).readcallback = entry.readcb;
2193 (*buf).closecallback = entry.closecb;
2194 return parser_input_from_buf(buf);
2195 }
2196 }
2197 }
2198 }
2199
2200 let buf =
2202 io::input_buffer_create_file(url, xmlCharEncoding::XML_CHAR_ENCODING_NONE as c_int);
2203 if buf.is_null() {
2204 return ptr::null_mut();
2205 }
2206 parser_input_from_buf(buf)
2207 }
2208}
2209
2210#[no_mangle]
2218pub unsafe extern "C" fn xmlSetExternalEntityLoader(f: Option<xmlExternalEntityLoader>) {
2219 *EXTERNAL_ENTITY_LOADER.lock() = f;
2220}
2221
2222#[no_mangle]
2230pub unsafe extern "C" fn xmlGetExternalEntityLoader() -> Option<xmlExternalEntityLoader> {
2231 *EXTERNAL_ENTITY_LOADER.lock()
2232}
2233
2234#[no_mangle]
2244pub unsafe extern "C" fn xmlNoNetExternalEntityLoader(
2245 URL: *const c_char,
2246 ID: *const c_char,
2247 ctxt: *mut _xmlParserCtxt,
2248) -> *mut _xmlParserInput {
2249 unsafe {
2250 let old_options = if ctxt.is_null() { 0 } else { (*ctxt).options };
2251 if !ctxt.is_null() {
2252 (*ctxt).options |= XML_PARSE_NONET;
2253 }
2254 let input = default_external_entity_loader(URL, ID, ctxt);
2255 if !ctxt.is_null() {
2256 (*ctxt).options = old_options;
2257 }
2258 input
2259 }
2260}
2261
2262#[no_mangle]
2271pub unsafe extern "C" fn xmlLoadExternalEntity(
2272 URL: *const c_char,
2273 ID: *const c_char,
2274 ctxt: *mut _xmlParserCtxt,
2275) -> *mut _xmlParserInput {
2276 let loader = *EXTERNAL_ENTITY_LOADER.lock();
2277 match loader {
2278 Some(f) => unsafe { f(URL, ID, ctxt) },
2279 None => unsafe { default_external_entity_loader(URL, ID, ctxt) },
2280 }
2281}
2282
2283#[no_mangle]
2293pub unsafe extern "C" fn xmlCheckHTTPInput(
2294 ctxt: *mut _xmlParserCtxt,
2295 ret: *mut _xmlParserInput,
2296) -> *mut _xmlParserInput {
2297 if ret.is_null() {
2298 return ptr::null_mut();
2299 }
2300 unsafe {
2301 if !ctxt.is_null() && (*ctxt).options & XML_PARSE_NONET != 0 {
2302 let filename = (*ret).filename;
2303 if !filename.is_null() {
2304 let len = libc::strlen(filename);
2305 if len >= 7
2306 && libc::strncasecmp(filename, b"http://\0".as_ptr() as *const c_char, 7) == 0
2307 {
2308 if !(*ret).buf.is_null() {
2309 io::input_buffer_free((*ret).buf);
2310 }
2311 helpers::free_parser_input(ret);
2312 return ptr::null_mut();
2313 }
2314 }
2315 }
2316 ret
2317 }
2318}
2319
2320#[no_mangle]
2332pub unsafe extern "C" fn xmlFileMatch(_filename: *const c_char) -> c_int {
2333 1
2334}
2335
2336#[no_mangle]
2344pub unsafe extern "C" fn xmlFileOpen(filename: *const c_char) -> *mut c_void {
2345 if filename.is_null() {
2346 return ptr::null_mut();
2347 }
2348 unsafe { libc::fopen(filename, b"rb\0".as_ptr() as *const c_char) as *mut c_void }
2349}
2350
2351#[no_mangle]
2359pub unsafe extern "C" fn xmlFileRead(
2360 context: *mut c_void,
2361 buffer: *mut c_char,
2362 len: c_int,
2363) -> c_int {
2364 if context.is_null() || buffer.is_null() || len <= 0 {
2365 return -1;
2366 }
2367 unsafe {
2368 let n = libc::fread(
2369 buffer as *mut c_void,
2370 1,
2371 len as usize,
2372 context as *mut libc::FILE,
2373 );
2374 if n < len as usize && libc::ferror(context as *mut libc::FILE) != 0 {
2375 return -1;
2376 }
2377 n as c_int
2378 }
2379}
2380
2381#[no_mangle]
2389pub unsafe extern "C" fn xmlFileClose(context: *mut c_void) -> c_int {
2390 if context.is_null() {
2391 return -1;
2392 }
2393 unsafe {
2394 let file = context as *mut libc::FILE;
2395 let fd = libc::fileno(file);
2396 if fd == 0 {
2397 return 0;
2399 }
2400 if fd == 1 || fd == 2 {
2401 return if libc::fflush(file) == 0 { 0 } else { -1 };
2403 }
2404 libc::fclose(file)
2405 }
2406}
2407
2408#[no_mangle]
2421pub unsafe extern "C" fn xmlCurrentChar(ctxt: *mut _xmlParserCtxt, len: *mut c_int) -> c_int {
2422 if ctxt.is_null() || len.is_null() || (*ctxt).input.is_null() {
2423 return 0;
2424 }
2425 unsafe {
2426 let pi = &*((*ctxt).input);
2427 let cur = pi.cur;
2428 if cur.is_null() {
2429 *len = 0;
2430 return 0;
2431 }
2432 let avail = (pi.end as usize).saturating_sub(cur as usize);
2433 let c = *cur;
2434
2435 if c < 0x80 {
2436 if c == b'\r' {
2437 if avail >= 2 && *cur.add(1) == b'\n' {
2439 (*(*ctxt).input).cur = cur.add(1);
2440 }
2441 *len = 1;
2442 return b'\n' as c_int;
2443 }
2444 if c == 0 {
2445 if avail == 0 {
2446 *len = 0;
2447 } else {
2448 *len = 1;
2449 }
2450 return 0;
2451 }
2452 *len = 1;
2453 return c as c_int;
2454 }
2455
2456 if avail < 2 || (*cur.add(1) & 0xc0) != 0x80 {
2458 *len = 1;
2459 return XML_INVALID_CHAR;
2460 }
2461 if c < 0xe0 {
2462 if c < 0xc2 {
2463 *len = 1;
2464 return XML_INVALID_CHAR;
2465 }
2466 let val = (((c & 0x1f) as c_int) << 6) | ((*cur.add(1) & 0x3f) as c_int);
2467 *len = 2;
2468 return val;
2469 }
2470 if avail < 3 || (*cur.add(2) & 0xc0) != 0x80 {
2471 *len = 1;
2472 return XML_INVALID_CHAR;
2473 }
2474 if c < 0xf0 {
2475 let val = (((c & 0x0f) as c_int) << 12)
2476 | (((*cur.add(1) & 0x3f) as c_int) << 6)
2477 | ((*cur.add(2) & 0x3f) as c_int);
2478 if val < 0x800 || (val >= 0xd800 && val < 0xe000) {
2479 *len = 1;
2480 return XML_INVALID_CHAR;
2481 }
2482 *len = 3;
2483 return val;
2484 }
2485 if avail < 4 || (*cur.add(3) & 0xc0) != 0x80 {
2486 *len = 1;
2487 return XML_INVALID_CHAR;
2488 }
2489 let val = (((c & 0x07) as c_int) << 18)
2490 | (((*cur.add(1) & 0x3f) as c_int) << 12)
2491 | (((*cur.add(2) & 0x3f) as c_int) << 6)
2492 | ((*cur.add(3) & 0x3f) as c_int);
2493 if val < 0x10000 || val >= 0x110000 {
2494 *len = 1;
2495 return XML_INVALID_CHAR;
2496 }
2497 *len = 4;
2498 val
2499 }
2500}
2501
2502#[no_mangle]
2510pub unsafe extern "C" fn xmlNextChar(ctxt: *mut _xmlParserCtxt) {
2511 if ctxt.is_null() || (*ctxt).input.is_null() {
2512 return;
2513 }
2514 unsafe {
2515 let pi = &mut *((*ctxt).input);
2516 let cur = pi.cur;
2517 if cur.is_null() {
2518 return;
2519 }
2520 let avail = (pi.end as usize).saturating_sub(cur as usize);
2521 if avail == 0 {
2522 return;
2523 }
2524 let c = *cur;
2525
2526 if c < 0x80 {
2527 if c == b'\n' {
2528 pi.cur = cur.add(1);
2529 pi.line += 1;
2530 pi.col = 1;
2531 } else if c == b'\r' {
2532 pi.cur = cur.add(if avail >= 2 && *cur.add(1) == b'\n' {
2534 2
2535 } else {
2536 1
2537 });
2538 pi.line += 1;
2539 pi.col = 1;
2540 } else {
2541 pi.cur = cur.add(1);
2542 pi.col += 1;
2543 }
2544 return;
2545 }
2546
2547 pi.col += 1;
2548
2549 if avail < 2 || (*cur.add(1) & 0xc0) != 0x80 {
2550 pi.cur = cur.add(1);
2551 return;
2552 }
2553 if c < 0xe0 {
2554 if c < 0xc2 {
2555 pi.cur = cur.add(1);
2556 return;
2557 }
2558 pi.cur = cur.add(2);
2559 return;
2560 }
2561 if avail < 3 || (*cur.add(2) & 0xc0) != 0x80 {
2562 pi.cur = cur.add(1);
2563 return;
2564 }
2565 if c < 0xf0 {
2566 let val = (((c as c_int) << 8) as u32) | (*cur.add(1) as u32);
2567 if (val < 0xe0a0) || (val >= 0xeda0 && val < 0xee00) {
2568 pi.cur = cur.add(1);
2569 return;
2570 }
2571 pi.cur = cur.add(3);
2572 return;
2573 }
2574 if avail < 4 || (*cur.add(3) & 0xc0) != 0x80 {
2575 pi.cur = cur.add(1);
2576 return;
2577 }
2578 let val = (((c as c_int) << 8) as u32) | (*cur.add(1) as u32);
2579 if val < 0xf090 || val >= 0xf490 {
2580 pi.cur = cur.add(1);
2581 return;
2582 }
2583 pi.cur = cur.add(4);
2584 }
2585}
2586
2587#[no_mangle]
2596pub unsafe extern "C" fn xmlSkipBlankChars(ctxt: *mut _xmlParserCtxt) -> c_int {
2597 if ctxt.is_null() || (*ctxt).input.is_null() {
2598 return 0;
2599 }
2600 unsafe {
2601 let pi = &mut *((*ctxt).input);
2602 let mut cur = pi.cur;
2603 if cur.is_null() {
2604 return 0;
2605 }
2606 let end = pi.end;
2607 let mut res = 0;
2608 while cur < end && (*cur == 0x20 || *cur == 0x09 || *cur == 0x0a || *cur == 0x0d) {
2609 if *cur == b'\n' {
2610 pi.line += 1;
2611 pi.col = 1;
2612 } else {
2613 pi.col += 1;
2614 }
2615 cur = cur.add(1);
2616 res += 1;
2617 }
2618 pi.cur = cur;
2619 res
2620 }
2621}
2622
2623fn is_name_start_char_new(c: c_int) -> bool {
2625 if c == b' ' as c_int || c == b'>' as c_int || c == b'/' as c_int {
2626 return false;
2627 }
2628 (c >= b'a' as c_int && c <= b'z' as c_int)
2629 || (c >= b'A' as c_int && c <= b'Z' as c_int)
2630 || c == b'_' as c_int
2631 || c == b':' as c_int
2632 || (c >= 0xC0 && c <= 0xD6)
2633 || (c >= 0xD8 && c <= 0xF6)
2634 || (c >= 0xF8 && c <= 0x2FF)
2635 || (c >= 0x370 && c <= 0x37D)
2636 || (c >= 0x37F && c <= 0x1FFF)
2637 || (c >= 0x200C && c <= 0x200D)
2638 || (c >= 0x2070 && c <= 0x218F)
2639 || (c >= 0x2C00 && c <= 0x2FEF)
2640 || (c >= 0x3001 && c <= 0xD7FF)
2641 || (c >= 0xF900 && c <= 0xFDCF)
2642 || (c >= 0xFDF0 && c <= 0xFFFD)
2643 || (c >= 0x10000 && c <= 0xEFFFF)
2644}
2645
2646fn is_name_char_new(c: c_int) -> bool {
2648 if c == b' ' as c_int || c == b'>' as c_int || c == b'/' as c_int {
2649 return false;
2650 }
2651 (c >= b'a' as c_int && c <= b'z' as c_int)
2652 || (c >= b'A' as c_int && c <= b'Z' as c_int)
2653 || (c >= b'0' as c_int && c <= b'9' as c_int)
2654 || c == b'_' as c_int
2655 || c == b':' as c_int
2656 || c == b'-' as c_int
2657 || c == b'.' as c_int
2658 || c == 0xB7
2659 || (c >= 0xC0 && c <= 0xD6)
2660 || (c >= 0xD8 && c <= 0xF6)
2661 || (c >= 0xF8 && c <= 0x2FF)
2662 || (c >= 0x300 && c <= 0x36F)
2663 || (c >= 0x370 && c <= 0x37D)
2664 || (c >= 0x37F && c <= 0x1FFF)
2665 || (c >= 0x200C && c <= 0x200D)
2666 || (c >= 0x203F && c <= 0x2040)
2667 || (c >= 0x2070 && c <= 0x218F)
2668 || (c >= 0x2C00 && c <= 0x2FEF)
2669 || (c >= 0x3001 && c <= 0xD7FF)
2670 || (c >= 0xF900 && c <= 0xFDCF)
2671 || (c >= 0xFDF0 && c <= 0xFFFD)
2672 || (c >= 0x10000 && c <= 0xEFFFF)
2673}
2674
2675#[no_mangle]
2685pub unsafe extern "C" fn xmlScanName(
2686 ctxt: *mut _xmlParserCtxt,
2687 max: c_int,
2688 flags: c_int,
2689) -> *const xmlChar {
2690 if ctxt.is_null() || (*ctxt).input.is_null() || max <= 0 {
2691 return ptr::null();
2692 }
2693 unsafe {
2694 let pi = &mut *((*ctxt).input);
2695 let mut ptr = pi.cur;
2696 if ptr.is_null() {
2697 return ptr::null();
2698 }
2699 let end = pi.end;
2700 let mut remaining = max as usize;
2701 let stop: u8 = if flags & XML_SCAN_NC != 0 { b':' } else { 0 };
2702 let old10 = flags & XML_SCAN_OLD10 != 0;
2703 let mut f = flags;
2704
2705 loop {
2706 if ptr >= end {
2707 break;
2708 }
2709 let c = *ptr;
2710 let (cp, len) = if c < 0x80 {
2711 if stop != 0 && c == stop {
2712 break;
2713 }
2714 (c as c_int, 1usize)
2715 } else {
2716 let avail = (end as usize).saturating_sub(ptr as usize);
2718 let mut l = 4usize;
2719 let cp = decode_utf8_char(ptr, avail, &mut l);
2720 if cp < 0 {
2721 break;
2722 }
2723 (cp, l)
2724 };
2725
2726 let ok = if f & XML_SCAN_NMTOKEN != 0 {
2727 if old10 {
2728 is_name_char_old10(cp)
2729 } else {
2730 is_name_char_new(cp)
2731 }
2732 } else if old10 {
2733 is_name_start_char_old10(cp)
2734 } else {
2735 is_name_start_char_new(cp)
2736 };
2737 if !ok {
2738 break;
2739 }
2740 if len > remaining {
2741 return ptr::null();
2742 }
2743 ptr = ptr.add(len);
2744 remaining -= len;
2745 f |= XML_SCAN_NMTOKEN;
2746 }
2747
2748 pi.cur = ptr;
2749 ptr
2750 }
2751}
2752
2753unsafe fn decode_utf8_char(ptr: *const u8, avail: usize, len: &mut usize) -> c_int {
2756 unsafe {
2757 let c = *ptr;
2758 if avail < 2 || (*ptr.add(1) & 0xc0) != 0x80 {
2759 return -1;
2760 }
2761 if c < 0xe0 {
2762 if c < 0xc2 {
2763 return -1;
2764 }
2765 *len = 2;
2766 return (((c & 0x1f) as c_int) << 6) | ((*ptr.add(1) & 0x3f) as c_int);
2767 }
2768 if avail < 3 || (*ptr.add(2) & 0xc0) != 0x80 {
2769 return -1;
2770 }
2771 if c < 0xf0 {
2772 let val = (((c & 0x0f) as c_int) << 12)
2773 | (((*ptr.add(1) & 0x3f) as c_int) << 6)
2774 | ((*ptr.add(2) & 0x3f) as c_int);
2775 if val < 0x800 || (val >= 0xd800 && val < 0xe000) {
2776 return -1;
2777 }
2778 *len = 3;
2779 return val;
2780 }
2781 if avail < 4 || (*ptr.add(3) & 0xc0) != 0x80 {
2782 return -1;
2783 }
2784 let val = (((c & 0x07) as c_int) << 18)
2785 | (((*ptr.add(1) & 0x3f) as c_int) << 12)
2786 | (((*ptr.add(2) & 0x3f) as c_int) << 6)
2787 | ((*ptr.add(3) & 0x3f) as c_int);
2788 if val < 0x10000 || val >= 0x110000 {
2789 return -1;
2790 }
2791 *len = 4;
2792 val
2793 }
2794}
2795
2796fn is_name_start_char_old10(c: c_int) -> bool {
2798 (c >= b'a' as c_int && c <= b'z' as c_int)
2799 || (c >= b'A' as c_int && c <= b'Z' as c_int)
2800 || c == b'_' as c_int
2801 || c == b':' as c_int
2802 || (c >= 0xC0 && c <= 0xD6)
2803 || (c >= 0xD8 && c <= 0xF6)
2804 || (c >= 0xF8 && c <= 0x2FF)
2805 || (c >= 0x370 && c <= 0x37D)
2806 || (c >= 0x37F && c <= 0x1FFF)
2807 || (c >= 0x200C && c <= 0x200D)
2808 || (c >= 0x2070 && c <= 0x218F)
2809 || (c >= 0x2C00 && c <= 0x2FEF)
2810 || (c >= 0x3001 && c <= 0xD7FF)
2811 || (c >= 0xF900 && c <= 0xFDCF)
2812 || (c >= 0xFDF0 && c <= 0xFFFD)
2813 || (c >= 0x10000 && c <= 0xEFFFF)
2814}
2815
2816fn is_name_char_old10(c: c_int) -> bool {
2819 is_name_start_char_old10(c)
2820 || (c >= b'0' as c_int && c <= b'9' as c_int)
2821 || c == b'.' as c_int
2822 || c == b'-' as c_int
2823 || c == 0xB7
2824 || (c >= 0x300 && c <= 0x36F)
2825 || c == 0x02D0
2826 || c == 0x02D1
2827 || c == 0x0387
2828 || c == 0x0640
2829 || c == 0x0E46
2830 || c == 0x0EC6
2831 || c == 0x3005
2832 || (c >= 0x3031 && c <= 0x3035)
2833 || (c >= 0x309D && c <= 0x309E)
2834 || (c >= 0x30FC && c <= 0x30FE)
2835}
2836
2837#[no_mangle]
2848pub unsafe extern "C" fn xmlDecodeEntities(
2849 ctxt: *mut _xmlParserCtxt,
2850 len: c_int,
2851 end: xmlChar,
2852 end2: xmlChar,
2853 end3: xmlChar,
2854) -> *mut xmlChar {
2855 if ctxt.is_null() || (*ctxt).input.is_null() {
2856 return ptr::null_mut();
2857 }
2858 unsafe {
2859 let pi = &*((*ctxt).input);
2860 let cur = pi.cur;
2861 if cur.is_null() {
2862 return ptr::null_mut();
2863 }
2864 let avail = (pi.end as usize).saturating_sub(cur as usize);
2865 let n = if len < 0 {
2866 avail
2867 } else {
2868 (len as usize).min(avail)
2869 };
2870
2871 let mut out: Vec<u8> = Vec::new();
2872 let mut i = 0usize;
2873
2874 while i < n {
2875 let c = *cur.add(i);
2876 if c == end || c == end2 || c == end3 {
2877 break;
2878 }
2879 if c != b'&' {
2880 out.push(c);
2881 i += 1;
2882 continue;
2883 }
2884
2885 if i + 1 < n && *cur.add(i + 1) == b'#' {
2887 let (value, consumed) = parse_char_ref(cur.add(i), n - i);
2888 if consumed == 0 {
2889 out.push(b'&');
2890 i += 1;
2891 continue;
2892 }
2893 let mut buf = [0u8; 4];
2894 let blen = copy_char_utf8(&mut buf, value);
2895 out.extend_from_slice(&buf[..blen]);
2896 i += consumed;
2897 continue;
2898 }
2899
2900 let mut j = i + 1;
2902 while j < n
2903 && ((*cur.add(j)).is_ascii_alphanumeric()
2904 || *cur.add(j) == b'_'
2905 || *cur.add(j) == b'-'
2906 || *cur.add(j) == b'.'
2907 || *cur.add(j) == b':')
2908 {
2909 j += 1;
2910 }
2911 if j < n && *cur.add(j) == b';' {
2912 let name = core::slice::from_raw_parts(cur.add(i + 1), j - i - 1);
2913 let mut replaced = false;
2914 let content: Option<&[u8]> = match name {
2916 b"amp" => Some(b"&"),
2917 b"lt" => Some(b"<"),
2918 b"gt" => Some(b">"),
2919 b"quot" => Some(b"\""),
2920 b"apos" => Some(b"'"),
2921 _ => None,
2922 };
2923 if let Some(c) = content {
2924 out.extend_from_slice(c);
2925 replaced = true;
2926 } else {
2927 let mut name_nul = name.to_vec();
2929 name_nul.push(0);
2930 let ent = entities::get_entity((*ctxt).myDoc, name_nul.as_ptr());
2931 if !ent.is_null() && !(*ent).content.is_null() {
2932 let clen = string::xml_strlen((*ent).content);
2933 out.extend_from_slice(core::slice::from_raw_parts((*ent).content, clen));
2934 replaced = true;
2935 }
2936 }
2937 if replaced {
2938 i = j + 1;
2939 continue;
2940 }
2941 }
2942 out.push(b'&');
2943 i += 1;
2944 }
2945
2946 out.push(0);
2947 let result = xmlMallocImpl(out.len()) as *mut xmlChar;
2948 if result.is_null() {
2949 return ptr::null_mut();
2950 }
2951 ptr::copy_nonoverlapping(out.as_ptr(), result, out.len());
2952 result
2953 }
2954}
2955
2956unsafe fn parse_char_ref(ptr: *const u8, avail: usize) -> (c_int, usize) {
2959 unsafe {
2960 if avail < 3 || *ptr != b'&' || *ptr.add(1) != b'#' {
2961 return (0, 0);
2962 }
2963 let mut i = 2usize;
2964 let hex = i < avail && (*ptr.add(i) == b'x' || *ptr.add(i) == b'X');
2965 if hex {
2966 i += 1;
2967 }
2968 let start = i;
2969 let mut value: u32 = 0;
2970 while i < avail && *ptr.add(i) != b';' {
2971 let d = (*ptr.add(i) as char).to_digit(if hex { 16 } else { 10 });
2972 match d {
2973 Some(d) => {
2974 value = value
2975 .saturating_mul(if hex { 16 } else { 10 })
2976 .saturating_add(d);
2977 i += 1;
2978 }
2979 None => return (0, 0),
2980 }
2981 }
2982 if i == start || i >= avail || *ptr.add(i) != b';' {
2983 return (0, 0);
2984 }
2985 (value as c_int, i + 1)
2986 }
2987}
2988
2989fn copy_char_utf8(out: &mut [u8; 4], val: c_int) -> usize {
2991 if val < 0x80 {
2992 out[0] = val as u8;
2993 1
2994 } else if val < 0x800 {
2995 out[0] = 0xC0 | ((val >> 6) as u8);
2996 out[1] = 0x80 | ((val & 0x3F) as u8);
2997 2
2998 } else if val < 0x10000 {
2999 out[0] = 0xE0 | ((val >> 12) as u8);
3000 out[1] = 0x80 | (((val >> 6) & 0x3F) as u8);
3001 out[2] = 0x80 | ((val & 0x3F) as u8);
3002 3
3003 } else if val < 0x110000 {
3004 out[0] = 0xF0 | ((val >> 18) as u8);
3005 out[1] = 0x80 | (((val >> 12) & 0x3F) as u8);
3006 out[2] = 0x80 | (((val >> 6) & 0x3F) as u8);
3007 out[3] = 0x80 | ((val & 0x3F) as u8);
3008 4
3009 } else {
3010 out[0] = 0;
3011 1
3012 }
3013}
3014
3015#[no_mangle]
3023pub unsafe extern "C" fn xmlDetectCharEncoding(in_: *const c_uchar, len: c_int) -> c_int {
3024 if in_.is_null() {
3025 return xmlCharEncoding::XML_CHAR_ENCODING_NONE as c_int;
3026 }
3027 unsafe {
3028 if len >= 4 {
3029 if *in_ == 0x00 && *in_.add(1) == 0x00 && *in_.add(2) == 0x00 && *in_.add(3) == 0x3C {
3030 return xmlCharEncoding::XML_CHAR_ENCODING_UCS4BE as c_int;
3031 }
3032 if *in_ == 0x3C && *in_.add(1) == 0x00 && *in_.add(2) == 0x00 && *in_.add(3) == 0x00 {
3033 return xmlCharEncoding::XML_CHAR_ENCODING_UCS4LE as c_int;
3034 }
3035 if *in_ == 0x4C && *in_.add(1) == 0x6F && *in_.add(2) == 0xA7 && *in_.add(3) == 0x94 {
3036 return xmlCharEncoding::XML_CHAR_ENCODING_EBCDIC as c_int;
3037 }
3038 if *in_ == 0x3C && *in_.add(1) == 0x3F && *in_.add(2) == 0x78 && *in_.add(3) == 0x6D {
3039 return xmlCharEncoding::XML_CHAR_ENCODING_UTF8 as c_int;
3040 }
3041 if *in_ == 0x3C && *in_.add(1) == 0x00 && *in_.add(2) == 0x3F && *in_.add(3) == 0x00 {
3042 return xmlCharEncoding::XML_CHAR_ENCODING_UTF16LE as c_int;
3043 }
3044 if *in_ == 0x00 && *in_.add(1) == 0x3C && *in_.add(2) == 0x00 && *in_.add(3) == 0x3F {
3045 return xmlCharEncoding::XML_CHAR_ENCODING_UTF16BE as c_int;
3046 }
3047 }
3048 if len >= 3 && *in_ == 0xEF && *in_.add(1) == 0xBB && *in_.add(2) == 0xBF {
3049 return xmlCharEncoding::XML_CHAR_ENCODING_UTF8 as c_int;
3050 }
3051 if len >= 2 {
3052 if *in_ == 0xFE && *in_.add(1) == 0xFF {
3053 return xmlCharEncoding::XML_CHAR_ENCODING_UTF16BE as c_int;
3054 }
3055 if *in_ == 0xFF && *in_.add(1) == 0xFE {
3056 return xmlCharEncoding::XML_CHAR_ENCODING_UTF16LE as c_int;
3057 }
3058 }
3059 }
3060 xmlCharEncoding::XML_CHAR_ENCODING_NONE as c_int
3061}
3062
3063#[no_mangle]
3073pub unsafe extern "C" fn xmlCharEncFirstLine(
3074 handler: *mut _xmlCharEncodingHandler,
3075 out: *mut _xmlBuffer,
3076 in_: *mut _xmlBuffer,
3077) -> c_int {
3078 encoding::xmlCharEncInFunc(handler, out, in_)
3079}
3080
3081#[no_mangle]
3089pub unsafe extern "C" fn xmlIsMainThread() -> c_int {
3090 1
3091}
3092
3093#[no_mangle]
3106pub unsafe extern "C" fn xmlParserPrintFileInfo(input: *mut _xmlParserInput) {
3107 if input.is_null() {
3108 return;
3109 }
3110 unsafe {
3111 let channel: Option<xmlGenericErrorFunc> = globals::get_generic_error_func();
3112 let data = globals::get_generic_error_ctx();
3113 let Some(ch) = channel else { return };
3114 let msg;
3115 if !(*input).filename.is_null() {
3116 let file = CStr::from_ptr((*input).filename);
3117 let s = format!("{}:{}: ", file.to_string_lossy(), (*input).line);
3118 msg = std::ffi::CString::new(s).unwrap_or_default();
3119 } else {
3120 let s = format!("Entity: line {}: ", (*input).line);
3121 msg = std::ffi::CString::new(s).unwrap_or_default();
3122 }
3123 ch(data, msg.as_ptr());
3124 }
3125}
3126
3127#[no_mangle]
3136pub unsafe extern "C" fn xmlParserPrintFileContext(input: *mut _xmlParserInput) {
3137 if input.is_null() || (*input).cur.is_null() {
3138 return;
3139 }
3140 unsafe {
3141 let channel: Option<xmlGenericErrorFunc> = globals::get_generic_error_func();
3142 let data = globals::get_generic_error_ctx();
3143 let Some(ch) = channel else { return };
3144
3145 let pi = &*input;
3146 let cur = pi.cur;
3147 let base = pi.base;
3148 let end = pi.end;
3149
3150 let before = if base.is_null() {
3152 0
3153 } else {
3154 (cur as usize).saturating_sub(base as usize)
3155 };
3156 let take = before.min(LINE_LEN);
3157 let start = cur.sub(take);
3158 let n = (end as usize).saturating_sub(start as usize).min(LINE_LEN);
3159
3160 let mut content = vec![0u8; n];
3161 if n > 0 {
3162 ptr::copy_nonoverlapping(start, content.as_mut_ptr(), n);
3163 }
3164 let line = std::ffi::CString::new(content.clone()).unwrap_or_default();
3165 ch(data, line.as_ptr());
3166
3167 let mut caret = vec![b' '; take];
3169 if take + 1 <= LINE_LEN + 1 {
3170 caret.push(b'^');
3171 }
3172 let caret_c = std::ffi::CString::new(caret).unwrap_or_default();
3173 ch(data, caret_c.as_ptr());
3174 }
3175}
3176
3177#[no_mangle]
3190pub unsafe extern "C" fn xmlHandleEntity(ctxt: *mut _xmlParserCtxt, entity: *mut c_void) {
3191 if ctxt.is_null() {
3192 return;
3193 }
3194 unsafe {
3195 let ent = entity as *mut _xmlEntity;
3196 if ent.is_null() {
3197 return;
3198 }
3199 if (*ent).etype == xmlEntityType::XML_EXTERNAL_GENERAL_UNPARSED_ENTITY as c_int {
3201 return;
3202 }
3203
3204 let mut input = ptr::null_mut();
3205 if !(*ent).content.is_null() {
3206 let content = (*ent).content;
3208 let pi = xmlNewInputStream(ctxt);
3209 if pi.is_null() {
3210 return;
3211 }
3212 let len = string::xml_strlen(content);
3213 (*pi).base = content;
3214 (*pi).cur = content;
3215 (*pi).end = content.add(len);
3216 (*pi).length = len as c_int;
3217 (*pi).entity = ent;
3218 input = pi;
3219 } else if !(*ent).URI.is_null() {
3220 input = xmlLoadExternalEntity(
3222 (*ent).URI as *const c_char,
3223 (*ent).ExternalID as *const c_char,
3224 ctxt,
3225 );
3226 if !input.is_null() {
3227 (*input).entity = ent;
3228 }
3229 }
3230
3231 if input.is_null() {
3232 return;
3233 }
3234 xmlPushInput(ctxt, input);
3235 }
3236}
3237
3238#[no_mangle]
3248pub unsafe extern "C" fn xmlSAXParseDTD(
3249 sax: *mut _xmlSAXHandler,
3250 publicId: *const xmlChar,
3251 systemId: *const xmlChar,
3252) -> *mut _xmlDtd {
3253 if publicId.is_null() && systemId.is_null() {
3254 return ptr::null_mut();
3255 }
3256 unsafe {
3257 let ctxt = xmlNewSAXParserCtxt(sax, ptr::null_mut());
3258 if ctxt.is_null() {
3259 return ptr::null_mut();
3260 }
3261 apply_options(ctxt, XML_PARSE_DTDLOAD);
3262
3263 let mut input = ptr::null_mut();
3266 if !sax.is_null() {
3267 if let Some(resolve) = (*sax).resolveEntity {
3268 input = resolve((*ctxt).userData, publicId, systemId);
3269 }
3270 }
3271 if input.is_null() {
3272 if systemId.is_null() {
3273 helpers::free_parser_ctxt(ctxt);
3274 return ptr::null_mut();
3275 }
3276 input = xmlLoadExternalEntity(systemId as *const c_char, ptr::null(), ctxt);
3277 }
3278 if input.is_null() {
3279 helpers::free_parser_ctxt(ctxt);
3280 return ptr::null_mut();
3281 }
3282
3283 let data: Vec<u8> = {
3285 let pi = &*input;
3286 if !pi.base.is_null() && !pi.end.is_null() && pi.end >= pi.base {
3287 let len = (pi.end as usize).saturating_sub(pi.base as usize);
3288 core::slice::from_raw_parts(pi.base, len).to_vec()
3289 } else if !pi.buf.is_null() {
3290 input_buffer_data(pi.buf)
3291 } else {
3292 Vec::new()
3293 }
3294 };
3295 helpers::free_parser_input(input);
3296
3297 let dtd = parse_dtd_text(ctxt, &data, publicId, systemId);
3298 helpers::free_parser_ctxt(ctxt);
3299 dtd
3300 }
3301}
3302
3303#[no_mangle]
3312pub unsafe extern "C" fn xmlIOParseDTD(
3313 sax: *mut _xmlSAXHandler,
3314 input: *mut _xmlParserInputBuffer,
3315 enc: c_int,
3316) -> *mut _xmlDtd {
3317 if input.is_null() {
3318 return ptr::null_mut();
3319 }
3320 unsafe {
3321 let ctxt = xmlNewSAXParserCtxt(sax, ptr::null_mut());
3322 if ctxt.is_null() {
3323 io::input_buffer_free(input);
3324 return ptr::null_mut();
3325 }
3326 apply_options(ctxt, XML_PARSE_DTDLOAD);
3327 if enc != xmlCharEncoding::XML_CHAR_ENCODING_NONE as c_int {
3328 (*ctxt).charset = enc;
3329 }
3330
3331 let data: Vec<u8> = input_buffer_data(input);
3333 io::input_buffer_free(input);
3334
3335 let dtd = parse_dtd_text(ctxt, &data, ptr::null(), ptr::null());
3336 helpers::free_parser_ctxt(ctxt);
3337 dtd
3338 }
3339}
3340
3341unsafe fn input_buffer_data(buf: *mut _xmlParserInputBuffer) -> Vec<u8> {
3343 unsafe {
3344 if buf.is_null() {
3345 return Vec::new();
3346 }
3347 let b = &*buf;
3348 if let Some(read) = b.readcallback {
3349 let mut out = Vec::new();
3350 let mut tmp = [0u8; 4096];
3351 loop {
3352 let n = read(
3353 b.context,
3354 tmp.as_mut_ptr() as *mut c_char,
3355 tmp.len() as c_int,
3356 );
3357 if n <= 0 {
3358 break;
3359 }
3360 out.extend_from_slice(&tmp[..n as usize]);
3361 }
3362 return out;
3363 }
3364 if !b.buffer.is_null() {
3365 let xbuf = &*(b.buffer as *mut _xmlBuffer);
3366 if !xbuf.content.is_null() && xbuf.use_ > 0 {
3367 return core::slice::from_raw_parts(xbuf.content, xbuf.use_ as usize).to_vec();
3368 }
3369 }
3370 Vec::new()
3371 }
3372}
3373
3374#[no_mangle]
3382pub unsafe extern "C" fn xmlSAXParseEntity(
3383 sax: *mut _xmlSAXHandler,
3384 filename: *const c_char,
3385) -> *mut _xmlDoc {
3386 if filename.is_null() {
3387 return ptr::null_mut();
3388 }
3389 unsafe {
3390 let ctxt = xmlNewSAXParserCtxt(sax, ptr::null_mut());
3391 if ctxt.is_null() {
3392 return ptr::null_mut();
3393 }
3394 let input = match helpers::input_from_file(filename) {
3395 Ok(i) => i,
3396 Err(_) => {
3397 helpers::free_parser_ctxt(ctxt);
3398 return ptr::null_mut();
3399 }
3400 };
3401 helpers::setup_parser_input(ctxt, input);
3402 let rc = helpers::parse_document(ctxt);
3403 let doc = (*ctxt).myDoc;
3404 (*ctxt).myDoc = ptr::null_mut();
3405 if rc != 0 || (*ctxt).wellFormed == 0 {
3406 if !doc.is_null() {
3407 tree::free_doc(doc);
3408 }
3409 helpers::free_parser_ctxt(ctxt);
3410 return ptr::null_mut();
3411 }
3412 helpers::free_parser_ctxt(ctxt);
3413 doc
3414 }
3415}
3416
3417#[no_mangle]
3431pub unsafe extern "C" fn xmlC14NDocSave(
3432 doc: *mut _xmlDoc,
3433 nodes: *mut _xmlNodeSet,
3434 mode: c_int,
3435 inclusive_ns_prefixes: *mut *mut xmlChar,
3436 with_comments: c_int,
3437 filename: *const c_char,
3438 compression: c_int,
3439) -> c_int {
3440 if filename.is_null() {
3441 return -1;
3442 }
3443 unsafe {
3444 let output = io::output_buffer_create_filename(filename, ptr::null_mut(), compression);
3445 if output.is_null() {
3446 return -1;
3447 }
3448 let node_tab = if nodes.is_null() {
3449 ptr::null_mut()
3450 } else {
3451 (*nodes).nodeTab
3452 };
3453 let ret = crate::xml::c14n::xmlC14NDocSaveTo(
3454 doc,
3455 node_tab,
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}