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 = ptr::null_mut();
3030 if !doc.is_null() {
3031 (*c).wellFormed = 1;
3032 }
3033 if !doc.is_null() && !url.is_null() {
3034 (*doc).URL = c_strdup(url) as *mut xmlChar;
3035 }
3036 }
3037 doc
3038}
3039
3040#[no_mangle]
3049pub unsafe extern "C" fn htmlCtxtReadMemory(
3050 ctxt: *mut c_void,
3051 buffer: *const c_char,
3052 size: c_int,
3053 URL: *const c_char,
3054 encoding: *const c_char,
3055 options: c_int,
3056) -> *mut _xmlDoc {
3057 if ctxt.is_null() || size < 0 {
3058 return ptr::null_mut();
3059 }
3060 unsafe { htmlCtxtReset(ctxt) };
3061 unsafe { htmlCtxtUseOptions(ctxt, options) };
3062 let st = unsafe { html_state(ctxt) };
3063 let doc = unsafe { html::parse_memory_enc(buffer, size, encoding, (*st).options) };
3064 unsafe { html_ctxt_finish_read(ctxt, doc, URL) }
3065}
3066
3067#[no_mangle]
3076pub unsafe extern "C" fn htmlCtxtReadDoc(
3077 ctxt: *mut c_void,
3078 str: *const xmlChar,
3079 URL: *const c_char,
3080 encoding: *const c_char,
3081 options: c_int,
3082) -> *mut _xmlDoc {
3083 if ctxt.is_null() {
3084 return ptr::null_mut();
3085 }
3086 unsafe { htmlCtxtReset(ctxt) };
3087 unsafe { htmlCtxtUseOptions(ctxt, options) };
3088 let st = unsafe { html_state(ctxt) };
3089 let doc = unsafe { html::parse_doc(str, encoding, (*st).options) };
3090 unsafe { html_ctxt_finish_read(ctxt, doc, URL) }
3091}
3092
3093#[no_mangle]
3103pub unsafe extern "C" fn htmlCtxtReadFile(
3104 ctxt: *mut c_void,
3105 filename: *const c_char,
3106 encoding: *const c_char,
3107 options: c_int,
3108) -> *mut _xmlDoc {
3109 if ctxt.is_null() {
3110 return ptr::null_mut();
3111 }
3112 unsafe { htmlCtxtReset(ctxt) };
3113 unsafe { htmlCtxtUseOptions(ctxt, options) };
3114 let st = unsafe { html_state(ctxt) };
3115 let doc = unsafe { html::parse_file(filename, encoding, (*st).options) };
3116 unsafe { html_ctxt_finish_read(ctxt, doc, filename) }
3117}
3118
3119unsafe fn html_read_fd(fd: c_int) -> Vec<u8> {
3121 let mut buf = Vec::new();
3122 let mut tmp = [0u8; 4096];
3123 loop {
3124 let n = libc::read(fd, tmp.as_mut_ptr() as *mut c_void, tmp.len());
3125 if n <= 0 {
3126 break;
3127 }
3128 buf.extend_from_slice(&tmp[..n as usize]);
3129 }
3130 buf
3131}
3132
3133unsafe fn html_read_io(ioread: Option<xmlInputReadCallback>, ioctx: *mut c_void) -> Vec<u8> {
3135 let mut buf = Vec::new();
3136 let mut tmp = [0u8; 4096];
3137 if let Some(read) = ioread {
3138 loop {
3139 let n = unsafe { read(ioctx, tmp.as_mut_ptr() as *mut c_char, tmp.len() as c_int) };
3140 if n <= 0 {
3141 break;
3142 }
3143 buf.extend_from_slice(&tmp[..n as usize]);
3144 }
3145 }
3146 buf
3147}
3148
3149#[no_mangle]
3158pub unsafe extern "C" fn htmlCtxtReadFd(
3159 ctxt: *mut c_void,
3160 fd: c_int,
3161 URL: *const c_char,
3162 encoding: *const c_char,
3163 options: c_int,
3164) -> *mut _xmlDoc {
3165 if ctxt.is_null() {
3166 return ptr::null_mut();
3167 }
3168 unsafe { htmlCtxtReset(ctxt) };
3169 unsafe { htmlCtxtUseOptions(ctxt, options) };
3170 let data = unsafe { html_read_fd(fd) };
3171 let st = unsafe { html_state(ctxt) };
3172 let doc = unsafe {
3173 html::parse_memory_enc(
3174 data.as_ptr() as *const c_char,
3175 data.len() as c_int,
3176 encoding,
3177 (*st).options,
3178 )
3179 };
3180 unsafe { html_ctxt_finish_read(ctxt, doc, URL) }
3181}
3182
3183#[no_mangle]
3193pub unsafe extern "C" fn htmlCtxtReadIO(
3194 ctxt: *mut c_void,
3195 ioread: Option<xmlInputReadCallback>,
3196 _ioclose: Option<xmlInputCloseCallback>,
3197 ioctx: *mut c_void,
3198 URL: *const c_char,
3199 encoding: *const c_char,
3200 options: c_int,
3201) -> *mut _xmlDoc {
3202 if ctxt.is_null() {
3203 return ptr::null_mut();
3204 }
3205 unsafe { htmlCtxtReset(ctxt) };
3206 unsafe { htmlCtxtUseOptions(ctxt, options) };
3207 let data = unsafe { html_read_io(ioread, ioctx) };
3208 let st = unsafe { html_state(ctxt) };
3209 let doc = unsafe {
3210 html::parse_memory_enc(
3211 data.as_ptr() as *const c_char,
3212 data.len() as c_int,
3213 encoding,
3214 (*st).options,
3215 )
3216 };
3217 unsafe { html_ctxt_finish_read(ctxt, doc, URL) }
3218}
3219
3220#[no_mangle]
3229pub unsafe extern "C" fn htmlReadMemory(
3230 buffer: *const c_char,
3231 size: c_int,
3232 url: *const c_char,
3233 encoding: *const c_char,
3234 options: c_int,
3235) -> *mut _xmlDoc {
3236 if size < 0 {
3237 return ptr::null_mut();
3238 }
3239 let ctxt = unsafe { htmlNewParserCtxt() };
3240 if ctxt.is_null() {
3241 return ptr::null_mut();
3242 }
3243 let doc = unsafe { htmlCtxtReadMemory(ctxt, buffer, size, url, encoding, options) };
3244 unsafe { crate::xml::html::free_parser_ctxt(ctxt) };
3245 doc
3246}
3247
3248#[no_mangle]
3258pub unsafe extern "C" fn htmlReadDoc(
3259 str: *const xmlChar,
3260 url: *const c_char,
3261 encoding: *const c_char,
3262 options: c_int,
3263) -> *mut _xmlDoc {
3264 let ctxt = unsafe { htmlNewParserCtxt() };
3265 if ctxt.is_null() {
3266 return ptr::null_mut();
3267 }
3268 let doc = unsafe { htmlCtxtReadDoc(ctxt, str, url, encoding, options) };
3269 unsafe { crate::xml::html::free_parser_ctxt(ctxt) };
3270 doc
3271}
3272
3273#[no_mangle]
3282pub unsafe extern "C" fn htmlReadFile(
3283 filename: *const c_char,
3284 encoding: *const c_char,
3285 options: c_int,
3286) -> *mut _xmlDoc {
3287 let ctxt = unsafe { htmlNewParserCtxt() };
3288 if ctxt.is_null() {
3289 return ptr::null_mut();
3290 }
3291 let doc = unsafe { htmlCtxtReadFile(ctxt, filename, encoding, options) };
3292 unsafe { crate::xml::html::free_parser_ctxt(ctxt) };
3293 doc
3294}
3295
3296#[no_mangle]
3304pub unsafe extern "C" fn htmlReadFd(
3305 fd: c_int,
3306 url: *const c_char,
3307 encoding: *const c_char,
3308 options: c_int,
3309) -> *mut _xmlDoc {
3310 let ctxt = unsafe { htmlNewParserCtxt() };
3311 if ctxt.is_null() {
3312 return ptr::null_mut();
3313 }
3314 let doc = unsafe { htmlCtxtReadFd(ctxt, fd, url, encoding, options) };
3315 unsafe { crate::xml::html::free_parser_ctxt(ctxt) };
3316 doc
3317}
3318
3319#[no_mangle]
3329pub unsafe extern "C" fn htmlReadIO(
3330 ioread: Option<xmlInputReadCallback>,
3331 ioclose: Option<xmlInputCloseCallback>,
3332 ioctx: *mut c_void,
3333 url: *const c_char,
3334 encoding: *const c_char,
3335 options: c_int,
3336) -> *mut _xmlDoc {
3337 let ctxt = unsafe { htmlNewParserCtxt() };
3338 if ctxt.is_null() {
3339 return ptr::null_mut();
3340 }
3341 let doc = unsafe { htmlCtxtReadIO(ctxt, ioread, ioclose, ioctx, url, encoding, options) };
3342 unsafe { crate::xml::html::free_parser_ctxt(ctxt) };
3343 doc
3344}
3345
3346#[no_mangle]
3357pub unsafe extern "C" fn htmlSAXParseDoc(
3358 cur: *const xmlChar,
3359 encoding: *const c_char,
3360 sax: *mut _xmlSAXHandler,
3361 userData: *mut c_void,
3362) -> *mut _xmlDoc {
3363 if cur.is_null() {
3364 return ptr::null_mut();
3365 }
3366 let ctxt = unsafe { htmlNewSAXParserCtxt(sax, userData) };
3367 if ctxt.is_null() {
3368 return ptr::null_mut();
3369 }
3370 let doc = unsafe { htmlCtxtReadDoc(ctxt, cur, ptr::null(), encoding, 0) };
3371 unsafe { crate::xml::html::free_parser_ctxt(ctxt) };
3372 doc
3373}
3374
3375#[no_mangle]
3386pub unsafe extern "C" fn htmlSAXParseFile(
3387 filename: *const c_char,
3388 encoding: *const c_char,
3389 sax: *mut _xmlSAXHandler,
3390 userData: *mut c_void,
3391) -> *mut _xmlDoc {
3392 let ctxt = unsafe { htmlNewSAXParserCtxt(sax, userData) };
3393 if ctxt.is_null() {
3394 return ptr::null_mut();
3395 }
3396 let doc = unsafe { htmlCtxtReadFile(ctxt, filename, encoding, 0) };
3397 unsafe { crate::xml::html::free_parser_ctxt(ctxt) };
3398 doc
3399}
3400
3401#[no_mangle]
3412pub unsafe extern "C" fn htmlParseElement(ctxt: *mut c_void) {
3413 if ctxt.is_null() {
3414 return;
3415 }
3416 let st = unsafe { html_state(ctxt) };
3417 if unsafe { (*st).input.is_null() } {
3418 return;
3419 }
3420 let doc = unsafe {
3421 html::parse_memory_enc(
3422 (*st).input as *const c_char,
3423 (*st).input_len as c_int,
3424 (*st).encoding,
3425 (*st).options,
3426 )
3427 };
3428 unsafe {
3429 (*st).doc = doc;
3430 (*(ctxt as *mut _xmlParserCtxt)).myDoc = doc;
3431 }
3432}
3433
3434#[no_mangle]
3447pub unsafe extern "C" fn htmlNewDocNoDtD(
3448 URI: *const xmlChar,
3449 publicId: *const xmlChar,
3450) -> *mut _xmlDoc {
3451 let doc = unsafe { html::new_doc_no_dtd(ptr::null()) };
3452 if doc.is_null() {
3453 return ptr::null_mut();
3454 }
3455 unsafe {
3456 (*doc).standalone = 1;
3459 (*doc).charset = crate::abi::types::xmlCharEncoding::XML_CHAR_ENCODING_UTF8 as c_int;
3460 (*doc).properties = crate::abi::types::xmlDocProperties::XML_DOC_HTML as c_int
3461 | crate::abi::types::xmlDocProperties::XML_DOC_USERBUILT as c_int;
3462 if !publicId.is_null() || !URI.is_null() {
3463 let dtd = crate::xml::dtd::create_int_subset(
3464 doc,
3465 b"html\0" as *const u8 as *const xmlChar,
3466 publicId,
3467 URI,
3468 );
3469 if dtd.is_null() {
3470 tree::free_doc(doc);
3471 return ptr::null_mut();
3472 }
3473 }
3474 }
3475 doc
3476}
3477
3478#[no_mangle]
3493pub unsafe extern "C" fn htmlNewDoc(
3494 URI: *const xmlChar,
3495 ExternalID: *const xmlChar,
3496) -> *mut _xmlDoc {
3497 let doc = unsafe { html::new_doc(ptr::null()) };
3498 if doc.is_null() {
3499 return ptr::null_mut();
3500 }
3501 unsafe {
3502 (*doc).standalone = 1;
3505 (*doc).charset = crate::abi::types::xmlCharEncoding::XML_CHAR_ENCODING_UTF8 as c_int;
3506 (*doc).properties = crate::abi::types::xmlDocProperties::XML_DOC_HTML as c_int
3507 | crate::abi::types::xmlDocProperties::XML_DOC_USERBUILT as c_int;
3508 if URI.is_null() && ExternalID.is_null() {
3509 let dtd = crate::xml::dtd::create_int_subset(
3510 doc,
3511 b"html\0" as *const u8 as *const xmlChar,
3512 b"-//W3C//DTD HTML 4.0 Transitional//EN\0" as *const u8 as *const xmlChar,
3513 b"http://www.w3.org/TR/REC-html40/loose.dtd\0" as *const u8 as *const xmlChar,
3514 );
3515 if dtd.is_null() {
3516 tree::free_doc(doc);
3517 return ptr::null_mut();
3518 }
3519 } else if !ExternalID.is_null() || !URI.is_null() {
3520 let dtd = crate::xml::dtd::create_int_subset(
3521 doc,
3522 b"html\0" as *const u8 as *const xmlChar,
3523 ExternalID,
3524 URI,
3525 );
3526 if dtd.is_null() {
3527 tree::free_doc(doc);
3528 return ptr::null_mut();
3529 }
3530 }
3531 }
3532 doc
3533}
3534
3535unsafe fn html_find_first_child(node: *mut _xmlNode, name: &[u8]) -> *mut _xmlNode {
3541 let mut c = unsafe { (*node).children };
3542 while !c.is_null() {
3543 let n = unsafe { &*c };
3544 if n.type_ == XML_ELEMENT_NODE as c_int
3545 && !n.name.is_null()
3546 && unsafe { xmlstr_to_bytes(n.name) }.eq_ignore_ascii_case(name)
3547 {
3548 return c;
3549 }
3550 c = unsafe { (*c).next };
3551 }
3552 ptr::null_mut()
3553}
3554
3555unsafe fn html_find_head(doc: *mut _xmlDoc) -> *mut _xmlNode {
3558 if doc.is_null() {
3559 return ptr::null_mut();
3560 }
3561 let html = unsafe { html_find_first_child(doc as *mut _xmlNode, b"html") };
3562 if html.is_null() {
3563 return ptr::null_mut();
3564 }
3565 unsafe { html_find_first_child(html, b"head") }
3566}
3567
3568unsafe fn html_find_meta_encoding_attr(elem: *mut _xmlNode) -> (*mut _xmlAttr, bool) {
3571 let n = unsafe { &*elem };
3572 if n.type_ != XML_ELEMENT_NODE as c_int || n.name.is_null() {
3573 return (ptr::null_mut(), false);
3574 }
3575 if !unsafe { xmlstr_to_bytes(n.name) }.eq_ignore_ascii_case(b"meta") {
3576 return (ptr::null_mut(), false);
3577 }
3578
3579 let mut content_attr: *mut _xmlAttr = ptr::null_mut();
3580 let mut is_content_type = false;
3581 let mut attr = n.properties;
3582 while !attr.is_null() {
3583 let a = unsafe { &*attr };
3584 if a.ns.is_null() && !a.name.is_null() {
3585 let nm = unsafe { xmlstr_to_bytes(a.name) };
3586 if nm.eq_ignore_ascii_case(b"charset") {
3587 return (attr, false);
3588 }
3589 if nm.eq_ignore_ascii_case(b"content") {
3590 content_attr = attr;
3591 }
3592 if nm.eq_ignore_ascii_case(b"http-equiv")
3593 && !a.children.is_null()
3594 && unsafe { (*(a.children)).type_ } == XML_TEXT_NODE as c_int
3595 && unsafe { (*(a.children)).next }.is_null()
3596 && !unsafe { (*(a.children)).content }.is_null()
3597 && unsafe { xmlstr_to_bytes((*(a.children)).content) }
3598 .eq_ignore_ascii_case(b"Content-Type")
3599 {
3600 is_content_type = true;
3601 }
3602 }
3603 attr = unsafe { (*attr).next };
3604 }
3605 if is_content_type && !content_attr.is_null() {
3606 (content_attr, true)
3607 } else {
3608 (ptr::null_mut(), false)
3609 }
3610}
3611
3612unsafe fn html_parse_content_type(val: *const xmlChar) -> Option<(usize, usize, usize)> {
3615 let bytes = unsafe { xmlstr_to_bytes(val) };
3616 let n = bytes.len();
3617 let at = |i: usize| -> u8 {
3618 if i < n {
3619 bytes[i]
3620 } else {
3621 0
3622 }
3623 };
3624
3625 let mut p = 0usize;
3626 loop {
3627 loop {
3629 let ch = at(p);
3630 if ch == b'c' || ch == b'C' {
3631 break;
3632 }
3633 if ch == 0 {
3634 return None;
3635 }
3636 p += 1;
3637 }
3638 p += 1;
3639
3640 let mut ok = true;
3642 for (k, want) in b"harset".iter().enumerate() {
3643 if at(p + k).to_ascii_lowercase() != *want {
3644 ok = false;
3645 break;
3646 }
3647 }
3648 if !ok {
3649 continue;
3650 }
3651 p += 6;
3652 while is_ws_html(at(p)) {
3653 p += 1;
3654 }
3655 if at(p) != b'=' {
3656 continue;
3657 }
3658 p += 1;
3659 while is_ws_html(at(p)) {
3660 p += 1;
3661 }
3662 if at(p) == 0 {
3663 return None;
3664 }
3665
3666 let (start, mut end): (usize, usize);
3667 if at(p) == b'"' || at(p) == b'\'' {
3668 let quote = at(p);
3669 p += 1;
3670 while is_ws_html(at(p)) {
3671 p += 1;
3672 }
3673 start = p;
3674 end = start;
3675 loop {
3676 if at(p) == 0 {
3677 return None;
3678 }
3679 if !is_ws_html(at(p)) {
3680 end = p + 1;
3681 }
3682 if at(p) == quote {
3683 break;
3684 }
3685 p += 1;
3686 }
3687 } else {
3688 start = p;
3689 while at(p) != 0 && at(p) != b';' && !is_ws_html(at(p)) {
3690 p += 1;
3691 }
3692 end = p;
3693 }
3694 let size = n;
3695 return Some((start, end, size));
3696 }
3697}
3698
3699#[no_mangle]
3711pub unsafe extern "C" fn htmlGetMetaEncoding(doc: *mut _xmlDoc) -> *const xmlChar {
3712 let head = unsafe { html_find_head(doc) };
3713 if head.is_null() {
3714 return ptr::null();
3715 }
3716 let mut node = unsafe { (*head).children };
3717 while !node.is_null() {
3718 let (attr, is_content_type) = unsafe { html_find_meta_encoding_attr(node) };
3719 if !attr.is_null() {
3720 let a = unsafe { &*attr };
3721 let val = if !a.children.is_null()
3722 && unsafe { (*(a.children)).type_ } == XML_TEXT_NODE as c_int
3723 && unsafe { (*(a.children)).next }.is_null()
3724 && !unsafe { (*(a.children)).content }.is_null()
3725 {
3726 unsafe { (*(a.children)).content }
3727 } else {
3728 b"\0" as *const u8 as *const xmlChar
3729 };
3730 if !is_content_type {
3731 let bytes = unsafe { xmlstr_to_bytes(val) };
3732 let mut start = 0usize;
3733 while start < bytes.len() && is_ws_html(bytes[start]) {
3734 start += 1;
3735 }
3736 return unsafe { val.add(start) };
3737 } else if let Some((start, _, _)) = unsafe { html_parse_content_type(val) } {
3738 return unsafe { val.add(start) };
3739 }
3740 }
3741 node = unsafe { (*node).next };
3742 }
3743 ptr::null()
3744}
3745
3746unsafe fn html_update_meta_encoding(
3749 attr_value: *const xmlChar,
3750 start: usize,
3751 end: usize,
3752 size: usize,
3753 encoding: &[u8],
3754) -> *mut xmlChar {
3755 let enc: &[u8] = if encoding.eq_ignore_ascii_case(b"HTML") {
3757 b"ASCII"
3758 } else {
3759 encoding
3760 };
3761 let bytes = unsafe { xmlstr_to_bytes(attr_value) };
3762 let e = end.min(bytes.len()).min(size);
3763 let s = start.min(e);
3764 let total = size - (e - s) + enc.len();
3765 let new_val = xmlMallocImpl(total + 1) as *mut xmlChar;
3766 if new_val.is_null() {
3767 return ptr::null_mut();
3768 }
3769 unsafe {
3770 let mut p = new_val;
3771 ptr::copy_nonoverlapping(bytes.as_ptr(), p, s);
3772 p = p.add(s);
3773 ptr::copy_nonoverlapping(enc.as_ptr(), p, enc.len());
3774 p = p.add(enc.len());
3775 ptr::copy_nonoverlapping(bytes.as_ptr().add(e), p, size - e);
3776 *new_val.add(total) = 0;
3777 }
3778 new_val
3779}
3780
3781unsafe fn html_set_attr_content(attr: *mut _xmlAttr, content: *const xmlChar) -> c_int {
3784 if attr.is_null() {
3785 return -1;
3786 }
3787 unsafe {
3788 if !(*attr).children.is_null() {
3789 tree::free_node_list((*attr).children);
3790 (*attr).children = ptr::null_mut();
3791 (*attr).last = ptr::null_mut();
3792 }
3793 let text = tree::new_text(content);
3794 if text.is_null() {
3795 return -1;
3796 }
3797 (*text).parent = attr as *mut _xmlNode;
3798 (*text).doc = (*attr).doc;
3799 (*attr).children = text;
3800 (*attr).last = text;
3801 }
3802 0
3803}
3804
3805#[no_mangle]
3813pub unsafe extern "C" fn htmlSetMetaEncoding(doc: *mut _xmlDoc, encoding: *const xmlChar) -> c_int {
3814 if encoding.is_null() {
3815 return 1;
3816 }
3817 let head = unsafe { html_find_head(doc) };
3818 if head.is_null() {
3819 return 1;
3820 }
3821 let enc_bytes = unsafe { xmlstr_to_bytes(encoding) }.to_vec();
3822
3823 let mut found = 0;
3824 let mut meta = unsafe { (*head).children };
3825 while !meta.is_null() {
3826 let (attr, is_content_type) = unsafe { html_find_meta_encoding_attr(meta) };
3827 if !attr.is_null() {
3828 let a = unsafe { &*attr };
3829 let val = if !a.children.is_null()
3830 && unsafe { (*(a.children)).type_ } == XML_TEXT_NODE as c_int
3831 && unsafe { (*(a.children)).next }.is_null()
3832 && !unsafe { (*(a.children)).content }.is_null()
3833 {
3834 unsafe { (*(a.children)).content }
3835 } else {
3836 b"\0" as *const u8 as *const xmlChar
3837 };
3838 found = 1;
3839 let off = if is_content_type {
3840 unsafe { html_parse_content_type(val) }
3841 } else {
3842 let bytes = unsafe { xmlstr_to_bytes(val) };
3843 let mut start = 0usize;
3844 let mut end = bytes.len();
3845 while start < end && is_ws_html(bytes[start]) {
3846 start += 1;
3847 }
3848 while end > start && is_ws_html(bytes[end - 1]) {
3849 end -= 1;
3850 }
3851 Some((start, end, bytes.len()))
3852 };
3853 if let Some((start, end, size)) = off {
3854 let new_val =
3855 unsafe { html_update_meta_encoding(val, start, end, size, &enc_bytes) };
3856 if new_val.is_null() {
3857 return -1;
3858 }
3859 let ret = unsafe { html_set_attr_content(attr, new_val) };
3860 unsafe { xmlFreeImpl(new_val as *mut c_void) };
3861 if ret < 0 {
3862 return -1;
3863 }
3864 } else {
3865 return -1;
3866 }
3867 }
3868 meta = unsafe { (*meta).next };
3869 }
3870
3871 if found != 0 {
3872 return 0;
3873 }
3874
3875 let meta_node =
3877 unsafe { tree::new_node(ptr::null_mut(), b"meta\0" as *const u8 as *const xmlChar) };
3878 if meta_node.is_null() {
3879 return -1;
3880 }
3881 unsafe {
3882 (*meta_node).doc = (*head).doc;
3883 }
3884 let prop = unsafe {
3885 tree::set_prop(
3886 meta_node,
3887 b"charset\0" as *const u8 as *const xmlChar,
3888 encoding,
3889 )
3890 };
3891 if prop.is_null() {
3892 unsafe { tree::free_node(meta_node) };
3893 return -1;
3894 }
3895 if unsafe { (*head).children }.is_null() {
3896 unsafe { tree::add_child(head, meta_node) };
3897 } else {
3898 unsafe { tree::add_sibling_before((*head).children, meta_node) };
3899 }
3900 0
3901}
3902
3903unsafe fn html_serialize_to_buffer(node: *mut _xmlNode, format: c_int) -> *mut _xmlBuffer {
3910 let buf = io::buf_create(0);
3911 if buf.is_null() {
3912 return ptr::null_mut();
3913 }
3914 unsafe { html::serialize_node(node, buf, format, 0) };
3915 buf
3916}
3917
3918const unsafe fn html_pseudo_encoding_in_force(encoding: *const c_char) -> bool {
3931 if encoding.is_null() {
3932 return true;
3933 }
3934 let b = unsafe { std::ffi::CStr::from_ptr(encoding) }.to_bytes();
3935 b.eq_ignore_ascii_case(b"HTML")
3936}
3937
3938unsafe fn html_buf_append_html_ascii(out: *mut _xmlBuffer, content: *const xmlChar, len: usize) {
3950 let mut i = 0usize;
3951 while i < len {
3952 let d = unsafe { *content.add(i) };
3953 if d < 0x80 {
3954 let start = i;
3956 i += 1;
3957 while i < len && unsafe { *content.add(i) } < 0x80 {
3958 i += 1;
3959 }
3960 io::buf_add(out, content.add(start), (i - start) as c_int);
3961 continue;
3962 }
3963 let (mut c, seqlen) = if d < 0xE0 {
3964 ((d & 0x1F) as c_uint, 2usize)
3965 } else if d < 0xF0 {
3966 ((d & 0x0F) as c_uint, 3usize)
3967 } else {
3968 ((d & 0x07) as c_uint, 4usize)
3969 };
3970 if len - i < seqlen {
3971 break;
3974 }
3975 for k in 1..seqlen {
3976 let dd = unsafe { *content.add(i + k) };
3977 c = (c << 6) | ((dd & 0x3F) as c_uint);
3978 }
3979 i += seqlen;
3980 let ent = unsafe { html_entity_value_lookup_static(c) };
3981 if ent.is_null() {
3982 io::buf_ccat(out, b'&');
3984 io::buf_ccat(out, b'#');
3985 let mut digits = [0u8; 10];
3986 let mut n = 0usize;
3987 let mut v = c;
3988 if v == 0 {
3989 digits[0] = b'0';
3990 n = 1;
3991 }
3992 while v > 0 {
3993 digits[n] = b'0' + (v % 10) as u8;
3994 n += 1;
3995 v /= 10;
3996 }
3997 while n > 0 {
3998 n -= 1;
3999 io::buf_ccat(out, digits[n]);
4000 }
4001 io::buf_ccat(out, b';');
4002 } else {
4003 io::buf_ccat(out, b'&');
4004 io::buf_cat(out, (*ent).name as *const xmlChar);
4005 io::buf_ccat(out, b';');
4006 }
4007 }
4008}
4009
4010unsafe fn html_buf_apply_pseudo_encoding(
4021 buf: *mut _xmlBuffer,
4022 encoding: *const c_char,
4023) -> *mut _xmlBuffer {
4024 if buf.is_null() || !unsafe { html_pseudo_encoding_in_force(encoding) } {
4025 return buf;
4026 }
4027 let len = io::buf_length(buf);
4028 if len <= 0 {
4029 return buf;
4030 }
4031 let content = io::buf_content(buf);
4032 let conv = io::buf_create(0);
4033 if conv.is_null() {
4034 return buf;
4035 }
4036 unsafe { html_buf_append_html_ascii(conv, content, len as usize) };
4037 io::buf_free(buf);
4038 conv
4039}
4040
4041unsafe fn html_serialize_to_obuf(obuf: *mut _xmlOutputBuffer, node: *mut _xmlNode, format: c_int) {
4044 unsafe { html_serialize_to_obuf_enc(obuf, node, format, None) }
4045}
4046
4047unsafe fn html_serialize_to_obuf_enc(
4051 obuf: *mut _xmlOutputBuffer,
4052 node: *mut _xmlNode,
4053 format: c_int,
4054 encoding: Option<&[u8]>,
4055) {
4056 if obuf.is_null() || node.is_null() {
4057 return;
4058 }
4059 let buf = if encoding.is_some() {
4060 let b = io::buf_create(0);
4061 if b.is_null() {
4062 return;
4063 }
4064 unsafe { html::serialize_node_enc(node, b, format, 0, encoding) };
4065 b
4066 } else {
4067 unsafe { html_serialize_to_buffer(node, format) }
4068 };
4069 if buf.is_null() {
4070 return;
4071 }
4072 let len = io::buf_length(buf);
4073 if len > 0 {
4074 let content = io::buf_content(buf);
4075 unsafe {
4076 io::output_buffer_write(obuf, len, content as *const c_char);
4077 }
4078 }
4079 io::buf_free(buf);
4080}
4081
4082#[no_mangle]
4090pub unsafe extern "C" fn htmlNodeDump(
4091 buf: *mut _xmlBuffer,
4092 _doc: *mut _xmlDoc,
4093 cur: *mut _xmlNode,
4094) -> c_int {
4095 if buf.is_null() || cur.is_null() {
4096 return -1;
4097 }
4098 let before = io::buf_length(buf);
4099 unsafe { html::serialize_node(cur, buf, 1, 0) };
4100 let after = io::buf_length(buf);
4101 if after < 0 || before < 0 {
4102 return -1;
4103 }
4104 after - before
4105}
4106
4107#[no_mangle]
4115pub unsafe extern "C" fn htmlNodeDumpFile(out: *mut c_void, doc: *mut _xmlDoc, cur: *mut _xmlNode) {
4116 unsafe { htmlNodeDumpFileFormat(out, doc, cur, ptr::null(), 1) };
4117}
4118
4119#[no_mangle]
4128pub unsafe extern "C" fn htmlNodeDumpFileFormat(
4129 out: *mut c_void,
4130 _doc: *mut _xmlDoc,
4131 cur: *mut _xmlNode,
4132 _encoding: *const c_char,
4133 format: c_int,
4134) -> c_int {
4135 let obuf = io::output_buffer_create_file(out as *mut libc::FILE, ptr::null_mut());
4136 if obuf.is_null() {
4137 return -1;
4138 }
4139 unsafe { html_serialize_to_obuf(obuf, cur, format) };
4140 io::output_buffer_close(obuf)
4141}
4142
4143#[no_mangle]
4152pub unsafe extern "C" fn htmlNodeDumpOutput(
4153 buf: *mut _xmlOutputBuffer,
4154 _doc: *mut _xmlDoc,
4155 cur: *mut _xmlNode,
4156 _encoding: *const c_char,
4157) {
4158 unsafe { html_serialize_to_obuf(buf, cur, 1) };
4159}
4160
4161#[no_mangle]
4170pub unsafe extern "C" fn htmlNodeDumpFormatOutput(
4171 buf: *mut _xmlOutputBuffer,
4172 _doc: *mut _xmlDoc,
4173 cur: *mut _xmlNode,
4174 _encoding: *const c_char,
4175 format: c_int,
4176) {
4177 unsafe { html_serialize_to_obuf(buf, cur, format) };
4178}
4179
4180#[no_mangle]
4189pub unsafe extern "C" fn htmlDocContentDumpOutput(
4190 buf: *mut _xmlOutputBuffer,
4191 cur: *mut _xmlDoc,
4192 _encoding: *const c_char,
4193) {
4194 unsafe { html_serialize_to_obuf(buf, cur as *mut _xmlNode, 1) };
4195}
4196
4197#[no_mangle]
4206pub unsafe extern "C" fn htmlDocContentDumpFormatOutput(
4207 buf: *mut _xmlOutputBuffer,
4208 cur: *mut _xmlDoc,
4209 _encoding: *const c_char,
4210 format: c_int,
4211) {
4212 unsafe { html_serialize_to_obuf(buf, cur as *mut _xmlNode, format) };
4213}
4214
4215#[no_mangle]
4225pub unsafe extern "C" fn htmlDocDumpMemoryFormat(
4226 cur: *mut _xmlDoc,
4227 mem: *mut *mut xmlChar,
4228 size: *mut c_int,
4229 format: c_int,
4230) {
4231 if mem.is_null() || size.is_null() {
4232 return;
4233 }
4234 unsafe {
4235 *mem = ptr::null_mut();
4236 *size = 0;
4237 }
4238 if cur.is_null() {
4239 return;
4240 }
4241 let buf = unsafe { html_serialize_to_buffer(cur as *mut _xmlNode, format) };
4242 if buf.is_null() {
4243 return;
4244 }
4245 let buf = unsafe { html_buf_apply_pseudo_encoding(buf, (*cur).encoding as *const c_char) };
4253 if buf.is_null() {
4254 return;
4255 }
4256 let len = io::buf_length(buf);
4257 if len > 0 {
4258 let content = io::buf_content(buf);
4259 unsafe {
4260 *mem = xml_strndup(content, len as usize);
4261 if !(*mem).is_null() {
4262 *size = len;
4263 }
4264 }
4265 }
4266 io::buf_free(buf);
4267}
4268
4269#[no_mangle]
4277pub unsafe extern "C" fn htmlDocDumpMemory(
4278 cur: *mut _xmlDoc,
4279 mem: *mut *mut xmlChar,
4280 size: *mut c_int,
4281) {
4282 unsafe { htmlDocDumpMemoryFormat(cur, mem, size, 1) };
4283}
4284
4285#[no_mangle]
4293pub unsafe extern "C" fn htmlDocDump(f: *mut c_void, cur: *mut _xmlDoc) -> c_int {
4294 if f.is_null() || cur.is_null() {
4295 return -1;
4296 }
4297 let obuf = io::output_buffer_create_file(f as *mut libc::FILE, ptr::null_mut());
4298 if obuf.is_null() {
4299 return -1;
4300 }
4301 unsafe { html_serialize_to_obuf(obuf, cur as *mut _xmlNode, 1) };
4302 io::output_buffer_close(obuf)
4303}
4304
4305#[no_mangle]
4314pub unsafe extern "C" fn htmlSaveFileFormat(
4315 filename: *const c_char,
4316 cur: *mut _xmlDoc,
4317 encoding: *const c_char,
4318 format: c_int,
4319) -> c_int {
4320 if cur.is_null() || filename.is_null() {
4321 return -1;
4322 }
4323 let enc: Option<&[u8]> = if encoding.is_null() {
4328 None
4329 } else {
4330 let s = std::ffi::CStr::from_ptr(encoding);
4331 Some(s.to_bytes())
4332 };
4333 let obuf = io::output_buffer_create_filename_routed(filename, ptr::null_mut(), 0);
4334 if obuf.is_null() {
4335 return 0;
4337 }
4338 let buf = if enc.is_some() {
4343 let b = io::buf_create(0);
4344 if b.is_null() {
4345 io::output_buffer_close(obuf);
4346 return 0;
4347 }
4348 unsafe { html::serialize_node_enc(cur as *mut _xmlNode, b, format, 0, enc) };
4349 b
4350 } else {
4351 unsafe { html_serialize_to_buffer(cur as *mut _xmlNode, format) }
4352 };
4353 let buf = unsafe { html_buf_apply_pseudo_encoding(buf, encoding) };
4354 if buf.is_null() {
4355 io::output_buffer_close(obuf);
4356 return 0;
4357 }
4358 let len = io::buf_length(buf);
4359 if len > 0 {
4360 let content = io::buf_content(buf);
4361 unsafe {
4362 io::output_buffer_write(obuf, len, content as *const c_char);
4363 }
4364 }
4365 io::buf_free(buf);
4366 io::output_buffer_close(obuf)
4367}
4368
4369#[no_mangle]
4378pub unsafe extern "C" fn htmlSaveFile(filename: *const c_char, cur: *mut _xmlDoc) -> c_int {
4379 unsafe { htmlSaveFileFormat(filename, cur, ptr::null(), 1) }
4380}
4381
4382#[no_mangle]
4390pub unsafe extern "C" fn htmlSaveFileEnc(
4391 filename: *const c_char,
4392 cur: *mut _xmlDoc,
4393 encoding: *const c_char,
4394) -> c_int {
4395 unsafe { htmlSaveFileFormat(filename, cur, encoding, 1) }
4396}
4397
4398#[no_mangle]
4406pub unsafe extern "C" fn htmlCtxtSetOptions(ctxt: *mut c_void, options: c_int) -> c_int {
4407 if ctxt.is_null() {
4408 return -1;
4409 }
4410 let c = ctxt as *mut _xmlParserCtxt;
4411 let st = unsafe { html_state(ctxt) };
4412 unsafe {
4413 (*c).options = options & HTML_OPTIONS_ALL_MASK;
4414 (*st).options = (*c).options;
4415 }
4416 options & !HTML_OPTIONS_ALL_MASK & !crate::abi::types::XML_PARSE_NOENT
4417}
4418
4419#[no_mangle]
4429pub unsafe extern "C" fn htmlUTF8ToHtml(
4430 out: *mut u8,
4431 outlen: *mut c_int,
4432 input: *const u8,
4433 inlen: *mut c_int,
4434) -> c_int {
4435 const XML_ENC_ERR_INTERNAL: c_int = -1;
4437 const XML_ENC_ERR_SUCCESS: c_int = 0;
4438 const XML_ENC_ERR_SPACE: c_int = -2;
4439 unsafe {
4440 if out.is_null() || outlen.is_null() || inlen.is_null() {
4441 return XML_ENC_ERR_INTERNAL;
4442 }
4443 if input.is_null() {
4444 *outlen = 0;
4445 *inlen = 0;
4446 return XML_ENC_ERR_SUCCESS;
4447 }
4448 let mut in_pos: usize = 0;
4449 let mut out_pos: usize = 0;
4450 let in_end = *inlen as usize;
4451 let out_cap = *outlen as usize;
4452 let mut ret = XML_ENC_ERR_SPACE;
4453 while in_pos < in_end {
4454 let d = *input.add(in_pos);
4455 if d < 0x80 {
4456 if out_pos >= out_cap {
4457 break;
4458 }
4459 *out.add(out_pos) = d;
4460 out_pos += 1;
4461 in_pos += 1;
4462 continue;
4463 }
4464 let (mut c, seqlen) = if d < 0xE0 {
4465 ((d & 0x1F) as u32, 2usize)
4466 } else if d < 0xF0 {
4467 ((d & 0x0F) as u32, 3usize)
4468 } else {
4469 ((d & 0x07) as u32, 4usize)
4470 };
4471 if in_end - in_pos < seqlen {
4472 break;
4473 }
4474 for i in 1..seqlen {
4475 let dd = *input.add(in_pos + i);
4476 c = (c << 6) | ((dd & 0x3F) as u32);
4477 }
4478 let ent = htmlEntityValueLookup(c);
4479 let mut nbuf = [0u8; 16];
4480 let cp: *const u8;
4481 let mut owned_len: usize = 0;
4482 if ent.is_null() {
4483 let s = format!("#{}", c);
4484 let bytes = s.as_bytes();
4485 nbuf[..bytes.len()].copy_from_slice(bytes);
4486 cp = nbuf.as_ptr();
4487 owned_len = bytes.len();
4488 } else {
4489 cp = (*ent).name as *const u8;
4490 let mut l = 0;
4491 while *cp.add(l) != 0 {
4492 l += 1;
4493 }
4494 owned_len = l;
4495 }
4496 let len = owned_len;
4497 if out_cap - out_pos < len + 2 {
4498 break;
4499 }
4500 *out.add(out_pos) = b'&';
4501 out_pos += 1;
4502 core::ptr::copy_nonoverlapping(cp, out.add(out_pos), len);
4503 out_pos += len;
4504 *out.add(out_pos) = b';';
4505 out_pos += 1;
4506 in_pos += seqlen;
4507 }
4508 ret = out_pos as c_int;
4509 *outlen = out_pos as c_int;
4510 *inlen = in_pos as c_int;
4511 ret
4512 }
4513}
4514
4515#[cfg(test)]
4516mod tests {
4517 use super::*;
4518 use crate::xml::string::{xml_strdup, xml_strlen};
4519
4520 unsafe fn transcode(input: &[u8]) -> String {
4523 let buf = io::buf_create(0);
4524 assert!(!buf.is_null());
4525 unsafe { html_buf_append_html_ascii(buf, input.as_ptr(), input.len()) };
4526 let content = io::buf_content(buf);
4527 let len = xml_strlen(content);
4528 let s = String::from_utf8_lossy(core::slice::from_raw_parts(content, len)).to_string();
4529 io::buf_free(buf);
4530 s
4531 }
4532
4533 #[test]
4539 fn test_pseudo_html_transcode_semantics() {
4540 unsafe {
4541 assert_eq!(transcode(b"a<b&c>d"), "a<b&c>d");
4544 assert_eq!(transcode("a\u{a0}b\u{e9}c".as_bytes()), "a béc");
4546 assert_eq!(transcode("\u{2603}".as_bytes()), "☃");
4548 assert_eq!(transcode(b"x\xc2"), "x");
4550 }
4551 }
4552
4553 #[test]
4560 fn test_html_doc_dump_memory_pseudo_encoding() {
4561 unsafe {
4562 let html = b"<html><body><p>a b c\xc3\xa9d</p></body></html>\0";
4563 let doc = html::parse_memory(html.as_ptr() as *const c_char, (html.len() - 1) as c_int);
4565 assert!(!doc.is_null());
4566 assert!(
4567 (*doc).encoding.is_null(),
4568 "a meta-less html parse must leave doc->encoding NULL"
4569 );
4570
4571 let mut mem: *mut xmlChar = ptr::null_mut();
4572 let mut size: c_int = 0;
4573 htmlDocDumpMemoryFormat(doc, &mut mem, &mut size, 0);
4574 assert!(!mem.is_null());
4575 assert!(size > 0);
4576 let s = String::from_utf8_lossy(core::slice::from_raw_parts(
4577 mem as *const u8,
4578 size as usize,
4579 ))
4580 .to_string();
4581 assert!(s.contains("a b céd"), "got: {s}");
4582 assert!(
4583 !s.contains('\u{a0}'),
4584 "no raw U+00A0 may survive the pseudo-HTML dump: got: {s}"
4585 );
4586 xmlFreeImpl(mem as *mut c_void);
4587
4588 (*doc).encoding = xml_strdup(b"UTF-8\0" as *const u8 as *const xmlChar);
4590 let mut mem2: *mut xmlChar = ptr::null_mut();
4591 let mut size2: c_int = 0;
4592 htmlDocDumpMemoryFormat(doc, &mut mem2, &mut size2, 0);
4593 assert!(!mem2.is_null());
4594 let s2 = String::from_utf8_lossy(core::slice::from_raw_parts(
4595 mem2 as *const u8,
4596 size2 as usize,
4597 ))
4598 .to_string();
4599 assert!(s2.contains("a\u{a0}b\u{a0}c\u{e9}d"), "got: {s2}");
4600 assert!(!s2.contains(" "), "got: {s2}");
4601 xmlFreeImpl(mem2 as *mut c_void);
4602
4603 tree::free_doc(doc);
4604 }
4605 }
4606}