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::{xmlFree, xmlMalloc, xmlMallocZero, xmlMemStrdup, xmlRealloc};
27use crate::abi::callbacks::{
28 xmlGenericErrorFunc, xmlInputCloseCallback, xmlInputReadCallback, xmlOutputCloseCallback,
29 xmlOutputWriteCallback, xmlStructuredErrorFunc,
30};
31use crate::abi::structs::*;
32use crate::abi::types::*;
33use crate::xml::parser::helpers;
34use crate::xml::parser::input::InputBuffer;
35use crate::xml::{dtd, encoding, entities, errors, globals, io, string, tree};
36
37type xmlInputMatchCallback = unsafe extern "C" fn(filename: *const c_char) -> c_int;
44
45type xmlInputOpenCallback = unsafe extern "C" fn(filename: *const c_char) -> *mut c_void;
47
48type xmlOutputMatchCallback = unsafe extern "C" fn(filename: *const c_char) -> c_int;
51
52type xmlOutputOpenCallback = unsafe extern "C" fn(filename: *const c_char) -> *mut c_void;
54
55type xmlExternalEntityLoader = unsafe extern "C" fn(
57 URL: *const c_char,
58 ID: *const c_char,
59 ctxt: *mut _xmlParserCtxt,
60) -> *mut _xmlParserInput;
61
62#[derive(Clone, Copy)]
63struct InputCallbackEntry {
64 matchcb: Option<xmlInputMatchCallback>,
65 opencb: Option<xmlInputOpenCallback>,
66 readcb: Option<xmlInputReadCallback>,
67 closecb: Option<xmlInputCloseCallback>,
68}
69
70#[derive(Clone, Copy)]
71struct OutputCallbackEntry {
72 matchcb: Option<xmlOutputMatchCallback>,
73 opencb: Option<xmlOutputOpenCallback>,
74 writecb: Option<xmlOutputWriteCallback>,
75 closecb: Option<xmlOutputCloseCallback>,
76}
77
78static INPUT_CALLBACKS: Mutex<Vec<InputCallbackEntry>> = Mutex::new(Vec::new());
79static OUTPUT_CALLBACKS: Mutex<Vec<OutputCallbackEntry>> = Mutex::new(Vec::new());
80
81static EXTERNAL_ENTITY_LOADER: Mutex<Option<xmlExternalEntityLoader>> =
82 Mutex::new(Some(default_external_entity_loader));
83
84const XML_ERR_USER_STOP: c_int = 111;
86const XML_ERR_RESOURCE_LIMIT: c_int = 114;
87
88const XML_SCAN_NC: c_int = 1;
90const XML_SCAN_NMTOKEN: c_int = 2;
91const XML_SCAN_OLD10: c_int = 4;
92
93const XML_DETECT_IDS: c_int = 1 << 0;
95const XML_COMPLETE_ATTRS: c_int = 1 << 1;
96
97const LINE_LEN: usize = 80;
99
100const INPUT_CHUNK: usize = 100;
102
103const XML_INVALID_CHAR: c_int = -1;
104
105unsafe fn init_sax_parser_ctxt(
116 ctxt: *mut _xmlParserCtxt,
117 sax: *const _xmlSAXHandler,
118 userData: *mut c_void,
119) -> c_int {
120 unsafe {
121 ptr::write_bytes(ctxt as *mut u8, 0, core::mem::size_of::<_xmlParserCtxt>());
122
123 let c = &mut *ctxt;
124
125 if c.sax.is_null() {
127 let new_sax =
128 xmlMallocZero(core::mem::size_of::<_xmlSAXHandler>()) as *mut _xmlSAXHandler;
129 if new_sax.is_null() {
130 return -1;
131 }
132 c.sax = new_sax;
133 }
134 if sax.is_null() {
135 crate::xml::sax::xmlSAX2InitDefaultSAXHandler(c.sax);
136 c.userData = ctxt as *mut c_void;
137 } else if (*sax).initialized == XML_SAX2_MAGIC as c_uint {
138 ptr::copy_nonoverlapping(sax, c.sax, 1);
140 c.userData = if userData.is_null() {
141 ctxt as *mut c_void
142 } else {
143 userData
144 };
145 } else {
146 ptr::write_bytes(c.sax as *mut u8, 0, core::mem::size_of::<_xmlSAXHandler>());
148 ptr::copy_nonoverlapping(
149 sax as *const u8,
150 c.sax as *mut u8,
151 core::mem::size_of::<_xmlSAXHandlerV1>(),
152 );
153 c.userData = if userData.is_null() {
154 ctxt as *mut c_void
155 } else {
156 userData
157 };
158 }
159
160 c.wellFormed = 1;
161 c.standalone = -1;
162 c.errNo = XML_ERR_OK;
163 c.valid = 1;
164 c.nsWellFormed = 1;
165 c.instate = xmlParserInputState::XML_PARSER_START as c_int;
166 c.keepBlanks = globals::get_keep_blanks_default();
167 c.replaceEntities = globals::get_substitute_entities_default();
168 c.linenumbers = 1;
169 c.charset = xmlCharEncoding::XML_CHAR_ENCODING_UTF8 as c_int;
170 c.pedantic = globals::get_pedantic_parser_default();
171 c.loadsubset = globals::get_load_ext_dtd_default();
172 c.docdict = 1;
173 c.options = 0;
174
175 c.vctxt.userData = ctxt as *mut c_void;
176 c.vctxt.valid = 1;
177 }
178 0
179}
180
181unsafe fn apply_options(ctxt: *mut _xmlParserCtxt, options: c_int) {
188 unsafe {
189 let c = &mut *ctxt;
190 c.options = options;
191 c.recovery = (options & XML_PARSE_RECOVER != 0) as c_int;
192 c.replaceEntities = (options & XML_PARSE_NOENT != 0) as c_int;
193 c.loadsubset = ((options & XML_PARSE_DTDLOAD != 0) as c_int)
194 | if options & XML_PARSE_DTDATTR != 0 {
195 XML_COMPLETE_ATTRS
196 } else {
197 0
198 };
199 c.validate = (options & XML_PARSE_DTDVALID != 0) as c_int;
200 c.pedantic = (options & XML_PARSE_PEDANTIC != 0) as c_int;
201 c.keepBlanks = if options & XML_PARSE_NOBLANKS != 0 { 0 } else { 1 };
202 c.dictNames = if options & XML_PARSE_NODICT != 0 { 0 } else { 1 };
203 }
204}
205
206unsafe fn encoding_handler_for(enc: c_int) -> *mut _xmlCharEncodingHandler {
208 let e: xmlCharEncoding = unsafe { core::mem::transmute(enc) };
209 match encoding::encoding_name(e) {
210 Some(name) => {
211 let mut nul = name.to_vec();
212 nul.push(0);
213 encoding::find_encoding_handler(nul.as_ptr() as *const xmlChar)
214 }
215 None => ptr::null_mut(),
216 }
217}
218
219unsafe fn parser_input_from_buf(buf: *mut _xmlParserInputBuffer) -> *mut _xmlParserInput {
228 let input = unsafe { xmlMallocZero(core::mem::size_of::<_xmlParserInput>()) }
229 as *mut _xmlParserInput;
230 if input.is_null() {
231 return ptr::null_mut();
232 }
233 unsafe {
234 (*input).buf = buf;
235 (*input).line = 1;
236 (*input).col = 1;
237 if !buf.is_null() {
238 let b = &*buf;
239 if !b.buffer.is_null() {
240 let xbuf = &*(b.buffer as *mut _xmlBuffer);
241 if !xbuf.content.is_null() {
242 (*input).base = xbuf.content;
243 (*input).cur = xbuf.content;
244 (*input).end = xbuf.content.add(xbuf.use_ as usize);
245 (*input).length = xbuf.use_ as c_int;
246 }
247 }
248 }
249 }
250 input
251}
252
253unsafe fn input_buffer_from_parser_input(input: *mut _xmlParserInput) -> InputBuffer {
260 unsafe {
261 let pi = &*input;
262 if !pi.buf.is_null() {
263 let b = &*pi.buf;
264 if let Some(read) = b.readcallback {
265 return helpers::input_from_io(Some(read), b.closecallback, b.context);
266 }
267 }
268 if !pi.base.is_null() && !pi.end.is_null() && pi.end >= pi.base {
269 let len = (pi.end as usize).saturating_sub(pi.base as usize);
270 let slice = core::slice::from_raw_parts(pi.base, len);
271 return InputBuffer::from_memory(slice, None);
272 }
273 InputBuffer::from_memory(&[], None)
274 }
275}
276
277unsafe fn ctxt_read_doc(
284 ctxt: *mut _xmlParserCtxt,
285 input: InputBuffer,
286 url: *const c_char,
287 options: c_int,
288) -> *mut _xmlDoc {
289 unsafe {
290 xmlCtxtReset(ctxt);
291 apply_options(ctxt, options);
292 helpers::setup_parser_input(ctxt, input);
293 if helpers::parse_document(ctxt) != 0 {
294 let doc = (*ctxt).myDoc;
295 (*ctxt).myDoc = ptr::null_mut();
296 if options & XML_PARSE_RECOVER != 0 {
297 return doc;
298 }
299 if !doc.is_null() {
300 tree::free_doc(doc);
301 }
302 return ptr::null_mut();
303 }
304 let doc = (*ctxt).myDoc;
305 if !doc.is_null() && !url.is_null() {
306 (*doc).URL = string::xml_strdup(url as *const xmlChar);
307 }
308 doc
309 }
310}
311
312unsafe fn parse_dtd_text(
323 ctxt: *mut _xmlParserCtxt,
324 data: &[u8],
325 public_id: *const xmlChar,
326 system_id: *const xmlChar,
327) -> *mut _xmlDtd {
328 unsafe {
329 let has_doctype = data
332 .windows(9)
333 .any(|w| w.eq_ignore_ascii_case(b"<!DOCTYPE"));
334 let mut wrapped: Vec<u8>;
335 let parse_data: &[u8] = if has_doctype {
336 data
337 } else {
338 wrapped = Vec::with_capacity(data.len() + 32);
339 wrapped.extend_from_slice(b"<!DOCTYPE none [");
340 wrapped.extend_from_slice(data);
341 wrapped.extend_from_slice(b"]><none/>");
342 &wrapped
343 };
344
345 let input = InputBuffer::from_memory(parse_data, None);
346 helpers::setup_parser_input(ctxt, input);
347 let rc = helpers::parse_document(ctxt);
348 let doc = (*ctxt).myDoc;
349 (*ctxt).myDoc = ptr::null_mut();
350
351 if rc == 0 && !doc.is_null() && !(*doc).intSubset.is_null() {
352 let dtd = (*doc).intSubset;
353 (*doc).intSubset = ptr::null_mut();
354 (*dtd).parent = ptr::null_mut();
355 (*dtd).doc = ptr::null_mut();
356 if !public_id.is_null() {
357 (*dtd).ExternalID = string::xml_strdup(public_id);
358 }
359 if !system_id.is_null() {
360 (*dtd).SystemID = string::xml_strdup(system_id);
361 }
362 tree::free_doc(doc);
363 return dtd;
364 }
365
366 if !doc.is_null() {
367 tree::free_doc(doc);
368 }
369 let dtd = dtd::new_dtd(ptr::null_mut(), b"none\0".as_ptr(), public_id, system_id);
371 dtd
372 }
373}
374
375#[no_mangle]
387pub unsafe extern "C" fn xmlNewParserCtxt() -> *mut _xmlParserCtxt {
388 unsafe {
389 globals::init_parser();
390 let ctxt = xmlMallocZero(core::mem::size_of::<_xmlParserCtxt>()) as *mut _xmlParserCtxt;
391 if ctxt.is_null() {
392 return ptr::null_mut();
393 }
394 if init_sax_parser_ctxt(ctxt, ptr::null(), ptr::null_mut()) < 0 {
395 helpers::free_parser_ctxt(ctxt);
396 return ptr::null_mut();
397 }
398 ctxt
399 }
400}
401
402#[no_mangle]
411pub unsafe extern "C" fn xmlNewSAXParserCtxt(
412 sax: *const _xmlSAXHandler,
413 userData: *mut c_void,
414) -> *mut _xmlParserCtxt {
415 unsafe {
416 globals::init_parser();
417 let ctxt = xmlMallocZero(core::mem::size_of::<_xmlParserCtxt>()) as *mut _xmlParserCtxt;
418 if ctxt.is_null() {
419 return ptr::null_mut();
420 }
421 if init_sax_parser_ctxt(ctxt, sax, userData) < 0 {
422 helpers::free_parser_ctxt(ctxt);
423 return ptr::null_mut();
424 }
425 ctxt
426 }
427}
428
429#[no_mangle]
438pub unsafe extern "C" fn xmlInitParserCtxt(ctxt: *mut _xmlParserCtxt) -> c_int {
439 unsafe { init_sax_parser_ctxt(ctxt, ptr::null(), ptr::null_mut()) }
440}
441
442#[no_mangle]
450pub unsafe extern "C" fn xmlClearParserCtxt(ctxt: *mut _xmlParserCtxt) {
451 unsafe { xmlCtxtReset(ctxt) }
452}
453
454#[no_mangle]
463pub unsafe extern "C" fn xmlCtxtReset(ctxt: *mut _xmlParserCtxt) {
464 if ctxt.is_null() {
465 return;
466 }
467 unsafe {
468 let c = &mut *ctxt;
469
470 let input_nr = c.inputNr;
472 let input_tab = c.inputTab;
473 if !input_tab.is_null() {
474 for i in 0..input_nr {
475 let input = *input_tab.add(i as usize);
476 if !input.is_null() {
477 helpers::free_parser_input(input);
478 }
479 }
480 xmlFree(input_tab as *mut c_void);
481 }
482 c.inputTab = ptr::null_mut();
483 c.inputMax = 0;
484 c.inputNr = 0;
485 c.input = ptr::null_mut();
486
487 if !c._private.is_null() {
489 let _ = Box::from_raw(c._private as *mut InputBuffer);
490 c._private = ptr::null_mut();
491 }
492
493 if !c.nodeTab.is_null() {
495 xmlFree(c.nodeTab as *mut c_void);
496 }
497 c.nodeTab = ptr::null_mut();
498 c.nodeMax = 0;
499 c.nodeNr = 0;
500 c.node = ptr::null_mut();
501
502 if !c.nameTab.is_null() {
504 xmlFree(c.nameTab as *mut c_void);
505 }
506 c.nameTab = ptr::null_mut();
507 c.nameMax = 0;
508 c.nameNr = 0;
509 c.name = ptr::null();
510
511 c.spaceNr = 0;
513 c.space = ptr::null_mut();
514
515 c.nsNr = 0;
517
518 if !c.version.is_null() {
520 xmlFree(c.version as *mut c_void);
521 c.version = ptr::null_mut();
522 }
523 if !c.encoding.is_null() {
524 xmlFree(c.encoding as *mut c_void);
525 c.encoding = ptr::null_mut();
526 }
527 if !c.extSubURI.is_null() {
528 xmlFree(c.extSubURI as *mut c_void);
529 c.extSubURI = ptr::null_mut();
530 }
531 if !c.extSubSystem.is_null() {
532 xmlFree(c.extSubSystem as *mut c_void);
533 c.extSubSystem = ptr::null_mut();
534 }
535 if !c.directory.is_null() {
536 xmlFree(c.directory as *mut c_void);
537 c.directory = ptr::null_mut();
538 }
539
540 if !c.myDoc.is_null() {
542 tree::free_doc(c.myDoc);
543 }
544 c.myDoc = ptr::null_mut();
545
546 c.standalone = -1;
548 c.hasExternalSubset = 0;
549 c.hasPErefs = 0;
550 c.instate = xmlParserInputState::XML_PARSER_START as c_int;
551 c.wellFormed = 1;
552 c.nsWellFormed = 1;
553 c.disableSAX = 0;
554 c.valid = 1;
555 c.record_info = 0;
556 c.checkIndex = 0;
557 c.inSubset = 0;
558 c.errNo = XML_ERR_OK;
559 c.depth = 0;
560 c.nbentities = 0;
561 c.sizeentities = 0;
562 c.nbErrors = 0;
563 c.nbWarnings = 0;
564
565 xmlInitNodeInfoSeq(&mut c.node_seq);
566
567 if c.lastError.code != XML_ERR_OK {
568 errors::reset_error(&mut c.lastError);
569 }
570 }
571}
572
573#[no_mangle]
582pub unsafe extern "C" fn xmlCtxtResetPush(
583 ctxt: *mut _xmlParserCtxt,
584 chunk: *const c_char,
585 size: c_int,
586 filename: *const c_char,
587 encoding: *const c_char,
588) -> c_int {
589 if ctxt.is_null() {
590 return 1;
591 }
592 unsafe {
593 xmlCtxtReset(ctxt);
594
595 let slice = if size > 0 && !chunk.is_null() {
596 core::slice::from_raw_parts(chunk as *const u8, size as usize)
597 } else {
598 &[]
599 };
600 let uri = if filename.is_null() {
601 None
602 } else {
603 CStr::from_ptr(filename).to_str().ok()
604 };
605 let input = InputBuffer::from_memory(slice, uri);
606 helpers::setup_parser_input(ctxt, input);
607
608 if !encoding.is_null() {
609 let handler = encoding::find_encoding_handler(encoding as *const xmlChar);
610 if !handler.is_null() {
611 xmlSwitchToEncoding(ctxt, handler);
612 }
613 }
614 }
615 0
616}
617
618#[no_mangle]
626pub unsafe extern "C" fn xmlCtxtSetOptions(ctxt: *mut _xmlParserCtxt, options: c_int) -> c_int {
627 if ctxt.is_null() {
628 return -1;
629 }
630 const ALL_MASK: c_int = XML_PARSE_RECOVER
631 | XML_PARSE_NOENT
632 | XML_PARSE_DTDLOAD
633 | XML_PARSE_DTDATTR
634 | XML_PARSE_DTDVALID
635 | XML_PARSE_NOERROR
636 | XML_PARSE_NOWARNING
637 | XML_PARSE_PEDANTIC
638 | XML_PARSE_NOBLANKS
639 | XML_PARSE_SAX1
640 | XML_PARSE_NONET
641 | XML_PARSE_NODICT
642 | XML_PARSE_NSCLEAN
643 | XML_PARSE_NOCDATA
644 | XML_PARSE_COMPACT
645 | XML_PARSE_OLD10
646 | XML_PARSE_HUGE
647 | XML_PARSE_OLDSAX
648 | XML_PARSE_IGNORE_ENC
649 | XML_PARSE_BIG_LINES;
650
651 unsafe {
652 apply_options(ctxt, options & ALL_MASK);
653 }
654 options & !ALL_MASK
655}
656
657#[no_mangle]
666pub unsafe extern "C" fn xmlCtxtSetErrorHandler(
667 ctxt: *mut _xmlParserCtxt,
668 handler: Option<xmlStructuredErrorFunc>,
669 data: *mut c_void,
670) {
671 if ctxt.is_null() {
672 return;
673 }
674 unsafe {
675 (*ctxt).errorHandler = handler;
676 (*ctxt).errorCtxt = data;
677 }
678}
679
680#[no_mangle]
688pub unsafe extern "C" fn xmlCtxtSetMaxAmplification(ctxt: *mut _xmlParserCtxt, maxAmpl: c_uint) {
689 if ctxt.is_null() || maxAmpl == 0 {
690 return;
691 }
692 unsafe {
693 (*ctxt).maxAmpl = maxAmpl;
694 }
695}
696
697#[no_mangle]
705pub unsafe extern "C" fn xmlCtxtGetLastError(ctx: *mut c_void) -> *const _xmlError {
706 if ctx.is_null() {
707 return ptr::null();
708 }
709 let ctxt = ctx as *mut _xmlParserCtxt;
710 unsafe {
711 if (*ctxt).lastError.code == XML_ERR_OK {
712 return ptr::null();
713 }
714 &(*ctxt).lastError
715 }
716}
717
718#[no_mangle]
726pub unsafe extern "C" fn xmlCtxtResetLastError(ctx: *mut c_void) {
727 if ctx.is_null() {
728 return;
729 }
730 let ctxt = ctx as *mut _xmlParserCtxt;
731 unsafe {
732 (*ctxt).errNo = XML_ERR_OK;
733 if (*ctxt).lastError.code != XML_ERR_OK {
734 errors::reset_error(&mut (*ctxt).lastError);
735 }
736 }
737}
738
739#[no_mangle]
747pub unsafe extern "C" fn xmlCtxtErrMemory(ctxt: *mut _xmlParserCtxt) {
748 if ctxt.is_null() {
749 return;
750 }
751 unsafe {
752 let c = &mut *ctxt;
753 c.errNo = XML_ERR_NO_MEMORY;
754 c.instate = xmlParserInputState::XML_PARSER_EOF as c_int;
755 c.wellFormed = 0;
756 c.disableSAX = 2;
757
758 c.lastError.domain = XML_FROM_PARSER;
759 c.lastError.code = XML_ERR_NO_MEMORY;
760 c.lastError.level = xmlErrorLevel::XML_ERR_FATAL as c_int;
761 c.lastError.message = b"out of memory\n\0".as_ptr() as *mut c_char;
762
763 if let Some(handler) = c.errorHandler {
764 handler(c.errorCtxt, &c.lastError);
765 } else if !c.sax.is_null() {
766 if let Some(serror) = (*c.sax).serror {
767 serror(c.userData, &c.lastError);
768 }
769 }
770 }
771}
772
773#[no_mangle]
781pub unsafe extern "C" fn xmlStopParser(ctxt: *mut _xmlParserCtxt) {
782 if ctxt.is_null() {
783 return;
784 }
785 unsafe {
786 (*ctxt).disableSAX = 2;
787 if (*ctxt).errNo == XML_ERR_OK {
788 (*ctxt).errNo = XML_ERR_USER_STOP;
789 (*ctxt).lastError.code = XML_ERR_USER_STOP;
790 (*ctxt).wellFormed = 0;
791 }
792 }
793}
794
795#[no_mangle]
804pub unsafe extern "C" fn xmlByteConsumed(ctxt: *mut _xmlParserCtxt) -> c_long {
805 if ctxt.is_null() {
806 return -1;
807 }
808 unsafe {
809 let input = (*ctxt).input;
810 if input.is_null() {
811 return -1;
812 }
813 if !(*input).buf.is_null() && !(*(*input).buf).encoder.is_null() {
814 return (*(*input).buf).rawconsumed as c_long;
817 }
818 let consumed = (*input).consumed;
819 if (*input).base.is_null() {
820 return consumed as c_long;
821 }
822 (consumed + ((*input).cur as usize).saturating_sub((*input).base as usize) as c_ulong)
823 as c_long
824 }
825}
826
827#[no_mangle]
835pub unsafe extern "C" fn xmlParserGetDirectory(filename: *const c_char) -> *mut c_char {
836 if filename.is_null() {
837 return ptr::null_mut();
838 }
839 unsafe {
840 let len = libc::strlen(filename);
841 let mut last_sep: Option<usize> = None;
842 for i in 0..len {
843 if *filename.add(i) == b'/' as c_char {
844 last_sep = Some(i);
845 }
846 }
847 match last_sep {
848 Some(0) => xmlMemStrdup(b"/\0".as_ptr() as *const c_char) as *mut c_char,
849 Some(pos) => {
850 let slice = core::slice::from_raw_parts(filename as *const u8, pos);
851 let mut v = slice.to_vec();
852 v.push(0);
853 xmlMemStrdup(v.as_ptr() as *const c_char) as *mut c_char
854 }
855 None => xmlMemStrdup(b".\0".as_ptr() as *const c_char) as *mut c_char,
856 }
857 }
858}
859
860#[no_mangle]
869pub unsafe extern "C" fn xmlCheckFilename(path: *const c_char) -> c_int {
870 if path.is_null() {
871 return 0;
872 }
873 unsafe {
874 let mut st: libc::stat = core::mem::zeroed();
875 if libc::stat(path, &mut st) != 0 {
876 return 0;
877 }
878 if st.st_mode & libc::S_IFMT == libc::S_IFDIR {
879 2
880 } else {
881 1
882 }
883 }
884}
885
886#[no_mangle]
894pub unsafe extern "C" fn xmlIsXHTML(
895 systemID: *const xmlChar,
896 publicID: *const xmlChar,
897) -> c_int {
898 const XHTML_STRICT_PUBLIC_ID: &[u8] = b"-//W3C//DTD XHTML 1.0 Strict//EN\0";
899 const XHTML_STRICT_SYSTEM_ID: &[u8] = b"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\0";
900 const XHTML_FRAME_PUBLIC_ID: &[u8] = b"-//W3C//DTD XHTML 1.0 Frameset//EN\0";
901 const XHTML_FRAME_SYSTEM_ID: &[u8] = b"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd\0";
902 const XHTML_TRANS_PUBLIC_ID: &[u8] = b"-//W3C//DTD XHTML 1.0 Transitional//EN\0";
903 const XHTML_TRANS_SYSTEM_ID: &[u8] =
904 b"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\0";
905
906 if systemID.is_null() && publicID.is_null() {
907 return -1;
908 }
909 unsafe {
910 if !publicID.is_null() {
911 if string::xml_strcmp(publicID, XHTML_STRICT_PUBLIC_ID.as_ptr() as *const xmlChar) == 0
912 || string::xml_strcmp(
913 publicID,
914 XHTML_FRAME_PUBLIC_ID.as_ptr() as *const xmlChar,
915 ) == 0
916 || string::xml_strcmp(
917 publicID,
918 XHTML_TRANS_PUBLIC_ID.as_ptr() as *const xmlChar,
919 ) == 0
920 {
921 return 1;
922 }
923 }
924 if !systemID.is_null() {
925 if string::xml_strcmp(systemID, XHTML_STRICT_SYSTEM_ID.as_ptr() as *const xmlChar) == 0
926 || string::xml_strcmp(systemID, XHTML_FRAME_SYSTEM_ID.as_ptr() as *const xmlChar)
927 == 0
928 || string::xml_strcmp(
929 systemID,
930 XHTML_TRANS_SYSTEM_ID.as_ptr() as *const xmlChar,
931 ) == 0
932 {
933 return 1;
934 }
935 }
936 }
937 0
938}
939
940#[no_mangle]
952pub unsafe extern "C" fn xmlCreateMemoryParserCtxt(
953 buffer: *const c_char,
954 size: c_int,
955) -> *mut _xmlParserCtxt {
956 if buffer.is_null() || size < 0 {
957 return ptr::null_mut();
958 }
959 unsafe {
960 let ctxt = xmlNewParserCtxt();
961 if ctxt.is_null() {
962 return ptr::null_mut();
963 }
964 let input = helpers::input_from_memory(buffer, size);
965 helpers::setup_parser_input(ctxt, input);
966 ctxt
967 }
968}
969
970#[no_mangle]
980pub unsafe extern "C" fn xmlCreatePushParserCtxt(
981 sax: *mut _xmlSAXHandler,
982 user_data: *mut c_void,
983 chunk: *const c_char,
984 size: c_int,
985 filename: *const c_char,
986) -> *mut _xmlParserCtxt {
987 unsafe {
988 let ctxt = xmlNewSAXParserCtxt(sax, user_data);
989 if ctxt.is_null() {
990 return ptr::null_mut();
991 }
992 let slice = if size > 0 && !chunk.is_null() {
993 core::slice::from_raw_parts(chunk as *const u8, size as usize)
994 } else {
995 &[]
996 };
997 let uri = if filename.is_null() {
998 None
999 } else {
1000 CStr::from_ptr(filename).to_str().ok()
1001 };
1002 let input = InputBuffer::from_memory(slice, uri);
1003 helpers::setup_parser_input(ctxt, input);
1004 ctxt
1005 }
1006}
1007
1008#[no_mangle]
1019pub unsafe extern "C" fn xmlCreateIOParserCtxt(
1020 sax: *mut _xmlSAXHandler,
1021 user_data: *mut c_void,
1022 ioread: Option<xmlInputReadCallback>,
1023 ioclose: Option<xmlInputCloseCallback>,
1024 ioctx: *mut c_void,
1025 enc: c_int,
1026) -> *mut _xmlParserCtxt {
1027 unsafe {
1028 let ctxt = xmlNewSAXParserCtxt(sax, user_data);
1029 if ctxt.is_null() {
1030 return ptr::null_mut();
1031 }
1032 let input = helpers::input_from_io(ioread, ioclose, ioctx);
1033 helpers::setup_parser_input(ctxt, input);
1034 if enc != xmlCharEncoding::XML_CHAR_ENCODING_NONE as c_int {
1035 xmlSwitchEncoding(ctxt, enc);
1036 }
1037 ctxt
1038 }
1039}
1040
1041#[no_mangle]
1049pub unsafe extern "C" fn xmlCreateURLParserCtxt(
1050 filename: *const c_char,
1051 options: c_int,
1052) -> *mut _xmlParserCtxt {
1053 if filename.is_null() {
1054 return ptr::null_mut();
1055 }
1056 unsafe {
1057 let ctxt = xmlNewParserCtxt();
1058 if ctxt.is_null() {
1059 return ptr::null_mut();
1060 }
1061 apply_options(ctxt, options);
1062 let input = match helpers::input_from_file(filename) {
1063 Ok(i) => i,
1064 Err(_) => {
1065 helpers::free_parser_ctxt(ctxt);
1066 return ptr::null_mut();
1067 }
1068 };
1069 helpers::setup_parser_input(ctxt, input);
1070 ctxt
1071 }
1072}
1073
1074#[no_mangle]
1084pub unsafe extern "C" fn xmlCreateEntityParserCtxt(
1085 URL: *const xmlChar,
1086 ID: *const xmlChar,
1087 base: *const xmlChar,
1088) -> *mut _xmlParserCtxt {
1089 let _ = base; unsafe {
1091 let ctxt = xmlNewParserCtxt();
1092 if ctxt.is_null() {
1093 return ptr::null_mut();
1094 }
1095 let input = xmlLoadExternalEntity(URL as *const c_char, ID as *const c_char, ctxt);
1096 if input.is_null() {
1097 helpers::free_parser_ctxt(ctxt);
1098 return ptr::null_mut();
1099 }
1100 if xmlPushInput(ctxt, input) < 0 {
1101 helpers::free_parser_input(input);
1102 helpers::free_parser_ctxt(ctxt);
1103 return ptr::null_mut();
1104 }
1105 ctxt
1106 }
1107}
1108
1109#[no_mangle]
1122pub unsafe extern "C" fn xmlCtxtReadDoc(
1123 ctxt: *mut _xmlParserCtxt,
1124 cur: *const xmlChar,
1125 URL: *const c_char,
1126 _encoding: *const c_char,
1127 options: c_int,
1128) -> *mut _xmlDoc {
1129 if ctxt.is_null() || cur.is_null() {
1130 return ptr::null_mut();
1131 }
1132 unsafe {
1133 let len = string::xml_strlen(cur);
1134 let input = helpers::input_from_memory(cur as *const c_char, len as c_int);
1135 ctxt_read_doc(ctxt, input, URL, options)
1136 }
1137}
1138
1139#[no_mangle]
1148pub unsafe extern "C" fn xmlCtxtReadFile(
1149 ctxt: *mut _xmlParserCtxt,
1150 filename: *const c_char,
1151 _encoding: *const c_char,
1152 options: c_int,
1153) -> *mut _xmlDoc {
1154 if ctxt.is_null() || filename.is_null() {
1155 return ptr::null_mut();
1156 }
1157 unsafe {
1158 match helpers::input_from_file(filename) {
1159 Ok(input) => ctxt_read_doc(ctxt, input, filename, options),
1160 Err(_) => ptr::null_mut(),
1161 }
1162 }
1163}
1164
1165#[no_mangle]
1175pub unsafe extern "C" fn xmlCtxtReadMemory(
1176 ctxt: *mut _xmlParserCtxt,
1177 buffer: *const c_char,
1178 size: c_int,
1179 URL: *const c_char,
1180 _encoding: *const c_char,
1181 options: c_int,
1182) -> *mut _xmlDoc {
1183 if ctxt.is_null() || buffer.is_null() || size < 0 {
1184 return ptr::null_mut();
1185 }
1186 unsafe {
1187 let input = helpers::input_from_memory(buffer, size);
1188 ctxt_read_doc(ctxt, input, URL, options)
1189 }
1190}
1191
1192#[no_mangle]
1201pub unsafe extern "C" fn xmlCtxtReadFd(
1202 ctxt: *mut _xmlParserCtxt,
1203 fd: c_int,
1204 URL: *const c_char,
1205 _encoding: *const c_char,
1206 options: c_int,
1207) -> *mut _xmlDoc {
1208 if ctxt.is_null() || fd < 0 {
1209 return ptr::null_mut();
1210 }
1211 unsafe {
1212 let mut buf = Vec::new();
1213 let mut tmp = [0u8; 4096];
1214 loop {
1215 let n = libc::read(fd, tmp.as_mut_ptr() as *mut c_void, tmp.len());
1216 if n <= 0 {
1217 break;
1218 }
1219 buf.extend_from_slice(&tmp[..n as usize]);
1220 }
1221 let input =
1222 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 xmlFree(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 && enc != xmlCharEncoding::XML_CHAR_ENCODING_ERROR as c_int {
1334 let handler = encoding_handler_for(enc);
1335 if !handler.is_null() {
1336 b.encoder = handler as *mut c_void;
1337 }
1338 }
1339 buf
1340 }
1341}
1342
1343#[no_mangle]
1351pub unsafe extern "C" fn xmlParserInputBufferGrow(
1352 in_: *mut _xmlParserInputBuffer,
1353 len: c_int,
1354) -> c_int {
1355 if in_.is_null() || len <= 0 {
1356 return 0;
1357 }
1358 unsafe {
1359 let b = &mut *in_;
1360 if b.error != 0 {
1361 return -1;
1362 }
1363 let Some(read_cb) = b.readcallback else {
1364 return 0;
1366 };
1367 let mut tmp = vec![0u8; len as usize];
1368 let n = read_cb(b.context, tmp.as_mut_ptr() as *mut c_char, len);
1369 if n < 0 {
1370 b.error = 1;
1371 return -1;
1372 }
1373 if n == 0 {
1374 return 0;
1375 }
1376 io::input_buffer_push(in_, tmp.as_ptr() as *const c_char, n);
1377 n
1378 }
1379}
1380
1381#[no_mangle]
1389pub unsafe extern "C" fn xmlParserInputBufferPush(
1390 in_: *mut _xmlParserInputBuffer,
1391 len: c_int,
1392 buf: *const c_char,
1393) -> c_int {
1394 if in_.is_null() {
1395 return -1;
1396 }
1397 if len < 0 || (len > 0 && buf.is_null()) {
1398 return -1;
1399 }
1400 if len == 0 {
1401 return 0;
1402 }
1403 io::input_buffer_push(in_, buf, len)
1404}
1405
1406#[no_mangle]
1414pub unsafe extern "C" fn xmlParserInputBufferRead(
1415 in_: *mut _xmlParserInputBuffer,
1416 len: c_int,
1417) -> c_int {
1418 xmlParserInputBufferGrow(in_, len)
1419}
1420
1421#[no_mangle]
1429pub unsafe extern "C" fn xmlParserInputRead(_in_: *mut _xmlParserInput, _len: c_int) -> c_int {
1430 -1
1431}
1432
1433#[no_mangle]
1441pub unsafe extern "C" fn xmlParserInputGrow(in_: *mut _xmlParserInput, len: c_int) -> c_int {
1442 if in_.is_null() || len < 0 {
1443 return -1;
1444 }
1445 unsafe {
1446 let pi = &*in_;
1447 if pi.base.is_null() || pi.cur.is_null() {
1448 return -1;
1449 }
1450 if pi.buf.is_null() {
1451 return 0;
1453 }
1454 let b = &*pi.buf;
1455 if b.readcallback.is_none() && b.encoder.is_null() {
1457 return 0;
1458 }
1459 xmlParserInputBufferGrow(pi.buf, len)
1460 }
1461}
1462
1463#[no_mangle]
1471pub unsafe extern "C" fn xmlParserInputShrink(in_: *mut _xmlParserInput) {
1472 if in_.is_null() {
1473 return;
1474 }
1475 unsafe {
1476 let pi = &mut *in_;
1477 if pi.buf.is_null() || pi.base.is_null() || pi.cur.is_null() {
1478 return;
1479 }
1480 let used = (pi.cur as usize).saturating_sub(pi.base as usize);
1481 if used > LINE_LEN {
1482 pi.consumed = pi.consumed.saturating_add((used - LINE_LEN) as c_ulong);
1485 }
1486 }
1487}
1488
1489#[no_mangle]
1497pub unsafe extern "C" fn xmlNewInputStream(ctxt: *mut _xmlParserCtxt) -> *mut _xmlParserInput {
1498 unsafe {
1499 let input = xmlMallocZero(core::mem::size_of::<_xmlParserInput>())
1500 as *mut _xmlParserInput;
1501 if input.is_null() {
1502 if !ctxt.is_null() {
1503 xmlCtxtErrMemory(ctxt);
1504 }
1505 return ptr::null_mut();
1506 }
1507 (*input).line = 1;
1508 (*input).col = 1;
1509 input
1510 }
1511}
1512
1513#[no_mangle]
1523pub unsafe extern "C" fn xmlNewIOInputStream(
1524 ctxt: *mut _xmlParserCtxt,
1525 input: *mut _xmlParserInputBuffer,
1526 enc: c_int,
1527) -> *mut _xmlParserInput {
1528 if ctxt.is_null() || input.is_null() {
1529 return ptr::null_mut();
1530 }
1531 unsafe {
1532 let pi = xmlNewInputStream(ctxt);
1533 if pi.is_null() {
1534 return ptr::null_mut();
1535 }
1536 (*pi).buf = input;
1537 if enc != xmlCharEncoding::XML_CHAR_ENCODING_NONE as c_int && enc != xmlCharEncoding::XML_CHAR_ENCODING_ERROR as c_int {
1538 let handler = encoding_handler_for(enc);
1539 if !handler.is_null() {
1540 io::input_buffer_set_encoder(input, handler);
1541 }
1542 }
1543 pi
1544 }
1545}
1546
1547#[no_mangle]
1557pub unsafe extern "C" fn xmlNewStringInputStream(
1558 ctxt: *mut _xmlParserCtxt,
1559 buffer: *const xmlChar,
1560) -> *mut _xmlParserInput {
1561 if ctxt.is_null() || buffer.is_null() {
1562 return ptr::null_mut();
1563 }
1564 unsafe {
1565 let input = xmlNewInputStream(ctxt);
1566 if input.is_null() {
1567 return ptr::null_mut();
1568 }
1569 let len = string::xml_strlen(buffer);
1570 (*input).base = buffer;
1571 (*input).cur = buffer;
1572 (*input).end = buffer.add(len);
1573 (*input).length = len as c_int;
1574 input
1575 }
1576}
1577
1578#[no_mangle]
1587pub unsafe extern "C" fn xmlSetupParserForBuffer(
1588 ctxt: *mut _xmlParserCtxt,
1589 buffer: *const xmlChar,
1590 filename: *const c_char,
1591) {
1592 if ctxt.is_null() || buffer.is_null() {
1593 return;
1594 }
1595 unsafe {
1596 xmlCtxtReset(ctxt);
1597 let len = string::xml_strlen(buffer);
1598 let uri = if filename.is_null() {
1599 None
1600 } else {
1601 CStr::from_ptr(filename).to_str().ok()
1602 };
1603 let input = InputBuffer::from_memory(
1604 core::slice::from_raw_parts(buffer, len),
1605 uri,
1606 );
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 = xmlRealloc(
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 xmlFree((*seq).block as *mut c_void);
1833 }
1834 if !(*seq).index.is_null() {
1835 xmlFree((*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 { 4 } else { seq.block_max * 2 };
1939 let new_block = xmlRealloc(
1940 seq.block as *mut c_void,
1941 (new_max as usize) * core::mem::size_of::<_xmlParserNodeInfo>(),
1942 ) as *mut _xmlParserNodeInfo;
1943 if new_block.is_null() {
1944 xmlCtxtErrMemory(ctxt);
1945 return;
1946 }
1947 seq.block = new_block;
1948 seq.block_max = new_max;
1949 }
1950
1951 let size = seq.size as usize;
1953 for i in (pos + 1..=size).rev() {
1954 ptr::copy_nonoverlapping(seq.block.add(i - 1), seq.block.add(i), 1);
1955 }
1956 ptr::copy_nonoverlapping(info, seq.block.add(pos), 1);
1957 seq.size += 1;
1958 }
1959}
1960
1961#[no_mangle]
1976pub unsafe extern "C" fn xmlRegisterInputCallbacks(
1977 matchFunc: Option<xmlInputMatchCallback>,
1978 openFunc: Option<xmlInputOpenCallback>,
1979 readFunc: Option<xmlInputReadCallback>,
1980 closeFunc: Option<xmlInputCloseCallback>,
1981) -> c_int {
1982 unsafe {
1983 globals::init_parser();
1984 }
1985 let mut table = INPUT_CALLBACKS.lock();
1986 if table.len() >= 10 {
1987 return -1;
1988 }
1989 table.push(InputCallbackEntry {
1990 matchcb: matchFunc,
1991 opencb: openFunc,
1992 readcb: readFunc,
1993 closecb: closeFunc,
1994 });
1995 (table.len() - 1) as c_int
1996}
1997
1998#[no_mangle]
2006pub unsafe extern "C" fn xmlRegisterDefaultInputCallbacks() {
2007 unsafe {
2008 xmlRegisterInputCallbacks(
2009 Some(xmlFileMatch),
2010 Some(xmlFileOpen),
2011 Some(xmlFileRead),
2012 Some(xmlFileClose),
2013 );
2014 }
2015}
2016
2017#[no_mangle]
2025pub unsafe extern "C" fn xmlPopInputCallbacks() -> c_int {
2026 unsafe {
2027 globals::init_parser();
2028 }
2029 let mut table = INPUT_CALLBACKS.lock();
2030 if table.is_empty() {
2031 return -1;
2032 }
2033 table.pop();
2034 table.len() as c_int
2035}
2036
2037#[no_mangle]
2045pub unsafe extern "C" fn xmlCleanupInputCallbacks() {
2046 unsafe {
2047 globals::init_parser();
2048 }
2049 INPUT_CALLBACKS.lock().clear();
2050}
2051
2052#[no_mangle]
2063pub unsafe extern "C" fn xmlRegisterOutputCallbacks(
2064 matchFunc: Option<xmlOutputMatchCallback>,
2065 openFunc: Option<xmlOutputOpenCallback>,
2066 writeFunc: Option<xmlOutputWriteCallback>,
2067 closeFunc: Option<xmlOutputCloseCallback>,
2068) -> c_int {
2069 unsafe {
2070 globals::init_parser();
2071 }
2072 let mut table = OUTPUT_CALLBACKS.lock();
2073 if table.len() >= 10 {
2074 return -1;
2075 }
2076 table.push(OutputCallbackEntry {
2077 matchcb: matchFunc,
2078 opencb: openFunc,
2079 writecb: writeFunc,
2080 closecb: closeFunc,
2081 });
2082 (table.len() - 1) as c_int
2083}
2084
2085#[no_mangle]
2093pub unsafe extern "C" fn xmlRegisterDefaultOutputCallbacks() {
2094 unsafe {
2095 xmlRegisterOutputCallbacks(Some(xmlFileMatch), None, None, None);
2096 }
2097}
2098
2099#[no_mangle]
2107pub unsafe extern "C" fn xmlRegisterHTTPPostCallbacks() {
2108 unsafe { xmlRegisterDefaultOutputCallbacks() }
2109}
2110
2111#[no_mangle]
2119pub unsafe extern "C" fn xmlPopOutputCallbacks() -> c_int {
2120 unsafe {
2121 globals::init_parser();
2122 }
2123 let mut table = OUTPUT_CALLBACKS.lock();
2124 if table.is_empty() {
2125 return -1;
2126 }
2127 table.pop();
2128 table.len() as c_int
2129}
2130
2131#[no_mangle]
2139pub unsafe extern "C" fn xmlCleanupOutputCallbacks() {
2140 unsafe {
2141 globals::init_parser();
2142 }
2143 OUTPUT_CALLBACKS.lock().clear();
2144}
2145
2146unsafe extern "C" fn default_external_entity_loader(
2157 url: *const c_char,
2158 public_id: *const c_char,
2159 ctxt: *mut _xmlParserCtxt,
2160) -> *mut _xmlParserInput {
2161 let _ = public_id;
2162 if url.is_null() {
2163 return ptr::null_mut();
2164 }
2165 unsafe {
2166 if !ctxt.is_null() && (*ctxt).options & XML_PARSE_NONET != 0 {
2168 let len = libc::strlen(url);
2169 if len >= 7 && libc::strncasecmp(url, b"http://\0".as_ptr() as *const c_char, 7) == 0 {
2170 return ptr::null_mut();
2171 }
2172 }
2173 let table = INPUT_CALLBACKS.lock();
2175 for entry in table.iter() {
2176 if let (Some(match_cb), Some(open_cb)) = (entry.matchcb, entry.opencb) {
2177 if match_cb(url) != 0 {
2178 let ctx = open_cb(url);
2179 if !ctx.is_null() {
2180 let buf = helpers::alloc_parser_input_buffer();
2181 if buf.is_null() {
2182 if let Some(close_cb) = entry.closecb {
2183 close_cb(ctx);
2184 }
2185 return ptr::null_mut();
2186 }
2187 (*buf).context = ctx;
2188 (*buf).readcallback = entry.readcb;
2189 (*buf).closecallback = entry.closecb;
2190 return parser_input_from_buf(buf);
2191 }
2192 }
2193 }
2194 }
2195
2196 let buf = io::input_buffer_create_file(url, xmlCharEncoding::XML_CHAR_ENCODING_NONE as c_int);
2198 if buf.is_null() {
2199 return ptr::null_mut();
2200 }
2201 parser_input_from_buf(buf)
2202 }
2203}
2204
2205#[no_mangle]
2213pub unsafe extern "C" fn xmlSetExternalEntityLoader(f: Option<xmlExternalEntityLoader>) {
2214 *EXTERNAL_ENTITY_LOADER.lock() = f;
2215}
2216
2217#[no_mangle]
2225pub unsafe extern "C" fn xmlGetExternalEntityLoader() -> Option<xmlExternalEntityLoader> {
2226 *EXTERNAL_ENTITY_LOADER.lock()
2227}
2228
2229#[no_mangle]
2239pub unsafe extern "C" fn xmlNoNetExternalEntityLoader(
2240 URL: *const c_char,
2241 ID: *const c_char,
2242 ctxt: *mut _xmlParserCtxt,
2243) -> *mut _xmlParserInput {
2244 unsafe {
2245 let old_options = if ctxt.is_null() { 0 } else { (*ctxt).options };
2246 if !ctxt.is_null() {
2247 (*ctxt).options |= XML_PARSE_NONET;
2248 }
2249 let input = default_external_entity_loader(URL, ID, ctxt);
2250 if !ctxt.is_null() {
2251 (*ctxt).options = old_options;
2252 }
2253 input
2254 }
2255}
2256
2257#[no_mangle]
2266pub unsafe extern "C" fn xmlLoadExternalEntity(
2267 URL: *const c_char,
2268 ID: *const c_char,
2269 ctxt: *mut _xmlParserCtxt,
2270) -> *mut _xmlParserInput {
2271 let loader = *EXTERNAL_ENTITY_LOADER.lock();
2272 match loader {
2273 Some(f) => unsafe { f(URL, ID, ctxt) },
2274 None => unsafe { default_external_entity_loader(URL, ID, ctxt) },
2275 }
2276}
2277
2278#[no_mangle]
2288pub unsafe extern "C" fn xmlCheckHTTPInput(
2289 ctxt: *mut _xmlParserCtxt,
2290 ret: *mut _xmlParserInput,
2291) -> *mut _xmlParserInput {
2292 if ret.is_null() {
2293 return ptr::null_mut();
2294 }
2295 unsafe {
2296 if !ctxt.is_null() && (*ctxt).options & XML_PARSE_NONET != 0 {
2297 let filename = (*ret).filename;
2298 if !filename.is_null() {
2299 let len = libc::strlen(filename);
2300 if len >= 7 && libc::strncasecmp(filename, b"http://\0".as_ptr() as *const c_char, 7) == 0 {
2301 if !(*ret).buf.is_null() {
2302 io::input_buffer_free((*ret).buf);
2303 }
2304 helpers::free_parser_input(ret);
2305 return ptr::null_mut();
2306 }
2307 }
2308 }
2309 ret
2310 }
2311}
2312
2313#[no_mangle]
2325pub unsafe extern "C" fn xmlFileMatch(_filename: *const c_char) -> c_int {
2326 1
2327}
2328
2329#[no_mangle]
2337pub unsafe extern "C" fn xmlFileOpen(filename: *const c_char) -> *mut c_void {
2338 if filename.is_null() {
2339 return ptr::null_mut();
2340 }
2341 unsafe { libc::fopen(filename, b"rb\0".as_ptr() as *const c_char) as *mut c_void }
2342}
2343
2344#[no_mangle]
2352pub unsafe extern "C" fn xmlFileRead(
2353 context: *mut c_void,
2354 buffer: *mut c_char,
2355 len: c_int,
2356) -> c_int {
2357 if context.is_null() || buffer.is_null() || len <= 0 {
2358 return -1;
2359 }
2360 unsafe {
2361 let n = libc::fread(buffer as *mut c_void, 1, len as usize, context as *mut libc::FILE);
2362 if n < len as usize && libc::ferror(context as *mut libc::FILE) != 0 {
2363 return -1;
2364 }
2365 n as c_int
2366 }
2367}
2368
2369#[no_mangle]
2377pub unsafe extern "C" fn xmlFileClose(context: *mut c_void) -> c_int {
2378 if context.is_null() {
2379 return -1;
2380 }
2381 unsafe {
2382 let file = context as *mut libc::FILE;
2383 let fd = libc::fileno(file);
2384 if fd == 0 {
2385 return 0;
2387 }
2388 if fd == 1 || fd == 2 {
2389 return if libc::fflush(file) == 0 { 0 } else { -1 };
2391 }
2392 libc::fclose(file)
2393 }
2394}
2395
2396#[no_mangle]
2409pub unsafe extern "C" fn xmlCurrentChar(ctxt: *mut _xmlParserCtxt, len: *mut c_int) -> c_int {
2410 if ctxt.is_null() || len.is_null() || (*ctxt).input.is_null() {
2411 return 0;
2412 }
2413 unsafe {
2414 let pi = &*((*ctxt).input);
2415 let cur = pi.cur;
2416 if cur.is_null() {
2417 *len = 0;
2418 return 0;
2419 }
2420 let avail = (pi.end as usize).saturating_sub(cur as usize);
2421 let c = *cur;
2422
2423 if c < 0x80 {
2424 if c == b'\r' {
2425 if avail >= 2 && *cur.add(1) == b'\n' {
2427 (*(*ctxt).input).cur = cur.add(1);
2428 }
2429 *len = 1;
2430 return b'\n' as c_int;
2431 }
2432 if c == 0 {
2433 if avail == 0 {
2434 *len = 0;
2435 } else {
2436 *len = 1;
2437 }
2438 return 0;
2439 }
2440 *len = 1;
2441 return c as c_int;
2442 }
2443
2444 if avail < 2 || (*cur.add(1) & 0xc0) != 0x80 {
2446 *len = 1;
2447 return XML_INVALID_CHAR;
2448 }
2449 if c < 0xe0 {
2450 if c < 0xc2 {
2451 *len = 1;
2452 return XML_INVALID_CHAR;
2453 }
2454 let val = (((c & 0x1f) as c_int) << 6) | ((*cur.add(1) & 0x3f) as c_int);
2455 *len = 2;
2456 return val;
2457 }
2458 if avail < 3 || (*cur.add(2) & 0xc0) != 0x80 {
2459 *len = 1;
2460 return XML_INVALID_CHAR;
2461 }
2462 if c < 0xf0 {
2463 let val = (((c & 0x0f) as c_int) << 12)
2464 | (((*cur.add(1) & 0x3f) as c_int) << 6)
2465 | ((*cur.add(2) & 0x3f) as c_int);
2466 if val < 0x800 || (val >= 0xd800 && val < 0xe000) {
2467 *len = 1;
2468 return XML_INVALID_CHAR;
2469 }
2470 *len = 3;
2471 return val;
2472 }
2473 if avail < 4 || (*cur.add(3) & 0xc0) != 0x80 {
2474 *len = 1;
2475 return XML_INVALID_CHAR;
2476 }
2477 let val = (((c & 0x07) as c_int) << 18)
2478 | (((*cur.add(1) & 0x3f) as c_int) << 12)
2479 | (((*cur.add(2) & 0x3f) as c_int) << 6)
2480 | ((*cur.add(3) & 0x3f) as c_int);
2481 if val < 0x10000 || val >= 0x110000 {
2482 *len = 1;
2483 return XML_INVALID_CHAR;
2484 }
2485 *len = 4;
2486 val
2487 }
2488}
2489
2490#[no_mangle]
2498pub unsafe extern "C" fn xmlNextChar(ctxt: *mut _xmlParserCtxt) {
2499 if ctxt.is_null() || (*ctxt).input.is_null() {
2500 return;
2501 }
2502 unsafe {
2503 let pi = &mut *((*ctxt).input);
2504 let cur = pi.cur;
2505 if cur.is_null() {
2506 return;
2507 }
2508 let avail = (pi.end as usize).saturating_sub(cur as usize);
2509 if avail == 0 {
2510 return;
2511 }
2512 let c = *cur;
2513
2514 if c < 0x80 {
2515 if c == b'\n' {
2516 pi.cur = cur.add(1);
2517 pi.line += 1;
2518 pi.col = 1;
2519 } else if c == b'\r' {
2520 pi.cur = cur.add(if avail >= 2 && *cur.add(1) == b'\n' { 2 } else { 1 });
2522 pi.line += 1;
2523 pi.col = 1;
2524 } else {
2525 pi.cur = cur.add(1);
2526 pi.col += 1;
2527 }
2528 return;
2529 }
2530
2531 pi.col += 1;
2532
2533 if avail < 2 || (*cur.add(1) & 0xc0) != 0x80 {
2534 pi.cur = cur.add(1);
2535 return;
2536 }
2537 if c < 0xe0 {
2538 if c < 0xc2 {
2539 pi.cur = cur.add(1);
2540 return;
2541 }
2542 pi.cur = cur.add(2);
2543 return;
2544 }
2545 if avail < 3 || (*cur.add(2) & 0xc0) != 0x80 {
2546 pi.cur = cur.add(1);
2547 return;
2548 }
2549 if c < 0xf0 {
2550 let val = (((c as c_int) << 8) as u32) | (*cur.add(1) as u32);
2551 if (val < 0xe0a0) || (val >= 0xeda0 && val < 0xee00) {
2552 pi.cur = cur.add(1);
2553 return;
2554 }
2555 pi.cur = cur.add(3);
2556 return;
2557 }
2558 if avail < 4 || (*cur.add(3) & 0xc0) != 0x80 {
2559 pi.cur = cur.add(1);
2560 return;
2561 }
2562 let val = (((c as c_int) << 8) as u32) | (*cur.add(1) as u32);
2563 if val < 0xf090 || val >= 0xf490 {
2564 pi.cur = cur.add(1);
2565 return;
2566 }
2567 pi.cur = cur.add(4);
2568 }
2569}
2570
2571#[no_mangle]
2580pub unsafe extern "C" fn xmlSkipBlankChars(ctxt: *mut _xmlParserCtxt) -> c_int {
2581 if ctxt.is_null() || (*ctxt).input.is_null() {
2582 return 0;
2583 }
2584 unsafe {
2585 let pi = &mut *((*ctxt).input);
2586 let mut cur = pi.cur;
2587 if cur.is_null() {
2588 return 0;
2589 }
2590 let end = pi.end;
2591 let mut res = 0;
2592 while cur < end && (*cur == 0x20 || *cur == 0x09 || *cur == 0x0a || *cur == 0x0d) {
2593 if *cur == b'\n' {
2594 pi.line += 1;
2595 pi.col = 1;
2596 } else {
2597 pi.col += 1;
2598 }
2599 cur = cur.add(1);
2600 res += 1;
2601 }
2602 pi.cur = cur;
2603 res
2604 }
2605}
2606
2607fn is_name_start_char_new(c: c_int) -> bool {
2609 if c == b' ' as c_int || c == b'>' as c_int || c == b'/' as c_int {
2610 return false;
2611 }
2612 (c >= b'a' as c_int && c <= b'z' as c_int)
2613 || (c >= b'A' as c_int && c <= b'Z' as c_int)
2614 || c == b'_' as c_int
2615 || c == b':' as c_int
2616 || (c >= 0xC0 && c <= 0xD6)
2617 || (c >= 0xD8 && c <= 0xF6)
2618 || (c >= 0xF8 && c <= 0x2FF)
2619 || (c >= 0x370 && c <= 0x37D)
2620 || (c >= 0x37F && c <= 0x1FFF)
2621 || (c >= 0x200C && c <= 0x200D)
2622 || (c >= 0x2070 && c <= 0x218F)
2623 || (c >= 0x2C00 && c <= 0x2FEF)
2624 || (c >= 0x3001 && c <= 0xD7FF)
2625 || (c >= 0xF900 && c <= 0xFDCF)
2626 || (c >= 0xFDF0 && c <= 0xFFFD)
2627 || (c >= 0x10000 && c <= 0xEFFFF)
2628}
2629
2630fn is_name_char_new(c: c_int) -> bool {
2632 if c == b' ' as c_int || c == b'>' as c_int || c == b'/' as c_int {
2633 return false;
2634 }
2635 (c >= b'a' as c_int && c <= b'z' as c_int)
2636 || (c >= b'A' as c_int && c <= b'Z' as c_int)
2637 || (c >= b'0' as c_int && c <= b'9' as c_int)
2638 || c == b'_' as c_int
2639 || c == b':' as c_int
2640 || c == b'-' as c_int
2641 || c == b'.' as c_int
2642 || c == 0xB7
2643 || (c >= 0xC0 && c <= 0xD6)
2644 || (c >= 0xD8 && c <= 0xF6)
2645 || (c >= 0xF8 && c <= 0x2FF)
2646 || (c >= 0x300 && c <= 0x36F)
2647 || (c >= 0x370 && c <= 0x37D)
2648 || (c >= 0x37F && c <= 0x1FFF)
2649 || (c >= 0x200C && c <= 0x200D)
2650 || (c >= 0x203F && c <= 0x2040)
2651 || (c >= 0x2070 && c <= 0x218F)
2652 || (c >= 0x2C00 && c <= 0x2FEF)
2653 || (c >= 0x3001 && c <= 0xD7FF)
2654 || (c >= 0xF900 && c <= 0xFDCF)
2655 || (c >= 0xFDF0 && c <= 0xFFFD)
2656 || (c >= 0x10000 && c <= 0xEFFFF)
2657}
2658
2659#[no_mangle]
2669pub unsafe extern "C" fn xmlScanName(
2670 ctxt: *mut _xmlParserCtxt,
2671 max: c_int,
2672 flags: c_int,
2673) -> *const xmlChar {
2674 if ctxt.is_null() || (*ctxt).input.is_null() || max <= 0 {
2675 return ptr::null();
2676 }
2677 unsafe {
2678 let pi = &mut *((*ctxt).input);
2679 let mut ptr = pi.cur;
2680 if ptr.is_null() {
2681 return ptr::null();
2682 }
2683 let end = pi.end;
2684 let mut remaining = max as usize;
2685 let stop: u8 = if flags & XML_SCAN_NC != 0 { b':' } else { 0 };
2686 let old10 = flags & XML_SCAN_OLD10 != 0;
2687 let mut f = flags;
2688
2689 loop {
2690 if ptr >= end {
2691 break;
2692 }
2693 let c = *ptr;
2694 let (cp, len) = if c < 0x80 {
2695 if stop != 0 && c == stop {
2696 break;
2697 }
2698 (c as c_int, 1usize)
2699 } else {
2700 let avail = (end as usize).saturating_sub(ptr as usize);
2702 let mut l = 4usize;
2703 let cp = decode_utf8_char(ptr, avail, &mut l);
2704 if cp < 0 {
2705 break;
2706 }
2707 (cp, l)
2708 };
2709
2710 let ok = if f & XML_SCAN_NMTOKEN != 0 {
2711 if old10 {
2712 is_name_char_old10(cp)
2713 } else {
2714 is_name_char_new(cp)
2715 }
2716 } else if old10 {
2717 is_name_start_char_old10(cp)
2718 } else {
2719 is_name_start_char_new(cp)
2720 };
2721 if !ok {
2722 break;
2723 }
2724 if len > remaining {
2725 return ptr::null();
2726 }
2727 ptr = ptr.add(len);
2728 remaining -= len;
2729 f |= XML_SCAN_NMTOKEN;
2730 }
2731
2732 pi.cur = ptr;
2733 ptr
2734 }
2735}
2736
2737unsafe fn decode_utf8_char(ptr: *const u8, avail: usize, len: &mut usize) -> c_int {
2740 unsafe {
2741 let c = *ptr;
2742 if avail < 2 || (*ptr.add(1) & 0xc0) != 0x80 {
2743 return -1;
2744 }
2745 if c < 0xe0 {
2746 if c < 0xc2 {
2747 return -1;
2748 }
2749 *len = 2;
2750 return (((c & 0x1f) as c_int) << 6) | ((*ptr.add(1) & 0x3f) as c_int);
2751 }
2752 if avail < 3 || (*ptr.add(2) & 0xc0) != 0x80 {
2753 return -1;
2754 }
2755 if c < 0xf0 {
2756 let val = (((c & 0x0f) as c_int) << 12)
2757 | (((*ptr.add(1) & 0x3f) as c_int) << 6)
2758 | ((*ptr.add(2) & 0x3f) as c_int);
2759 if val < 0x800 || (val >= 0xd800 && val < 0xe000) {
2760 return -1;
2761 }
2762 *len = 3;
2763 return val;
2764 }
2765 if avail < 4 || (*ptr.add(3) & 0xc0) != 0x80 {
2766 return -1;
2767 }
2768 let val = (((c & 0x07) as c_int) << 18)
2769 | (((*ptr.add(1) & 0x3f) as c_int) << 12)
2770 | (((*ptr.add(2) & 0x3f) as c_int) << 6)
2771 | ((*ptr.add(3) & 0x3f) as c_int);
2772 if val < 0x10000 || val >= 0x110000 {
2773 return -1;
2774 }
2775 *len = 4;
2776 val
2777 }
2778}
2779
2780fn is_name_start_char_old10(c: c_int) -> bool {
2782 (c >= b'a' as c_int && c <= b'z' as c_int)
2783 || (c >= b'A' as c_int && c <= b'Z' as c_int)
2784 || c == b'_' as c_int
2785 || c == b':' as c_int
2786 || (c >= 0xC0 && c <= 0xD6)
2787 || (c >= 0xD8 && c <= 0xF6)
2788 || (c >= 0xF8 && c <= 0x2FF)
2789 || (c >= 0x370 && c <= 0x37D)
2790 || (c >= 0x37F && c <= 0x1FFF)
2791 || (c >= 0x200C && c <= 0x200D)
2792 || (c >= 0x2070 && c <= 0x218F)
2793 || (c >= 0x2C00 && c <= 0x2FEF)
2794 || (c >= 0x3001 && c <= 0xD7FF)
2795 || (c >= 0xF900 && c <= 0xFDCF)
2796 || (c >= 0xFDF0 && c <= 0xFFFD)
2797 || (c >= 0x10000 && c <= 0xEFFFF)
2798}
2799
2800fn is_name_char_old10(c: c_int) -> bool {
2803 is_name_start_char_old10(c)
2804 || (c >= b'0' as c_int && c <= b'9' as c_int)
2805 || c == b'.' as c_int
2806 || c == b'-' as c_int
2807 || c == 0xB7
2808 || (c >= 0x300 && c <= 0x36F)
2809 || c == 0x02D0
2810 || c == 0x02D1
2811 || c == 0x0387
2812 || c == 0x0640
2813 || c == 0x0E46
2814 || c == 0x0EC6
2815 || c == 0x3005
2816 || (c >= 0x3031 && c <= 0x3035)
2817 || (c >= 0x309D && c <= 0x309E)
2818 || (c >= 0x30FC && c <= 0x30FE)
2819}
2820
2821#[no_mangle]
2832pub unsafe extern "C" fn xmlDecodeEntities(
2833 ctxt: *mut _xmlParserCtxt,
2834 len: c_int,
2835 end: xmlChar,
2836 end2: xmlChar,
2837 end3: xmlChar,
2838) -> *mut xmlChar {
2839 if ctxt.is_null() || (*ctxt).input.is_null() {
2840 return ptr::null_mut();
2841 }
2842 unsafe {
2843 let pi = &*((*ctxt).input);
2844 let cur = pi.cur;
2845 if cur.is_null() {
2846 return ptr::null_mut();
2847 }
2848 let avail = (pi.end as usize).saturating_sub(cur as usize);
2849 let n = if len < 0 {
2850 avail
2851 } else {
2852 (len as usize).min(avail)
2853 };
2854
2855 let mut out: Vec<u8> = Vec::new();
2856 let mut i = 0usize;
2857
2858 while i < n {
2859 let c = *cur.add(i);
2860 if c == end || c == end2 || c == end3 {
2861 break;
2862 }
2863 if c != b'&' {
2864 out.push(c);
2865 i += 1;
2866 continue;
2867 }
2868
2869 if i + 1 < n && *cur.add(i + 1) == b'#' {
2871 let (value, consumed) = parse_char_ref(cur.add(i), n - i);
2872 if consumed == 0 {
2873 out.push(b'&');
2874 i += 1;
2875 continue;
2876 }
2877 let mut buf = [0u8; 4];
2878 let blen = copy_char_utf8(&mut buf, value);
2879 out.extend_from_slice(&buf[..blen]);
2880 i += consumed;
2881 continue;
2882 }
2883
2884 let mut j = i + 1;
2886 while j < n
2887 && ((*cur.add(j)).is_ascii_alphanumeric()
2888 || *cur.add(j) == b'_'
2889 || *cur.add(j) == b'-'
2890 || *cur.add(j) == b'.'
2891 || *cur.add(j) == b':')
2892 {
2893 j += 1;
2894 }
2895 if j < n && *cur.add(j) == b';' {
2896 let name = core::slice::from_raw_parts(cur.add(i + 1), j - i - 1);
2897 let mut replaced = false;
2898 let content: Option<&[u8]> = match name {
2900 b"amp" => Some(b"&"),
2901 b"lt" => Some(b"<"),
2902 b"gt" => Some(b">"),
2903 b"quot" => Some(b"\""),
2904 b"apos" => Some(b"'"),
2905 _ => None,
2906 };
2907 if let Some(c) = content {
2908 out.extend_from_slice(c);
2909 replaced = true;
2910 } else {
2911 let mut name_nul = name.to_vec();
2913 name_nul.push(0);
2914 let ent = entities::get_entity((*ctxt).myDoc, name_nul.as_ptr());
2915 if !ent.is_null() && !(*ent).content.is_null() {
2916 let clen = string::xml_strlen((*ent).content);
2917 out.extend_from_slice(core::slice::from_raw_parts(
2918 (*ent).content,
2919 clen,
2920 ));
2921 replaced = true;
2922 }
2923 }
2924 if replaced {
2925 i = j + 1;
2926 continue;
2927 }
2928 }
2929 out.push(b'&');
2930 i += 1;
2931 }
2932
2933 out.push(0);
2934 let result = xmlMalloc(out.len()) as *mut xmlChar;
2935 if result.is_null() {
2936 return ptr::null_mut();
2937 }
2938 ptr::copy_nonoverlapping(out.as_ptr(), result, out.len());
2939 result
2940 }
2941}
2942
2943unsafe fn parse_char_ref(ptr: *const u8, avail: usize) -> (c_int, usize) {
2946 unsafe {
2947 if avail < 3 || *ptr != b'&' || *ptr.add(1) != b'#' {
2948 return (0, 0);
2949 }
2950 let mut i = 2usize;
2951 let hex = i < avail && (*ptr.add(i) == b'x' || *ptr.add(i) == b'X');
2952 if hex {
2953 i += 1;
2954 }
2955 let start = i;
2956 let mut value: u32 = 0;
2957 while i < avail && *ptr.add(i) != b';' {
2958 let d = (*ptr.add(i) as char).to_digit(if hex { 16 } else { 10 });
2959 match d {
2960 Some(d) => {
2961 value = value
2962 .saturating_mul(if hex { 16 } else { 10 })
2963 .saturating_add(d);
2964 i += 1;
2965 }
2966 None => return (0, 0),
2967 }
2968 }
2969 if i == start || i >= avail || *ptr.add(i) != b';' {
2970 return (0, 0);
2971 }
2972 (value as c_int, i + 1)
2973 }
2974}
2975
2976fn copy_char_utf8(out: &mut [u8; 4], val: c_int) -> usize {
2978 if val < 0x80 {
2979 out[0] = val as u8;
2980 1
2981 } else if val < 0x800 {
2982 out[0] = 0xC0 | ((val >> 6) as u8);
2983 out[1] = 0x80 | ((val & 0x3F) as u8);
2984 2
2985 } else if val < 0x10000 {
2986 out[0] = 0xE0 | ((val >> 12) as u8);
2987 out[1] = 0x80 | (((val >> 6) & 0x3F) as u8);
2988 out[2] = 0x80 | ((val & 0x3F) as u8);
2989 3
2990 } else if val < 0x110000 {
2991 out[0] = 0xF0 | ((val >> 18) as u8);
2992 out[1] = 0x80 | (((val >> 12) & 0x3F) as u8);
2993 out[2] = 0x80 | (((val >> 6) & 0x3F) as u8);
2994 out[3] = 0x80 | ((val & 0x3F) as u8);
2995 4
2996 } else {
2997 out[0] = 0;
2998 1
2999 }
3000}
3001
3002#[no_mangle]
3010pub unsafe extern "C" fn xmlDetectCharEncoding(in_: *const c_uchar, len: c_int) -> c_int {
3011 if in_.is_null() {
3012 return xmlCharEncoding::XML_CHAR_ENCODING_NONE as c_int;
3013 }
3014 unsafe {
3015 if len >= 4 {
3016 if *in_ == 0x00 && *in_.add(1) == 0x00 && *in_.add(2) == 0x00 && *in_.add(3) == 0x3C {
3017 return xmlCharEncoding::XML_CHAR_ENCODING_UCS4BE as c_int;
3018 }
3019 if *in_ == 0x3C && *in_.add(1) == 0x00 && *in_.add(2) == 0x00 && *in_.add(3) == 0x00 {
3020 return xmlCharEncoding::XML_CHAR_ENCODING_UCS4LE as c_int;
3021 }
3022 if *in_ == 0x4C && *in_.add(1) == 0x6F && *in_.add(2) == 0xA7 && *in_.add(3) == 0x94 {
3023 return xmlCharEncoding::XML_CHAR_ENCODING_EBCDIC as c_int;
3024 }
3025 if *in_ == 0x3C && *in_.add(1) == 0x3F && *in_.add(2) == 0x78 && *in_.add(3) == 0x6D {
3026 return xmlCharEncoding::XML_CHAR_ENCODING_UTF8 as c_int;
3027 }
3028 if *in_ == 0x3C && *in_.add(1) == 0x00 && *in_.add(2) == 0x3F && *in_.add(3) == 0x00 {
3029 return xmlCharEncoding::XML_CHAR_ENCODING_UTF16LE as c_int;
3030 }
3031 if *in_ == 0x00 && *in_.add(1) == 0x3C && *in_.add(2) == 0x00 && *in_.add(3) == 0x3F {
3032 return xmlCharEncoding::XML_CHAR_ENCODING_UTF16BE as c_int;
3033 }
3034 }
3035 if len >= 3 && *in_ == 0xEF && *in_.add(1) == 0xBB && *in_.add(2) == 0xBF {
3036 return xmlCharEncoding::XML_CHAR_ENCODING_UTF8 as c_int;
3037 }
3038 if len >= 2 {
3039 if *in_ == 0xFE && *in_.add(1) == 0xFF {
3040 return xmlCharEncoding::XML_CHAR_ENCODING_UTF16BE as c_int;
3041 }
3042 if *in_ == 0xFF && *in_.add(1) == 0xFE {
3043 return xmlCharEncoding::XML_CHAR_ENCODING_UTF16LE as c_int;
3044 }
3045 }
3046 }
3047 xmlCharEncoding::XML_CHAR_ENCODING_NONE as c_int
3048}
3049
3050#[no_mangle]
3060pub unsafe extern "C" fn xmlCharEncFirstLine(
3061 handler: *mut _xmlCharEncodingHandler,
3062 out: *mut _xmlBuffer,
3063 in_: *mut _xmlBuffer,
3064) -> c_int {
3065 encoding::xmlCharEncInFunc(handler, out, in_)
3066}
3067
3068#[no_mangle]
3076pub unsafe extern "C" fn xmlIsMainThread() -> c_int {
3077 1
3078}
3079
3080#[no_mangle]
3093pub unsafe extern "C" fn xmlParserPrintFileInfo(input: *mut _xmlParserInput) {
3094 if input.is_null() {
3095 return;
3096 }
3097 unsafe {
3098 let channel: Option<xmlGenericErrorFunc> = globals::get_generic_error_func();
3099 let data = globals::get_generic_error_ctx();
3100 let Some(ch) = channel else { return };
3101 let msg;
3102 if !(*input).filename.is_null() {
3103 let file = CStr::from_ptr((*input).filename);
3104 let s = format!("{}:{}: ", file.to_string_lossy(), (*input).line);
3105 msg = std::ffi::CString::new(s).unwrap_or_default();
3106 } else {
3107 let s = format!("Entity: line {}: ", (*input).line);
3108 msg = std::ffi::CString::new(s).unwrap_or_default();
3109 }
3110 ch(data, msg.as_ptr());
3111 }
3112}
3113
3114#[no_mangle]
3123pub unsafe extern "C" fn xmlParserPrintFileContext(input: *mut _xmlParserInput) {
3124 if input.is_null() || (*input).cur.is_null() {
3125 return;
3126 }
3127 unsafe {
3128 let channel: Option<xmlGenericErrorFunc> = globals::get_generic_error_func();
3129 let data = globals::get_generic_error_ctx();
3130 let Some(ch) = channel else { return };
3131
3132 let pi = &*input;
3133 let cur = pi.cur;
3134 let base = pi.base;
3135 let end = pi.end;
3136
3137 let before = if base.is_null() {
3139 0
3140 } else {
3141 (cur as usize).saturating_sub(base as usize)
3142 };
3143 let take = before.min(LINE_LEN);
3144 let start = cur.sub(take);
3145 let n = (end as usize).saturating_sub(start as usize).min(LINE_LEN);
3146
3147 let mut content = vec![0u8; n];
3148 if n > 0 {
3149 ptr::copy_nonoverlapping(start, content.as_mut_ptr(), n);
3150 }
3151 let line = std::ffi::CString::new(content.clone()).unwrap_or_default();
3152 ch(data, line.as_ptr());
3153
3154 let mut caret = vec![b' '; take];
3156 if take + 1 <= LINE_LEN + 1 {
3157 caret.push(b'^');
3158 }
3159 let caret_c = std::ffi::CString::new(caret).unwrap_or_default();
3160 ch(data, caret_c.as_ptr());
3161 }
3162}
3163
3164#[no_mangle]
3177pub unsafe extern "C" fn xmlHandleEntity(ctxt: *mut _xmlParserCtxt, entity: *mut c_void) {
3178 if ctxt.is_null() {
3179 return;
3180 }
3181 unsafe {
3182 let ent = entity as *mut _xmlEntity;
3183 if ent.is_null() {
3184 return;
3185 }
3186 if (*ent).etype == xmlEntityType::XML_EXTERNAL_GENERAL_UNPARSED_ENTITY as c_int {
3188 return;
3189 }
3190
3191 let mut input = ptr::null_mut();
3192 if !(*ent).content.is_null() {
3193 let content = (*ent).content;
3195 let pi = xmlNewInputStream(ctxt);
3196 if pi.is_null() {
3197 return;
3198 }
3199 let len = string::xml_strlen(content);
3200 (*pi).base = content;
3201 (*pi).cur = content;
3202 (*pi).end = content.add(len);
3203 (*pi).length = len as c_int;
3204 (*pi).entity = ent;
3205 input = pi;
3206 } else if !(*ent).URI.is_null() {
3207 input = xmlLoadExternalEntity(
3209 (*ent).URI as *const c_char,
3210 (*ent).ExternalID as *const c_char,
3211 ctxt,
3212 );
3213 if !input.is_null() {
3214 (*input).entity = ent;
3215 }
3216 }
3217
3218 if input.is_null() {
3219 return;
3220 }
3221 xmlPushInput(ctxt, input);
3222 }
3223}
3224
3225#[no_mangle]
3235pub unsafe extern "C" fn xmlSAXParseDTD(
3236 sax: *mut _xmlSAXHandler,
3237 publicId: *const xmlChar,
3238 systemId: *const xmlChar,
3239) -> *mut _xmlDtd {
3240 if publicId.is_null() && systemId.is_null() {
3241 return ptr::null_mut();
3242 }
3243 unsafe {
3244 let ctxt = xmlNewSAXParserCtxt(sax, ptr::null_mut());
3245 if ctxt.is_null() {
3246 return ptr::null_mut();
3247 }
3248 apply_options(ctxt, XML_PARSE_DTDLOAD);
3249
3250 let mut input = ptr::null_mut();
3253 if !sax.is_null() {
3254 if let Some(resolve) = (*sax).resolveEntity {
3255 input = resolve((*ctxt).userData, publicId, systemId);
3256 }
3257 }
3258 if input.is_null() {
3259 if systemId.is_null() {
3260 helpers::free_parser_ctxt(ctxt);
3261 return ptr::null_mut();
3262 }
3263 input = xmlLoadExternalEntity(systemId as *const c_char, ptr::null(), ctxt);
3264 }
3265 if input.is_null() {
3266 helpers::free_parser_ctxt(ctxt);
3267 return ptr::null_mut();
3268 }
3269
3270 let data: Vec<u8> = {
3272 let pi = &*input;
3273 if !pi.base.is_null() && !pi.end.is_null() && pi.end >= pi.base {
3274 let len = (pi.end as usize).saturating_sub(pi.base as usize);
3275 core::slice::from_raw_parts(pi.base, len).to_vec()
3276 } else if !pi.buf.is_null() {
3277 input_buffer_data(pi.buf)
3278 } else {
3279 Vec::new()
3280 }
3281 };
3282 helpers::free_parser_input(input);
3283
3284 let dtd = parse_dtd_text(ctxt, &data, publicId, systemId);
3285 helpers::free_parser_ctxt(ctxt);
3286 dtd
3287 }
3288}
3289
3290#[no_mangle]
3299pub unsafe extern "C" fn xmlIOParseDTD(
3300 sax: *mut _xmlSAXHandler,
3301 input: *mut _xmlParserInputBuffer,
3302 enc: c_int,
3303) -> *mut _xmlDtd {
3304 if input.is_null() {
3305 return ptr::null_mut();
3306 }
3307 unsafe {
3308 let ctxt = xmlNewSAXParserCtxt(sax, ptr::null_mut());
3309 if ctxt.is_null() {
3310 io::input_buffer_free(input);
3311 return ptr::null_mut();
3312 }
3313 apply_options(ctxt, XML_PARSE_DTDLOAD);
3314 if enc != xmlCharEncoding::XML_CHAR_ENCODING_NONE as c_int {
3315 (*ctxt).charset = enc;
3316 }
3317
3318 let data: Vec<u8> = input_buffer_data(input);
3320 io::input_buffer_free(input);
3321
3322 let dtd = parse_dtd_text(ctxt, &data, ptr::null(), ptr::null());
3323 helpers::free_parser_ctxt(ctxt);
3324 dtd
3325 }
3326}
3327
3328unsafe fn input_buffer_data(buf: *mut _xmlParserInputBuffer) -> Vec<u8> {
3330 unsafe {
3331 if buf.is_null() {
3332 return Vec::new();
3333 }
3334 let b = &*buf;
3335 if let Some(read) = b.readcallback {
3336 let mut out = Vec::new();
3337 let mut tmp = [0u8; 4096];
3338 loop {
3339 let n = read(b.context, tmp.as_mut_ptr() as *mut c_char, tmp.len() as c_int);
3340 if n <= 0 {
3341 break;
3342 }
3343 out.extend_from_slice(&tmp[..n as usize]);
3344 }
3345 return out;
3346 }
3347 if !b.buffer.is_null() {
3348 let xbuf = &*(b.buffer as *mut _xmlBuffer);
3349 if !xbuf.content.is_null() && xbuf.use_ > 0 {
3350 return core::slice::from_raw_parts(xbuf.content, xbuf.use_ as usize).to_vec();
3351 }
3352 }
3353 Vec::new()
3354 }
3355}
3356
3357#[no_mangle]
3365pub unsafe extern "C" fn xmlSAXParseEntity(
3366 sax: *mut _xmlSAXHandler,
3367 filename: *const c_char,
3368) -> *mut _xmlDoc {
3369 if filename.is_null() {
3370 return ptr::null_mut();
3371 }
3372 unsafe {
3373 let ctxt = xmlNewSAXParserCtxt(sax, ptr::null_mut());
3374 if ctxt.is_null() {
3375 return ptr::null_mut();
3376 }
3377 let input = match helpers::input_from_file(filename) {
3378 Ok(i) => i,
3379 Err(_) => {
3380 helpers::free_parser_ctxt(ctxt);
3381 return ptr::null_mut();
3382 }
3383 };
3384 helpers::setup_parser_input(ctxt, input);
3385 let rc = helpers::parse_document(ctxt);
3386 let doc = (*ctxt).myDoc;
3387 (*ctxt).myDoc = ptr::null_mut();
3388 if rc != 0 || (*ctxt).wellFormed == 0 {
3389 if !doc.is_null() {
3390 tree::free_doc(doc);
3391 }
3392 helpers::free_parser_ctxt(ctxt);
3393 return ptr::null_mut();
3394 }
3395 helpers::free_parser_ctxt(ctxt);
3396 doc
3397 }
3398}
3399
3400#[no_mangle]
3414pub unsafe extern "C" fn xmlC14NDocSave(
3415 doc: *mut _xmlDoc,
3416 nodes: *mut _xmlNodeSet,
3417 mode: c_int,
3418 inclusive_ns_prefixes: *mut *mut xmlChar,
3419 with_comments: c_int,
3420 filename: *const c_char,
3421 compression: c_int,
3422) -> c_int {
3423 if filename.is_null() {
3424 return -1;
3425 }
3426 unsafe {
3427 let output = io::output_buffer_create_filename(filename, ptr::null_mut(), compression);
3428 if output.is_null() {
3429 return -1;
3430 }
3431 let node_tab = if nodes.is_null() {
3432 ptr::null_mut()
3433 } else {
3434 (*nodes).nodeTab
3435 };
3436 let ret = crate::xml::c14n::xmlC14NDocSaveTo(
3437 doc,
3438 node_tab,
3439 mode,
3440 inclusive_ns_prefixes,
3441 with_comments,
3442 output,
3443 );
3444 if ret < 0 {
3445 io::output_buffer_close(output);
3446 return -1;
3447 }
3448 let close_ret = io::output_buffer_close(output);
3449 if close_ret < 0 {
3450 -1
3451 } else {
3452 ret
3453 }
3454 }
3455}