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_cross_dso()
2755 .is_some()
2756 {
2757 crate::abi::exports_parser::call_loader_materialize(filename).ok()
2758 } else {
2759 let name = std::ffi::CStr::from_ptr(filename)
2760 .to_string_lossy()
2761 .into_owned();
2762 std::fs::read(name).ok()
2763 };
2764 let Some(bytes) = loaded else {
2765 let msg = crate::abi::exports_parser::io_load_failure_message(filename);
2773 unsafe {
2774 crate::abi::exports_parser::emit_io_warning(
2775 host as *mut crate::abi::structs::_xmlParserCtxt,
2776 msg,
2777 );
2778 }
2779 crate::xml::html::free_parser_ctxt(host);
2780 return ptr::null_mut();
2781 };
2782 if bytes.is_empty() {
2783 crate::xml::html::free_parser_ctxt(host);
2784 return ptr::null_mut();
2785 }
2786 if !encoding.is_null() {
2787 let st = html_state(host);
2788 (*st).encoding = c_strdup(encoding);
2789 }
2790 html_ctxt_set_input(host, bytes.as_ptr() as *const c_char, bytes.len() as c_int);
2791 let st = html_state(host);
2792 if (*st).input.is_null() {
2793 crate::xml::html::free_parser_ctxt(host);
2794 return ptr::null_mut();
2795 }
2796 host
2797 }
2798}
2799
2800#[no_mangle]
2808pub unsafe extern "C" fn htmlCtxtReset(ctxt: *mut c_void) {
2809 if ctxt.is_null() {
2810 return;
2811 }
2812 let st = unsafe { html_state(ctxt) };
2813 let c = ctxt as *mut _xmlParserCtxt;
2814 unsafe {
2815 if !(*st).input.is_null() {
2816 xmlFreeImpl((*st).input as *mut c_void);
2817 }
2818 (*st).input = ptr::null_mut();
2819 (*st).input_len = 0;
2820 (*st).input_pos = 0;
2821 (*st).doc = ptr::null_mut();
2822 (*st).options = 0;
2823 (*st).line = 1;
2824 (*st).err = false;
2825 (*c).myDoc = ptr::null_mut();
2829 (*c).errNo = 0;
2830 (*c).wellFormed = 1;
2831 (*c).options = 0;
2832 }
2833}
2834
2835#[no_mangle]
2846pub unsafe extern "C" fn htmlCtxtUseOptions(ctxt: *mut c_void, options: c_int) -> c_int {
2847 if ctxt.is_null() {
2848 return -1;
2849 }
2850 let c = ctxt as *mut _xmlParserCtxt;
2851 let st = unsafe { html_state(ctxt) };
2852 unsafe {
2854 (*c).options = ((*c).options & HTML_OPTIONS_KEEP_MASK) | (options & HTML_OPTIONS_ALL_MASK);
2855 (*st).options = (*c).options;
2856 }
2857 options & !HTML_OPTIONS_ALL_MASK & !crate::abi::types::XML_PARSE_NOENT
2860}
2861
2862#[no_mangle]
2871pub unsafe extern "C" fn htmlParseDocument(ctxt: *mut c_void) -> c_int {
2872 if ctxt.is_null() {
2873 return -1;
2874 }
2875 let st = unsafe { html_state(ctxt) };
2876 if unsafe { (*st).input.is_null() } {
2877 return -1;
2878 }
2879 let doc = unsafe {
2880 html::parse_memory_enc(
2881 (*st).input as *const c_char,
2882 (*st).input_len as c_int,
2883 (*st).encoding,
2884 (*st).options,
2885 )
2886 };
2887 let c = ctxt as *mut _xmlParserCtxt;
2888 unsafe {
2889 (*st).doc = doc;
2890 (*c).myDoc = doc;
2891 if !doc.is_null() {
2892 (*c).wellFormed = 1;
2893 }
2894 }
2895 if doc.is_null() {
2896 -1
2897 } else {
2898 0
2899 }
2900}
2901
2902#[no_mangle]
2913pub unsafe extern "C" fn htmlParseChunk(
2914 ctxt: *mut c_void,
2915 chunk: *const c_char,
2916 size: c_int,
2917 terminate: c_int,
2918) -> c_int {
2919 if ctxt.is_null() || size < 0 || (size > 0 && chunk.is_null()) {
2920 return XML_ERR_ARGUMENT;
2921 }
2922 let st = unsafe { html_state(ctxt) };
2923 if unsafe { (*st).input.is_null() } {
2924 return XML_ERR_ARGUMENT;
2925 }
2926
2927 if size > 0 {
2928 let new_len = unsafe { (*st).input_len }.wrapping_add(size as usize);
2929 let nb = unsafe { xmlReallocImpl((*st).input as *mut c_void, new_len) } as *mut u8;
2930 if nb.is_null() {
2931 return XML_ERR_NO_MEMORY;
2932 }
2933 unsafe {
2934 ptr::copy_nonoverlapping(chunk as *const u8, nb.add((*st).input_len), size as usize);
2935 (*st).input = nb;
2936 (*st).input_len = new_len;
2937 }
2938 }
2939
2940 if terminate != 0 {
2941 let doc = unsafe {
2942 html::parse_memory_enc(
2943 (*st).input as *const c_char,
2944 (*st).input_len as c_int,
2945 (*st).encoding,
2946 (*st).options,
2947 )
2948 };
2949 let c = ctxt as *mut _xmlParserCtxt;
2950 unsafe {
2951 (*st).doc = doc;
2952 (*c).myDoc = doc;
2953 if !doc.is_null() {
2954 (*c).wellFormed = 1;
2955 }
2956 xmlFreeImpl((*st).input as *mut c_void);
2958 (*st).input = ptr::null_mut();
2959 (*st).input_len = 0;
2960 }
2961 }
2962 XML_ERR_OK
2963}
2964
2965#[no_mangle]
2973pub unsafe extern "C" fn htmlCtxtParseDocument(
2974 ctxt: *mut c_void,
2975 input: *mut _xmlParserInput,
2976) -> *mut _xmlDoc {
2977 if ctxt.is_null() || input.is_null() {
2978 return ptr::null_mut();
2979 }
2980 let cur = unsafe { (*input).cur };
2981 let end = unsafe { (*input).end };
2982 if cur.is_null() {
2983 return ptr::null_mut();
2984 }
2985 let len = (end as usize).wrapping_sub(cur as usize) as c_int;
2986 if len <= 0 {
2987 return ptr::null_mut();
2988 }
2989 let st = unsafe { html_state(ctxt) };
2990 let doc =
2991 unsafe { html::parse_memory_enc(cur as *const c_char, len, (*st).encoding, (*st).options) };
2992 let c = ctxt as *mut _xmlParserCtxt;
2993 unsafe {
2994 (*st).doc = doc;
2995 (*c).myDoc = doc;
2996 if !doc.is_null() {
2997 (*c).wellFormed = 1;
2998 }
2999 }
3000 doc
3001}
3002
3003unsafe fn html_ctxt_finish_read(
3010 ctxt: *mut c_void,
3011 doc: *mut _xmlDoc,
3012 url: *const c_char,
3013) -> *mut _xmlDoc {
3014 if ctxt.is_null() {
3015 return doc;
3016 }
3017 let st = unsafe { html_state(ctxt) };
3018 let c = ctxt as *mut _xmlParserCtxt;
3019 unsafe {
3020 (*st).doc = doc;
3021 (*c).myDoc = doc;
3022 if !doc.is_null() {
3023 (*c).wellFormed = 1;
3024 }
3025 if !doc.is_null() && !url.is_null() {
3026 (*doc).URL = c_strdup(url) as *mut xmlChar;
3027 }
3028 }
3029 doc
3030}
3031
3032#[no_mangle]
3041pub unsafe extern "C" fn htmlCtxtReadMemory(
3042 ctxt: *mut c_void,
3043 buffer: *const c_char,
3044 size: c_int,
3045 URL: *const c_char,
3046 encoding: *const c_char,
3047 options: c_int,
3048) -> *mut _xmlDoc {
3049 if ctxt.is_null() || size < 0 {
3050 return ptr::null_mut();
3051 }
3052 unsafe { htmlCtxtReset(ctxt) };
3053 unsafe { htmlCtxtUseOptions(ctxt, options) };
3054 let st = unsafe { html_state(ctxt) };
3055 let doc = unsafe { html::parse_memory_enc(buffer, size, encoding, (*st).options) };
3056 unsafe { html_ctxt_finish_read(ctxt, doc, URL) }
3057}
3058
3059#[no_mangle]
3068pub unsafe extern "C" fn htmlCtxtReadDoc(
3069 ctxt: *mut c_void,
3070 str: *const xmlChar,
3071 URL: *const c_char,
3072 encoding: *const c_char,
3073 options: c_int,
3074) -> *mut _xmlDoc {
3075 if ctxt.is_null() {
3076 return ptr::null_mut();
3077 }
3078 unsafe { htmlCtxtReset(ctxt) };
3079 unsafe { htmlCtxtUseOptions(ctxt, options) };
3080 let st = unsafe { html_state(ctxt) };
3081 let doc = unsafe { html::parse_doc(str, encoding, (*st).options) };
3082 unsafe { html_ctxt_finish_read(ctxt, doc, URL) }
3083}
3084
3085#[no_mangle]
3095pub unsafe extern "C" fn htmlCtxtReadFile(
3096 ctxt: *mut c_void,
3097 filename: *const c_char,
3098 encoding: *const c_char,
3099 options: c_int,
3100) -> *mut _xmlDoc {
3101 if ctxt.is_null() {
3102 return ptr::null_mut();
3103 }
3104 unsafe { htmlCtxtReset(ctxt) };
3105 unsafe { htmlCtxtUseOptions(ctxt, options) };
3106 let st = unsafe { html_state(ctxt) };
3107 let doc = unsafe { html::parse_file(filename, encoding, (*st).options) };
3108 unsafe { html_ctxt_finish_read(ctxt, doc, filename) }
3109}
3110
3111unsafe fn html_read_fd(fd: c_int) -> Vec<u8> {
3113 let mut buf = Vec::new();
3114 let mut tmp = [0u8; 4096];
3115 loop {
3116 let n = libc::read(fd, tmp.as_mut_ptr() as *mut c_void, tmp.len());
3117 if n <= 0 {
3118 break;
3119 }
3120 buf.extend_from_slice(&tmp[..n as usize]);
3121 }
3122 buf
3123}
3124
3125unsafe fn html_read_io(ioread: Option<xmlInputReadCallback>, ioctx: *mut c_void) -> Vec<u8> {
3127 let mut buf = Vec::new();
3128 let mut tmp = [0u8; 4096];
3129 if let Some(read) = ioread {
3130 loop {
3131 let n = unsafe { read(ioctx, tmp.as_mut_ptr() as *mut c_char, tmp.len() as c_int) };
3132 if n <= 0 {
3133 break;
3134 }
3135 buf.extend_from_slice(&tmp[..n as usize]);
3136 }
3137 }
3138 buf
3139}
3140
3141#[no_mangle]
3150pub unsafe extern "C" fn htmlCtxtReadFd(
3151 ctxt: *mut c_void,
3152 fd: c_int,
3153 URL: *const c_char,
3154 encoding: *const c_char,
3155 options: c_int,
3156) -> *mut _xmlDoc {
3157 if ctxt.is_null() {
3158 return ptr::null_mut();
3159 }
3160 unsafe { htmlCtxtReset(ctxt) };
3161 unsafe { htmlCtxtUseOptions(ctxt, options) };
3162 let data = unsafe { html_read_fd(fd) };
3163 let st = unsafe { html_state(ctxt) };
3164 let doc = unsafe {
3165 html::parse_memory_enc(
3166 data.as_ptr() as *const c_char,
3167 data.len() as c_int,
3168 encoding,
3169 (*st).options,
3170 )
3171 };
3172 unsafe { html_ctxt_finish_read(ctxt, doc, URL) }
3173}
3174
3175#[no_mangle]
3185pub unsafe extern "C" fn htmlCtxtReadIO(
3186 ctxt: *mut c_void,
3187 ioread: Option<xmlInputReadCallback>,
3188 _ioclose: Option<xmlInputCloseCallback>,
3189 ioctx: *mut c_void,
3190 URL: *const c_char,
3191 encoding: *const c_char,
3192 options: c_int,
3193) -> *mut _xmlDoc {
3194 if ctxt.is_null() {
3195 return ptr::null_mut();
3196 }
3197 unsafe { htmlCtxtReset(ctxt) };
3198 unsafe { htmlCtxtUseOptions(ctxt, options) };
3199 let data = unsafe { html_read_io(ioread, ioctx) };
3200 let st = unsafe { html_state(ctxt) };
3201 let doc = unsafe {
3202 html::parse_memory_enc(
3203 data.as_ptr() as *const c_char,
3204 data.len() as c_int,
3205 encoding,
3206 (*st).options,
3207 )
3208 };
3209 unsafe { html_ctxt_finish_read(ctxt, doc, URL) }
3210}
3211
3212#[no_mangle]
3221pub unsafe extern "C" fn htmlReadMemory(
3222 buffer: *const c_char,
3223 size: c_int,
3224 url: *const c_char,
3225 encoding: *const c_char,
3226 options: c_int,
3227) -> *mut _xmlDoc {
3228 if size < 0 {
3229 return ptr::null_mut();
3230 }
3231 let ctxt = unsafe { htmlNewParserCtxt() };
3232 if ctxt.is_null() {
3233 return ptr::null_mut();
3234 }
3235 let doc = unsafe { htmlCtxtReadMemory(ctxt, buffer, size, url, encoding, options) };
3236 unsafe { crate::xml::html::free_parser_ctxt(ctxt) };
3237 doc
3238}
3239
3240#[no_mangle]
3250pub unsafe extern "C" fn htmlReadDoc(
3251 str: *const xmlChar,
3252 url: *const c_char,
3253 encoding: *const c_char,
3254 options: c_int,
3255) -> *mut _xmlDoc {
3256 let ctxt = unsafe { htmlNewParserCtxt() };
3257 if ctxt.is_null() {
3258 return ptr::null_mut();
3259 }
3260 let doc = unsafe { htmlCtxtReadDoc(ctxt, str, url, encoding, options) };
3261 unsafe { crate::xml::html::free_parser_ctxt(ctxt) };
3262 doc
3263}
3264
3265#[no_mangle]
3274pub unsafe extern "C" fn htmlReadFile(
3275 filename: *const c_char,
3276 encoding: *const c_char,
3277 options: c_int,
3278) -> *mut _xmlDoc {
3279 let ctxt = unsafe { htmlNewParserCtxt() };
3280 if ctxt.is_null() {
3281 return ptr::null_mut();
3282 }
3283 let doc = unsafe { htmlCtxtReadFile(ctxt, filename, encoding, options) };
3284 unsafe { crate::xml::html::free_parser_ctxt(ctxt) };
3285 doc
3286}
3287
3288#[no_mangle]
3296pub unsafe extern "C" fn htmlReadFd(
3297 fd: c_int,
3298 url: *const c_char,
3299 encoding: *const c_char,
3300 options: c_int,
3301) -> *mut _xmlDoc {
3302 let ctxt = unsafe { htmlNewParserCtxt() };
3303 if ctxt.is_null() {
3304 return ptr::null_mut();
3305 }
3306 let doc = unsafe { htmlCtxtReadFd(ctxt, fd, url, encoding, options) };
3307 unsafe { crate::xml::html::free_parser_ctxt(ctxt) };
3308 doc
3309}
3310
3311#[no_mangle]
3321pub unsafe extern "C" fn htmlReadIO(
3322 ioread: Option<xmlInputReadCallback>,
3323 ioclose: Option<xmlInputCloseCallback>,
3324 ioctx: *mut c_void,
3325 url: *const c_char,
3326 encoding: *const c_char,
3327 options: c_int,
3328) -> *mut _xmlDoc {
3329 let ctxt = unsafe { htmlNewParserCtxt() };
3330 if ctxt.is_null() {
3331 return ptr::null_mut();
3332 }
3333 let doc = unsafe { htmlCtxtReadIO(ctxt, ioread, ioclose, ioctx, url, encoding, options) };
3334 unsafe { crate::xml::html::free_parser_ctxt(ctxt) };
3335 doc
3336}
3337
3338#[no_mangle]
3349pub unsafe extern "C" fn htmlSAXParseDoc(
3350 cur: *const xmlChar,
3351 encoding: *const c_char,
3352 sax: *mut _xmlSAXHandler,
3353 userData: *mut c_void,
3354) -> *mut _xmlDoc {
3355 if cur.is_null() {
3356 return ptr::null_mut();
3357 }
3358 let ctxt = unsafe { htmlNewSAXParserCtxt(sax, userData) };
3359 if ctxt.is_null() {
3360 return ptr::null_mut();
3361 }
3362 let doc = unsafe { htmlCtxtReadDoc(ctxt, cur, ptr::null(), encoding, 0) };
3363 unsafe { crate::xml::html::free_parser_ctxt(ctxt) };
3364 doc
3365}
3366
3367#[no_mangle]
3378pub unsafe extern "C" fn htmlSAXParseFile(
3379 filename: *const c_char,
3380 encoding: *const c_char,
3381 sax: *mut _xmlSAXHandler,
3382 userData: *mut c_void,
3383) -> *mut _xmlDoc {
3384 let ctxt = unsafe { htmlNewSAXParserCtxt(sax, userData) };
3385 if ctxt.is_null() {
3386 return ptr::null_mut();
3387 }
3388 let doc = unsafe { htmlCtxtReadFile(ctxt, filename, encoding, 0) };
3389 unsafe { crate::xml::html::free_parser_ctxt(ctxt) };
3390 doc
3391}
3392
3393#[no_mangle]
3404pub unsafe extern "C" fn htmlParseElement(ctxt: *mut c_void) {
3405 if ctxt.is_null() {
3406 return;
3407 }
3408 let st = unsafe { html_state(ctxt) };
3409 if unsafe { (*st).input.is_null() } {
3410 return;
3411 }
3412 let doc = unsafe {
3413 html::parse_memory_enc(
3414 (*st).input as *const c_char,
3415 (*st).input_len as c_int,
3416 (*st).encoding,
3417 (*st).options,
3418 )
3419 };
3420 unsafe {
3421 (*st).doc = doc;
3422 (*(ctxt as *mut _xmlParserCtxt)).myDoc = doc;
3423 }
3424}
3425
3426#[no_mangle]
3439pub unsafe extern "C" fn htmlNewDocNoDtD(
3440 URI: *const xmlChar,
3441 publicId: *const xmlChar,
3442) -> *mut _xmlDoc {
3443 let doc = unsafe { html::new_doc_no_dtd(ptr::null()) };
3444 if doc.is_null() {
3445 return ptr::null_mut();
3446 }
3447 unsafe {
3448 (*doc).standalone = 1;
3451 (*doc).charset = crate::abi::types::xmlCharEncoding::XML_CHAR_ENCODING_UTF8 as c_int;
3452 (*doc).properties = crate::abi::types::xmlDocProperties::XML_DOC_HTML as c_int
3453 | crate::abi::types::xmlDocProperties::XML_DOC_USERBUILT as c_int;
3454 if !publicId.is_null() || !URI.is_null() {
3455 let dtd = crate::xml::dtd::create_int_subset(
3456 doc,
3457 b"html\0" as *const u8 as *const xmlChar,
3458 publicId,
3459 URI,
3460 );
3461 if dtd.is_null() {
3462 tree::free_doc(doc);
3463 return ptr::null_mut();
3464 }
3465 }
3466 }
3467 doc
3468}
3469
3470#[no_mangle]
3485pub unsafe extern "C" fn htmlNewDoc(
3486 URI: *const xmlChar,
3487 ExternalID: *const xmlChar,
3488) -> *mut _xmlDoc {
3489 let doc = unsafe { html::new_doc(ptr::null()) };
3490 if doc.is_null() {
3491 return ptr::null_mut();
3492 }
3493 unsafe {
3494 (*doc).standalone = 1;
3497 (*doc).charset = crate::abi::types::xmlCharEncoding::XML_CHAR_ENCODING_UTF8 as c_int;
3498 (*doc).properties = crate::abi::types::xmlDocProperties::XML_DOC_HTML as c_int
3499 | crate::abi::types::xmlDocProperties::XML_DOC_USERBUILT as c_int;
3500 if URI.is_null() && ExternalID.is_null() {
3501 let dtd = crate::xml::dtd::create_int_subset(
3502 doc,
3503 b"html\0" as *const u8 as *const xmlChar,
3504 b"-//W3C//DTD HTML 4.0 Transitional//EN\0" as *const u8 as *const xmlChar,
3505 b"http://www.w3.org/TR/REC-html40/loose.dtd\0" as *const u8 as *const xmlChar,
3506 );
3507 if dtd.is_null() {
3508 tree::free_doc(doc);
3509 return ptr::null_mut();
3510 }
3511 } else if !ExternalID.is_null() || !URI.is_null() {
3512 let dtd = crate::xml::dtd::create_int_subset(
3513 doc,
3514 b"html\0" as *const u8 as *const xmlChar,
3515 ExternalID,
3516 URI,
3517 );
3518 if dtd.is_null() {
3519 tree::free_doc(doc);
3520 return ptr::null_mut();
3521 }
3522 }
3523 }
3524 doc
3525}
3526
3527unsafe fn html_find_first_child(node: *mut _xmlNode, name: &[u8]) -> *mut _xmlNode {
3533 let mut c = unsafe { (*node).children };
3534 while !c.is_null() {
3535 let n = unsafe { &*c };
3536 if n.type_ == XML_ELEMENT_NODE as c_int
3537 && !n.name.is_null()
3538 && unsafe { xmlstr_to_bytes(n.name) }.eq_ignore_ascii_case(name)
3539 {
3540 return c;
3541 }
3542 c = unsafe { (*c).next };
3543 }
3544 ptr::null_mut()
3545}
3546
3547unsafe fn html_find_head(doc: *mut _xmlDoc) -> *mut _xmlNode {
3550 if doc.is_null() {
3551 return ptr::null_mut();
3552 }
3553 let html = unsafe { html_find_first_child(doc as *mut _xmlNode, b"html") };
3554 if html.is_null() {
3555 return ptr::null_mut();
3556 }
3557 unsafe { html_find_first_child(html, b"head") }
3558}
3559
3560unsafe fn html_find_meta_encoding_attr(elem: *mut _xmlNode) -> (*mut _xmlAttr, bool) {
3563 let n = unsafe { &*elem };
3564 if n.type_ != XML_ELEMENT_NODE as c_int || n.name.is_null() {
3565 return (ptr::null_mut(), false);
3566 }
3567 if !unsafe { xmlstr_to_bytes(n.name) }.eq_ignore_ascii_case(b"meta") {
3568 return (ptr::null_mut(), false);
3569 }
3570
3571 let mut content_attr: *mut _xmlAttr = ptr::null_mut();
3572 let mut is_content_type = false;
3573 let mut attr = n.properties;
3574 while !attr.is_null() {
3575 let a = unsafe { &*attr };
3576 if a.ns.is_null() && !a.name.is_null() {
3577 let nm = unsafe { xmlstr_to_bytes(a.name) };
3578 if nm.eq_ignore_ascii_case(b"charset") {
3579 return (attr, false);
3580 }
3581 if nm.eq_ignore_ascii_case(b"content") {
3582 content_attr = attr;
3583 }
3584 if nm.eq_ignore_ascii_case(b"http-equiv")
3585 && !a.children.is_null()
3586 && unsafe { (*(a.children)).type_ } == XML_TEXT_NODE as c_int
3587 && unsafe { (*(a.children)).next }.is_null()
3588 && !unsafe { (*(a.children)).content }.is_null()
3589 && unsafe { xmlstr_to_bytes((*(a.children)).content) }
3590 .eq_ignore_ascii_case(b"Content-Type")
3591 {
3592 is_content_type = true;
3593 }
3594 }
3595 attr = unsafe { (*attr).next };
3596 }
3597 if is_content_type && !content_attr.is_null() {
3598 (content_attr, true)
3599 } else {
3600 (ptr::null_mut(), false)
3601 }
3602}
3603
3604unsafe fn html_parse_content_type(val: *const xmlChar) -> Option<(usize, usize, usize)> {
3607 let bytes = unsafe { xmlstr_to_bytes(val) };
3608 let n = bytes.len();
3609 let at = |i: usize| -> u8 {
3610 if i < n {
3611 bytes[i]
3612 } else {
3613 0
3614 }
3615 };
3616
3617 let mut p = 0usize;
3618 loop {
3619 loop {
3621 let ch = at(p);
3622 if ch == b'c' || ch == b'C' {
3623 break;
3624 }
3625 if ch == 0 {
3626 return None;
3627 }
3628 p += 1;
3629 }
3630 p += 1;
3631
3632 let mut ok = true;
3634 for (k, want) in b"harset".iter().enumerate() {
3635 if at(p + k).to_ascii_lowercase() != *want {
3636 ok = false;
3637 break;
3638 }
3639 }
3640 if !ok {
3641 continue;
3642 }
3643 p += 6;
3644 while is_ws_html(at(p)) {
3645 p += 1;
3646 }
3647 if at(p) != b'=' {
3648 continue;
3649 }
3650 p += 1;
3651 while is_ws_html(at(p)) {
3652 p += 1;
3653 }
3654 if at(p) == 0 {
3655 return None;
3656 }
3657
3658 let (start, mut end): (usize, usize);
3659 if at(p) == b'"' || at(p) == b'\'' {
3660 let quote = at(p);
3661 p += 1;
3662 while is_ws_html(at(p)) {
3663 p += 1;
3664 }
3665 start = p;
3666 end = start;
3667 loop {
3668 if at(p) == 0 {
3669 return None;
3670 }
3671 if !is_ws_html(at(p)) {
3672 end = p + 1;
3673 }
3674 if at(p) == quote {
3675 break;
3676 }
3677 p += 1;
3678 }
3679 } else {
3680 start = p;
3681 while at(p) != 0 && at(p) != b';' && !is_ws_html(at(p)) {
3682 p += 1;
3683 }
3684 end = p;
3685 }
3686 let size = n;
3687 return Some((start, end, size));
3688 }
3689}
3690
3691#[no_mangle]
3703pub unsafe extern "C" fn htmlGetMetaEncoding(doc: *mut _xmlDoc) -> *const xmlChar {
3704 let head = unsafe { html_find_head(doc) };
3705 if head.is_null() {
3706 return ptr::null();
3707 }
3708 let mut node = unsafe { (*head).children };
3709 while !node.is_null() {
3710 let (attr, is_content_type) = unsafe { html_find_meta_encoding_attr(node) };
3711 if !attr.is_null() {
3712 let a = unsafe { &*attr };
3713 let val = if !a.children.is_null()
3714 && unsafe { (*(a.children)).type_ } == XML_TEXT_NODE as c_int
3715 && unsafe { (*(a.children)).next }.is_null()
3716 && !unsafe { (*(a.children)).content }.is_null()
3717 {
3718 unsafe { (*(a.children)).content }
3719 } else {
3720 b"\0" as *const u8 as *const xmlChar
3721 };
3722 if !is_content_type {
3723 let bytes = unsafe { xmlstr_to_bytes(val) };
3724 let mut start = 0usize;
3725 while start < bytes.len() && is_ws_html(bytes[start]) {
3726 start += 1;
3727 }
3728 return unsafe { val.add(start) };
3729 } else if let Some((start, _, _)) = unsafe { html_parse_content_type(val) } {
3730 return unsafe { val.add(start) };
3731 }
3732 }
3733 node = unsafe { (*node).next };
3734 }
3735 ptr::null()
3736}
3737
3738unsafe fn html_update_meta_encoding(
3741 attr_value: *const xmlChar,
3742 start: usize,
3743 end: usize,
3744 size: usize,
3745 encoding: &[u8],
3746) -> *mut xmlChar {
3747 let enc: &[u8] = if encoding.eq_ignore_ascii_case(b"HTML") {
3749 b"ASCII"
3750 } else {
3751 encoding
3752 };
3753 let bytes = unsafe { xmlstr_to_bytes(attr_value) };
3754 let e = end.min(bytes.len()).min(size);
3755 let s = start.min(e);
3756 let total = size - (e - s) + enc.len();
3757 let new_val = xmlMallocImpl(total + 1) as *mut xmlChar;
3758 if new_val.is_null() {
3759 return ptr::null_mut();
3760 }
3761 unsafe {
3762 let mut p = new_val;
3763 ptr::copy_nonoverlapping(bytes.as_ptr(), p, s);
3764 p = p.add(s);
3765 ptr::copy_nonoverlapping(enc.as_ptr(), p, enc.len());
3766 p = p.add(enc.len());
3767 ptr::copy_nonoverlapping(bytes.as_ptr().add(e), p, size - e);
3768 *new_val.add(total) = 0;
3769 }
3770 new_val
3771}
3772
3773unsafe fn html_set_attr_content(attr: *mut _xmlAttr, content: *const xmlChar) -> c_int {
3776 if attr.is_null() {
3777 return -1;
3778 }
3779 unsafe {
3780 if !(*attr).children.is_null() {
3781 tree::free_node_list((*attr).children);
3782 (*attr).children = ptr::null_mut();
3783 (*attr).last = ptr::null_mut();
3784 }
3785 let text = tree::new_text(content);
3786 if text.is_null() {
3787 return -1;
3788 }
3789 (*text).parent = attr as *mut _xmlNode;
3790 (*text).doc = (*attr).doc;
3791 (*attr).children = text;
3792 (*attr).last = text;
3793 }
3794 0
3795}
3796
3797#[no_mangle]
3805pub unsafe extern "C" fn htmlSetMetaEncoding(doc: *mut _xmlDoc, encoding: *const xmlChar) -> c_int {
3806 if encoding.is_null() {
3807 return 1;
3808 }
3809 let head = unsafe { html_find_head(doc) };
3810 if head.is_null() {
3811 return 1;
3812 }
3813 let enc_bytes = unsafe { xmlstr_to_bytes(encoding) }.to_vec();
3814
3815 let mut found = 0;
3816 let mut meta = unsafe { (*head).children };
3817 while !meta.is_null() {
3818 let (attr, is_content_type) = unsafe { html_find_meta_encoding_attr(meta) };
3819 if !attr.is_null() {
3820 let a = unsafe { &*attr };
3821 let val = if !a.children.is_null()
3822 && unsafe { (*(a.children)).type_ } == XML_TEXT_NODE as c_int
3823 && unsafe { (*(a.children)).next }.is_null()
3824 && !unsafe { (*(a.children)).content }.is_null()
3825 {
3826 unsafe { (*(a.children)).content }
3827 } else {
3828 b"\0" as *const u8 as *const xmlChar
3829 };
3830 found = 1;
3831 let off = if is_content_type {
3832 unsafe { html_parse_content_type(val) }
3833 } else {
3834 let bytes = unsafe { xmlstr_to_bytes(val) };
3835 let mut start = 0usize;
3836 let mut end = bytes.len();
3837 while start < end && is_ws_html(bytes[start]) {
3838 start += 1;
3839 }
3840 while end > start && is_ws_html(bytes[end - 1]) {
3841 end -= 1;
3842 }
3843 Some((start, end, bytes.len()))
3844 };
3845 if let Some((start, end, size)) = off {
3846 let new_val =
3847 unsafe { html_update_meta_encoding(val, start, end, size, &enc_bytes) };
3848 if new_val.is_null() {
3849 return -1;
3850 }
3851 let ret = unsafe { html_set_attr_content(attr, new_val) };
3852 unsafe { xmlFreeImpl(new_val as *mut c_void) };
3853 if ret < 0 {
3854 return -1;
3855 }
3856 } else {
3857 return -1;
3858 }
3859 }
3860 meta = unsafe { (*meta).next };
3861 }
3862
3863 if found != 0 {
3864 return 0;
3865 }
3866
3867 let meta_node =
3869 unsafe { tree::new_node(ptr::null_mut(), b"meta\0" as *const u8 as *const xmlChar) };
3870 if meta_node.is_null() {
3871 return -1;
3872 }
3873 unsafe {
3874 (*meta_node).doc = (*head).doc;
3875 }
3876 let prop = unsafe {
3877 tree::set_prop(
3878 meta_node,
3879 b"charset\0" as *const u8 as *const xmlChar,
3880 encoding,
3881 )
3882 };
3883 if prop.is_null() {
3884 unsafe { tree::free_node(meta_node) };
3885 return -1;
3886 }
3887 if unsafe { (*head).children }.is_null() {
3888 unsafe { tree::add_child(head, meta_node) };
3889 } else {
3890 unsafe { tree::add_sibling_before((*head).children, meta_node) };
3891 }
3892 0
3893}
3894
3895unsafe fn html_serialize_to_buffer(node: *mut _xmlNode, format: c_int) -> *mut _xmlBuffer {
3902 let buf = io::buf_create(0);
3903 if buf.is_null() {
3904 return ptr::null_mut();
3905 }
3906 unsafe { html::serialize_node(node, buf, format, 0) };
3907 buf
3908}
3909
3910const unsafe fn html_pseudo_encoding_in_force(encoding: *const c_char) -> bool {
3923 if encoding.is_null() {
3924 return true;
3925 }
3926 let b = unsafe { std::ffi::CStr::from_ptr(encoding) }.to_bytes();
3927 b.eq_ignore_ascii_case(b"HTML")
3928}
3929
3930unsafe fn html_buf_append_html_ascii(out: *mut _xmlBuffer, content: *const xmlChar, len: usize) {
3942 let mut i = 0usize;
3943 while i < len {
3944 let d = unsafe { *content.add(i) };
3945 if d < 0x80 {
3946 let start = i;
3948 i += 1;
3949 while i < len && unsafe { *content.add(i) } < 0x80 {
3950 i += 1;
3951 }
3952 io::buf_add(out, content.add(start), (i - start) as c_int);
3953 continue;
3954 }
3955 let (mut c, seqlen) = if d < 0xE0 {
3956 ((d & 0x1F) as c_uint, 2usize)
3957 } else if d < 0xF0 {
3958 ((d & 0x0F) as c_uint, 3usize)
3959 } else {
3960 ((d & 0x07) as c_uint, 4usize)
3961 };
3962 if len - i < seqlen {
3963 break;
3966 }
3967 for k in 1..seqlen {
3968 let dd = unsafe { *content.add(i + k) };
3969 c = (c << 6) | ((dd & 0x3F) as c_uint);
3970 }
3971 i += seqlen;
3972 let ent = unsafe { html_entity_value_lookup_static(c) };
3973 if ent.is_null() {
3974 io::buf_ccat(out, b'&');
3976 io::buf_ccat(out, b'#');
3977 let mut digits = [0u8; 10];
3978 let mut n = 0usize;
3979 let mut v = c;
3980 if v == 0 {
3981 digits[0] = b'0';
3982 n = 1;
3983 }
3984 while v > 0 {
3985 digits[n] = b'0' + (v % 10) as u8;
3986 n += 1;
3987 v /= 10;
3988 }
3989 while n > 0 {
3990 n -= 1;
3991 io::buf_ccat(out, digits[n]);
3992 }
3993 io::buf_ccat(out, b';');
3994 } else {
3995 io::buf_ccat(out, b'&');
3996 io::buf_cat(out, (*ent).name as *const xmlChar);
3997 io::buf_ccat(out, b';');
3998 }
3999 }
4000}
4001
4002unsafe fn html_buf_apply_pseudo_encoding(
4013 buf: *mut _xmlBuffer,
4014 encoding: *const c_char,
4015) -> *mut _xmlBuffer {
4016 if buf.is_null() || !unsafe { html_pseudo_encoding_in_force(encoding) } {
4017 return buf;
4018 }
4019 let len = io::buf_length(buf);
4020 if len <= 0 {
4021 return buf;
4022 }
4023 let content = io::buf_content(buf);
4024 let conv = io::buf_create(0);
4025 if conv.is_null() {
4026 return buf;
4027 }
4028 unsafe { html_buf_append_html_ascii(conv, content, len as usize) };
4029 io::buf_free(buf);
4030 conv
4031}
4032
4033unsafe fn html_serialize_to_obuf(obuf: *mut _xmlOutputBuffer, node: *mut _xmlNode, format: c_int) {
4036 unsafe { html_serialize_to_obuf_enc(obuf, node, format, None) }
4037}
4038
4039unsafe fn html_serialize_to_obuf_enc(
4043 obuf: *mut _xmlOutputBuffer,
4044 node: *mut _xmlNode,
4045 format: c_int,
4046 encoding: Option<&[u8]>,
4047) {
4048 if obuf.is_null() || node.is_null() {
4049 return;
4050 }
4051 let buf = if encoding.is_some() {
4052 let b = io::buf_create(0);
4053 if b.is_null() {
4054 return;
4055 }
4056 unsafe { html::serialize_node_enc(node, b, format, 0, encoding) };
4057 b
4058 } else {
4059 unsafe { html_serialize_to_buffer(node, format) }
4060 };
4061 if buf.is_null() {
4062 return;
4063 }
4064 let len = io::buf_length(buf);
4065 if len > 0 {
4066 let content = io::buf_content(buf);
4067 unsafe {
4068 io::output_buffer_write(obuf, len, content as *const c_char);
4069 }
4070 }
4071 io::buf_free(buf);
4072}
4073
4074#[no_mangle]
4082pub unsafe extern "C" fn htmlNodeDump(
4083 buf: *mut _xmlBuffer,
4084 _doc: *mut _xmlDoc,
4085 cur: *mut _xmlNode,
4086) -> c_int {
4087 if buf.is_null() || cur.is_null() {
4088 return -1;
4089 }
4090 let before = io::buf_length(buf);
4091 unsafe { html::serialize_node(cur, buf, 1, 0) };
4092 let after = io::buf_length(buf);
4093 if after < 0 || before < 0 {
4094 return -1;
4095 }
4096 after - before
4097}
4098
4099#[no_mangle]
4107pub unsafe extern "C" fn htmlNodeDumpFile(out: *mut c_void, doc: *mut _xmlDoc, cur: *mut _xmlNode) {
4108 unsafe { htmlNodeDumpFileFormat(out, doc, cur, ptr::null(), 1) };
4109}
4110
4111#[no_mangle]
4120pub unsafe extern "C" fn htmlNodeDumpFileFormat(
4121 out: *mut c_void,
4122 _doc: *mut _xmlDoc,
4123 cur: *mut _xmlNode,
4124 _encoding: *const c_char,
4125 format: c_int,
4126) -> c_int {
4127 let obuf = io::output_buffer_create_file(out as *mut libc::FILE, ptr::null_mut());
4128 if obuf.is_null() {
4129 return -1;
4130 }
4131 unsafe { html_serialize_to_obuf(obuf, cur, format) };
4132 io::output_buffer_close(obuf)
4133}
4134
4135#[no_mangle]
4144pub unsafe extern "C" fn htmlNodeDumpOutput(
4145 buf: *mut _xmlOutputBuffer,
4146 _doc: *mut _xmlDoc,
4147 cur: *mut _xmlNode,
4148 _encoding: *const c_char,
4149) {
4150 unsafe { html_serialize_to_obuf(buf, cur, 1) };
4151}
4152
4153#[no_mangle]
4162pub unsafe extern "C" fn htmlNodeDumpFormatOutput(
4163 buf: *mut _xmlOutputBuffer,
4164 _doc: *mut _xmlDoc,
4165 cur: *mut _xmlNode,
4166 _encoding: *const c_char,
4167 format: c_int,
4168) {
4169 unsafe { html_serialize_to_obuf(buf, cur, format) };
4170}
4171
4172#[no_mangle]
4181pub unsafe extern "C" fn htmlDocContentDumpOutput(
4182 buf: *mut _xmlOutputBuffer,
4183 cur: *mut _xmlDoc,
4184 _encoding: *const c_char,
4185) {
4186 unsafe { html_serialize_to_obuf(buf, cur as *mut _xmlNode, 1) };
4187}
4188
4189#[no_mangle]
4198pub unsafe extern "C" fn htmlDocContentDumpFormatOutput(
4199 buf: *mut _xmlOutputBuffer,
4200 cur: *mut _xmlDoc,
4201 _encoding: *const c_char,
4202 format: c_int,
4203) {
4204 unsafe { html_serialize_to_obuf(buf, cur as *mut _xmlNode, format) };
4205}
4206
4207#[no_mangle]
4217pub unsafe extern "C" fn htmlDocDumpMemoryFormat(
4218 cur: *mut _xmlDoc,
4219 mem: *mut *mut xmlChar,
4220 size: *mut c_int,
4221 format: c_int,
4222) {
4223 if mem.is_null() || size.is_null() {
4224 return;
4225 }
4226 unsafe {
4227 *mem = ptr::null_mut();
4228 *size = 0;
4229 }
4230 if cur.is_null() {
4231 return;
4232 }
4233 let buf = unsafe { html_serialize_to_buffer(cur as *mut _xmlNode, format) };
4234 if buf.is_null() {
4235 return;
4236 }
4237 let buf = unsafe { html_buf_apply_pseudo_encoding(buf, (*cur).encoding as *const c_char) };
4245 if buf.is_null() {
4246 return;
4247 }
4248 let len = io::buf_length(buf);
4249 if len > 0 {
4250 let content = io::buf_content(buf);
4251 unsafe {
4252 *mem = xml_strndup(content, len as usize);
4253 if !(*mem).is_null() {
4254 *size = len;
4255 }
4256 }
4257 }
4258 io::buf_free(buf);
4259}
4260
4261#[no_mangle]
4269pub unsafe extern "C" fn htmlDocDumpMemory(
4270 cur: *mut _xmlDoc,
4271 mem: *mut *mut xmlChar,
4272 size: *mut c_int,
4273) {
4274 unsafe { htmlDocDumpMemoryFormat(cur, mem, size, 1) };
4275}
4276
4277#[no_mangle]
4285pub unsafe extern "C" fn htmlDocDump(f: *mut c_void, cur: *mut _xmlDoc) -> c_int {
4286 if f.is_null() || cur.is_null() {
4287 return -1;
4288 }
4289 let obuf = io::output_buffer_create_file(f as *mut libc::FILE, ptr::null_mut());
4290 if obuf.is_null() {
4291 return -1;
4292 }
4293 unsafe { html_serialize_to_obuf(obuf, cur as *mut _xmlNode, 1) };
4294 io::output_buffer_close(obuf)
4295}
4296
4297#[no_mangle]
4306pub unsafe extern "C" fn htmlSaveFileFormat(
4307 filename: *const c_char,
4308 cur: *mut _xmlDoc,
4309 encoding: *const c_char,
4310 format: c_int,
4311) -> c_int {
4312 if cur.is_null() || filename.is_null() {
4313 return -1;
4314 }
4315 let enc: Option<&[u8]> = if encoding.is_null() {
4320 None
4321 } else {
4322 let s = std::ffi::CStr::from_ptr(encoding);
4323 Some(s.to_bytes())
4324 };
4325 let obuf = io::output_buffer_create_filename_routed(filename, ptr::null_mut(), 0);
4326 if obuf.is_null() {
4327 return 0;
4329 }
4330 let buf = if enc.is_some() {
4335 let b = io::buf_create(0);
4336 if b.is_null() {
4337 io::output_buffer_close(obuf);
4338 return 0;
4339 }
4340 unsafe { html::serialize_node_enc(cur as *mut _xmlNode, b, format, 0, enc) };
4341 b
4342 } else {
4343 unsafe { html_serialize_to_buffer(cur as *mut _xmlNode, format) }
4344 };
4345 let buf = unsafe { html_buf_apply_pseudo_encoding(buf, encoding) };
4346 if buf.is_null() {
4347 io::output_buffer_close(obuf);
4348 return 0;
4349 }
4350 let len = io::buf_length(buf);
4351 if len > 0 {
4352 let content = io::buf_content(buf);
4353 unsafe {
4354 io::output_buffer_write(obuf, len, content as *const c_char);
4355 }
4356 }
4357 io::buf_free(buf);
4358 io::output_buffer_close(obuf)
4359}
4360
4361#[no_mangle]
4370pub unsafe extern "C" fn htmlSaveFile(filename: *const c_char, cur: *mut _xmlDoc) -> c_int {
4371 unsafe { htmlSaveFileFormat(filename, cur, ptr::null(), 1) }
4372}
4373
4374#[no_mangle]
4382pub unsafe extern "C" fn htmlSaveFileEnc(
4383 filename: *const c_char,
4384 cur: *mut _xmlDoc,
4385 encoding: *const c_char,
4386) -> c_int {
4387 unsafe { htmlSaveFileFormat(filename, cur, encoding, 1) }
4388}
4389
4390#[no_mangle]
4398pub unsafe extern "C" fn htmlCtxtSetOptions(ctxt: *mut c_void, options: c_int) -> c_int {
4399 if ctxt.is_null() {
4400 return -1;
4401 }
4402 let c = ctxt as *mut _xmlParserCtxt;
4403 let st = unsafe { html_state(ctxt) };
4404 unsafe {
4405 (*c).options = options & HTML_OPTIONS_ALL_MASK;
4406 (*st).options = (*c).options;
4407 }
4408 options & !HTML_OPTIONS_ALL_MASK & !crate::abi::types::XML_PARSE_NOENT
4409}
4410
4411#[no_mangle]
4421pub unsafe extern "C" fn htmlUTF8ToHtml(
4422 out: *mut u8,
4423 outlen: *mut c_int,
4424 input: *const u8,
4425 inlen: *mut c_int,
4426) -> c_int {
4427 const XML_ENC_ERR_INTERNAL: c_int = -1;
4429 const XML_ENC_ERR_SUCCESS: c_int = 0;
4430 const XML_ENC_ERR_SPACE: c_int = -2;
4431 unsafe {
4432 if out.is_null() || outlen.is_null() || inlen.is_null() {
4433 return XML_ENC_ERR_INTERNAL;
4434 }
4435 if input.is_null() {
4436 *outlen = 0;
4437 *inlen = 0;
4438 return XML_ENC_ERR_SUCCESS;
4439 }
4440 let mut in_pos: usize = 0;
4441 let mut out_pos: usize = 0;
4442 let in_end = *inlen as usize;
4443 let out_cap = *outlen as usize;
4444 let mut ret = XML_ENC_ERR_SPACE;
4445 while in_pos < in_end {
4446 let d = *input.add(in_pos);
4447 if d < 0x80 {
4448 if out_pos >= out_cap {
4449 break;
4450 }
4451 *out.add(out_pos) = d;
4452 out_pos += 1;
4453 in_pos += 1;
4454 continue;
4455 }
4456 let (mut c, seqlen) = if d < 0xE0 {
4457 ((d & 0x1F) as u32, 2usize)
4458 } else if d < 0xF0 {
4459 ((d & 0x0F) as u32, 3usize)
4460 } else {
4461 ((d & 0x07) as u32, 4usize)
4462 };
4463 if in_end - in_pos < seqlen {
4464 break;
4465 }
4466 for i in 1..seqlen {
4467 let dd = *input.add(in_pos + i);
4468 c = (c << 6) | ((dd & 0x3F) as u32);
4469 }
4470 let ent = htmlEntityValueLookup(c);
4471 let mut nbuf = [0u8; 16];
4472 let cp: *const u8;
4473 let mut owned_len: usize = 0;
4474 if ent.is_null() {
4475 let s = format!("#{}", c);
4476 let bytes = s.as_bytes();
4477 nbuf[..bytes.len()].copy_from_slice(bytes);
4478 cp = nbuf.as_ptr();
4479 owned_len = bytes.len();
4480 } else {
4481 cp = (*ent).name as *const u8;
4482 let mut l = 0;
4483 while *cp.add(l) != 0 {
4484 l += 1;
4485 }
4486 owned_len = l;
4487 }
4488 let len = owned_len;
4489 if out_cap - out_pos < len + 2 {
4490 break;
4491 }
4492 *out.add(out_pos) = b'&';
4493 out_pos += 1;
4494 core::ptr::copy_nonoverlapping(cp, out.add(out_pos), len);
4495 out_pos += len;
4496 *out.add(out_pos) = b';';
4497 out_pos += 1;
4498 in_pos += seqlen;
4499 }
4500 ret = out_pos as c_int;
4501 *outlen = out_pos as c_int;
4502 *inlen = in_pos as c_int;
4503 ret
4504 }
4505}
4506
4507#[cfg(test)]
4508mod tests {
4509 use super::*;
4510 use crate::xml::string::{xml_strdup, xml_strlen};
4511
4512 unsafe fn transcode(input: &[u8]) -> String {
4515 let buf = io::buf_create(0);
4516 assert!(!buf.is_null());
4517 unsafe { html_buf_append_html_ascii(buf, input.as_ptr(), input.len()) };
4518 let content = io::buf_content(buf);
4519 let len = xml_strlen(content);
4520 let s = String::from_utf8_lossy(core::slice::from_raw_parts(content, len)).to_string();
4521 io::buf_free(buf);
4522 s
4523 }
4524
4525 #[test]
4531 fn test_pseudo_html_transcode_semantics() {
4532 unsafe {
4533 assert_eq!(transcode(b"a<b&c>d"), "a<b&c>d");
4536 assert_eq!(transcode("a\u{a0}b\u{e9}c".as_bytes()), "a béc");
4538 assert_eq!(transcode("\u{2603}".as_bytes()), "☃");
4540 assert_eq!(transcode(b"x\xc2"), "x");
4542 }
4543 }
4544
4545 #[test]
4552 fn test_html_doc_dump_memory_pseudo_encoding() {
4553 unsafe {
4554 let html = b"<html><body><p>a b c\xc3\xa9d</p></body></html>\0";
4555 let doc = html::parse_memory(html.as_ptr() as *const c_char, (html.len() - 1) as c_int);
4557 assert!(!doc.is_null());
4558 assert!(
4559 (*doc).encoding.is_null(),
4560 "a meta-less html parse must leave doc->encoding NULL"
4561 );
4562
4563 let mut mem: *mut xmlChar = ptr::null_mut();
4564 let mut size: c_int = 0;
4565 htmlDocDumpMemoryFormat(doc, &mut mem, &mut size, 0);
4566 assert!(!mem.is_null());
4567 assert!(size > 0);
4568 let s = String::from_utf8_lossy(core::slice::from_raw_parts(
4569 mem as *const u8,
4570 size as usize,
4571 ))
4572 .to_string();
4573 assert!(s.contains("a b céd"), "got: {s}");
4574 assert!(
4575 !s.contains('\u{a0}'),
4576 "no raw U+00A0 may survive the pseudo-HTML dump: got: {s}"
4577 );
4578 xmlFreeImpl(mem as *mut c_void);
4579
4580 (*doc).encoding = xml_strdup(b"UTF-8\0" as *const u8 as *const xmlChar);
4582 let mut mem2: *mut xmlChar = ptr::null_mut();
4583 let mut size2: c_int = 0;
4584 htmlDocDumpMemoryFormat(doc, &mut mem2, &mut size2, 0);
4585 assert!(!mem2.is_null());
4586 let s2 = String::from_utf8_lossy(core::slice::from_raw_parts(
4587 mem2 as *const u8,
4588 size2 as usize,
4589 ))
4590 .to_string();
4591 assert!(s2.contains("a\u{a0}b\u{a0}c\u{e9}d"), "got: {s2}");
4592 assert!(!s2.contains(" "), "got: {s2}");
4593 xmlFreeImpl(mem2 as *mut c_void);
4594
4595 tree::free_doc(doc);
4596 }
4597 }
4598}