1#![allow(
101 missing_docs,
102 non_snake_case,
103 non_camel_case_types,
104 non_upper_case_globals
105)]
106#![allow(unused_variables)]
107#![allow(private_interfaces)]
108#![allow(unused_assignments)]
109#![allow(unused_unsafe)]
110#![allow(clippy::missing_safety_doc)]
111#![allow(clippy::not_unsafe_ptr_arg_deref)]
112
113use core::ffi::c_void;
124use core::ptr;
125use core::sync::atomic::{AtomicBool, AtomicI32, Ordering};
126use std::mem::size_of;
127use std::os::raw::{c_char, c_int, c_uint};
128
129use crate::abi::allocator::{xmlFreeImpl, xmlMallocImpl, xmlMallocZero, xmlReallocImpl};
130use crate::abi::callbacks::{xmlInputCloseCallback, xmlInputReadCallback};
131use crate::abi::structs::*;
132use crate::abi::types::xmlChar;
133use crate::abi::types::xmlCharEncoding;
134use crate::abi::types::xmlElementType::*;
135use crate::xml::html;
136use crate::xml::io;
137use crate::xml::string::{c_strdup, xml_strcmp, xml_strlen, xml_strndup, xmlstr_to_bytes};
138use crate::xml::tree;
139
140const HTML_PARSE_RECOVER: c_int = 1 << 0;
145const HTML_PARSE_NODEFDTD: c_int = 1 << 2;
146const HTML_PARSE_NOERROR: c_int = 1 << 5;
147const HTML_PARSE_NOWARNING: c_int = 1 << 6;
148const HTML_PARSE_PEDANTIC: c_int = 1 << 7;
149const HTML_PARSE_NOBLANKS: c_int = 1 << 8;
150const HTML_PARSE_NONET: c_int = 1 << 11;
151const HTML_PARSE_NOIMPLIED: c_int = 1 << 13;
152const HTML_PARSE_COMPACT: c_int = 1 << 16;
153const HTML_PARSE_HUGE: c_int = 1 << 19;
154const HTML_PARSE_IGNORE_ENC: c_int = 1 << 21;
155const HTML_PARSE_BIG_LINES: c_int = 1 << 22;
156const HTML_PARSE_HTML5: c_int = 1 << 26;
157
158const HTML_OPTIONS_KEEP_MASK: c_int = HTML_PARSE_NODEFDTD
160 | HTML_PARSE_NOERROR
161 | HTML_PARSE_NOWARNING
162 | HTML_PARSE_NOIMPLIED
163 | HTML_PARSE_COMPACT
164 | HTML_PARSE_HUGE
165 | HTML_PARSE_IGNORE_ENC
166 | HTML_PARSE_BIG_LINES;
167
168const HTML_OPTIONS_ALL_MASK: c_int = HTML_PARSE_RECOVER
170 | HTML_PARSE_HTML5
171 | HTML_PARSE_NODEFDTD
172 | HTML_PARSE_NOERROR
173 | HTML_PARSE_NOWARNING
174 | HTML_PARSE_PEDANTIC
175 | HTML_PARSE_NOBLANKS
176 | HTML_PARSE_NONET
177 | HTML_PARSE_NOIMPLIED
178 | HTML_PARSE_COMPACT
179 | HTML_PARSE_HUGE
180 | HTML_PARSE_IGNORE_ENC
181 | HTML_PARSE_BIG_LINES;
182
183const XML_ERR_OK: c_int = 0;
185const XML_ERR_NO_MEMORY: c_int = 2;
186const XML_ERR_ARGUMENT: c_int = 115;
187
188const HTML_VALID: c_int = 0x4;
190
191const DATA_NEUTRAL: c_int = 0;
193const DATA_RCDATA: c_int = 1;
194const DATA_RAWTEXT: c_int = 2;
195const DATA_PLAINTEXT: c_int = 3;
196const DATA_SCRIPT: c_int = 4;
197
198#[inline]
200const fn is_ws_html(c: u8) -> bool {
201 c == 0x20 || (c >= 0x09 && c <= 0x0d && c != 0x0b)
202}
203
204#[derive(Debug)]
213#[repr(C)]
214pub struct _htmlElemDesc {
215 pub name: *const c_char,
216 pub startTag: c_char,
217 pub endTag: c_char,
218 pub saveEndTag: c_char,
219 pub empty: c_char,
220 pub depr: c_char,
221 pub dtd: c_char,
222 pub isinline: c_char,
223 pub desc: *const c_char,
224 pub subelts: *const *const c_char,
225 pub defaultsubelt: *const c_char,
226 pub attrs_opt: *const *const c_char,
227 pub attrs_depr: *const *const c_char,
228 pub attrs_req: *const *const c_char,
229 pub dataMode: c_int,
230}
231
232unsafe impl Sync for _htmlElemDesc {}
234unsafe impl Send for _htmlElemDesc {}
235
236macro_rules! elem {
240 ($name:literal, $startTag:expr, $endTag:expr, $saveEndTag:expr, $empty:expr, $depr:expr, $dtd:expr, $isinline:expr, $desc:literal, $dataMode:expr) => {
241 _htmlElemDesc {
242 name: concat!($name, "\0").as_ptr() as *const c_char,
243 startTag: $startTag,
244 endTag: $endTag,
245 saveEndTag: $saveEndTag,
246 empty: $empty,
247 depr: $depr,
248 dtd: $dtd,
249 isinline: $isinline,
250 desc: concat!($desc, "\0").as_ptr() as *const c_char,
251 subelts: ptr::null(),
252 defaultsubelt: ptr::null(),
253 attrs_opt: ptr::null(),
254 attrs_depr: ptr::null(),
255 attrs_req: ptr::null(),
256 dataMode: $dataMode,
257 }
258 };
259}
260
261static HTML40_ELEMENTS: &[_htmlElemDesc] = &[
264 elem!("a", 0, 0, 0, 0, 0, 0, 1, "anchor ", DATA_NEUTRAL),
265 elem!(
266 "abbr",
267 0,
268 0,
269 0,
270 0,
271 0,
272 0,
273 1,
274 "abbreviated form",
275 DATA_NEUTRAL
276 ),
277 elem!("acronym", 0, 0, 0, 0, 0, 0, 1, "", DATA_NEUTRAL),
278 elem!(
279 "address",
280 0,
281 0,
282 0,
283 0,
284 0,
285 0,
286 0,
287 "information on author ",
288 DATA_NEUTRAL
289 ),
290 elem!("applet", 0, 0, 0, 0, 1, 1, 2, "java applet ", DATA_NEUTRAL),
291 elem!(
292 "area",
293 0,
294 2,
295 2,
296 1,
297 0,
298 0,
299 0,
300 "client-side image map area ",
301 DATA_NEUTRAL
302 ),
303 elem!("b", 0, 3, 0, 0, 0, 0, 1, "bold text style", DATA_NEUTRAL),
304 elem!(
305 "base",
306 0,
307 2,
308 2,
309 1,
310 0,
311 0,
312 0,
313 "document base uri ",
314 DATA_NEUTRAL
315 ),
316 elem!(
317 "basefont",
318 0,
319 2,
320 2,
321 1,
322 1,
323 1,
324 1,
325 "base font size ",
326 DATA_NEUTRAL
327 ),
328 elem!(
329 "bdo",
330 0,
331 0,
332 0,
333 0,
334 0,
335 0,
336 1,
337 "i18n bidi over-ride ",
338 DATA_NEUTRAL
339 ),
340 elem!("bgsound", 0, 0, 2, 1, 0, 0, 0, "", DATA_NEUTRAL),
341 elem!("big", 0, 3, 0, 0, 0, 0, 1, "large text style", DATA_NEUTRAL),
342 elem!(
343 "blockquote",
344 0,
345 0,
346 0,
347 0,
348 0,
349 0,
350 0,
351 "long quotation ",
352 DATA_NEUTRAL
353 ),
354 elem!("body", 1, 1, 0, 0, 0, 0, 0, "document body ", DATA_NEUTRAL),
355 elem!(
356 "br",
357 0,
358 2,
359 2,
360 1,
361 0,
362 0,
363 1,
364 "forced line break ",
365 DATA_NEUTRAL
366 ),
367 elem!("button", 0, 0, 0, 0, 0, 0, 2, "push button ", DATA_NEUTRAL),
368 elem!(
369 "caption",
370 0,
371 0,
372 0,
373 0,
374 0,
375 0,
376 0,
377 "table caption ",
378 DATA_NEUTRAL
379 ),
380 elem!(
381 "center",
382 0,
383 3,
384 0,
385 0,
386 1,
387 1,
388 0,
389 "shorthand for div align=center ",
390 DATA_NEUTRAL
391 ),
392 elem!("cite", 0, 0, 0, 0, 0, 0, 1, "citation", DATA_NEUTRAL),
393 elem!(
394 "code",
395 0,
396 0,
397 0,
398 0,
399 0,
400 0,
401 1,
402 "computer code fragment",
403 DATA_NEUTRAL
404 ),
405 elem!("col", 0, 2, 2, 1, 0, 0, 0, "table column ", DATA_NEUTRAL),
406 elem!(
407 "colgroup",
408 0,
409 1,
410 0,
411 0,
412 0,
413 0,
414 0,
415 "table column group ",
416 DATA_NEUTRAL
417 ),
418 elem!(
419 "dd",
420 0,
421 1,
422 0,
423 0,
424 0,
425 0,
426 0,
427 "definition description ",
428 DATA_NEUTRAL
429 ),
430 elem!("del", 0, 0, 0, 0, 0, 0, 2, "deleted text ", DATA_NEUTRAL),
431 elem!(
432 "dfn",
433 0,
434 0,
435 0,
436 0,
437 0,
438 0,
439 1,
440 "instance definition",
441 DATA_NEUTRAL
442 ),
443 elem!("dir", 0, 0, 0, 0, 1, 1, 0, "directory list", DATA_NEUTRAL),
444 elem!(
445 "div",
446 0,
447 0,
448 0,
449 0,
450 0,
451 0,
452 0,
453 "generic language/style container",
454 DATA_NEUTRAL
455 ),
456 elem!("dl", 0, 0, 0, 0, 0, 0, 0, "definition list ", DATA_NEUTRAL),
457 elem!("dt", 0, 1, 0, 0, 0, 0, 0, "definition term ", DATA_NEUTRAL),
458 elem!("em", 0, 3, 0, 0, 0, 0, 1, "emphasis", DATA_NEUTRAL),
459 elem!(
460 "embed",
461 0,
462 1,
463 2,
464 1,
465 1,
466 1,
467 1,
468 "generic embedded object ",
469 DATA_NEUTRAL
470 ),
471 elem!(
472 "fieldset",
473 0,
474 0,
475 0,
476 0,
477 0,
478 0,
479 0,
480 "form control group ",
481 DATA_NEUTRAL
482 ),
483 elem!(
484 "font",
485 0,
486 3,
487 0,
488 0,
489 1,
490 1,
491 1,
492 "local change to font ",
493 DATA_NEUTRAL
494 ),
495 elem!(
496 "form",
497 0,
498 0,
499 0,
500 0,
501 0,
502 0,
503 0,
504 "interactive form ",
505 DATA_NEUTRAL
506 ),
507 elem!("frame", 0, 2, 2, 1, 0, 2, 0, "subwindow ", DATA_NEUTRAL),
508 elem!(
509 "frameset",
510 0,
511 0,
512 0,
513 0,
514 0,
515 2,
516 0,
517 "window subdivision",
518 DATA_NEUTRAL
519 ),
520 elem!("h1", 0, 0, 0, 0, 0, 0, 0, "heading ", DATA_NEUTRAL),
521 elem!("h2", 0, 0, 0, 0, 0, 0, 0, "heading ", DATA_NEUTRAL),
522 elem!("h3", 0, 0, 0, 0, 0, 0, 0, "heading ", DATA_NEUTRAL),
523 elem!("h4", 0, 0, 0, 0, 0, 0, 0, "heading ", DATA_NEUTRAL),
524 elem!("h5", 0, 0, 0, 0, 0, 0, 0, "heading ", DATA_NEUTRAL),
525 elem!("h6", 0, 0, 0, 0, 0, 0, 0, "heading ", DATA_NEUTRAL),
526 elem!("head", 1, 1, 0, 0, 0, 0, 0, "document head ", DATA_NEUTRAL),
527 elem!("hr", 0, 2, 2, 1, 0, 0, 0, "horizontal rule ", DATA_NEUTRAL),
528 elem!(
529 "html",
530 1,
531 1,
532 0,
533 0,
534 0,
535 0,
536 0,
537 "document root element ",
538 DATA_NEUTRAL
539 ),
540 elem!("i", 0, 3, 0, 0, 0, 0, 1, "italic text style", DATA_NEUTRAL),
541 elem!(
542 "iframe",
543 0,
544 0,
545 0,
546 0,
547 0,
548 1,
549 2,
550 "inline subwindow ",
551 DATA_RAWTEXT
552 ),
553 elem!("img", 0, 2, 2, 1, 0, 0, 1, "embedded image ", DATA_NEUTRAL),
554 elem!("input", 0, 2, 2, 1, 0, 0, 1, "form control ", DATA_NEUTRAL),
555 elem!("ins", 0, 0, 0, 0, 0, 0, 2, "inserted text", DATA_NEUTRAL),
556 elem!(
557 "isindex",
558 0,
559 2,
560 2,
561 1,
562 1,
563 1,
564 0,
565 "single line prompt ",
566 DATA_NEUTRAL
567 ),
568 elem!(
569 "kbd",
570 0,
571 0,
572 0,
573 0,
574 0,
575 0,
576 1,
577 "text to be entered by the user",
578 DATA_NEUTRAL
579 ),
580 elem!("keygen", 0, 0, 2, 1, 0, 0, 0, "", DATA_NEUTRAL),
581 elem!(
582 "label",
583 0,
584 0,
585 0,
586 0,
587 0,
588 0,
589 1,
590 "form field label text ",
591 DATA_NEUTRAL
592 ),
593 elem!(
594 "legend",
595 0,
596 0,
597 0,
598 0,
599 0,
600 0,
601 0,
602 "fieldset legend ",
603 DATA_NEUTRAL
604 ),
605 elem!("li", 0, 1, 1, 0, 0, 0, 0, "list item ", DATA_NEUTRAL),
606 elem!(
607 "link",
608 0,
609 2,
610 2,
611 1,
612 0,
613 0,
614 0,
615 "a media-independent link ",
616 DATA_NEUTRAL
617 ),
618 elem!(
619 "map",
620 0,
621 0,
622 0,
623 0,
624 0,
625 0,
626 2,
627 "client-side image map ",
628 DATA_NEUTRAL
629 ),
630 elem!("menu", 0, 0, 0, 0, 1, 1, 0, "menu list ", DATA_NEUTRAL),
631 elem!(
632 "meta",
633 0,
634 2,
635 2,
636 1,
637 0,
638 0,
639 0,
640 "generic metainformation ",
641 DATA_NEUTRAL
642 ),
643 elem!("noembed", 0, 0, 0, 0, 0, 0, 0, "", DATA_RAWTEXT),
644 elem!(
645 "noframes",
646 0,
647 0,
648 0,
649 0,
650 0,
651 2,
652 0,
653 "alternate content container for non frame-based rendering ",
654 DATA_RAWTEXT
655 ),
656 elem!(
657 "noscript",
658 0,
659 0,
660 0,
661 0,
662 0,
663 0,
664 0,
665 "alternate content container for non script-based rendering ",
666 DATA_NEUTRAL
667 ),
668 elem!(
669 "object",
670 0,
671 0,
672 0,
673 0,
674 0,
675 0,
676 2,
677 "generic embedded object ",
678 DATA_NEUTRAL
679 ),
680 elem!("ol", 0, 0, 0, 0, 0, 0, 0, "ordered list ", DATA_NEUTRAL),
681 elem!(
682 "optgroup",
683 0,
684 0,
685 0,
686 0,
687 0,
688 0,
689 0,
690 "option group ",
691 DATA_NEUTRAL
692 ),
693 elem!(
694 "option",
695 0,
696 1,
697 0,
698 0,
699 0,
700 0,
701 0,
702 "selectable choice ",
703 DATA_NEUTRAL
704 ),
705 elem!("p", 0, 1, 0, 0, 0, 0, 0, "paragraph ", DATA_NEUTRAL),
706 elem!(
707 "param",
708 0,
709 2,
710 2,
711 1,
712 0,
713 0,
714 0,
715 "named property value ",
716 DATA_NEUTRAL
717 ),
718 elem!("plaintext", 0, 0, 0, 0, 0, 0, 0, "", DATA_PLAINTEXT),
719 elem!(
720 "pre",
721 0,
722 0,
723 0,
724 0,
725 0,
726 0,
727 0,
728 "preformatted text ",
729 DATA_NEUTRAL
730 ),
731 elem!(
732 "q",
733 0,
734 0,
735 0,
736 0,
737 0,
738 0,
739 1,
740 "short inline quotation ",
741 DATA_NEUTRAL
742 ),
743 elem!(
744 "s",
745 0,
746 3,
747 0,
748 0,
749 1,
750 1,
751 1,
752 "strike-through text style",
753 DATA_NEUTRAL
754 ),
755 elem!(
756 "samp",
757 0,
758 0,
759 0,
760 0,
761 0,
762 0,
763 1,
764 "sample program output, scripts, etc.",
765 DATA_NEUTRAL
766 ),
767 elem!(
768 "script",
769 0,
770 0,
771 0,
772 0,
773 0,
774 0,
775 2,
776 "script statements ",
777 DATA_SCRIPT
778 ),
779 elem!(
780 "select",
781 0,
782 0,
783 0,
784 0,
785 0,
786 0,
787 1,
788 "option selector ",
789 DATA_NEUTRAL
790 ),
791 elem!(
792 "small",
793 0,
794 3,
795 0,
796 0,
797 0,
798 0,
799 1,
800 "small text style",
801 DATA_NEUTRAL
802 ),
803 elem!("source", 0, 0, 2, 1, 0, 0, 0, "", DATA_NEUTRAL),
804 elem!(
805 "span",
806 0,
807 0,
808 0,
809 0,
810 0,
811 0,
812 1,
813 "generic language/style container ",
814 DATA_NEUTRAL
815 ),
816 elem!(
817 "strike",
818 0,
819 3,
820 0,
821 0,
822 1,
823 1,
824 1,
825 "strike-through text",
826 DATA_NEUTRAL
827 ),
828 elem!(
829 "strong",
830 0,
831 3,
832 0,
833 0,
834 0,
835 0,
836 1,
837 "strong emphasis",
838 DATA_NEUTRAL
839 ),
840 elem!("style", 0, 0, 0, 0, 0, 0, 0, "style info ", DATA_RAWTEXT),
841 elem!("sub", 0, 3, 0, 0, 0, 0, 1, "subscript", DATA_NEUTRAL),
842 elem!("sup", 0, 3, 0, 0, 0, 0, 1, "superscript ", DATA_NEUTRAL),
843 elem!("table", 0, 0, 0, 0, 0, 0, 0, "", DATA_NEUTRAL),
844 elem!("tbody", 1, 0, 0, 0, 0, 0, 0, "table body ", DATA_NEUTRAL),
845 elem!("td", 0, 0, 0, 0, 0, 0, 0, "table data cell", DATA_NEUTRAL),
846 elem!(
847 "textarea",
848 0,
849 0,
850 0,
851 0,
852 0,
853 0,
854 1,
855 "multi-line text field ",
856 DATA_RCDATA
857 ),
858 elem!("tfoot", 0, 1, 0, 0, 0, 0, 0, "table footer ", DATA_NEUTRAL),
859 elem!("th", 0, 1, 0, 0, 0, 0, 0, "table header cell", DATA_NEUTRAL),
860 elem!("thead", 0, 1, 0, 0, 0, 0, 0, "table header ", DATA_NEUTRAL),
861 elem!("title", 0, 0, 0, 0, 0, 0, 0, "document title ", DATA_RCDATA),
862 elem!("tr", 0, 0, 0, 0, 0, 0, 0, "table row ", DATA_NEUTRAL),
863 elem!("track", 0, 0, 2, 1, 0, 0, 0, "", DATA_NEUTRAL),
864 elem!(
865 "tt",
866 0,
867 3,
868 0,
869 0,
870 0,
871 0,
872 1,
873 "teletype or monospaced text style",
874 DATA_NEUTRAL
875 ),
876 elem!(
877 "u",
878 0,
879 3,
880 0,
881 0,
882 1,
883 1,
884 1,
885 "underlined text style",
886 DATA_NEUTRAL
887 ),
888 elem!("ul", 0, 0, 0, 0, 0, 0, 0, "unordered list ", DATA_NEUTRAL),
889 elem!(
890 "var",
891 0,
892 0,
893 0,
894 0,
895 0,
896 0,
897 1,
898 "instance of a variable or program argument",
899 DATA_NEUTRAL
900 ),
901 elem!("wbr", 0, 0, 2, 1, 0, 0, 0, "", DATA_NEUTRAL),
902 elem!("xmp", 0, 0, 0, 0, 0, 0, 1, "", DATA_RAWTEXT),
903];
904
905#[no_mangle]
917pub unsafe extern "C" fn htmlTagLookup(tag: *const xmlChar) -> *const _htmlElemDesc {
918 if tag.is_null() {
919 return ptr::null();
920 }
921 let bytes = unsafe { xmlstr_to_bytes(tag) };
922 for e in HTML40_ELEMENTS {
923 let name = unsafe { core::ffi::CStr::from_ptr(e.name) }.to_bytes();
924 if bytes.eq_ignore_ascii_case(name) {
925 return e as *const _htmlElemDesc;
926 }
927 }
928 ptr::null()
929}
930
931#[derive(Debug)]
937#[repr(C)]
938pub struct _htmlEntityDesc {
939 pub value: c_uint,
940 pub name: *const c_char,
941 pub desc: *const c_char,
942}
943
944unsafe impl Sync for _htmlEntityDesc {}
946unsafe impl Send for _htmlEntityDesc {}
947
948macro_rules! ent {
950 ($value:expr, $name:literal, $desc:literal) => {
951 _htmlEntityDesc {
952 value: $value,
953 name: concat!($name, "\0").as_ptr() as *const c_char,
954 desc: concat!($desc, "\0").as_ptr() as *const c_char,
955 }
956 };
957}
958
959static HTML40_ENTITIES: &[_htmlEntityDesc] = &[
963 ent!(34, "quot", "quotation mark = APL quote, U+0022 ISOnum"),
964 ent!(38, "amp", "ampersand, U+0026 ISOnum"),
965 ent!(39, "apos", "single quote"),
966 ent!(60, "lt", "less-than sign, U+003C ISOnum"),
967 ent!(62, "gt", "greater-than sign, U+003E ISOnum"),
968 ent!(
969 160,
970 "nbsp",
971 "no-break space = non-breaking space, U+00A0 ISOnum"
972 ),
973 ent!(161, "iexcl", "inverted exclamation mark, U+00A1 ISOnum"),
974 ent!(162, "cent", "cent sign, U+00A2 ISOnum"),
975 ent!(163, "pound", "pound sign, U+00A3 ISOnum"),
976 ent!(164, "curren", "currency sign, U+00A4 ISOnum"),
977 ent!(165, "yen", "yen sign = yuan sign, U+00A5 ISOnum"),
978 ent!(
979 166,
980 "brvbar",
981 "broken bar = broken vertical bar, U+00A6 ISOnum"
982 ),
983 ent!(167, "sect", "section sign, U+00A7 ISOnum"),
984 ent!(168, "uml", "diaeresis = spacing diaeresis, U+00A8 ISOdia"),
985 ent!(169, "copy", "copyright sign, U+00A9 ISOnum"),
986 ent!(170, "ordf", "feminine ordinal indicator, U+00AA ISOnum"),
987 ent!(
988 171,
989 "laquo",
990 "left-pointing double angle quotation mark = left pointing guillemet, U+00AB ISOnum"
991 ),
992 ent!(172, "not", "not sign, U+00AC ISOnum"),
993 ent!(
994 173,
995 "shy",
996 "soft hyphen = discretionary hyphen, U+00AD ISOnum"
997 ),
998 ent!(
999 174,
1000 "reg",
1001 "registered sign = registered trade mark sign, U+00AE ISOnum"
1002 ),
1003 ent!(
1004 175,
1005 "macr",
1006 "macron = spacing macron = overline = APL overbar, U+00AF ISOdia"
1007 ),
1008 ent!(176, "deg", "degree sign, U+00B0 ISOnum"),
1009 ent!(
1010 177,
1011 "plusmn",
1012 "plus-minus sign = plus-or-minus sign, U+00B1 ISOnum"
1013 ),
1014 ent!(
1015 178,
1016 "sup2",
1017 "superscript two = superscript digit two = squared, U+00B2 ISOnum"
1018 ),
1019 ent!(
1020 179,
1021 "sup3",
1022 "superscript three = superscript digit three = cubed, U+00B3 ISOnum"
1023 ),
1024 ent!(180, "acute", "acute accent = spacing acute, U+00B4 ISOdia"),
1025 ent!(181, "micro", "micro sign, U+00B5 ISOnum"),
1026 ent!(182, "para", "pilcrow sign = paragraph sign, U+00B6 ISOnum"),
1027 ent!(
1028 183,
1029 "middot",
1030 "middle dot = Georgian comma Greek middle dot, U+00B7 ISOnum"
1031 ),
1032 ent!(184, "cedil", "cedilla = spacing cedilla, U+00B8 ISOdia"),
1033 ent!(
1034 185,
1035 "sup1",
1036 "superscript one = superscript digit one, U+00B9 ISOnum"
1037 ),
1038 ent!(186, "ordm", "masculine ordinal indicator, U+00BA ISOnum"),
1039 ent!(
1040 187,
1041 "raquo",
1042 "right-pointing double angle quotation mark right pointing guillemet, U+00BB ISOnum"
1043 ),
1044 ent!(
1045 188,
1046 "frac14",
1047 "vulgar fraction one quarter = fraction one quarter, U+00BC ISOnum"
1048 ),
1049 ent!(
1050 189,
1051 "frac12",
1052 "vulgar fraction one half = fraction one half, U+00BD ISOnum"
1053 ),
1054 ent!(
1055 190,
1056 "frac34",
1057 "vulgar fraction three quarters = fraction three quarters, U+00BE ISOnum"
1058 ),
1059 ent!(
1060 191,
1061 "iquest",
1062 "inverted question mark = turned question mark, U+00BF ISOnum"
1063 ),
1064 ent!(
1065 192,
1066 "Agrave",
1067 "latin capital letter A with grave = latin capital letter A grave, U+00C0 ISOlat1"
1068 ),
1069 ent!(
1070 193,
1071 "Aacute",
1072 "latin capital letter A with acute, U+00C1 ISOlat1"
1073 ),
1074 ent!(
1075 194,
1076 "Acirc",
1077 "latin capital letter A with circumflex, U+00C2 ISOlat1"
1078 ),
1079 ent!(
1080 195,
1081 "Atilde",
1082 "latin capital letter A with tilde, U+00C3 ISOlat1"
1083 ),
1084 ent!(
1085 196,
1086 "Auml",
1087 "latin capital letter A with diaeresis, U+00C4 ISOlat1"
1088 ),
1089 ent!(
1090 197,
1091 "Aring",
1092 "latin capital letter A with ring above = latin capital letter A ring, U+00C5 ISOlat1"
1093 ),
1094 ent!(
1095 198,
1096 "AElig",
1097 "latin capital letter AE = latin capital ligature AE, U+00C6 ISOlat1"
1098 ),
1099 ent!(
1100 199,
1101 "Ccedil",
1102 "latin capital letter C with cedilla, U+00C7 ISOlat1"
1103 ),
1104 ent!(
1105 200,
1106 "Egrave",
1107 "latin capital letter E with grave, U+00C8 ISOlat1"
1108 ),
1109 ent!(
1110 201,
1111 "Eacute",
1112 "latin capital letter E with acute, U+00C9 ISOlat1"
1113 ),
1114 ent!(
1115 202,
1116 "Ecirc",
1117 "latin capital letter E with circumflex, U+00CA ISOlat1"
1118 ),
1119 ent!(
1120 203,
1121 "Euml",
1122 "latin capital letter E with diaeresis, U+00CB ISOlat1"
1123 ),
1124 ent!(
1125 204,
1126 "Igrave",
1127 "latin capital letter I with grave, U+00CC ISOlat1"
1128 ),
1129 ent!(
1130 205,
1131 "Iacute",
1132 "latin capital letter I with acute, U+00CD ISOlat1"
1133 ),
1134 ent!(
1135 206,
1136 "Icirc",
1137 "latin capital letter I with circumflex, U+00CE ISOlat1"
1138 ),
1139 ent!(
1140 207,
1141 "Iuml",
1142 "latin capital letter I with diaeresis, U+00CF ISOlat1"
1143 ),
1144 ent!(208, "ETH", "latin capital letter ETH, U+00D0 ISOlat1"),
1145 ent!(
1146 209,
1147 "Ntilde",
1148 "latin capital letter N with tilde, U+00D1 ISOlat1"
1149 ),
1150 ent!(
1151 210,
1152 "Ograve",
1153 "latin capital letter O with grave, U+00D2 ISOlat1"
1154 ),
1155 ent!(
1156 211,
1157 "Oacute",
1158 "latin capital letter O with acute, U+00D3 ISOlat1"
1159 ),
1160 ent!(
1161 212,
1162 "Ocirc",
1163 "latin capital letter O with circumflex, U+00D4 ISOlat1"
1164 ),
1165 ent!(
1166 213,
1167 "Otilde",
1168 "latin capital letter O with tilde, U+00D5 ISOlat1"
1169 ),
1170 ent!(
1171 214,
1172 "Ouml",
1173 "latin capital letter O with diaeresis, U+00D6 ISOlat1"
1174 ),
1175 ent!(215, "times", "multiplication sign, U+00D7 ISOnum"),
1176 ent!(
1177 216,
1178 "Oslash",
1179 "latin capital letter O with stroke latin capital letter O slash, U+00D8 ISOlat1"
1180 ),
1181 ent!(
1182 217,
1183 "Ugrave",
1184 "latin capital letter U with grave, U+00D9 ISOlat1"
1185 ),
1186 ent!(
1187 218,
1188 "Uacute",
1189 "latin capital letter U with acute, U+00DA ISOlat1"
1190 ),
1191 ent!(
1192 219,
1193 "Ucirc",
1194 "latin capital letter U with circumflex, U+00DB ISOlat1"
1195 ),
1196 ent!(
1197 220,
1198 "Uuml",
1199 "latin capital letter U with diaeresis, U+00DC ISOlat1"
1200 ),
1201 ent!(
1202 221,
1203 "Yacute",
1204 "latin capital letter Y with acute, U+00DD ISOlat1"
1205 ),
1206 ent!(222, "THORN", "latin capital letter THORN, U+00DE ISOlat1"),
1207 ent!(
1208 223,
1209 "szlig",
1210 "latin small letter sharp s = ess-zed, U+00DF ISOlat1"
1211 ),
1212 ent!(
1213 224,
1214 "agrave",
1215 "latin small letter a with grave = latin small letter a grave, U+00E0 ISOlat1"
1216 ),
1217 ent!(
1218 225,
1219 "aacute",
1220 "latin small letter a with acute, U+00E1 ISOlat1"
1221 ),
1222 ent!(
1223 226,
1224 "acirc",
1225 "latin small letter a with circumflex, U+00E2 ISOlat1"
1226 ),
1227 ent!(
1228 227,
1229 "atilde",
1230 "latin small letter a with tilde, U+00E3 ISOlat1"
1231 ),
1232 ent!(
1233 228,
1234 "auml",
1235 "latin small letter a with diaeresis, U+00E4 ISOlat1"
1236 ),
1237 ent!(
1238 229,
1239 "aring",
1240 "latin small letter a with ring above = latin small letter a ring, U+00E5 ISOlat1"
1241 ),
1242 ent!(
1243 230,
1244 "aelig",
1245 "latin small letter ae = latin small ligature ae, U+00E6 ISOlat1"
1246 ),
1247 ent!(
1248 231,
1249 "ccedil",
1250 "latin small letter c with cedilla, U+00E7 ISOlat1"
1251 ),
1252 ent!(
1253 232,
1254 "egrave",
1255 "latin small letter e with grave, U+00E8 ISOlat1"
1256 ),
1257 ent!(
1258 233,
1259 "eacute",
1260 "latin small letter e with acute, U+00E9 ISOlat1"
1261 ),
1262 ent!(
1263 234,
1264 "ecirc",
1265 "latin small letter e with circumflex, U+00EA ISOlat1"
1266 ),
1267 ent!(
1268 235,
1269 "euml",
1270 "latin small letter e with diaeresis, U+00EB ISOlat1"
1271 ),
1272 ent!(
1273 236,
1274 "igrave",
1275 "latin small letter i with grave, U+00EC ISOlat1"
1276 ),
1277 ent!(
1278 237,
1279 "iacute",
1280 "latin small letter i with acute, U+00ED ISOlat1"
1281 ),
1282 ent!(
1283 238,
1284 "icirc",
1285 "latin small letter i with circumflex, U+00EE ISOlat1"
1286 ),
1287 ent!(
1288 239,
1289 "iuml",
1290 "latin small letter i with diaeresis, U+00EF ISOlat1"
1291 ),
1292 ent!(240, "eth", "latin small letter eth, U+00F0 ISOlat1"),
1293 ent!(
1294 241,
1295 "ntilde",
1296 "latin small letter n with tilde, U+00F1 ISOlat1"
1297 ),
1298 ent!(
1299 242,
1300 "ograve",
1301 "latin small letter o with grave, U+00F2 ISOlat1"
1302 ),
1303 ent!(
1304 243,
1305 "oacute",
1306 "latin small letter o with acute, U+00F3 ISOlat1"
1307 ),
1308 ent!(
1309 244,
1310 "ocirc",
1311 "latin small letter o with circumflex, U+00F4 ISOlat1"
1312 ),
1313 ent!(
1314 245,
1315 "otilde",
1316 "latin small letter o with tilde, U+00F5 ISOlat1"
1317 ),
1318 ent!(
1319 246,
1320 "ouml",
1321 "latin small letter o with diaeresis, U+00F6 ISOlat1"
1322 ),
1323 ent!(247, "divide", "division sign, U+00F7 ISOnum"),
1324 ent!(
1325 248,
1326 "oslash",
1327 "latin small letter o with stroke, = latin small letter o slash, U+00F8 ISOlat1"
1328 ),
1329 ent!(
1330 249,
1331 "ugrave",
1332 "latin small letter u with grave, U+00F9 ISOlat1"
1333 ),
1334 ent!(
1335 250,
1336 "uacute",
1337 "latin small letter u with acute, U+00FA ISOlat1"
1338 ),
1339 ent!(
1340 251,
1341 "ucirc",
1342 "latin small letter u with circumflex, U+00FB ISOlat1"
1343 ),
1344 ent!(
1345 252,
1346 "uuml",
1347 "latin small letter u with diaeresis, U+00FC ISOlat1"
1348 ),
1349 ent!(
1350 253,
1351 "yacute",
1352 "latin small letter y with acute, U+00FD ISOlat1"
1353 ),
1354 ent!(
1355 254,
1356 "thorn",
1357 "latin small letter thorn with, U+00FE ISOlat1"
1358 ),
1359 ent!(
1360 255,
1361 "yuml",
1362 "latin small letter y with diaeresis, U+00FF ISOlat1"
1363 ),
1364 ent!(338, "OElig", "latin capital ligature OE, U+0152 ISOlat2"),
1365 ent!(339, "oelig", "latin small ligature oe, U+0153 ISOlat2"),
1366 ent!(
1367 352,
1368 "Scaron",
1369 "latin capital letter S with caron, U+0160 ISOlat2"
1370 ),
1371 ent!(
1372 353,
1373 "scaron",
1374 "latin small letter s with caron, U+0161 ISOlat2"
1375 ),
1376 ent!(
1377 376,
1378 "Yuml",
1379 "latin capital letter Y with diaeresis, U+0178 ISOlat2"
1380 ),
1381 ent!(
1382 402,
1383 "fnof",
1384 "latin small f with hook = function = florin, U+0192 ISOtech"
1385 ),
1386 ent!(
1387 710,
1388 "circ",
1389 "modifier letter circumflex accent, U+02C6 ISOpub"
1390 ),
1391 ent!(732, "tilde", "small tilde, U+02DC ISOdia"),
1392 ent!(913, "Alpha", "greek capital letter alpha, U+0391"),
1393 ent!(914, "Beta", "greek capital letter beta, U+0392"),
1394 ent!(915, "Gamma", "greek capital letter gamma, U+0393 ISOgrk3"),
1395 ent!(916, "Delta", "greek capital letter delta, U+0394 ISOgrk3"),
1396 ent!(917, "Epsilon", "greek capital letter epsilon, U+0395"),
1397 ent!(918, "Zeta", "greek capital letter zeta, U+0396"),
1398 ent!(919, "Eta", "greek capital letter eta, U+0397"),
1399 ent!(920, "Theta", "greek capital letter theta, U+0398 ISOgrk3"),
1400 ent!(921, "Iota", "greek capital letter iota, U+0399"),
1401 ent!(922, "Kappa", "greek capital letter kappa, U+039A"),
1402 ent!(923, "Lambda", "greek capital letter lambda, U+039B ISOgrk3"),
1403 ent!(924, "Mu", "greek capital letter mu, U+039C"),
1404 ent!(925, "Nu", "greek capital letter nu, U+039D"),
1405 ent!(926, "Xi", "greek capital letter xi, U+039E ISOgrk3"),
1406 ent!(927, "Omicron", "greek capital letter omicron, U+039F"),
1407 ent!(928, "Pi", "greek capital letter pi, U+03A0 ISOgrk3"),
1408 ent!(929, "Rho", "greek capital letter rho, U+03A1"),
1409 ent!(931, "Sigma", "greek capital letter sigma, U+03A3 ISOgrk3"),
1410 ent!(932, "Tau", "greek capital letter tau, U+03A4"),
1411 ent!(
1412 933,
1413 "Upsilon",
1414 "greek capital letter upsilon, U+03A5 ISOgrk3"
1415 ),
1416 ent!(934, "Phi", "greek capital letter phi, U+03A6 ISOgrk3"),
1417 ent!(935, "Chi", "greek capital letter chi, U+03A7"),
1418 ent!(936, "Psi", "greek capital letter psi, U+03A8 ISOgrk3"),
1419 ent!(937, "Omega", "greek capital letter omega, U+03A9 ISOgrk3"),
1420 ent!(945, "alpha", "greek small letter alpha, U+03B1 ISOgrk3"),
1421 ent!(946, "beta", "greek small letter beta, U+03B2 ISOgrk3"),
1422 ent!(947, "gamma", "greek small letter gamma, U+03B3 ISOgrk3"),
1423 ent!(948, "delta", "greek small letter delta, U+03B4 ISOgrk3"),
1424 ent!(949, "epsilon", "greek small letter epsilon, U+03B5 ISOgrk3"),
1425 ent!(950, "zeta", "greek small letter zeta, U+03B6 ISOgrk3"),
1426 ent!(951, "eta", "greek small letter eta, U+03B7 ISOgrk3"),
1427 ent!(952, "theta", "greek small letter theta, U+03B8 ISOgrk3"),
1428 ent!(953, "iota", "greek small letter iota, U+03B9 ISOgrk3"),
1429 ent!(954, "kappa", "greek small letter kappa, U+03BA ISOgrk3"),
1430 ent!(955, "lambda", "greek small letter lambda, U+03BB ISOgrk3"),
1431 ent!(956, "mu", "greek small letter mu, U+03BC ISOgrk3"),
1432 ent!(957, "nu", "greek small letter nu, U+03BD ISOgrk3"),
1433 ent!(958, "xi", "greek small letter xi, U+03BE ISOgrk3"),
1434 ent!(959, "omicron", "greek small letter omicron, U+03BF NEW"),
1435 ent!(960, "pi", "greek small letter pi, U+03C0 ISOgrk3"),
1436 ent!(961, "rho", "greek small letter rho, U+03C1 ISOgrk3"),
1437 ent!(
1438 962,
1439 "sigmaf",
1440 "greek small letter final sigma, U+03C2 ISOgrk3"
1441 ),
1442 ent!(963, "sigma", "greek small letter sigma, U+03C3 ISOgrk3"),
1443 ent!(964, "tau", "greek small letter tau, U+03C4 ISOgrk3"),
1444 ent!(965, "upsilon", "greek small letter upsilon, U+03C5 ISOgrk3"),
1445 ent!(966, "phi", "greek small letter phi, U+03C6 ISOgrk3"),
1446 ent!(967, "chi", "greek small letter chi, U+03C7 ISOgrk3"),
1447 ent!(968, "psi", "greek small letter psi, U+03C8 ISOgrk3"),
1448 ent!(969, "omega", "greek small letter omega, U+03C9 ISOgrk3"),
1449 ent!(
1450 977,
1451 "thetasym",
1452 "greek small letter theta symbol, U+03D1 NEW"
1453 ),
1454 ent!(978, "upsih", "greek upsilon with hook symbol, U+03D2 NEW"),
1455 ent!(982, "piv", "greek pi symbol, U+03D6 ISOgrk3"),
1456 ent!(8194, "ensp", "en space, U+2002 ISOpub"),
1457 ent!(8195, "emsp", "em space, U+2003 ISOpub"),
1458 ent!(8201, "thinsp", "thin space, U+2009 ISOpub"),
1459 ent!(8204, "zwnj", "zero width non-joiner, U+200C NEW RFC 2070"),
1460 ent!(8205, "zwj", "zero width joiner, U+200D NEW RFC 2070"),
1461 ent!(8206, "lrm", "left-to-right mark, U+200E NEW RFC 2070"),
1462 ent!(8207, "rlm", "right-to-left mark, U+200F NEW RFC 2070"),
1463 ent!(8211, "ndash", "en dash, U+2013 ISOpub"),
1464 ent!(8212, "mdash", "em dash, U+2014 ISOpub"),
1465 ent!(8216, "lsquo", "left single quotation mark, U+2018 ISOnum"),
1466 ent!(8217, "rsquo", "right single quotation mark, U+2019 ISOnum"),
1467 ent!(8218, "sbquo", "single low-9 quotation mark, U+201A NEW"),
1468 ent!(8220, "ldquo", "left double quotation mark, U+201C ISOnum"),
1469 ent!(8221, "rdquo", "right double quotation mark, U+201D ISOnum"),
1470 ent!(8222, "bdquo", "double low-9 quotation mark, U+201E NEW"),
1471 ent!(8224, "dagger", "dagger, U+2020 ISOpub"),
1472 ent!(8225, "Dagger", "double dagger, U+2021 ISOpub"),
1473 ent!(8226, "bull", "bullet = black small circle, U+2022 ISOpub"),
1474 ent!(
1475 8230,
1476 "hellip",
1477 "horizontal ellipsis = three dot leader, U+2026 ISOpub"
1478 ),
1479 ent!(8240, "permil", "per mille sign, U+2030 ISOtech"),
1480 ent!(8242, "prime", "prime = minutes = feet, U+2032 ISOtech"),
1481 ent!(
1482 8243,
1483 "Prime",
1484 "double prime = seconds = inches, U+2033 ISOtech"
1485 ),
1486 ent!(
1487 8249,
1488 "lsaquo",
1489 "single left-pointing angle quotation mark, U+2039 ISO proposed"
1490 ),
1491 ent!(
1492 8250,
1493 "rsaquo",
1494 "single right-pointing angle quotation mark, U+203A ISO proposed"
1495 ),
1496 ent!(8254, "oline", "overline = spacing overscore, U+203E NEW"),
1497 ent!(8260, "frasl", "fraction slash, U+2044 NEW"),
1498 ent!(8364, "euro", "euro sign, U+20AC NEW"),
1499 ent!(
1500 8465,
1501 "image",
1502 "blackletter capital I = imaginary part, U+2111 ISOamso"
1503 ),
1504 ent!(
1505 8472,
1506 "weierp",
1507 "script capital P = power set = Weierstrass p, U+2118 ISOamso"
1508 ),
1509 ent!(
1510 8476,
1511 "real",
1512 "blackletter capital R = real part symbol, U+211C ISOamso"
1513 ),
1514 ent!(8482, "trade", "trade mark sign, U+2122 ISOnum"),
1515 ent!(
1516 8501,
1517 "alefsym",
1518 "alef symbol = first transfinite cardinal, U+2135 NEW"
1519 ),
1520 ent!(8592, "larr", "leftwards arrow, U+2190 ISOnum"),
1521 ent!(8593, "uarr", "upwards arrow, U+2191 ISOnum"),
1522 ent!(8594, "rarr", "rightwards arrow, U+2192 ISOnum"),
1523 ent!(8595, "darr", "downwards arrow, U+2193 ISOnum"),
1524 ent!(8596, "harr", "left right arrow, U+2194 ISOamsa"),
1525 ent!(
1526 8629,
1527 "crarr",
1528 "downwards arrow with corner leftwards = carriage return, U+21B5 NEW"
1529 ),
1530 ent!(8656, "lArr", "leftwards double arrow, U+21D0 ISOtech"),
1531 ent!(8657, "uArr", "upwards double arrow, U+21D1 ISOamsa"),
1532 ent!(8658, "rArr", "rightwards double arrow, U+21D2 ISOtech"),
1533 ent!(8659, "dArr", "downwards double arrow, U+21D3 ISOamsa"),
1534 ent!(8660, "hArr", "left right double arrow, U+21D4 ISOamsa"),
1535 ent!(8704, "forall", "for all, U+2200 ISOtech"),
1536 ent!(8706, "part", "partial differential, U+2202 ISOtech"),
1537 ent!(8707, "exist", "there exists, U+2203 ISOtech"),
1538 ent!(
1539 8709,
1540 "empty",
1541 "empty set = null set = diameter, U+2205 ISOamso"
1542 ),
1543 ent!(8711, "nabla", "nabla = backward difference, U+2207 ISOtech"),
1544 ent!(8712, "isin", "element of, U+2208 ISOtech"),
1545 ent!(8713, "notin", "not an element of, U+2209 ISOtech"),
1546 ent!(8715, "ni", "contains as member, U+220B ISOtech"),
1547 ent!(8719, "prod", "n-ary product = product sign, U+220F ISOamsb"),
1548 ent!(8721, "sum", "n-ary summation, U+2211 ISOamsb"),
1549 ent!(8722, "minus", "minus sign, U+2212 ISOtech"),
1550 ent!(8727, "lowast", "asterisk operator, U+2217 ISOtech"),
1551 ent!(8730, "radic", "square root = radical sign, U+221A ISOtech"),
1552 ent!(8733, "prop", "proportional to, U+221D ISOtech"),
1553 ent!(8734, "infin", "infinity, U+221E ISOtech"),
1554 ent!(8736, "ang", "angle, U+2220 ISOamso"),
1555 ent!(8743, "and", "logical and = wedge, U+2227 ISOtech"),
1556 ent!(8744, "or", "logical or = vee, U+2228 ISOtech"),
1557 ent!(8745, "cap", "intersection = cap, U+2229 ISOtech"),
1558 ent!(8746, "cup", "union = cup, U+222A ISOtech"),
1559 ent!(8747, "int", "integral, U+222B ISOtech"),
1560 ent!(8756, "there4", "therefore, U+2234 ISOtech"),
1561 ent!(
1562 8764,
1563 "sim",
1564 "tilde operator = varies with = similar to, U+223C ISOtech"
1565 ),
1566 ent!(8773, "cong", "approximately equal to, U+2245 ISOtech"),
1567 ent!(
1568 8776,
1569 "asymp",
1570 "almost equal to = asymptotic to, U+2248 ISOamsr"
1571 ),
1572 ent!(8800, "ne", "not equal to, U+2260 ISOtech"),
1573 ent!(8801, "equiv", "identical to, U+2261 ISOtech"),
1574 ent!(8804, "le", "less-than or equal to, U+2264 ISOtech"),
1575 ent!(8805, "ge", "greater-than or equal to, U+2265 ISOtech"),
1576 ent!(8834, "sub", "subset of, U+2282 ISOtech"),
1577 ent!(8835, "sup", "superset of, U+2283 ISOtech"),
1578 ent!(8836, "nsub", "not a subset of, U+2284 ISOamsn"),
1579 ent!(8838, "sube", "subset of or equal to, U+2286 ISOtech"),
1580 ent!(8839, "supe", "superset of or equal to, U+2287 ISOtech"),
1581 ent!(8853, "oplus", "circled plus = direct sum, U+2295 ISOamsb"),
1582 ent!(
1583 8855,
1584 "otimes",
1585 "circled times = vector product, U+2297 ISOamsb"
1586 ),
1587 ent!(
1588 8869,
1589 "perp",
1590 "up tack = orthogonal to = perpendicular, U+22A5 ISOtech"
1591 ),
1592 ent!(8901, "sdot", "dot operator, U+22C5 ISOamsb"),
1593 ent!(8968, "lceil", "left ceiling = apl upstile, U+2308 ISOamsc"),
1594 ent!(8969, "rceil", "right ceiling, U+2309 ISOamsc"),
1595 ent!(8970, "lfloor", "left floor = apl downstile, U+230A ISOamsc"),
1596 ent!(8971, "rfloor", "right floor, U+230B ISOamsc"),
1597 ent!(
1598 9001,
1599 "lang",
1600 "left-pointing angle bracket = bra, U+2329 ISOtech"
1601 ),
1602 ent!(
1603 9002,
1604 "rang",
1605 "right-pointing angle bracket = ket, U+232A ISOtech"
1606 ),
1607 ent!(9674, "loz", "lozenge, U+25CA ISOpub"),
1608 ent!(9824, "spades", "black spade suit, U+2660 ISOpub"),
1609 ent!(9827, "clubs", "black club suit = shamrock, U+2663 ISOpub"),
1610 ent!(
1611 9829,
1612 "hearts",
1613 "black heart suit = valentine, U+2665 ISOpub"
1614 ),
1615 ent!(9830, "diams", "black diamond suit, U+2666 ISOpub"),
1616];
1617
1618#[no_mangle]
1629pub unsafe extern "C" fn htmlEntityLookup(name: *const xmlChar) -> *const _htmlEntityDesc {
1630 if name.is_null() {
1631 return ptr::null();
1632 }
1633 let bytes = unsafe { xmlstr_to_bytes(name) };
1634 for e in HTML40_ENTITIES {
1635 let ename = unsafe { core::ffi::CStr::from_ptr(e.name) }.to_bytes();
1636 if bytes == ename {
1637 return e as *const _htmlEntityDesc;
1638 }
1639 }
1640 ptr::null()
1641}
1642
1643#[no_mangle]
1654pub unsafe extern "C" fn htmlEntityValueLookup(value: c_uint) -> *const _htmlEntityDesc {
1655 for e in HTML40_ENTITIES {
1656 if e.value == value {
1657 return e as *const _htmlEntityDesc;
1658 }
1659 }
1660 ptr::null()
1661}
1662
1663#[inline]
1666unsafe fn html_entity_value_lookup_static(value: c_uint) -> *const _htmlEntityDesc {
1667 for e in HTML40_ENTITIES {
1668 if e.value == value {
1669 return e as *const _htmlEntityDesc;
1670 }
1671 }
1672 ptr::null()
1673}
1674
1675static HTML_START_CLOSE: &[(&str, &str)] = &[
1683 ("a", "a"),
1684 ("a", "fieldset"),
1685 ("a", "table"),
1686 ("a", "td"),
1687 ("a", "th"),
1688 ("address", "dd"),
1689 ("address", "dl"),
1690 ("address", "dt"),
1691 ("address", "form"),
1692 ("address", "li"),
1693 ("address", "ul"),
1694 ("b", "center"),
1695 ("b", "p"),
1696 ("b", "td"),
1697 ("b", "th"),
1698 ("big", "p"),
1699 ("caption", "col"),
1700 ("caption", "colgroup"),
1701 ("caption", "tbody"),
1702 ("caption", "tfoot"),
1703 ("caption", "thead"),
1704 ("caption", "tr"),
1705 ("col", "col"),
1706 ("col", "colgroup"),
1707 ("col", "tbody"),
1708 ("col", "tfoot"),
1709 ("col", "thead"),
1710 ("col", "tr"),
1711 ("colgroup", "colgroup"),
1712 ("colgroup", "tbody"),
1713 ("colgroup", "tfoot"),
1714 ("colgroup", "thead"),
1715 ("colgroup", "tr"),
1716 ("dd", "dt"),
1717 ("dir", "dd"),
1718 ("dir", "dl"),
1719 ("dir", "dt"),
1720 ("dir", "form"),
1721 ("dir", "ul"),
1722 ("dl", "form"),
1723 ("dl", "li"),
1724 ("dt", "dd"),
1725 ("dt", "dl"),
1726 ("font", "center"),
1727 ("font", "td"),
1728 ("font", "th"),
1729 ("form", "form"),
1730 ("h1", "fieldset"),
1731 ("h1", "form"),
1732 ("h1", "li"),
1733 ("h1", "p"),
1734 ("h1", "table"),
1735 ("h2", "fieldset"),
1736 ("h2", "form"),
1737 ("h2", "li"),
1738 ("h2", "p"),
1739 ("h2", "table"),
1740 ("h3", "fieldset"),
1741 ("h3", "form"),
1742 ("h3", "li"),
1743 ("h3", "p"),
1744 ("h3", "table"),
1745 ("h4", "fieldset"),
1746 ("h4", "form"),
1747 ("h4", "li"),
1748 ("h4", "p"),
1749 ("h4", "table"),
1750 ("h5", "fieldset"),
1751 ("h5", "form"),
1752 ("h5", "li"),
1753 ("h5", "p"),
1754 ("h5", "table"),
1755 ("h6", "fieldset"),
1756 ("h6", "form"),
1757 ("h6", "li"),
1758 ("h6", "p"),
1759 ("h6", "table"),
1760 ("head", "a"),
1761 ("head", "abbr"),
1762 ("head", "acronym"),
1763 ("head", "address"),
1764 ("head", "b"),
1765 ("head", "bdo"),
1766 ("head", "big"),
1767 ("head", "blockquote"),
1768 ("head", "body"),
1769 ("head", "br"),
1770 ("head", "center"),
1771 ("head", "cite"),
1772 ("head", "code"),
1773 ("head", "dd"),
1774 ("head", "dfn"),
1775 ("head", "dir"),
1776 ("head", "div"),
1777 ("head", "dl"),
1778 ("head", "dt"),
1779 ("head", "em"),
1780 ("head", "fieldset"),
1781 ("head", "font"),
1782 ("head", "form"),
1783 ("head", "frameset"),
1784 ("head", "h1"),
1785 ("head", "h2"),
1786 ("head", "h3"),
1787 ("head", "h4"),
1788 ("head", "h5"),
1789 ("head", "h6"),
1790 ("head", "hr"),
1791 ("head", "i"),
1792 ("head", "iframe"),
1793 ("head", "img"),
1794 ("head", "kbd"),
1795 ("head", "li"),
1796 ("head", "listing"),
1797 ("head", "map"),
1798 ("head", "menu"),
1799 ("head", "ol"),
1800 ("head", "p"),
1801 ("head", "pre"),
1802 ("head", "q"),
1803 ("head", "s"),
1804 ("head", "samp"),
1805 ("head", "small"),
1806 ("head", "span"),
1807 ("head", "strike"),
1808 ("head", "strong"),
1809 ("head", "sub"),
1810 ("head", "sup"),
1811 ("head", "table"),
1812 ("head", "tt"),
1813 ("head", "u"),
1814 ("head", "ul"),
1815 ("head", "var"),
1816 ("head", "xmp"),
1817 ("hr", "form"),
1818 ("i", "center"),
1819 ("i", "p"),
1820 ("i", "td"),
1821 ("i", "th"),
1822 ("legend", "fieldset"),
1823 ("li", "li"),
1824 ("link", "body"),
1825 ("link", "frameset"),
1826 ("listing", "dd"),
1827 ("listing", "dl"),
1828 ("listing", "dt"),
1829 ("listing", "fieldset"),
1830 ("listing", "form"),
1831 ("listing", "li"),
1832 ("listing", "table"),
1833 ("listing", "ul"),
1834 ("menu", "dd"),
1835 ("menu", "dl"),
1836 ("menu", "dt"),
1837 ("menu", "form"),
1838 ("menu", "ul"),
1839 ("ol", "form"),
1840 ("option", "optgroup"),
1841 ("option", "option"),
1842 ("p", "address"),
1843 ("p", "blockquote"),
1844 ("p", "body"),
1845 ("p", "caption"),
1846 ("p", "center"),
1847 ("p", "col"),
1848 ("p", "colgroup"),
1849 ("p", "dd"),
1850 ("p", "dir"),
1851 ("p", "div"),
1852 ("p", "dl"),
1853 ("p", "dt"),
1854 ("p", "fieldset"),
1855 ("p", "form"),
1856 ("p", "frameset"),
1857 ("p", "h1"),
1858 ("p", "h2"),
1859 ("p", "h3"),
1860 ("p", "h4"),
1861 ("p", "h5"),
1862 ("p", "h6"),
1863 ("p", "head"),
1864 ("p", "hr"),
1865 ("p", "li"),
1866 ("p", "listing"),
1867 ("p", "menu"),
1868 ("p", "ol"),
1869 ("p", "p"),
1870 ("p", "pre"),
1871 ("p", "table"),
1872 ("p", "tbody"),
1873 ("p", "td"),
1874 ("p", "tfoot"),
1875 ("p", "th"),
1876 ("p", "title"),
1877 ("p", "tr"),
1878 ("p", "ul"),
1879 ("p", "xmp"),
1880 ("pre", "dd"),
1881 ("pre", "dl"),
1882 ("pre", "dt"),
1883 ("pre", "fieldset"),
1884 ("pre", "form"),
1885 ("pre", "li"),
1886 ("pre", "table"),
1887 ("pre", "ul"),
1888 ("s", "p"),
1889 ("script", "noscript"),
1890 ("small", "p"),
1891 ("span", "td"),
1892 ("span", "th"),
1893 ("strike", "p"),
1894 ("style", "body"),
1895 ("style", "frameset"),
1896 ("tbody", "tbody"),
1897 ("tbody", "tfoot"),
1898 ("td", "tbody"),
1899 ("td", "td"),
1900 ("td", "tfoot"),
1901 ("td", "th"),
1902 ("td", "tr"),
1903 ("tfoot", "tbody"),
1904 ("th", "tbody"),
1905 ("th", "td"),
1906 ("th", "tfoot"),
1907 ("th", "th"),
1908 ("th", "tr"),
1909 ("thead", "tbody"),
1910 ("thead", "tfoot"),
1911 ("title", "body"),
1912 ("title", "frameset"),
1913 ("tr", "tbody"),
1914 ("tr", "tfoot"),
1915 ("tr", "tr"),
1916 ("tt", "p"),
1917 ("u", "p"),
1918 ("u", "td"),
1919 ("u", "th"),
1920 ("ul", "address"),
1921 ("ul", "form"),
1922 ("ul", "menu"),
1923 ("ul", "pre"),
1924 ("xmp", "dd"),
1925 ("xmp", "dl"),
1926 ("xmp", "dt"),
1927 ("xmp", "fieldset"),
1928 ("xmp", "form"),
1929 ("xmp", "li"),
1930 ("xmp", "table"),
1931 ("xmp", "ul"),
1932];
1933
1934unsafe fn html_check_auto_close(newtag: *const xmlChar, oldtag: *const xmlChar) -> bool {
1938 if newtag.is_null() || oldtag.is_null() {
1939 return false;
1940 }
1941 let new_bytes = unsafe { xmlstr_to_bytes(newtag) };
1942 let old_bytes = unsafe { xmlstr_to_bytes(oldtag) };
1943 HTML_START_CLOSE
1944 .iter()
1945 .any(|(old, new)| old.as_bytes() == old_bytes && new.as_bytes() == new_bytes)
1946}
1947
1948#[no_mangle]
1958pub unsafe extern "C" fn htmlAutoCloseTag(
1959 _doc: *mut _xmlDoc,
1960 name: *const xmlChar,
1961 elem: *mut _xmlNode,
1962) -> c_int {
1963 if elem.is_null() {
1964 return 1;
1965 }
1966 let n = unsafe { &*elem };
1967 if n.name.is_null() {
1968 } else if unsafe { xml_strcmp(name, n.name) } == 0 {
1971 return 0;
1972 }
1973 if unsafe { html_check_auto_close(n.name, name) } {
1974 return 1;
1975 }
1976 let mut child = n.children;
1977 while !child.is_null() {
1978 if unsafe { htmlAutoCloseTag(_doc, name, child) } != 0 {
1979 return 1;
1980 }
1981 child = unsafe { (*child).next };
1982 }
1983 0
1984}
1985
1986#[no_mangle]
1995pub unsafe extern "C" fn htmlIsAutoClosed(doc: *mut _xmlDoc, elem: *mut _xmlNode) -> c_int {
1996 if elem.is_null() {
1997 return 1;
1998 }
1999 let n = unsafe { &*elem };
2000 let mut child = n.children;
2001 while !child.is_null() {
2002 if unsafe { htmlAutoCloseTag(doc, n.name, child) } != 0 {
2003 return 1;
2004 }
2005 child = unsafe { (*child).next };
2006 }
2007 0
2008}
2009
2010static HTML_SCRIPT_ATTRIBUTES: &[&str] = &[
2013 "onclick",
2014 "ondblclick",
2015 "onmousedown",
2016 "onmouseup",
2017 "onmouseover",
2018 "onmousemove",
2019 "onmouseout",
2020 "onkeypress",
2021 "onkeydown",
2022 "onkeyup",
2023 "onload",
2024 "onunload",
2025 "onfocus",
2026 "onblur",
2027 "onsubmit",
2028 "onreset",
2029 "onchange",
2030 "onselect",
2031];
2032
2033#[no_mangle]
2042pub unsafe extern "C" fn htmlIsScriptAttribute(name: *const xmlChar) -> c_int {
2043 if name.is_null() {
2044 return 0;
2045 }
2046 let bytes = unsafe { xmlstr_to_bytes(name) };
2047 if bytes.len() < 3 || bytes[0] != b'o' || bytes[1] != b'n' {
2048 return 0;
2049 }
2050 for cand in HTML_SCRIPT_ATTRIBUTES {
2051 if bytes == cand.as_bytes() {
2052 return 1;
2053 }
2054 }
2055 0
2056}
2057
2058#[no_mangle]
2070pub const unsafe extern "C" fn htmlElementAllowedHere(
2071 _parent: *const _htmlElemDesc,
2072 _elt: *const xmlChar,
2073) -> c_int {
2074 1
2075}
2076
2077#[no_mangle]
2085pub const unsafe extern "C" fn htmlElementStatusHere(
2086 _parent: *const _htmlElemDesc,
2087 _elt: *const _htmlElemDesc,
2088) -> c_int {
2089 HTML_VALID
2090}
2091
2092#[no_mangle]
2100pub const unsafe extern "C" fn htmlAttrAllowed(
2101 _elt: *const _htmlElemDesc,
2102 _attr: *const xmlChar,
2103 _legacy: c_int,
2104) -> c_int {
2105 HTML_VALID
2106}
2107
2108#[no_mangle]
2116pub const unsafe extern "C" fn htmlNodeStatus(_node: *mut _xmlNode, _legacy: c_int) -> c_int {
2117 HTML_VALID
2118}
2119
2120#[no_mangle]
2139pub unsafe extern "C" fn htmlEncodeEntities(
2140 out: *mut u8,
2141 outlen: *mut c_int,
2142 input: *const u8,
2143 inlen: *mut c_int,
2144 quoteChar: c_int,
2145) -> c_int {
2146 if out.is_null() || outlen.is_null() || inlen.is_null() || input.is_null() {
2147 return -1;
2148 }
2149 let outend = (out as usize).wrapping_add((*outlen).max(0) as usize);
2150 let inend = (input as usize).wrapping_add((*inlen).max(0) as usize);
2151 let mut in_ptr = input as usize;
2152 let mut out_ptr = out as usize;
2153 let mut processed = in_ptr;
2154
2155 while in_ptr < inend {
2156 let mut c: c_uint;
2157
2158 let mut trailing: c_int;
2159
2160 let d: c_uint = unsafe { *(in_ptr as *const u8) as c_uint };
2161 in_ptr += 1;
2162 if d < 0x80 {
2163 c = d;
2164 trailing = 0;
2165 } else if d < 0xC0 {
2166 *outlen = (out_ptr - out as usize) as c_int;
2168 *inlen = (processed - input as usize) as c_int;
2169 return -2;
2170 } else if d < 0xE0 {
2171 c = d & 0x1F;
2172 trailing = 1;
2173 } else if d < 0xF0 {
2174 c = d & 0x0F;
2175 trailing = 2;
2176 } else if d < 0xF8 {
2177 c = d & 0x07;
2178 trailing = 3;
2179 } else {
2180 *outlen = (out_ptr - out as usize) as c_int;
2182 *inlen = (processed - input as usize) as c_int;
2183 return -2;
2184 }
2185
2186 if inend - in_ptr < trailing as usize {
2187 break;
2188 }
2189
2190 while trailing > 0 {
2191 let t = unsafe { *(in_ptr as *const u8) as c_uint };
2192 in_ptr += 1;
2193 if (t & 0xC0) != 0x80 {
2194 *outlen = (out_ptr - out as usize) as c_int;
2195 *inlen = (processed - input as usize) as c_int;
2196 return -2;
2197 }
2198 c = (c << 6) | (t & 0x3F);
2199 trailing -= 1;
2200 }
2201
2202 if (c < 0x80)
2204 && (c != quoteChar as c_uint)
2205 && (c != b'&' as c_uint)
2206 && (c != b'<' as c_uint)
2207 && (c != b'>' as c_uint)
2208 {
2209 if out_ptr >= outend {
2210 break;
2211 }
2212 unsafe { *(out_ptr as *mut u8) = c as u8 };
2213 out_ptr += 1;
2214 } else {
2215 let ent = unsafe { html_entity_value_lookup_static(c) };
2216 let mut nbuf = [0u8; 16];
2217 let (cp, len): (*const u8, usize) = if ent.is_null() {
2218 nbuf[0] = b'#';
2220 let mut i = 1usize;
2221 let mut digits = [0u8; 10];
2222 let mut nd = 0usize;
2223 let mut v = c;
2224 if v == 0 {
2225 digits[0] = b'0';
2226 nd = 1;
2227 }
2228 while v > 0 {
2229 digits[nd] = b'0' + (v % 10) as u8;
2230 nd += 1;
2231 v /= 10;
2232 }
2233 while nd > 0 {
2234 nd -= 1;
2235 nbuf[i] = digits[nd];
2236 i += 1;
2237 }
2238 (nbuf.as_ptr(), i)
2239 } else {
2240 (unsafe { (*ent).name } as *const u8, unsafe {
2241 xml_strlen((*ent).name as *const xmlChar)
2242 })
2243 };
2244 if outend - out_ptr < len + 2 {
2245 break;
2246 }
2247 unsafe {
2248 *(out_ptr as *mut u8) = b'&';
2249 ptr::copy_nonoverlapping(cp, (out_ptr + 1) as *mut u8, len);
2250 *((out_ptr + 1 + len) as *mut u8) = b';';
2251 }
2252 out_ptr += len + 2;
2253 }
2254 processed = in_ptr;
2255 }
2256
2257 *outlen = (out_ptr - out as usize) as c_int;
2258 *inlen = (processed - input as usize) as c_int;
2259 0
2260}
2261
2262#[no_mangle]
2275pub unsafe extern "C" fn htmlDecodeEntities(
2276 _ctxt: *mut c_void,
2277 _len: c_int,
2278 _end: xmlChar,
2279 _end2: xmlChar,
2280 _end3: xmlChar,
2281) -> *mut xmlChar {
2282 static DEPRECATED: AtomicBool = AtomicBool::new(false);
2283 if !DEPRECATED.swap(true, Ordering::Relaxed) {
2284 let msg = b"htmlDecodeEntities() deprecated function reached\n";
2286 unsafe {
2287 libc::fwrite(
2288 msg.as_ptr() as *const c_void,
2289 1,
2290 msg.len(),
2291 libc::fdopen(2, b"w\0" as *const u8 as *const c_char),
2292 );
2293 }
2294 }
2295 ptr::null_mut()
2296}
2297
2298#[no_mangle]
2308pub unsafe extern "C" fn htmlIsBooleanAttr(name: *const xmlChar) -> c_int {
2309 if name.is_null() {
2310 return 0;
2311 }
2312 let b = unsafe { xmlstr_to_bytes(name) };
2313 if b.is_empty() {
2314 return 0;
2315 }
2316 let mut i = 0usize;
2317 let mut suffix: Option<&'static [u8]> = None;
2318 match b[i].to_ascii_lowercase() {
2319 b'c' => {
2320 i += 1;
2321 match b.get(i).map(|&x| x.to_ascii_lowercase()) {
2322 Some(b'h') => suffix = Some(b"ecked"),
2323 Some(b'o') => suffix = Some(b"mpact"),
2324 _ => {}
2325 }
2326 }
2327 b'd' => {
2328 i += 1;
2329 match b.get(i).map(|&x| x.to_ascii_lowercase()) {
2330 Some(b'e') => {
2331 i += 1;
2332 match b.get(i).map(|&x| x.to_ascii_lowercase()) {
2333 Some(b'c') => suffix = Some(b"lare"),
2334 Some(b'f') => suffix = Some(b"er"),
2335 _ => {}
2336 }
2337 }
2338 Some(b'i') => suffix = Some(b"sabled"),
2339 _ => {}
2340 }
2341 }
2342 b'i' => suffix = Some(b"smap"),
2343 b'm' => suffix = Some(b"ultiple"),
2344 b'n' => {
2345 i += 1;
2346 if b.get(i).map(|&x| x.to_ascii_lowercase()) == Some(b'o') {
2347 i += 1;
2348 match b.get(i).map(|&x| x.to_ascii_lowercase()) {
2349 Some(b'h') => suffix = Some(b"ref"),
2350 Some(b'r') => suffix = Some(b"esize"),
2351 Some(b's') => suffix = Some(b"hade"),
2352 Some(b'w') => suffix = Some(b"rap"),
2353 _ => {}
2354 }
2355 }
2356 }
2357 b'r' => suffix = Some(b"eadonly"),
2358 b's' => suffix = Some(b"elected"),
2359 _ => {}
2360 }
2361 let Some(suffix) = suffix else {
2362 return 0;
2363 };
2364 if b.len() == i + 1 + suffix.len() && b[i + 1..].eq_ignore_ascii_case(suffix) {
2365 1
2366 } else {
2367 0
2368 }
2369}
2370
2371static HTML_OMITTED_DEFAULT_VALUE: AtomicI32 = AtomicI32::new(1);
2378
2379#[no_mangle]
2387pub unsafe extern "C" fn htmlHandleOmittedElem(val: c_int) -> c_int {
2388 HTML_OMITTED_DEFAULT_VALUE.swap(val, Ordering::Relaxed)
2389}
2390
2391#[no_mangle]
2399pub const unsafe extern "C" fn htmlInitAutoClose() {
2400 }
2402
2403#[no_mangle]
2414pub const unsafe extern "C" fn htmlDefaultSAXHandlerInit() {
2415 }
2417
2418#[no_mangle]
2430pub const unsafe extern "C" fn htmlParseEntityRef(
2431 _ctxt: *mut c_void,
2432 _str: *mut *const xmlChar,
2433) -> *const _htmlEntityDesc {
2434 ptr::null()
2435}
2436
2437#[no_mangle]
2445pub const unsafe extern "C" fn htmlParseCharRef(_ctxt: *mut c_void) -> c_int {
2446 0
2447}
2448
2449#[allow(dead_code)]
2467struct HtmlOpaqueCtxt {
2468 doc: *mut _xmlDoc,
2470 current: *mut _xmlNode,
2471 html: *mut _xmlNode,
2472 head: *mut _xmlNode,
2473 body: *mut _xmlNode,
2474 in_head: bool,
2475 in_body: bool,
2476 html_created: bool,
2477 head_created: bool,
2478 body_created: bool,
2479 seen_body_content: bool,
2480 input: *mut u8,
2482 input_pos: usize,
2483 input_len: usize,
2484 line: c_int,
2485 err: bool,
2486 filename: *mut c_char,
2487 encoding: *mut c_char,
2488 options: c_int,
2490 sax: *mut _xmlSAXHandler,
2491 user_data: *mut c_void,
2492}
2493
2494const HTML_CTXT_STATE_OFFSET: usize = size_of::<_xmlParserCtxt>();
2497
2498const unsafe fn html_state(ctxt: *mut c_void) -> *mut HtmlOpaqueCtxt {
2505 (ctxt as *mut u8).add(HTML_CTXT_STATE_OFFSET) as *mut HtmlOpaqueCtxt
2506}
2507
2508unsafe fn html_ctxt_alloc() -> *mut c_void {
2514 let total = HTML_CTXT_STATE_OFFSET + size_of::<HtmlOpaqueCtxt>();
2515 let mem = xmlMallocZero(total) as *mut u8;
2516 if mem.is_null() {
2517 return ptr::null_mut();
2518 }
2519 let state = mem.add(HTML_CTXT_STATE_OFFSET) as *mut HtmlOpaqueCtxt;
2520 unsafe {
2521 ptr::write(
2522 state,
2523 HtmlOpaqueCtxt {
2524 doc: ptr::null_mut(),
2525 current: ptr::null_mut(),
2526 html: ptr::null_mut(),
2527 head: ptr::null_mut(),
2528 body: ptr::null_mut(),
2529 in_head: false,
2530 in_body: false,
2531 html_created: false,
2532 head_created: false,
2533 body_created: false,
2534 seen_body_content: false,
2535 input: ptr::null_mut(),
2536 input_pos: 0,
2537 input_len: 0,
2538 line: 1,
2539 err: false,
2540 filename: ptr::null_mut(),
2541 encoding: ptr::null_mut(),
2542 options: 0,
2543 sax: ptr::null_mut(),
2544 user_data: ptr::null_mut(),
2545 },
2546 );
2547 let c = mem as *mut _xmlParserCtxt;
2551 (*c).html = 1;
2552 (*c).sax = ptr::addr_of!(crate::abi::data_globals::htmlDefaultSAXHandler)
2553 as *const _xmlSAXHandler as *mut _xmlSAXHandler;
2554 (*state).sax = (*c).sax;
2555 }
2556 mem as *mut c_void
2557}
2558
2559unsafe fn html_ctxt_set_input(ctxt: *mut c_void, buffer: *const c_char, size: c_int) {
2561 if buffer.is_null() || size <= 0 {
2562 return;
2563 }
2564 let st = unsafe { html_state(ctxt) };
2565 let len = size as usize;
2566 let nb = xmlMallocImpl(len) as *mut u8;
2567 if nb.is_null() {
2568 return;
2569 }
2570 unsafe {
2571 ptr::copy_nonoverlapping(buffer as *const u8, nb, len);
2572 (*st).input = nb;
2573 (*st).input_len = len;
2574 (*st).input_pos = 0;
2575 }
2576}
2577
2578#[no_mangle]
2586pub unsafe extern "C" fn htmlNewSAXParserCtxt(
2587 sax: *const _xmlSAXHandler,
2588 userData: *mut c_void,
2589) -> *mut c_void {
2590 let host = unsafe { html_ctxt_alloc() };
2591 if host.is_null() {
2592 return ptr::null_mut();
2593 }
2594 let c = host as *mut _xmlParserCtxt;
2595 unsafe {
2596 (*c).sax = if sax.is_null() {
2600 ptr::addr_of!(crate::abi::data_globals::htmlDefaultSAXHandler) as *const _xmlSAXHandler
2601 as *mut _xmlSAXHandler
2602 } else {
2603 sax as *mut _xmlSAXHandler
2604 };
2605 (*c).userData = userData;
2606 (*c).html = 1;
2607 let st = unsafe { html_state(host) };
2608 (*st).sax = (*c).sax;
2609 (*st).user_data = userData;
2610 }
2611 host
2612}
2613
2614#[no_mangle]
2622pub unsafe extern "C" fn htmlNewParserCtxt() -> *mut c_void {
2623 unsafe { htmlNewSAXParserCtxt(ptr::null(), ptr::null_mut()) }
2624}
2625
2626#[no_mangle]
2635pub unsafe extern "C" fn htmlCreateMemoryParserCtxt(
2636 buffer: *const c_char,
2637 size: c_int,
2638) -> *mut c_void {
2639 if buffer.is_null() || size <= 0 {
2640 return ptr::null_mut();
2641 }
2642 let host = unsafe { html_ctxt_alloc() };
2643 if host.is_null() {
2644 return ptr::null_mut();
2645 }
2646 unsafe { html_ctxt_set_input(host, buffer, size) };
2647 let st = unsafe { html_state(host) };
2648 if unsafe { (*st).input.is_null() } {
2649 unsafe { crate::xml::html::free_parser_ctxt(host) };
2650 return ptr::null_mut();
2651 }
2652 host
2653}
2654
2655#[no_mangle]
2665pub unsafe extern "C" fn htmlCreatePushParserCtxt(
2666 sax: *mut _xmlSAXHandler,
2667 user_data: *mut c_void,
2668 chunk: *const c_char,
2669 size: c_int,
2670 filename: *const c_char,
2671 enc: xmlCharEncoding,
2672) -> *mut c_void {
2673 let host = unsafe { html_ctxt_alloc() };
2674 if host.is_null() {
2675 return ptr::null_mut();
2676 }
2677 let c = host as *mut _xmlParserCtxt;
2678 let st = unsafe { html_state(host) };
2679 unsafe {
2680 (*c).sax = if sax.is_null() {
2683 ptr::addr_of!(crate::abi::data_globals::htmlDefaultSAXHandler) as *const _xmlSAXHandler
2684 as *mut _xmlSAXHandler
2685 } else {
2686 sax
2687 };
2688 (*c).userData = user_data;
2689 (*c).html = 1;
2690 (*st).sax = (*c).sax;
2691 (*st).user_data = user_data;
2692 if !filename.is_null() {
2693 (*st).filename = c_strdup(filename);
2694 }
2695 if enc != xmlCharEncoding::XML_CHAR_ENCODING_NONE {
2699 if let Some(name) = crate::xml::encoding::encoding_name(enc) {
2700 let mut nb = name.to_vec();
2701 nb.push(0);
2702 (*st).encoding = c_strdup(nb.as_ptr() as *const c_char);
2703 }
2704 }
2705 if size > 0 && !chunk.is_null() {
2706 html_ctxt_set_input(host, chunk, size);
2707 } else {
2708 let nb = xmlMallocImpl(1) as *mut u8;
2711 if !nb.is_null() {
2712 (*st).input = nb;
2713 (*st).input_len = 0;
2714 (*st).input_pos = 0;
2715 }
2716 }
2717 }
2718 host
2719}
2720
2721#[no_mangle]
2737pub unsafe extern "C" fn htmlCreateFileParserCtxt(
2738 filename: *const c_char,
2739 encoding: *const c_char,
2740) -> *mut c_void {
2741 unsafe {
2742 if filename.is_null() {
2743 return ptr::null_mut();
2744 }
2745 let host = html_ctxt_alloc();
2750 if host.is_null() {
2751 return ptr::null_mut();
2752 }
2753 let loaded =
2754 if crate::xml::globals::get_parser_input_buffer_create_filename_value().is_some() {
2755 crate::abi::exports_parser::call_loader_materialize(filename).ok()
2756 } else {
2757 let name = std::ffi::CStr::from_ptr(filename)
2758 .to_string_lossy()
2759 .into_owned();
2760 std::fs::read(name).ok()
2761 };
2762 let Some(bytes) = loaded else {
2763 let msg = crate::abi::exports_parser::io_load_failure_message(filename);
2771 unsafe {
2772 crate::abi::exports_parser::emit_io_warning(
2773 host as *mut crate::abi::structs::_xmlParserCtxt,
2774 msg,
2775 );
2776 }
2777 crate::xml::html::free_parser_ctxt(host);
2778 return ptr::null_mut();
2779 };
2780 if bytes.is_empty() {
2781 crate::xml::html::free_parser_ctxt(host);
2782 return ptr::null_mut();
2783 }
2784 if !encoding.is_null() {
2785 let st = html_state(host);
2786 (*st).encoding = c_strdup(encoding);
2787 }
2788 html_ctxt_set_input(host, bytes.as_ptr() as *const c_char, bytes.len() as c_int);
2789 let st = html_state(host);
2790 if (*st).input.is_null() {
2791 crate::xml::html::free_parser_ctxt(host);
2792 return ptr::null_mut();
2793 }
2794 host
2795 }
2796}
2797
2798#[no_mangle]
2806pub unsafe extern "C" fn htmlCtxtReset(ctxt: *mut c_void) {
2807 if ctxt.is_null() {
2808 return;
2809 }
2810 let st = unsafe { html_state(ctxt) };
2811 let c = ctxt as *mut _xmlParserCtxt;
2812 unsafe {
2813 if !(*st).input.is_null() {
2814 xmlFreeImpl((*st).input as *mut c_void);
2815 }
2816 (*st).input = ptr::null_mut();
2817 (*st).input_len = 0;
2818 (*st).input_pos = 0;
2819 (*st).doc = ptr::null_mut();
2820 (*st).options = 0;
2821 (*st).line = 1;
2822 (*st).err = false;
2823 (*c).myDoc = ptr::null_mut();
2827 (*c).errNo = 0;
2828 (*c).wellFormed = 1;
2829 (*c).options = 0;
2830 }
2831}
2832
2833#[no_mangle]
2844pub unsafe extern "C" fn htmlCtxtUseOptions(ctxt: *mut c_void, options: c_int) -> c_int {
2845 if ctxt.is_null() {
2846 return -1;
2847 }
2848 let c = ctxt as *mut _xmlParserCtxt;
2849 let st = unsafe { html_state(ctxt) };
2850 unsafe {
2852 (*c).options = ((*c).options & HTML_OPTIONS_KEEP_MASK) | (options & HTML_OPTIONS_ALL_MASK);
2853 (*st).options = (*c).options;
2854 }
2855 options & !HTML_OPTIONS_ALL_MASK & !crate::abi::types::XML_PARSE_NOENT
2858}
2859
2860#[no_mangle]
2869pub unsafe extern "C" fn htmlParseDocument(ctxt: *mut c_void) -> c_int {
2870 if ctxt.is_null() {
2871 return -1;
2872 }
2873 let st = unsafe { html_state(ctxt) };
2874 if unsafe { (*st).input.is_null() } {
2875 return -1;
2876 }
2877 let doc = unsafe {
2878 html::parse_memory_enc(
2879 (*st).input as *const c_char,
2880 (*st).input_len as c_int,
2881 (*st).encoding,
2882 (*st).options,
2883 )
2884 };
2885 let c = ctxt as *mut _xmlParserCtxt;
2886 unsafe {
2887 (*st).doc = doc;
2888 (*c).myDoc = doc;
2889 if !doc.is_null() {
2890 (*c).wellFormed = 1;
2891 }
2892 }
2893 if doc.is_null() {
2894 -1
2895 } else {
2896 0
2897 }
2898}
2899
2900#[no_mangle]
2911pub unsafe extern "C" fn htmlParseChunk(
2912 ctxt: *mut c_void,
2913 chunk: *const c_char,
2914 size: c_int,
2915 terminate: c_int,
2916) -> c_int {
2917 if ctxt.is_null() || size < 0 || (size > 0 && chunk.is_null()) {
2918 return XML_ERR_ARGUMENT;
2919 }
2920 let st = unsafe { html_state(ctxt) };
2921 if unsafe { (*st).input.is_null() } {
2922 return XML_ERR_ARGUMENT;
2923 }
2924
2925 if size > 0 {
2926 let new_len = unsafe { (*st).input_len }.wrapping_add(size as usize);
2927 let nb = unsafe { xmlReallocImpl((*st).input as *mut c_void, new_len) } as *mut u8;
2928 if nb.is_null() {
2929 return XML_ERR_NO_MEMORY;
2930 }
2931 unsafe {
2932 ptr::copy_nonoverlapping(chunk as *const u8, nb.add((*st).input_len), size as usize);
2933 (*st).input = nb;
2934 (*st).input_len = new_len;
2935 }
2936 }
2937
2938 if terminate != 0 {
2939 let doc = unsafe {
2940 html::parse_memory_enc(
2941 (*st).input as *const c_char,
2942 (*st).input_len as c_int,
2943 (*st).encoding,
2944 (*st).options,
2945 )
2946 };
2947 let c = ctxt as *mut _xmlParserCtxt;
2948 unsafe {
2949 (*st).doc = doc;
2950 (*c).myDoc = doc;
2951 if !doc.is_null() {
2952 (*c).wellFormed = 1;
2953 }
2954 xmlFreeImpl((*st).input as *mut c_void);
2956 (*st).input = ptr::null_mut();
2957 (*st).input_len = 0;
2958 }
2959 }
2960 XML_ERR_OK
2961}
2962
2963#[no_mangle]
2971pub unsafe extern "C" fn htmlCtxtParseDocument(
2972 ctxt: *mut c_void,
2973 input: *mut _xmlParserInput,
2974) -> *mut _xmlDoc {
2975 if ctxt.is_null() || input.is_null() {
2976 return ptr::null_mut();
2977 }
2978 let cur = unsafe { (*input).cur };
2979 let end = unsafe { (*input).end };
2980 if cur.is_null() {
2981 return ptr::null_mut();
2982 }
2983 let len = (end as usize).wrapping_sub(cur as usize) as c_int;
2984 if len <= 0 {
2985 return ptr::null_mut();
2986 }
2987 let st = unsafe { html_state(ctxt) };
2988 let doc =
2989 unsafe { html::parse_memory_enc(cur as *const c_char, len, (*st).encoding, (*st).options) };
2990 let c = ctxt as *mut _xmlParserCtxt;
2991 unsafe {
2992 (*st).doc = doc;
2993 (*c).myDoc = doc;
2994 if !doc.is_null() {
2995 (*c).wellFormed = 1;
2996 }
2997 }
2998 doc
2999}
3000
3001unsafe fn html_ctxt_finish_read(
3008 ctxt: *mut c_void,
3009 doc: *mut _xmlDoc,
3010 url: *const c_char,
3011) -> *mut _xmlDoc {
3012 if ctxt.is_null() {
3013 return doc;
3014 }
3015 let st = unsafe { html_state(ctxt) };
3016 let c = ctxt as *mut _xmlParserCtxt;
3017 unsafe {
3018 (*st).doc = doc;
3019 (*c).myDoc = doc;
3020 if !doc.is_null() {
3021 (*c).wellFormed = 1;
3022 }
3023 if !doc.is_null() && !url.is_null() {
3024 (*doc).URL = c_strdup(url) as *mut xmlChar;
3025 }
3026 }
3027 doc
3028}
3029
3030#[no_mangle]
3039pub unsafe extern "C" fn htmlCtxtReadMemory(
3040 ctxt: *mut c_void,
3041 buffer: *const c_char,
3042 size: c_int,
3043 URL: *const c_char,
3044 encoding: *const c_char,
3045 options: c_int,
3046) -> *mut _xmlDoc {
3047 if ctxt.is_null() || size < 0 {
3048 return ptr::null_mut();
3049 }
3050 unsafe { htmlCtxtReset(ctxt) };
3051 unsafe { htmlCtxtUseOptions(ctxt, options) };
3052 let st = unsafe { html_state(ctxt) };
3053 let doc = unsafe { html::parse_memory_enc(buffer, size, encoding, (*st).options) };
3054 unsafe { html_ctxt_finish_read(ctxt, doc, URL) }
3055}
3056
3057#[no_mangle]
3066pub unsafe extern "C" fn htmlCtxtReadDoc(
3067 ctxt: *mut c_void,
3068 str: *const xmlChar,
3069 URL: *const c_char,
3070 encoding: *const c_char,
3071 options: c_int,
3072) -> *mut _xmlDoc {
3073 if ctxt.is_null() {
3074 return ptr::null_mut();
3075 }
3076 unsafe { htmlCtxtReset(ctxt) };
3077 unsafe { htmlCtxtUseOptions(ctxt, options) };
3078 let st = unsafe { html_state(ctxt) };
3079 let doc = unsafe { html::parse_doc(str, encoding, (*st).options) };
3080 unsafe { html_ctxt_finish_read(ctxt, doc, URL) }
3081}
3082
3083#[no_mangle]
3093pub unsafe extern "C" fn htmlCtxtReadFile(
3094 ctxt: *mut c_void,
3095 filename: *const c_char,
3096 encoding: *const c_char,
3097 options: c_int,
3098) -> *mut _xmlDoc {
3099 if ctxt.is_null() {
3100 return ptr::null_mut();
3101 }
3102 unsafe { htmlCtxtReset(ctxt) };
3103 unsafe { htmlCtxtUseOptions(ctxt, options) };
3104 let st = unsafe { html_state(ctxt) };
3105 let doc = unsafe { html::parse_file(filename, encoding, (*st).options) };
3106 unsafe { html_ctxt_finish_read(ctxt, doc, filename) }
3107}
3108
3109unsafe fn html_read_fd(fd: c_int) -> Vec<u8> {
3111 let mut buf = Vec::new();
3112 let mut tmp = [0u8; 4096];
3113 loop {
3114 let n = libc::read(fd, tmp.as_mut_ptr() as *mut c_void, tmp.len());
3115 if n <= 0 {
3116 break;
3117 }
3118 buf.extend_from_slice(&tmp[..n as usize]);
3119 }
3120 buf
3121}
3122
3123unsafe fn html_read_io(ioread: Option<xmlInputReadCallback>, ioctx: *mut c_void) -> Vec<u8> {
3125 let mut buf = Vec::new();
3126 let mut tmp = [0u8; 4096];
3127 if let Some(read) = ioread {
3128 loop {
3129 let n = unsafe { read(ioctx, tmp.as_mut_ptr() as *mut c_char, tmp.len() as c_int) };
3130 if n <= 0 {
3131 break;
3132 }
3133 buf.extend_from_slice(&tmp[..n as usize]);
3134 }
3135 }
3136 buf
3137}
3138
3139#[no_mangle]
3148pub unsafe extern "C" fn htmlCtxtReadFd(
3149 ctxt: *mut c_void,
3150 fd: c_int,
3151 URL: *const c_char,
3152 encoding: *const c_char,
3153 options: c_int,
3154) -> *mut _xmlDoc {
3155 if ctxt.is_null() {
3156 return ptr::null_mut();
3157 }
3158 unsafe { htmlCtxtReset(ctxt) };
3159 unsafe { htmlCtxtUseOptions(ctxt, options) };
3160 let data = unsafe { html_read_fd(fd) };
3161 let st = unsafe { html_state(ctxt) };
3162 let doc = unsafe {
3163 html::parse_memory_enc(
3164 data.as_ptr() as *const c_char,
3165 data.len() as c_int,
3166 encoding,
3167 (*st).options,
3168 )
3169 };
3170 unsafe { html_ctxt_finish_read(ctxt, doc, URL) }
3171}
3172
3173#[no_mangle]
3183pub unsafe extern "C" fn htmlCtxtReadIO(
3184 ctxt: *mut c_void,
3185 ioread: Option<xmlInputReadCallback>,
3186 _ioclose: Option<xmlInputCloseCallback>,
3187 ioctx: *mut c_void,
3188 URL: *const c_char,
3189 encoding: *const c_char,
3190 options: c_int,
3191) -> *mut _xmlDoc {
3192 if ctxt.is_null() {
3193 return ptr::null_mut();
3194 }
3195 unsafe { htmlCtxtReset(ctxt) };
3196 unsafe { htmlCtxtUseOptions(ctxt, options) };
3197 let data = unsafe { html_read_io(ioread, ioctx) };
3198 let st = unsafe { html_state(ctxt) };
3199 let doc = unsafe {
3200 html::parse_memory_enc(
3201 data.as_ptr() as *const c_char,
3202 data.len() as c_int,
3203 encoding,
3204 (*st).options,
3205 )
3206 };
3207 unsafe { html_ctxt_finish_read(ctxt, doc, URL) }
3208}
3209
3210#[no_mangle]
3219pub unsafe extern "C" fn htmlReadMemory(
3220 buffer: *const c_char,
3221 size: c_int,
3222 url: *const c_char,
3223 encoding: *const c_char,
3224 options: c_int,
3225) -> *mut _xmlDoc {
3226 if size < 0 {
3227 return ptr::null_mut();
3228 }
3229 let ctxt = unsafe { htmlNewParserCtxt() };
3230 if ctxt.is_null() {
3231 return ptr::null_mut();
3232 }
3233 let doc = unsafe { htmlCtxtReadMemory(ctxt, buffer, size, url, encoding, options) };
3234 unsafe { crate::xml::html::free_parser_ctxt(ctxt) };
3235 doc
3236}
3237
3238#[no_mangle]
3248pub unsafe extern "C" fn htmlReadDoc(
3249 str: *const xmlChar,
3250 url: *const c_char,
3251 encoding: *const c_char,
3252 options: c_int,
3253) -> *mut _xmlDoc {
3254 let ctxt = unsafe { htmlNewParserCtxt() };
3255 if ctxt.is_null() {
3256 return ptr::null_mut();
3257 }
3258 let doc = unsafe { htmlCtxtReadDoc(ctxt, str, url, encoding, options) };
3259 unsafe { crate::xml::html::free_parser_ctxt(ctxt) };
3260 doc
3261}
3262
3263#[no_mangle]
3272pub unsafe extern "C" fn htmlReadFile(
3273 filename: *const c_char,
3274 encoding: *const c_char,
3275 options: c_int,
3276) -> *mut _xmlDoc {
3277 let ctxt = unsafe { htmlNewParserCtxt() };
3278 if ctxt.is_null() {
3279 return ptr::null_mut();
3280 }
3281 let doc = unsafe { htmlCtxtReadFile(ctxt, filename, encoding, options) };
3282 unsafe { crate::xml::html::free_parser_ctxt(ctxt) };
3283 doc
3284}
3285
3286#[no_mangle]
3294pub unsafe extern "C" fn htmlReadFd(
3295 fd: c_int,
3296 url: *const c_char,
3297 encoding: *const c_char,
3298 options: c_int,
3299) -> *mut _xmlDoc {
3300 let ctxt = unsafe { htmlNewParserCtxt() };
3301 if ctxt.is_null() {
3302 return ptr::null_mut();
3303 }
3304 let doc = unsafe { htmlCtxtReadFd(ctxt, fd, url, encoding, options) };
3305 unsafe { crate::xml::html::free_parser_ctxt(ctxt) };
3306 doc
3307}
3308
3309#[no_mangle]
3319pub unsafe extern "C" fn htmlReadIO(
3320 ioread: Option<xmlInputReadCallback>,
3321 ioclose: Option<xmlInputCloseCallback>,
3322 ioctx: *mut c_void,
3323 url: *const c_char,
3324 encoding: *const c_char,
3325 options: c_int,
3326) -> *mut _xmlDoc {
3327 let ctxt = unsafe { htmlNewParserCtxt() };
3328 if ctxt.is_null() {
3329 return ptr::null_mut();
3330 }
3331 let doc = unsafe { htmlCtxtReadIO(ctxt, ioread, ioclose, ioctx, url, encoding, options) };
3332 unsafe { crate::xml::html::free_parser_ctxt(ctxt) };
3333 doc
3334}
3335
3336#[no_mangle]
3347pub unsafe extern "C" fn htmlSAXParseDoc(
3348 cur: *const xmlChar,
3349 encoding: *const c_char,
3350 sax: *mut _xmlSAXHandler,
3351 userData: *mut c_void,
3352) -> *mut _xmlDoc {
3353 if cur.is_null() {
3354 return ptr::null_mut();
3355 }
3356 let ctxt = unsafe { htmlNewSAXParserCtxt(sax, userData) };
3357 if ctxt.is_null() {
3358 return ptr::null_mut();
3359 }
3360 let doc = unsafe { htmlCtxtReadDoc(ctxt, cur, ptr::null(), encoding, 0) };
3361 unsafe { crate::xml::html::free_parser_ctxt(ctxt) };
3362 doc
3363}
3364
3365#[no_mangle]
3376pub unsafe extern "C" fn htmlSAXParseFile(
3377 filename: *const c_char,
3378 encoding: *const c_char,
3379 sax: *mut _xmlSAXHandler,
3380 userData: *mut c_void,
3381) -> *mut _xmlDoc {
3382 let ctxt = unsafe { htmlNewSAXParserCtxt(sax, userData) };
3383 if ctxt.is_null() {
3384 return ptr::null_mut();
3385 }
3386 let doc = unsafe { htmlCtxtReadFile(ctxt, filename, encoding, 0) };
3387 unsafe { crate::xml::html::free_parser_ctxt(ctxt) };
3388 doc
3389}
3390
3391#[no_mangle]
3402pub unsafe extern "C" fn htmlParseElement(ctxt: *mut c_void) {
3403 if ctxt.is_null() {
3404 return;
3405 }
3406 let st = unsafe { html_state(ctxt) };
3407 if unsafe { (*st).input.is_null() } {
3408 return;
3409 }
3410 let doc = unsafe {
3411 html::parse_memory_enc(
3412 (*st).input as *const c_char,
3413 (*st).input_len as c_int,
3414 (*st).encoding,
3415 (*st).options,
3416 )
3417 };
3418 unsafe {
3419 (*st).doc = doc;
3420 (*(ctxt as *mut _xmlParserCtxt)).myDoc = doc;
3421 }
3422}
3423
3424#[no_mangle]
3437pub unsafe extern "C" fn htmlNewDocNoDtD(
3438 URI: *const xmlChar,
3439 publicId: *const xmlChar,
3440) -> *mut _xmlDoc {
3441 let doc = unsafe { html::new_doc_no_dtd(ptr::null()) };
3442 if doc.is_null() {
3443 return ptr::null_mut();
3444 }
3445 unsafe {
3446 (*doc).standalone = 1;
3449 (*doc).charset = crate::abi::types::xmlCharEncoding::XML_CHAR_ENCODING_UTF8 as c_int;
3450 (*doc).properties = crate::abi::types::xmlDocProperties::XML_DOC_HTML as c_int
3451 | crate::abi::types::xmlDocProperties::XML_DOC_USERBUILT as c_int;
3452 if !publicId.is_null() || !URI.is_null() {
3453 let dtd = crate::xml::dtd::create_int_subset(
3454 doc,
3455 b"html\0" as *const u8 as *const xmlChar,
3456 publicId,
3457 URI,
3458 );
3459 if dtd.is_null() {
3460 tree::free_doc(doc);
3461 return ptr::null_mut();
3462 }
3463 }
3464 }
3465 doc
3466}
3467
3468#[no_mangle]
3483pub unsafe extern "C" fn htmlNewDoc(
3484 URI: *const xmlChar,
3485 ExternalID: *const xmlChar,
3486) -> *mut _xmlDoc {
3487 let doc = unsafe { html::new_doc(ptr::null()) };
3488 if doc.is_null() {
3489 return ptr::null_mut();
3490 }
3491 unsafe {
3492 (*doc).standalone = 1;
3495 (*doc).charset = crate::abi::types::xmlCharEncoding::XML_CHAR_ENCODING_UTF8 as c_int;
3496 (*doc).properties = crate::abi::types::xmlDocProperties::XML_DOC_HTML as c_int
3497 | crate::abi::types::xmlDocProperties::XML_DOC_USERBUILT as c_int;
3498 if URI.is_null() && ExternalID.is_null() {
3499 let dtd = crate::xml::dtd::create_int_subset(
3500 doc,
3501 b"html\0" as *const u8 as *const xmlChar,
3502 b"-//W3C//DTD HTML 4.0 Transitional//EN\0" as *const u8 as *const xmlChar,
3503 b"http://www.w3.org/TR/REC-html40/loose.dtd\0" as *const u8 as *const xmlChar,
3504 );
3505 if dtd.is_null() {
3506 tree::free_doc(doc);
3507 return ptr::null_mut();
3508 }
3509 } else if !ExternalID.is_null() || !URI.is_null() {
3510 let dtd = crate::xml::dtd::create_int_subset(
3511 doc,
3512 b"html\0" as *const u8 as *const xmlChar,
3513 ExternalID,
3514 URI,
3515 );
3516 if dtd.is_null() {
3517 tree::free_doc(doc);
3518 return ptr::null_mut();
3519 }
3520 }
3521 }
3522 doc
3523}
3524
3525unsafe fn html_find_first_child(node: *mut _xmlNode, name: &[u8]) -> *mut _xmlNode {
3531 let mut c = unsafe { (*node).children };
3532 while !c.is_null() {
3533 let n = unsafe { &*c };
3534 if n.type_ == XML_ELEMENT_NODE as c_int
3535 && !n.name.is_null()
3536 && unsafe { xmlstr_to_bytes(n.name) }.eq_ignore_ascii_case(name)
3537 {
3538 return c;
3539 }
3540 c = unsafe { (*c).next };
3541 }
3542 ptr::null_mut()
3543}
3544
3545unsafe fn html_find_head(doc: *mut _xmlDoc) -> *mut _xmlNode {
3548 if doc.is_null() {
3549 return ptr::null_mut();
3550 }
3551 let html = unsafe { html_find_first_child(doc as *mut _xmlNode, b"html") };
3552 if html.is_null() {
3553 return ptr::null_mut();
3554 }
3555 unsafe { html_find_first_child(html, b"head") }
3556}
3557
3558unsafe fn html_find_meta_encoding_attr(elem: *mut _xmlNode) -> (*mut _xmlAttr, bool) {
3561 let n = unsafe { &*elem };
3562 if n.type_ != XML_ELEMENT_NODE as c_int || n.name.is_null() {
3563 return (ptr::null_mut(), false);
3564 }
3565 if !unsafe { xmlstr_to_bytes(n.name) }.eq_ignore_ascii_case(b"meta") {
3566 return (ptr::null_mut(), false);
3567 }
3568
3569 let mut content_attr: *mut _xmlAttr = ptr::null_mut();
3570 let mut is_content_type = false;
3571 let mut attr = n.properties;
3572 while !attr.is_null() {
3573 let a = unsafe { &*attr };
3574 if a.ns.is_null() && !a.name.is_null() {
3575 let nm = unsafe { xmlstr_to_bytes(a.name) };
3576 if nm.eq_ignore_ascii_case(b"charset") {
3577 return (attr, false);
3578 }
3579 if nm.eq_ignore_ascii_case(b"content") {
3580 content_attr = attr;
3581 }
3582 if nm.eq_ignore_ascii_case(b"http-equiv")
3583 && !a.children.is_null()
3584 && unsafe { (*(a.children)).type_ } == XML_TEXT_NODE as c_int
3585 && unsafe { (*(a.children)).next }.is_null()
3586 && !unsafe { (*(a.children)).content }.is_null()
3587 && unsafe { xmlstr_to_bytes((*(a.children)).content) }
3588 .eq_ignore_ascii_case(b"Content-Type")
3589 {
3590 is_content_type = true;
3591 }
3592 }
3593 attr = unsafe { (*attr).next };
3594 }
3595 if is_content_type && !content_attr.is_null() {
3596 (content_attr, true)
3597 } else {
3598 (ptr::null_mut(), false)
3599 }
3600}
3601
3602unsafe fn html_parse_content_type(val: *const xmlChar) -> Option<(usize, usize, usize)> {
3605 let bytes = unsafe { xmlstr_to_bytes(val) };
3606 let n = bytes.len();
3607 let at = |i: usize| -> u8 {
3608 if i < n {
3609 bytes[i]
3610 } else {
3611 0
3612 }
3613 };
3614
3615 let mut p = 0usize;
3616 loop {
3617 loop {
3619 let ch = at(p);
3620 if ch == b'c' || ch == b'C' {
3621 break;
3622 }
3623 if ch == 0 {
3624 return None;
3625 }
3626 p += 1;
3627 }
3628 p += 1;
3629
3630 let mut ok = true;
3632 for (k, want) in b"harset".iter().enumerate() {
3633 if at(p + k).to_ascii_lowercase() != *want {
3634 ok = false;
3635 break;
3636 }
3637 }
3638 if !ok {
3639 continue;
3640 }
3641 p += 6;
3642 while is_ws_html(at(p)) {
3643 p += 1;
3644 }
3645 if at(p) != b'=' {
3646 continue;
3647 }
3648 p += 1;
3649 while is_ws_html(at(p)) {
3650 p += 1;
3651 }
3652 if at(p) == 0 {
3653 return None;
3654 }
3655
3656 let (start, mut end): (usize, usize);
3657 if at(p) == b'"' || at(p) == b'\'' {
3658 let quote = at(p);
3659 p += 1;
3660 while is_ws_html(at(p)) {
3661 p += 1;
3662 }
3663 start = p;
3664 end = start;
3665 loop {
3666 if at(p) == 0 {
3667 return None;
3668 }
3669 if !is_ws_html(at(p)) {
3670 end = p + 1;
3671 }
3672 if at(p) == quote {
3673 break;
3674 }
3675 p += 1;
3676 }
3677 } else {
3678 start = p;
3679 while at(p) != 0 && at(p) != b';' && !is_ws_html(at(p)) {
3680 p += 1;
3681 }
3682 end = p;
3683 }
3684 let size = n;
3685 return Some((start, end, size));
3686 }
3687}
3688
3689#[no_mangle]
3701pub unsafe extern "C" fn htmlGetMetaEncoding(doc: *mut _xmlDoc) -> *const xmlChar {
3702 let head = unsafe { html_find_head(doc) };
3703 if head.is_null() {
3704 return ptr::null();
3705 }
3706 let mut node = unsafe { (*head).children };
3707 while !node.is_null() {
3708 let (attr, is_content_type) = unsafe { html_find_meta_encoding_attr(node) };
3709 if !attr.is_null() {
3710 let a = unsafe { &*attr };
3711 let val = if !a.children.is_null()
3712 && unsafe { (*(a.children)).type_ } == XML_TEXT_NODE as c_int
3713 && unsafe { (*(a.children)).next }.is_null()
3714 && !unsafe { (*(a.children)).content }.is_null()
3715 {
3716 unsafe { (*(a.children)).content }
3717 } else {
3718 b"\0" as *const u8 as *const xmlChar
3719 };
3720 if !is_content_type {
3721 let bytes = unsafe { xmlstr_to_bytes(val) };
3722 let mut start = 0usize;
3723 while start < bytes.len() && is_ws_html(bytes[start]) {
3724 start += 1;
3725 }
3726 return unsafe { val.add(start) };
3727 } else if let Some((start, _, _)) = unsafe { html_parse_content_type(val) } {
3728 return unsafe { val.add(start) };
3729 }
3730 }
3731 node = unsafe { (*node).next };
3732 }
3733 ptr::null()
3734}
3735
3736unsafe fn html_update_meta_encoding(
3739 attr_value: *const xmlChar,
3740 start: usize,
3741 end: usize,
3742 size: usize,
3743 encoding: &[u8],
3744) -> *mut xmlChar {
3745 let enc: &[u8] = if encoding.eq_ignore_ascii_case(b"HTML") {
3747 b"ASCII"
3748 } else {
3749 encoding
3750 };
3751 let bytes = unsafe { xmlstr_to_bytes(attr_value) };
3752 let e = end.min(bytes.len()).min(size);
3753 let s = start.min(e);
3754 let total = size - (e - s) + enc.len();
3755 let new_val = xmlMallocImpl(total + 1) as *mut xmlChar;
3756 if new_val.is_null() {
3757 return ptr::null_mut();
3758 }
3759 unsafe {
3760 let mut p = new_val;
3761 ptr::copy_nonoverlapping(bytes.as_ptr(), p, s);
3762 p = p.add(s);
3763 ptr::copy_nonoverlapping(enc.as_ptr(), p, enc.len());
3764 p = p.add(enc.len());
3765 ptr::copy_nonoverlapping(bytes.as_ptr().add(e), p, size - e);
3766 *new_val.add(total) = 0;
3767 }
3768 new_val
3769}
3770
3771unsafe fn html_set_attr_content(attr: *mut _xmlAttr, content: *const xmlChar) -> c_int {
3774 if attr.is_null() {
3775 return -1;
3776 }
3777 unsafe {
3778 if !(*attr).children.is_null() {
3779 tree::free_node_list((*attr).children);
3780 (*attr).children = ptr::null_mut();
3781 (*attr).last = ptr::null_mut();
3782 }
3783 let text = tree::new_text(content);
3784 if text.is_null() {
3785 return -1;
3786 }
3787 (*text).parent = attr as *mut _xmlNode;
3788 (*text).doc = (*attr).doc;
3789 (*attr).children = text;
3790 (*attr).last = text;
3791 }
3792 0
3793}
3794
3795#[no_mangle]
3803pub unsafe extern "C" fn htmlSetMetaEncoding(doc: *mut _xmlDoc, encoding: *const xmlChar) -> c_int {
3804 if encoding.is_null() {
3805 return 1;
3806 }
3807 let head = unsafe { html_find_head(doc) };
3808 if head.is_null() {
3809 return 1;
3810 }
3811 let enc_bytes = unsafe { xmlstr_to_bytes(encoding) }.to_vec();
3812
3813 let mut found = 0;
3814 let mut meta = unsafe { (*head).children };
3815 while !meta.is_null() {
3816 let (attr, is_content_type) = unsafe { html_find_meta_encoding_attr(meta) };
3817 if !attr.is_null() {
3818 let a = unsafe { &*attr };
3819 let val = if !a.children.is_null()
3820 && unsafe { (*(a.children)).type_ } == XML_TEXT_NODE as c_int
3821 && unsafe { (*(a.children)).next }.is_null()
3822 && !unsafe { (*(a.children)).content }.is_null()
3823 {
3824 unsafe { (*(a.children)).content }
3825 } else {
3826 b"\0" as *const u8 as *const xmlChar
3827 };
3828 found = 1;
3829 let off = if is_content_type {
3830 unsafe { html_parse_content_type(val) }
3831 } else {
3832 let bytes = unsafe { xmlstr_to_bytes(val) };
3833 let mut start = 0usize;
3834 let mut end = bytes.len();
3835 while start < end && is_ws_html(bytes[start]) {
3836 start += 1;
3837 }
3838 while end > start && is_ws_html(bytes[end - 1]) {
3839 end -= 1;
3840 }
3841 Some((start, end, bytes.len()))
3842 };
3843 if let Some((start, end, size)) = off {
3844 let new_val =
3845 unsafe { html_update_meta_encoding(val, start, end, size, &enc_bytes) };
3846 if new_val.is_null() {
3847 return -1;
3848 }
3849 let ret = unsafe { html_set_attr_content(attr, new_val) };
3850 unsafe { xmlFreeImpl(new_val as *mut c_void) };
3851 if ret < 0 {
3852 return -1;
3853 }
3854 } else {
3855 return -1;
3856 }
3857 }
3858 meta = unsafe { (*meta).next };
3859 }
3860
3861 if found != 0 {
3862 return 0;
3863 }
3864
3865 let meta_node =
3867 unsafe { tree::new_node(ptr::null_mut(), b"meta\0" as *const u8 as *const xmlChar) };
3868 if meta_node.is_null() {
3869 return -1;
3870 }
3871 unsafe {
3872 (*meta_node).doc = (*head).doc;
3873 }
3874 let prop = unsafe {
3875 tree::set_prop(
3876 meta_node,
3877 b"charset\0" as *const u8 as *const xmlChar,
3878 encoding,
3879 )
3880 };
3881 if prop.is_null() {
3882 unsafe { tree::free_node(meta_node) };
3883 return -1;
3884 }
3885 if unsafe { (*head).children }.is_null() {
3886 unsafe { tree::add_child(head, meta_node) };
3887 } else {
3888 unsafe { tree::add_sibling_before((*head).children, meta_node) };
3889 }
3890 0
3891}
3892
3893unsafe fn html_serialize_to_buffer(node: *mut _xmlNode, format: c_int) -> *mut _xmlBuffer {
3900 let buf = io::buf_create(0);
3901 if buf.is_null() {
3902 return ptr::null_mut();
3903 }
3904 unsafe { html::serialize_node(node, buf, format, 0) };
3905 buf
3906}
3907
3908const unsafe fn html_pseudo_encoding_in_force(encoding: *const c_char) -> bool {
3921 if encoding.is_null() {
3922 return true;
3923 }
3924 let b = unsafe { std::ffi::CStr::from_ptr(encoding) }.to_bytes();
3925 b.eq_ignore_ascii_case(b"HTML")
3926}
3927
3928unsafe fn html_buf_append_html_ascii(out: *mut _xmlBuffer, content: *const xmlChar, len: usize) {
3940 let mut i = 0usize;
3941 while i < len {
3942 let d = unsafe { *content.add(i) };
3943 if d < 0x80 {
3944 let start = i;
3946 i += 1;
3947 while i < len && unsafe { *content.add(i) } < 0x80 {
3948 i += 1;
3949 }
3950 io::buf_add(out, content.add(start), (i - start) as c_int);
3951 continue;
3952 }
3953 let (mut c, seqlen) = if d < 0xE0 {
3954 ((d & 0x1F) as c_uint, 2usize)
3955 } else if d < 0xF0 {
3956 ((d & 0x0F) as c_uint, 3usize)
3957 } else {
3958 ((d & 0x07) as c_uint, 4usize)
3959 };
3960 if len - i < seqlen {
3961 break;
3964 }
3965 for k in 1..seqlen {
3966 let dd = unsafe { *content.add(i + k) };
3967 c = (c << 6) | ((dd & 0x3F) as c_uint);
3968 }
3969 i += seqlen;
3970 let ent = unsafe { html_entity_value_lookup_static(c) };
3971 if ent.is_null() {
3972 io::buf_ccat(out, b'&');
3974 io::buf_ccat(out, b'#');
3975 let mut digits = [0u8; 10];
3976 let mut n = 0usize;
3977 let mut v = c;
3978 if v == 0 {
3979 digits[0] = b'0';
3980 n = 1;
3981 }
3982 while v > 0 {
3983 digits[n] = b'0' + (v % 10) as u8;
3984 n += 1;
3985 v /= 10;
3986 }
3987 while n > 0 {
3988 n -= 1;
3989 io::buf_ccat(out, digits[n]);
3990 }
3991 io::buf_ccat(out, b';');
3992 } else {
3993 io::buf_ccat(out, b'&');
3994 io::buf_cat(out, (*ent).name as *const xmlChar);
3995 io::buf_ccat(out, b';');
3996 }
3997 }
3998}
3999
4000unsafe fn html_buf_apply_pseudo_encoding(
4011 buf: *mut _xmlBuffer,
4012 encoding: *const c_char,
4013) -> *mut _xmlBuffer {
4014 if buf.is_null() || !unsafe { html_pseudo_encoding_in_force(encoding) } {
4015 return buf;
4016 }
4017 let len = io::buf_length(buf);
4018 if len <= 0 {
4019 return buf;
4020 }
4021 let content = io::buf_content(buf);
4022 let conv = io::buf_create(0);
4023 if conv.is_null() {
4024 return buf;
4025 }
4026 unsafe { html_buf_append_html_ascii(conv, content, len as usize) };
4027 io::buf_free(buf);
4028 conv
4029}
4030
4031unsafe fn html_serialize_to_obuf(obuf: *mut _xmlOutputBuffer, node: *mut _xmlNode, format: c_int) {
4034 unsafe { html_serialize_to_obuf_enc(obuf, node, format, None) }
4035}
4036
4037unsafe fn html_serialize_to_obuf_enc(
4041 obuf: *mut _xmlOutputBuffer,
4042 node: *mut _xmlNode,
4043 format: c_int,
4044 encoding: Option<&[u8]>,
4045) {
4046 if obuf.is_null() || node.is_null() {
4047 return;
4048 }
4049 let buf = if encoding.is_some() {
4050 let b = io::buf_create(0);
4051 if b.is_null() {
4052 return;
4053 }
4054 unsafe { html::serialize_node_enc(node, b, format, 0, encoding) };
4055 b
4056 } else {
4057 unsafe { html_serialize_to_buffer(node, format) }
4058 };
4059 if buf.is_null() {
4060 return;
4061 }
4062 let len = io::buf_length(buf);
4063 if len > 0 {
4064 let content = io::buf_content(buf);
4065 unsafe {
4066 io::output_buffer_write(obuf, len, content as *const c_char);
4067 }
4068 }
4069 io::buf_free(buf);
4070}
4071
4072#[no_mangle]
4080pub unsafe extern "C" fn htmlNodeDump(
4081 buf: *mut _xmlBuffer,
4082 _doc: *mut _xmlDoc,
4083 cur: *mut _xmlNode,
4084) -> c_int {
4085 if buf.is_null() || cur.is_null() {
4086 return -1;
4087 }
4088 let before = io::buf_length(buf);
4089 unsafe { html::serialize_node(cur, buf, 1, 0) };
4090 let after = io::buf_length(buf);
4091 if after < 0 || before < 0 {
4092 return -1;
4093 }
4094 after - before
4095}
4096
4097#[no_mangle]
4105pub unsafe extern "C" fn htmlNodeDumpFile(out: *mut c_void, doc: *mut _xmlDoc, cur: *mut _xmlNode) {
4106 unsafe { htmlNodeDumpFileFormat(out, doc, cur, ptr::null(), 1) };
4107}
4108
4109#[no_mangle]
4118pub unsafe extern "C" fn htmlNodeDumpFileFormat(
4119 out: *mut c_void,
4120 _doc: *mut _xmlDoc,
4121 cur: *mut _xmlNode,
4122 _encoding: *const c_char,
4123 format: c_int,
4124) -> c_int {
4125 let obuf = io::output_buffer_create_file(out as *mut libc::FILE, ptr::null_mut());
4126 if obuf.is_null() {
4127 return -1;
4128 }
4129 unsafe { html_serialize_to_obuf(obuf, cur, format) };
4130 io::output_buffer_close(obuf)
4131}
4132
4133#[no_mangle]
4142pub unsafe extern "C" fn htmlNodeDumpOutput(
4143 buf: *mut _xmlOutputBuffer,
4144 _doc: *mut _xmlDoc,
4145 cur: *mut _xmlNode,
4146 _encoding: *const c_char,
4147) {
4148 unsafe { html_serialize_to_obuf(buf, cur, 1) };
4149}
4150
4151#[no_mangle]
4160pub unsafe extern "C" fn htmlNodeDumpFormatOutput(
4161 buf: *mut _xmlOutputBuffer,
4162 _doc: *mut _xmlDoc,
4163 cur: *mut _xmlNode,
4164 _encoding: *const c_char,
4165 format: c_int,
4166) {
4167 unsafe { html_serialize_to_obuf(buf, cur, format) };
4168}
4169
4170#[no_mangle]
4179pub unsafe extern "C" fn htmlDocContentDumpOutput(
4180 buf: *mut _xmlOutputBuffer,
4181 cur: *mut _xmlDoc,
4182 _encoding: *const c_char,
4183) {
4184 unsafe { html_serialize_to_obuf(buf, cur as *mut _xmlNode, 1) };
4185}
4186
4187#[no_mangle]
4196pub unsafe extern "C" fn htmlDocContentDumpFormatOutput(
4197 buf: *mut _xmlOutputBuffer,
4198 cur: *mut _xmlDoc,
4199 _encoding: *const c_char,
4200 format: c_int,
4201) {
4202 unsafe { html_serialize_to_obuf(buf, cur as *mut _xmlNode, format) };
4203}
4204
4205#[no_mangle]
4215pub unsafe extern "C" fn htmlDocDumpMemoryFormat(
4216 cur: *mut _xmlDoc,
4217 mem: *mut *mut xmlChar,
4218 size: *mut c_int,
4219 format: c_int,
4220) {
4221 if mem.is_null() || size.is_null() {
4222 return;
4223 }
4224 unsafe {
4225 *mem = ptr::null_mut();
4226 *size = 0;
4227 }
4228 if cur.is_null() {
4229 return;
4230 }
4231 let buf = unsafe { html_serialize_to_buffer(cur as *mut _xmlNode, format) };
4232 if buf.is_null() {
4233 return;
4234 }
4235 let buf = unsafe { html_buf_apply_pseudo_encoding(buf, (*cur).encoding as *const c_char) };
4243 if buf.is_null() {
4244 return;
4245 }
4246 let len = io::buf_length(buf);
4247 if len > 0 {
4248 let content = io::buf_content(buf);
4249 unsafe {
4250 *mem = xml_strndup(content, len as usize);
4251 if !(*mem).is_null() {
4252 *size = len;
4253 }
4254 }
4255 }
4256 io::buf_free(buf);
4257}
4258
4259#[no_mangle]
4267pub unsafe extern "C" fn htmlDocDumpMemory(
4268 cur: *mut _xmlDoc,
4269 mem: *mut *mut xmlChar,
4270 size: *mut c_int,
4271) {
4272 unsafe { htmlDocDumpMemoryFormat(cur, mem, size, 1) };
4273}
4274
4275#[no_mangle]
4283pub unsafe extern "C" fn htmlDocDump(f: *mut c_void, cur: *mut _xmlDoc) -> c_int {
4284 if f.is_null() || cur.is_null() {
4285 return -1;
4286 }
4287 let obuf = io::output_buffer_create_file(f as *mut libc::FILE, ptr::null_mut());
4288 if obuf.is_null() {
4289 return -1;
4290 }
4291 unsafe { html_serialize_to_obuf(obuf, cur as *mut _xmlNode, 1) };
4292 io::output_buffer_close(obuf)
4293}
4294
4295#[no_mangle]
4304pub unsafe extern "C" fn htmlSaveFileFormat(
4305 filename: *const c_char,
4306 cur: *mut _xmlDoc,
4307 encoding: *const c_char,
4308 format: c_int,
4309) -> c_int {
4310 if cur.is_null() || filename.is_null() {
4311 return -1;
4312 }
4313 let enc: Option<&[u8]> = if encoding.is_null() {
4318 None
4319 } else {
4320 let s = std::ffi::CStr::from_ptr(encoding);
4321 Some(s.to_bytes())
4322 };
4323 let obuf = io::output_buffer_create_filename_routed(filename, ptr::null_mut(), 0);
4324 if obuf.is_null() {
4325 return 0;
4327 }
4328 let buf = if enc.is_some() {
4333 let b = io::buf_create(0);
4334 if b.is_null() {
4335 io::output_buffer_close(obuf);
4336 return 0;
4337 }
4338 unsafe { html::serialize_node_enc(cur as *mut _xmlNode, b, format, 0, enc) };
4339 b
4340 } else {
4341 unsafe { html_serialize_to_buffer(cur as *mut _xmlNode, format) }
4342 };
4343 let buf = unsafe { html_buf_apply_pseudo_encoding(buf, encoding) };
4344 if buf.is_null() {
4345 io::output_buffer_close(obuf);
4346 return 0;
4347 }
4348 let len = io::buf_length(buf);
4349 if len > 0 {
4350 let content = io::buf_content(buf);
4351 unsafe {
4352 io::output_buffer_write(obuf, len, content as *const c_char);
4353 }
4354 }
4355 io::buf_free(buf);
4356 io::output_buffer_close(obuf)
4357}
4358
4359#[no_mangle]
4368pub unsafe extern "C" fn htmlSaveFile(filename: *const c_char, cur: *mut _xmlDoc) -> c_int {
4369 unsafe { htmlSaveFileFormat(filename, cur, ptr::null(), 1) }
4370}
4371
4372#[no_mangle]
4380pub unsafe extern "C" fn htmlSaveFileEnc(
4381 filename: *const c_char,
4382 cur: *mut _xmlDoc,
4383 encoding: *const c_char,
4384) -> c_int {
4385 unsafe { htmlSaveFileFormat(filename, cur, encoding, 1) }
4386}
4387
4388#[no_mangle]
4396pub unsafe extern "C" fn htmlCtxtSetOptions(ctxt: *mut c_void, options: c_int) -> c_int {
4397 if ctxt.is_null() {
4398 return -1;
4399 }
4400 let c = ctxt as *mut _xmlParserCtxt;
4401 let st = unsafe { html_state(ctxt) };
4402 unsafe {
4403 (*c).options = options & HTML_OPTIONS_ALL_MASK;
4404 (*st).options = (*c).options;
4405 }
4406 options & !HTML_OPTIONS_ALL_MASK & !crate::abi::types::XML_PARSE_NOENT
4407}
4408
4409#[no_mangle]
4419pub unsafe extern "C" fn htmlUTF8ToHtml(
4420 out: *mut u8,
4421 outlen: *mut c_int,
4422 input: *const u8,
4423 inlen: *mut c_int,
4424) -> c_int {
4425 const XML_ENC_ERR_INTERNAL: c_int = -1;
4427 const XML_ENC_ERR_SUCCESS: c_int = 0;
4428 const XML_ENC_ERR_SPACE: c_int = -2;
4429 unsafe {
4430 if out.is_null() || outlen.is_null() || inlen.is_null() {
4431 return XML_ENC_ERR_INTERNAL;
4432 }
4433 if input.is_null() {
4434 *outlen = 0;
4435 *inlen = 0;
4436 return XML_ENC_ERR_SUCCESS;
4437 }
4438 let mut in_pos: usize = 0;
4439 let mut out_pos: usize = 0;
4440 let in_end = *inlen as usize;
4441 let out_cap = *outlen as usize;
4442 let mut ret = XML_ENC_ERR_SPACE;
4443 while in_pos < in_end {
4444 let d = *input.add(in_pos);
4445 if d < 0x80 {
4446 if out_pos >= out_cap {
4447 break;
4448 }
4449 *out.add(out_pos) = d;
4450 out_pos += 1;
4451 in_pos += 1;
4452 continue;
4453 }
4454 let (mut c, seqlen) = if d < 0xE0 {
4455 ((d & 0x1F) as u32, 2usize)
4456 } else if d < 0xF0 {
4457 ((d & 0x0F) as u32, 3usize)
4458 } else {
4459 ((d & 0x07) as u32, 4usize)
4460 };
4461 if in_end - in_pos < seqlen {
4462 break;
4463 }
4464 for i in 1..seqlen {
4465 let dd = *input.add(in_pos + i);
4466 c = (c << 6) | ((dd & 0x3F) as u32);
4467 }
4468 let ent = htmlEntityValueLookup(c);
4469 let mut nbuf = [0u8; 16];
4470 let cp: *const u8;
4471 let mut owned_len: usize = 0;
4472 if ent.is_null() {
4473 let s = format!("#{}", c);
4474 let bytes = s.as_bytes();
4475 nbuf[..bytes.len()].copy_from_slice(bytes);
4476 cp = nbuf.as_ptr();
4477 owned_len = bytes.len();
4478 } else {
4479 cp = (*ent).name as *const u8;
4480 let mut l = 0;
4481 while *cp.add(l) != 0 {
4482 l += 1;
4483 }
4484 owned_len = l;
4485 }
4486 let len = owned_len;
4487 if out_cap - out_pos < len + 2 {
4488 break;
4489 }
4490 *out.add(out_pos) = b'&';
4491 out_pos += 1;
4492 core::ptr::copy_nonoverlapping(cp, out.add(out_pos), len);
4493 out_pos += len;
4494 *out.add(out_pos) = b';';
4495 out_pos += 1;
4496 in_pos += seqlen;
4497 }
4498 ret = out_pos as c_int;
4499 *outlen = out_pos as c_int;
4500 *inlen = in_pos as c_int;
4501 ret
4502 }
4503}
4504
4505#[cfg(test)]
4506mod tests {
4507 use super::*;
4508 use crate::xml::string::{xml_strdup, xml_strlen};
4509
4510 unsafe fn transcode(input: &[u8]) -> String {
4513 let buf = io::buf_create(0);
4514 assert!(!buf.is_null());
4515 unsafe { html_buf_append_html_ascii(buf, input.as_ptr(), input.len()) };
4516 let content = io::buf_content(buf);
4517 let len = xml_strlen(content);
4518 let s = String::from_utf8_lossy(core::slice::from_raw_parts(content, len)).to_string();
4519 io::buf_free(buf);
4520 s
4521 }
4522
4523 #[test]
4529 fn test_pseudo_html_transcode_semantics() {
4530 unsafe {
4531 assert_eq!(transcode(b"a<b&c>d"), "a<b&c>d");
4534 assert_eq!(transcode("a\u{a0}b\u{e9}c".as_bytes()), "a béc");
4536 assert_eq!(transcode("\u{2603}".as_bytes()), "☃");
4538 assert_eq!(transcode(b"x\xc2"), "x");
4540 }
4541 }
4542
4543 #[test]
4550 fn test_html_doc_dump_memory_pseudo_encoding() {
4551 unsafe {
4552 let html = b"<html><body><p>a b c\xc3\xa9d</p></body></html>\0";
4553 let doc = html::parse_memory(html.as_ptr() as *const c_char, (html.len() - 1) as c_int);
4555 assert!(!doc.is_null());
4556 assert!(
4557 (*doc).encoding.is_null(),
4558 "a meta-less html parse must leave doc->encoding NULL"
4559 );
4560
4561 let mut mem: *mut xmlChar = ptr::null_mut();
4562 let mut size: c_int = 0;
4563 htmlDocDumpMemoryFormat(doc, &mut mem, &mut size, 0);
4564 assert!(!mem.is_null());
4565 assert!(size > 0);
4566 let s = String::from_utf8_lossy(core::slice::from_raw_parts(
4567 mem as *const u8,
4568 size as usize,
4569 ))
4570 .to_string();
4571 assert!(s.contains("a b céd"), "got: {s}");
4572 assert!(
4573 !s.contains('\u{a0}'),
4574 "no raw U+00A0 may survive the pseudo-HTML dump: got: {s}"
4575 );
4576 xmlFreeImpl(mem as *mut c_void);
4577
4578 (*doc).encoding = xml_strdup(b"UTF-8\0" as *const u8 as *const xmlChar);
4580 let mut mem2: *mut xmlChar = ptr::null_mut();
4581 let mut size2: c_int = 0;
4582 htmlDocDumpMemoryFormat(doc, &mut mem2, &mut size2, 0);
4583 assert!(!mem2.is_null());
4584 let s2 = String::from_utf8_lossy(core::slice::from_raw_parts(
4585 mem2 as *const u8,
4586 size2 as usize,
4587 ))
4588 .to_string();
4589 assert!(s2.contains("a\u{a0}b\u{a0}c\u{e9}d"), "got: {s2}");
4590 assert!(!s2.contains(" "), "got: {s2}");
4591 xmlFreeImpl(mem2 as *mut c_void);
4592
4593 tree::free_doc(doc);
4594 }
4595 }
4596}