1#![allow(
95 missing_docs,
96 non_snake_case,
97 non_camel_case_types,
98 non_upper_case_globals
99)]
100#![allow(unused_variables)]
101#![allow(private_interfaces)]
102#![allow(unused_assignments)]
103#![allow(unused_unsafe)]
104#![allow(clippy::missing_safety_doc)]
105#![allow(clippy::not_unsafe_ptr_arg_deref)]
106
107use core::ffi::c_void;
118use core::ptr;
119use core::sync::atomic::{AtomicBool, AtomicI32, Ordering};
120use std::mem::size_of;
121use std::os::raw::{c_char, c_int, c_uint};
122
123use crate::abi::allocator::{xmlFreeImpl, xmlMallocImpl, xmlMallocZero, xmlReallocImpl};
124use crate::abi::callbacks::{xmlInputCloseCallback, xmlInputReadCallback};
125use crate::abi::structs::*;
126use crate::abi::types::xmlChar;
127use crate::abi::types::xmlCharEncoding;
128use crate::abi::types::xmlElementType::*;
129use crate::xml::html;
130use crate::xml::io;
131use crate::xml::string::{c_strdup, xml_strcmp, xml_strlen, xml_strndup, xmlstr_to_bytes};
132use crate::xml::tree;
133
134const HTML_PARSE_RECOVER: c_int = 1 << 0;
139const HTML_PARSE_NODEFDTD: c_int = 1 << 2;
140const HTML_PARSE_NOERROR: c_int = 1 << 5;
141const HTML_PARSE_NOWARNING: c_int = 1 << 6;
142const HTML_PARSE_PEDANTIC: c_int = 1 << 7;
143const HTML_PARSE_NOBLANKS: c_int = 1 << 8;
144const HTML_PARSE_NONET: c_int = 1 << 11;
145const HTML_PARSE_NOIMPLIED: c_int = 1 << 13;
146const HTML_PARSE_COMPACT: c_int = 1 << 16;
147const HTML_PARSE_HUGE: c_int = 1 << 19;
148const HTML_PARSE_IGNORE_ENC: c_int = 1 << 21;
149const HTML_PARSE_BIG_LINES: c_int = 1 << 22;
150const HTML_PARSE_HTML5: c_int = 1 << 26;
151
152const HTML_OPTIONS_KEEP_MASK: c_int = HTML_PARSE_NODEFDTD
154 | HTML_PARSE_NOERROR
155 | HTML_PARSE_NOWARNING
156 | HTML_PARSE_NOIMPLIED
157 | HTML_PARSE_COMPACT
158 | HTML_PARSE_HUGE
159 | HTML_PARSE_IGNORE_ENC
160 | HTML_PARSE_BIG_LINES;
161
162const HTML_OPTIONS_ALL_MASK: c_int = HTML_PARSE_RECOVER
164 | HTML_PARSE_HTML5
165 | HTML_PARSE_NODEFDTD
166 | HTML_PARSE_NOERROR
167 | HTML_PARSE_NOWARNING
168 | HTML_PARSE_PEDANTIC
169 | HTML_PARSE_NOBLANKS
170 | HTML_PARSE_NONET
171 | HTML_PARSE_NOIMPLIED
172 | HTML_PARSE_COMPACT
173 | HTML_PARSE_HUGE
174 | HTML_PARSE_IGNORE_ENC
175 | HTML_PARSE_BIG_LINES;
176
177const XML_ERR_OK: c_int = 0;
179const XML_ERR_NO_MEMORY: c_int = 2;
180const XML_ERR_ARGUMENT: c_int = 115;
181
182const HTML_VALID: c_int = 0x4;
184
185const DATA_NEUTRAL: c_int = 0;
187const DATA_RCDATA: c_int = 1;
188const DATA_RAWTEXT: c_int = 2;
189const DATA_PLAINTEXT: c_int = 3;
190const DATA_SCRIPT: c_int = 4;
191
192#[inline]
194const fn is_ws_html(c: u8) -> bool {
195 c == 0x20 || (c >= 0x09 && c <= 0x0d && c != 0x0b)
196}
197
198#[derive(Debug)]
207#[repr(C)]
208pub struct _htmlElemDesc {
209 pub name: *const c_char,
210 pub startTag: c_char,
211 pub endTag: c_char,
212 pub saveEndTag: c_char,
213 pub empty: c_char,
214 pub depr: c_char,
215 pub dtd: c_char,
216 pub isinline: c_char,
217 pub desc: *const c_char,
218 pub subelts: *const *const c_char,
219 pub defaultsubelt: *const c_char,
220 pub attrs_opt: *const *const c_char,
221 pub attrs_depr: *const *const c_char,
222 pub attrs_req: *const *const c_char,
223 pub dataMode: c_int,
224}
225
226unsafe impl Sync for _htmlElemDesc {}
228unsafe impl Send for _htmlElemDesc {}
229
230macro_rules! elem {
234 ($name:literal, $startTag:expr, $endTag:expr, $saveEndTag:expr, $empty:expr, $depr:expr, $dtd:expr, $isinline:expr, $desc:literal, $dataMode:expr) => {
235 _htmlElemDesc {
236 name: concat!($name, "\0").as_ptr() as *const c_char,
237 startTag: $startTag,
238 endTag: $endTag,
239 saveEndTag: $saveEndTag,
240 empty: $empty,
241 depr: $depr,
242 dtd: $dtd,
243 isinline: $isinline,
244 desc: concat!($desc, "\0").as_ptr() as *const c_char,
245 subelts: ptr::null(),
246 defaultsubelt: ptr::null(),
247 attrs_opt: ptr::null(),
248 attrs_depr: ptr::null(),
249 attrs_req: ptr::null(),
250 dataMode: $dataMode,
251 }
252 };
253}
254
255static HTML40_ELEMENTS: &[_htmlElemDesc] = &[
258 elem!("a", 0, 0, 0, 0, 0, 0, 1, "anchor ", DATA_NEUTRAL),
259 elem!(
260 "abbr",
261 0,
262 0,
263 0,
264 0,
265 0,
266 0,
267 1,
268 "abbreviated form",
269 DATA_NEUTRAL
270 ),
271 elem!("acronym", 0, 0, 0, 0, 0, 0, 1, "", DATA_NEUTRAL),
272 elem!(
273 "address",
274 0,
275 0,
276 0,
277 0,
278 0,
279 0,
280 0,
281 "information on author ",
282 DATA_NEUTRAL
283 ),
284 elem!("applet", 0, 0, 0, 0, 1, 1, 2, "java applet ", DATA_NEUTRAL),
285 elem!(
286 "area",
287 0,
288 2,
289 2,
290 1,
291 0,
292 0,
293 0,
294 "client-side image map area ",
295 DATA_NEUTRAL
296 ),
297 elem!("b", 0, 3, 0, 0, 0, 0, 1, "bold text style", DATA_NEUTRAL),
298 elem!(
299 "base",
300 0,
301 2,
302 2,
303 1,
304 0,
305 0,
306 0,
307 "document base uri ",
308 DATA_NEUTRAL
309 ),
310 elem!(
311 "basefont",
312 0,
313 2,
314 2,
315 1,
316 1,
317 1,
318 1,
319 "base font size ",
320 DATA_NEUTRAL
321 ),
322 elem!(
323 "bdo",
324 0,
325 0,
326 0,
327 0,
328 0,
329 0,
330 1,
331 "i18n bidi over-ride ",
332 DATA_NEUTRAL
333 ),
334 elem!("bgsound", 0, 0, 2, 1, 0, 0, 0, "", DATA_NEUTRAL),
335 elem!("big", 0, 3, 0, 0, 0, 0, 1, "large text style", DATA_NEUTRAL),
336 elem!(
337 "blockquote",
338 0,
339 0,
340 0,
341 0,
342 0,
343 0,
344 0,
345 "long quotation ",
346 DATA_NEUTRAL
347 ),
348 elem!("body", 1, 1, 0, 0, 0, 0, 0, "document body ", DATA_NEUTRAL),
349 elem!(
350 "br",
351 0,
352 2,
353 2,
354 1,
355 0,
356 0,
357 1,
358 "forced line break ",
359 DATA_NEUTRAL
360 ),
361 elem!("button", 0, 0, 0, 0, 0, 0, 2, "push button ", DATA_NEUTRAL),
362 elem!(
363 "caption",
364 0,
365 0,
366 0,
367 0,
368 0,
369 0,
370 0,
371 "table caption ",
372 DATA_NEUTRAL
373 ),
374 elem!(
375 "center",
376 0,
377 3,
378 0,
379 0,
380 1,
381 1,
382 0,
383 "shorthand for div align=center ",
384 DATA_NEUTRAL
385 ),
386 elem!("cite", 0, 0, 0, 0, 0, 0, 1, "citation", DATA_NEUTRAL),
387 elem!(
388 "code",
389 0,
390 0,
391 0,
392 0,
393 0,
394 0,
395 1,
396 "computer code fragment",
397 DATA_NEUTRAL
398 ),
399 elem!("col", 0, 2, 2, 1, 0, 0, 0, "table column ", DATA_NEUTRAL),
400 elem!(
401 "colgroup",
402 0,
403 1,
404 0,
405 0,
406 0,
407 0,
408 0,
409 "table column group ",
410 DATA_NEUTRAL
411 ),
412 elem!(
413 "dd",
414 0,
415 1,
416 0,
417 0,
418 0,
419 0,
420 0,
421 "definition description ",
422 DATA_NEUTRAL
423 ),
424 elem!("del", 0, 0, 0, 0, 0, 0, 2, "deleted text ", DATA_NEUTRAL),
425 elem!(
426 "dfn",
427 0,
428 0,
429 0,
430 0,
431 0,
432 0,
433 1,
434 "instance definition",
435 DATA_NEUTRAL
436 ),
437 elem!("dir", 0, 0, 0, 0, 1, 1, 0, "directory list", DATA_NEUTRAL),
438 elem!(
439 "div",
440 0,
441 0,
442 0,
443 0,
444 0,
445 0,
446 0,
447 "generic language/style container",
448 DATA_NEUTRAL
449 ),
450 elem!("dl", 0, 0, 0, 0, 0, 0, 0, "definition list ", DATA_NEUTRAL),
451 elem!("dt", 0, 1, 0, 0, 0, 0, 0, "definition term ", DATA_NEUTRAL),
452 elem!("em", 0, 3, 0, 0, 0, 0, 1, "emphasis", DATA_NEUTRAL),
453 elem!(
454 "embed",
455 0,
456 1,
457 2,
458 1,
459 1,
460 1,
461 1,
462 "generic embedded object ",
463 DATA_NEUTRAL
464 ),
465 elem!(
466 "fieldset",
467 0,
468 0,
469 0,
470 0,
471 0,
472 0,
473 0,
474 "form control group ",
475 DATA_NEUTRAL
476 ),
477 elem!(
478 "font",
479 0,
480 3,
481 0,
482 0,
483 1,
484 1,
485 1,
486 "local change to font ",
487 DATA_NEUTRAL
488 ),
489 elem!(
490 "form",
491 0,
492 0,
493 0,
494 0,
495 0,
496 0,
497 0,
498 "interactive form ",
499 DATA_NEUTRAL
500 ),
501 elem!("frame", 0, 2, 2, 1, 0, 2, 0, "subwindow ", DATA_NEUTRAL),
502 elem!(
503 "frameset",
504 0,
505 0,
506 0,
507 0,
508 0,
509 2,
510 0,
511 "window subdivision",
512 DATA_NEUTRAL
513 ),
514 elem!("h1", 0, 0, 0, 0, 0, 0, 0, "heading ", DATA_NEUTRAL),
515 elem!("h2", 0, 0, 0, 0, 0, 0, 0, "heading ", DATA_NEUTRAL),
516 elem!("h3", 0, 0, 0, 0, 0, 0, 0, "heading ", DATA_NEUTRAL),
517 elem!("h4", 0, 0, 0, 0, 0, 0, 0, "heading ", DATA_NEUTRAL),
518 elem!("h5", 0, 0, 0, 0, 0, 0, 0, "heading ", DATA_NEUTRAL),
519 elem!("h6", 0, 0, 0, 0, 0, 0, 0, "heading ", DATA_NEUTRAL),
520 elem!("head", 1, 1, 0, 0, 0, 0, 0, "document head ", DATA_NEUTRAL),
521 elem!("hr", 0, 2, 2, 1, 0, 0, 0, "horizontal rule ", DATA_NEUTRAL),
522 elem!(
523 "html",
524 1,
525 1,
526 0,
527 0,
528 0,
529 0,
530 0,
531 "document root element ",
532 DATA_NEUTRAL
533 ),
534 elem!("i", 0, 3, 0, 0, 0, 0, 1, "italic text style", DATA_NEUTRAL),
535 elem!(
536 "iframe",
537 0,
538 0,
539 0,
540 0,
541 0,
542 1,
543 2,
544 "inline subwindow ",
545 DATA_RAWTEXT
546 ),
547 elem!("img", 0, 2, 2, 1, 0, 0, 1, "embedded image ", DATA_NEUTRAL),
548 elem!("input", 0, 2, 2, 1, 0, 0, 1, "form control ", DATA_NEUTRAL),
549 elem!("ins", 0, 0, 0, 0, 0, 0, 2, "inserted text", DATA_NEUTRAL),
550 elem!(
551 "isindex",
552 0,
553 2,
554 2,
555 1,
556 1,
557 1,
558 0,
559 "single line prompt ",
560 DATA_NEUTRAL
561 ),
562 elem!(
563 "kbd",
564 0,
565 0,
566 0,
567 0,
568 0,
569 0,
570 1,
571 "text to be entered by the user",
572 DATA_NEUTRAL
573 ),
574 elem!("keygen", 0, 0, 2, 1, 0, 0, 0, "", DATA_NEUTRAL),
575 elem!(
576 "label",
577 0,
578 0,
579 0,
580 0,
581 0,
582 0,
583 1,
584 "form field label text ",
585 DATA_NEUTRAL
586 ),
587 elem!(
588 "legend",
589 0,
590 0,
591 0,
592 0,
593 0,
594 0,
595 0,
596 "fieldset legend ",
597 DATA_NEUTRAL
598 ),
599 elem!("li", 0, 1, 1, 0, 0, 0, 0, "list item ", DATA_NEUTRAL),
600 elem!(
601 "link",
602 0,
603 2,
604 2,
605 1,
606 0,
607 0,
608 0,
609 "a media-independent link ",
610 DATA_NEUTRAL
611 ),
612 elem!(
613 "map",
614 0,
615 0,
616 0,
617 0,
618 0,
619 0,
620 2,
621 "client-side image map ",
622 DATA_NEUTRAL
623 ),
624 elem!("menu", 0, 0, 0, 0, 1, 1, 0, "menu list ", DATA_NEUTRAL),
625 elem!(
626 "meta",
627 0,
628 2,
629 2,
630 1,
631 0,
632 0,
633 0,
634 "generic metainformation ",
635 DATA_NEUTRAL
636 ),
637 elem!("noembed", 0, 0, 0, 0, 0, 0, 0, "", DATA_RAWTEXT),
638 elem!(
639 "noframes",
640 0,
641 0,
642 0,
643 0,
644 0,
645 2,
646 0,
647 "alternate content container for non frame-based rendering ",
648 DATA_RAWTEXT
649 ),
650 elem!(
651 "noscript",
652 0,
653 0,
654 0,
655 0,
656 0,
657 0,
658 0,
659 "alternate content container for non script-based rendering ",
660 DATA_NEUTRAL
661 ),
662 elem!(
663 "object",
664 0,
665 0,
666 0,
667 0,
668 0,
669 0,
670 2,
671 "generic embedded object ",
672 DATA_NEUTRAL
673 ),
674 elem!("ol", 0, 0, 0, 0, 0, 0, 0, "ordered list ", DATA_NEUTRAL),
675 elem!(
676 "optgroup",
677 0,
678 0,
679 0,
680 0,
681 0,
682 0,
683 0,
684 "option group ",
685 DATA_NEUTRAL
686 ),
687 elem!(
688 "option",
689 0,
690 1,
691 0,
692 0,
693 0,
694 0,
695 0,
696 "selectable choice ",
697 DATA_NEUTRAL
698 ),
699 elem!("p", 0, 1, 0, 0, 0, 0, 0, "paragraph ", DATA_NEUTRAL),
700 elem!(
701 "param",
702 0,
703 2,
704 2,
705 1,
706 0,
707 0,
708 0,
709 "named property value ",
710 DATA_NEUTRAL
711 ),
712 elem!("plaintext", 0, 0, 0, 0, 0, 0, 0, "", DATA_PLAINTEXT),
713 elem!(
714 "pre",
715 0,
716 0,
717 0,
718 0,
719 0,
720 0,
721 0,
722 "preformatted text ",
723 DATA_NEUTRAL
724 ),
725 elem!(
726 "q",
727 0,
728 0,
729 0,
730 0,
731 0,
732 0,
733 1,
734 "short inline quotation ",
735 DATA_NEUTRAL
736 ),
737 elem!(
738 "s",
739 0,
740 3,
741 0,
742 0,
743 1,
744 1,
745 1,
746 "strike-through text style",
747 DATA_NEUTRAL
748 ),
749 elem!(
750 "samp",
751 0,
752 0,
753 0,
754 0,
755 0,
756 0,
757 1,
758 "sample program output, scripts, etc.",
759 DATA_NEUTRAL
760 ),
761 elem!(
762 "script",
763 0,
764 0,
765 0,
766 0,
767 0,
768 0,
769 2,
770 "script statements ",
771 DATA_SCRIPT
772 ),
773 elem!(
774 "select",
775 0,
776 0,
777 0,
778 0,
779 0,
780 0,
781 1,
782 "option selector ",
783 DATA_NEUTRAL
784 ),
785 elem!(
786 "small",
787 0,
788 3,
789 0,
790 0,
791 0,
792 0,
793 1,
794 "small text style",
795 DATA_NEUTRAL
796 ),
797 elem!("source", 0, 0, 2, 1, 0, 0, 0, "", DATA_NEUTRAL),
798 elem!(
799 "span",
800 0,
801 0,
802 0,
803 0,
804 0,
805 0,
806 1,
807 "generic language/style container ",
808 DATA_NEUTRAL
809 ),
810 elem!(
811 "strike",
812 0,
813 3,
814 0,
815 0,
816 1,
817 1,
818 1,
819 "strike-through text",
820 DATA_NEUTRAL
821 ),
822 elem!(
823 "strong",
824 0,
825 3,
826 0,
827 0,
828 0,
829 0,
830 1,
831 "strong emphasis",
832 DATA_NEUTRAL
833 ),
834 elem!("style", 0, 0, 0, 0, 0, 0, 0, "style info ", DATA_RAWTEXT),
835 elem!("sub", 0, 3, 0, 0, 0, 0, 1, "subscript", DATA_NEUTRAL),
836 elem!("sup", 0, 3, 0, 0, 0, 0, 1, "superscript ", DATA_NEUTRAL),
837 elem!("table", 0, 0, 0, 0, 0, 0, 0, "", DATA_NEUTRAL),
838 elem!("tbody", 1, 0, 0, 0, 0, 0, 0, "table body ", DATA_NEUTRAL),
839 elem!("td", 0, 0, 0, 0, 0, 0, 0, "table data cell", DATA_NEUTRAL),
840 elem!(
841 "textarea",
842 0,
843 0,
844 0,
845 0,
846 0,
847 0,
848 1,
849 "multi-line text field ",
850 DATA_RCDATA
851 ),
852 elem!("tfoot", 0, 1, 0, 0, 0, 0, 0, "table footer ", DATA_NEUTRAL),
853 elem!("th", 0, 1, 0, 0, 0, 0, 0, "table header cell", DATA_NEUTRAL),
854 elem!("thead", 0, 1, 0, 0, 0, 0, 0, "table header ", DATA_NEUTRAL),
855 elem!("title", 0, 0, 0, 0, 0, 0, 0, "document title ", DATA_RCDATA),
856 elem!("tr", 0, 0, 0, 0, 0, 0, 0, "table row ", DATA_NEUTRAL),
857 elem!("track", 0, 0, 2, 1, 0, 0, 0, "", DATA_NEUTRAL),
858 elem!(
859 "tt",
860 0,
861 3,
862 0,
863 0,
864 0,
865 0,
866 1,
867 "teletype or monospaced text style",
868 DATA_NEUTRAL
869 ),
870 elem!(
871 "u",
872 0,
873 3,
874 0,
875 0,
876 1,
877 1,
878 1,
879 "underlined text style",
880 DATA_NEUTRAL
881 ),
882 elem!("ul", 0, 0, 0, 0, 0, 0, 0, "unordered list ", DATA_NEUTRAL),
883 elem!(
884 "var",
885 0,
886 0,
887 0,
888 0,
889 0,
890 0,
891 1,
892 "instance of a variable or program argument",
893 DATA_NEUTRAL
894 ),
895 elem!("wbr", 0, 0, 2, 1, 0, 0, 0, "", DATA_NEUTRAL),
896 elem!("xmp", 0, 0, 0, 0, 0, 0, 1, "", DATA_RAWTEXT),
897];
898
899#[no_mangle]
911pub unsafe extern "C" fn htmlTagLookup(tag: *const xmlChar) -> *const _htmlElemDesc {
912 if tag.is_null() {
913 return ptr::null();
914 }
915 let bytes = unsafe { xmlstr_to_bytes(tag) };
916 for e in HTML40_ELEMENTS {
917 let name = unsafe { core::ffi::CStr::from_ptr(e.name) }.to_bytes();
918 if bytes.eq_ignore_ascii_case(name) {
919 return e as *const _htmlElemDesc;
920 }
921 }
922 ptr::null()
923}
924
925#[derive(Debug)]
931#[repr(C)]
932pub struct _htmlEntityDesc {
933 pub value: c_uint,
934 pub name: *const c_char,
935 pub desc: *const c_char,
936}
937
938unsafe impl Sync for _htmlEntityDesc {}
940unsafe impl Send for _htmlEntityDesc {}
941
942macro_rules! ent {
944 ($value:expr, $name:literal, $desc:literal) => {
945 _htmlEntityDesc {
946 value: $value,
947 name: concat!($name, "\0").as_ptr() as *const c_char,
948 desc: concat!($desc, "\0").as_ptr() as *const c_char,
949 }
950 };
951}
952
953static HTML40_ENTITIES: &[_htmlEntityDesc] = &[
957 ent!(34, "quot", "quotation mark = APL quote, U+0022 ISOnum"),
958 ent!(38, "amp", "ampersand, U+0026 ISOnum"),
959 ent!(39, "apos", "single quote"),
960 ent!(60, "lt", "less-than sign, U+003C ISOnum"),
961 ent!(62, "gt", "greater-than sign, U+003E ISOnum"),
962 ent!(
963 160,
964 "nbsp",
965 "no-break space = non-breaking space, U+00A0 ISOnum"
966 ),
967 ent!(161, "iexcl", "inverted exclamation mark, U+00A1 ISOnum"),
968 ent!(162, "cent", "cent sign, U+00A2 ISOnum"),
969 ent!(163, "pound", "pound sign, U+00A3 ISOnum"),
970 ent!(164, "curren", "currency sign, U+00A4 ISOnum"),
971 ent!(165, "yen", "yen sign = yuan sign, U+00A5 ISOnum"),
972 ent!(
973 166,
974 "brvbar",
975 "broken bar = broken vertical bar, U+00A6 ISOnum"
976 ),
977 ent!(167, "sect", "section sign, U+00A7 ISOnum"),
978 ent!(168, "uml", "diaeresis = spacing diaeresis, U+00A8 ISOdia"),
979 ent!(169, "copy", "copyright sign, U+00A9 ISOnum"),
980 ent!(170, "ordf", "feminine ordinal indicator, U+00AA ISOnum"),
981 ent!(
982 171,
983 "laquo",
984 "left-pointing double angle quotation mark = left pointing guillemet, U+00AB ISOnum"
985 ),
986 ent!(172, "not", "not sign, U+00AC ISOnum"),
987 ent!(
988 173,
989 "shy",
990 "soft hyphen = discretionary hyphen, U+00AD ISOnum"
991 ),
992 ent!(
993 174,
994 "reg",
995 "registered sign = registered trade mark sign, U+00AE ISOnum"
996 ),
997 ent!(
998 175,
999 "macr",
1000 "macron = spacing macron = overline = APL overbar, U+00AF ISOdia"
1001 ),
1002 ent!(176, "deg", "degree sign, U+00B0 ISOnum"),
1003 ent!(
1004 177,
1005 "plusmn",
1006 "plus-minus sign = plus-or-minus sign, U+00B1 ISOnum"
1007 ),
1008 ent!(
1009 178,
1010 "sup2",
1011 "superscript two = superscript digit two = squared, U+00B2 ISOnum"
1012 ),
1013 ent!(
1014 179,
1015 "sup3",
1016 "superscript three = superscript digit three = cubed, U+00B3 ISOnum"
1017 ),
1018 ent!(180, "acute", "acute accent = spacing acute, U+00B4 ISOdia"),
1019 ent!(181, "micro", "micro sign, U+00B5 ISOnum"),
1020 ent!(182, "para", "pilcrow sign = paragraph sign, U+00B6 ISOnum"),
1021 ent!(
1022 183,
1023 "middot",
1024 "middle dot = Georgian comma Greek middle dot, U+00B7 ISOnum"
1025 ),
1026 ent!(184, "cedil", "cedilla = spacing cedilla, U+00B8 ISOdia"),
1027 ent!(
1028 185,
1029 "sup1",
1030 "superscript one = superscript digit one, U+00B9 ISOnum"
1031 ),
1032 ent!(186, "ordm", "masculine ordinal indicator, U+00BA ISOnum"),
1033 ent!(
1034 187,
1035 "raquo",
1036 "right-pointing double angle quotation mark right pointing guillemet, U+00BB ISOnum"
1037 ),
1038 ent!(
1039 188,
1040 "frac14",
1041 "vulgar fraction one quarter = fraction one quarter, U+00BC ISOnum"
1042 ),
1043 ent!(
1044 189,
1045 "frac12",
1046 "vulgar fraction one half = fraction one half, U+00BD ISOnum"
1047 ),
1048 ent!(
1049 190,
1050 "frac34",
1051 "vulgar fraction three quarters = fraction three quarters, U+00BE ISOnum"
1052 ),
1053 ent!(
1054 191,
1055 "iquest",
1056 "inverted question mark = turned question mark, U+00BF ISOnum"
1057 ),
1058 ent!(
1059 192,
1060 "Agrave",
1061 "latin capital letter A with grave = latin capital letter A grave, U+00C0 ISOlat1"
1062 ),
1063 ent!(
1064 193,
1065 "Aacute",
1066 "latin capital letter A with acute, U+00C1 ISOlat1"
1067 ),
1068 ent!(
1069 194,
1070 "Acirc",
1071 "latin capital letter A with circumflex, U+00C2 ISOlat1"
1072 ),
1073 ent!(
1074 195,
1075 "Atilde",
1076 "latin capital letter A with tilde, U+00C3 ISOlat1"
1077 ),
1078 ent!(
1079 196,
1080 "Auml",
1081 "latin capital letter A with diaeresis, U+00C4 ISOlat1"
1082 ),
1083 ent!(
1084 197,
1085 "Aring",
1086 "latin capital letter A with ring above = latin capital letter A ring, U+00C5 ISOlat1"
1087 ),
1088 ent!(
1089 198,
1090 "AElig",
1091 "latin capital letter AE = latin capital ligature AE, U+00C6 ISOlat1"
1092 ),
1093 ent!(
1094 199,
1095 "Ccedil",
1096 "latin capital letter C with cedilla, U+00C7 ISOlat1"
1097 ),
1098 ent!(
1099 200,
1100 "Egrave",
1101 "latin capital letter E with grave, U+00C8 ISOlat1"
1102 ),
1103 ent!(
1104 201,
1105 "Eacute",
1106 "latin capital letter E with acute, U+00C9 ISOlat1"
1107 ),
1108 ent!(
1109 202,
1110 "Ecirc",
1111 "latin capital letter E with circumflex, U+00CA ISOlat1"
1112 ),
1113 ent!(
1114 203,
1115 "Euml",
1116 "latin capital letter E with diaeresis, U+00CB ISOlat1"
1117 ),
1118 ent!(
1119 204,
1120 "Igrave",
1121 "latin capital letter I with grave, U+00CC ISOlat1"
1122 ),
1123 ent!(
1124 205,
1125 "Iacute",
1126 "latin capital letter I with acute, U+00CD ISOlat1"
1127 ),
1128 ent!(
1129 206,
1130 "Icirc",
1131 "latin capital letter I with circumflex, U+00CE ISOlat1"
1132 ),
1133 ent!(
1134 207,
1135 "Iuml",
1136 "latin capital letter I with diaeresis, U+00CF ISOlat1"
1137 ),
1138 ent!(208, "ETH", "latin capital letter ETH, U+00D0 ISOlat1"),
1139 ent!(
1140 209,
1141 "Ntilde",
1142 "latin capital letter N with tilde, U+00D1 ISOlat1"
1143 ),
1144 ent!(
1145 210,
1146 "Ograve",
1147 "latin capital letter O with grave, U+00D2 ISOlat1"
1148 ),
1149 ent!(
1150 211,
1151 "Oacute",
1152 "latin capital letter O with acute, U+00D3 ISOlat1"
1153 ),
1154 ent!(
1155 212,
1156 "Ocirc",
1157 "latin capital letter O with circumflex, U+00D4 ISOlat1"
1158 ),
1159 ent!(
1160 213,
1161 "Otilde",
1162 "latin capital letter O with tilde, U+00D5 ISOlat1"
1163 ),
1164 ent!(
1165 214,
1166 "Ouml",
1167 "latin capital letter O with diaeresis, U+00D6 ISOlat1"
1168 ),
1169 ent!(215, "times", "multiplication sign, U+00D7 ISOnum"),
1170 ent!(
1171 216,
1172 "Oslash",
1173 "latin capital letter O with stroke latin capital letter O slash, U+00D8 ISOlat1"
1174 ),
1175 ent!(
1176 217,
1177 "Ugrave",
1178 "latin capital letter U with grave, U+00D9 ISOlat1"
1179 ),
1180 ent!(
1181 218,
1182 "Uacute",
1183 "latin capital letter U with acute, U+00DA ISOlat1"
1184 ),
1185 ent!(
1186 219,
1187 "Ucirc",
1188 "latin capital letter U with circumflex, U+00DB ISOlat1"
1189 ),
1190 ent!(
1191 220,
1192 "Uuml",
1193 "latin capital letter U with diaeresis, U+00DC ISOlat1"
1194 ),
1195 ent!(
1196 221,
1197 "Yacute",
1198 "latin capital letter Y with acute, U+00DD ISOlat1"
1199 ),
1200 ent!(222, "THORN", "latin capital letter THORN, U+00DE ISOlat1"),
1201 ent!(
1202 223,
1203 "szlig",
1204 "latin small letter sharp s = ess-zed, U+00DF ISOlat1"
1205 ),
1206 ent!(
1207 224,
1208 "agrave",
1209 "latin small letter a with grave = latin small letter a grave, U+00E0 ISOlat1"
1210 ),
1211 ent!(
1212 225,
1213 "aacute",
1214 "latin small letter a with acute, U+00E1 ISOlat1"
1215 ),
1216 ent!(
1217 226,
1218 "acirc",
1219 "latin small letter a with circumflex, U+00E2 ISOlat1"
1220 ),
1221 ent!(
1222 227,
1223 "atilde",
1224 "latin small letter a with tilde, U+00E3 ISOlat1"
1225 ),
1226 ent!(
1227 228,
1228 "auml",
1229 "latin small letter a with diaeresis, U+00E4 ISOlat1"
1230 ),
1231 ent!(
1232 229,
1233 "aring",
1234 "latin small letter a with ring above = latin small letter a ring, U+00E5 ISOlat1"
1235 ),
1236 ent!(
1237 230,
1238 "aelig",
1239 "latin small letter ae = latin small ligature ae, U+00E6 ISOlat1"
1240 ),
1241 ent!(
1242 231,
1243 "ccedil",
1244 "latin small letter c with cedilla, U+00E7 ISOlat1"
1245 ),
1246 ent!(
1247 232,
1248 "egrave",
1249 "latin small letter e with grave, U+00E8 ISOlat1"
1250 ),
1251 ent!(
1252 233,
1253 "eacute",
1254 "latin small letter e with acute, U+00E9 ISOlat1"
1255 ),
1256 ent!(
1257 234,
1258 "ecirc",
1259 "latin small letter e with circumflex, U+00EA ISOlat1"
1260 ),
1261 ent!(
1262 235,
1263 "euml",
1264 "latin small letter e with diaeresis, U+00EB ISOlat1"
1265 ),
1266 ent!(
1267 236,
1268 "igrave",
1269 "latin small letter i with grave, U+00EC ISOlat1"
1270 ),
1271 ent!(
1272 237,
1273 "iacute",
1274 "latin small letter i with acute, U+00ED ISOlat1"
1275 ),
1276 ent!(
1277 238,
1278 "icirc",
1279 "latin small letter i with circumflex, U+00EE ISOlat1"
1280 ),
1281 ent!(
1282 239,
1283 "iuml",
1284 "latin small letter i with diaeresis, U+00EF ISOlat1"
1285 ),
1286 ent!(240, "eth", "latin small letter eth, U+00F0 ISOlat1"),
1287 ent!(
1288 241,
1289 "ntilde",
1290 "latin small letter n with tilde, U+00F1 ISOlat1"
1291 ),
1292 ent!(
1293 242,
1294 "ograve",
1295 "latin small letter o with grave, U+00F2 ISOlat1"
1296 ),
1297 ent!(
1298 243,
1299 "oacute",
1300 "latin small letter o with acute, U+00F3 ISOlat1"
1301 ),
1302 ent!(
1303 244,
1304 "ocirc",
1305 "latin small letter o with circumflex, U+00F4 ISOlat1"
1306 ),
1307 ent!(
1308 245,
1309 "otilde",
1310 "latin small letter o with tilde, U+00F5 ISOlat1"
1311 ),
1312 ent!(
1313 246,
1314 "ouml",
1315 "latin small letter o with diaeresis, U+00F6 ISOlat1"
1316 ),
1317 ent!(247, "divide", "division sign, U+00F7 ISOnum"),
1318 ent!(
1319 248,
1320 "oslash",
1321 "latin small letter o with stroke, = latin small letter o slash, U+00F8 ISOlat1"
1322 ),
1323 ent!(
1324 249,
1325 "ugrave",
1326 "latin small letter u with grave, U+00F9 ISOlat1"
1327 ),
1328 ent!(
1329 250,
1330 "uacute",
1331 "latin small letter u with acute, U+00FA ISOlat1"
1332 ),
1333 ent!(
1334 251,
1335 "ucirc",
1336 "latin small letter u with circumflex, U+00FB ISOlat1"
1337 ),
1338 ent!(
1339 252,
1340 "uuml",
1341 "latin small letter u with diaeresis, U+00FC ISOlat1"
1342 ),
1343 ent!(
1344 253,
1345 "yacute",
1346 "latin small letter y with acute, U+00FD ISOlat1"
1347 ),
1348 ent!(
1349 254,
1350 "thorn",
1351 "latin small letter thorn with, U+00FE ISOlat1"
1352 ),
1353 ent!(
1354 255,
1355 "yuml",
1356 "latin small letter y with diaeresis, U+00FF ISOlat1"
1357 ),
1358 ent!(338, "OElig", "latin capital ligature OE, U+0152 ISOlat2"),
1359 ent!(339, "oelig", "latin small ligature oe, U+0153 ISOlat2"),
1360 ent!(
1361 352,
1362 "Scaron",
1363 "latin capital letter S with caron, U+0160 ISOlat2"
1364 ),
1365 ent!(
1366 353,
1367 "scaron",
1368 "latin small letter s with caron, U+0161 ISOlat2"
1369 ),
1370 ent!(
1371 376,
1372 "Yuml",
1373 "latin capital letter Y with diaeresis, U+0178 ISOlat2"
1374 ),
1375 ent!(
1376 402,
1377 "fnof",
1378 "latin small f with hook = function = florin, U+0192 ISOtech"
1379 ),
1380 ent!(
1381 710,
1382 "circ",
1383 "modifier letter circumflex accent, U+02C6 ISOpub"
1384 ),
1385 ent!(732, "tilde", "small tilde, U+02DC ISOdia"),
1386 ent!(913, "Alpha", "greek capital letter alpha, U+0391"),
1387 ent!(914, "Beta", "greek capital letter beta, U+0392"),
1388 ent!(915, "Gamma", "greek capital letter gamma, U+0393 ISOgrk3"),
1389 ent!(916, "Delta", "greek capital letter delta, U+0394 ISOgrk3"),
1390 ent!(917, "Epsilon", "greek capital letter epsilon, U+0395"),
1391 ent!(918, "Zeta", "greek capital letter zeta, U+0396"),
1392 ent!(919, "Eta", "greek capital letter eta, U+0397"),
1393 ent!(920, "Theta", "greek capital letter theta, U+0398 ISOgrk3"),
1394 ent!(921, "Iota", "greek capital letter iota, U+0399"),
1395 ent!(922, "Kappa", "greek capital letter kappa, U+039A"),
1396 ent!(923, "Lambda", "greek capital letter lambda, U+039B ISOgrk3"),
1397 ent!(924, "Mu", "greek capital letter mu, U+039C"),
1398 ent!(925, "Nu", "greek capital letter nu, U+039D"),
1399 ent!(926, "Xi", "greek capital letter xi, U+039E ISOgrk3"),
1400 ent!(927, "Omicron", "greek capital letter omicron, U+039F"),
1401 ent!(928, "Pi", "greek capital letter pi, U+03A0 ISOgrk3"),
1402 ent!(929, "Rho", "greek capital letter rho, U+03A1"),
1403 ent!(931, "Sigma", "greek capital letter sigma, U+03A3 ISOgrk3"),
1404 ent!(932, "Tau", "greek capital letter tau, U+03A4"),
1405 ent!(
1406 933,
1407 "Upsilon",
1408 "greek capital letter upsilon, U+03A5 ISOgrk3"
1409 ),
1410 ent!(934, "Phi", "greek capital letter phi, U+03A6 ISOgrk3"),
1411 ent!(935, "Chi", "greek capital letter chi, U+03A7"),
1412 ent!(936, "Psi", "greek capital letter psi, U+03A8 ISOgrk3"),
1413 ent!(937, "Omega", "greek capital letter omega, U+03A9 ISOgrk3"),
1414 ent!(945, "alpha", "greek small letter alpha, U+03B1 ISOgrk3"),
1415 ent!(946, "beta", "greek small letter beta, U+03B2 ISOgrk3"),
1416 ent!(947, "gamma", "greek small letter gamma, U+03B3 ISOgrk3"),
1417 ent!(948, "delta", "greek small letter delta, U+03B4 ISOgrk3"),
1418 ent!(949, "epsilon", "greek small letter epsilon, U+03B5 ISOgrk3"),
1419 ent!(950, "zeta", "greek small letter zeta, U+03B6 ISOgrk3"),
1420 ent!(951, "eta", "greek small letter eta, U+03B7 ISOgrk3"),
1421 ent!(952, "theta", "greek small letter theta, U+03B8 ISOgrk3"),
1422 ent!(953, "iota", "greek small letter iota, U+03B9 ISOgrk3"),
1423 ent!(954, "kappa", "greek small letter kappa, U+03BA ISOgrk3"),
1424 ent!(955, "lambda", "greek small letter lambda, U+03BB ISOgrk3"),
1425 ent!(956, "mu", "greek small letter mu, U+03BC ISOgrk3"),
1426 ent!(957, "nu", "greek small letter nu, U+03BD ISOgrk3"),
1427 ent!(958, "xi", "greek small letter xi, U+03BE ISOgrk3"),
1428 ent!(959, "omicron", "greek small letter omicron, U+03BF NEW"),
1429 ent!(960, "pi", "greek small letter pi, U+03C0 ISOgrk3"),
1430 ent!(961, "rho", "greek small letter rho, U+03C1 ISOgrk3"),
1431 ent!(
1432 962,
1433 "sigmaf",
1434 "greek small letter final sigma, U+03C2 ISOgrk3"
1435 ),
1436 ent!(963, "sigma", "greek small letter sigma, U+03C3 ISOgrk3"),
1437 ent!(964, "tau", "greek small letter tau, U+03C4 ISOgrk3"),
1438 ent!(965, "upsilon", "greek small letter upsilon, U+03C5 ISOgrk3"),
1439 ent!(966, "phi", "greek small letter phi, U+03C6 ISOgrk3"),
1440 ent!(967, "chi", "greek small letter chi, U+03C7 ISOgrk3"),
1441 ent!(968, "psi", "greek small letter psi, U+03C8 ISOgrk3"),
1442 ent!(969, "omega", "greek small letter omega, U+03C9 ISOgrk3"),
1443 ent!(
1444 977,
1445 "thetasym",
1446 "greek small letter theta symbol, U+03D1 NEW"
1447 ),
1448 ent!(978, "upsih", "greek upsilon with hook symbol, U+03D2 NEW"),
1449 ent!(982, "piv", "greek pi symbol, U+03D6 ISOgrk3"),
1450 ent!(8194, "ensp", "en space, U+2002 ISOpub"),
1451 ent!(8195, "emsp", "em space, U+2003 ISOpub"),
1452 ent!(8201, "thinsp", "thin space, U+2009 ISOpub"),
1453 ent!(8204, "zwnj", "zero width non-joiner, U+200C NEW RFC 2070"),
1454 ent!(8205, "zwj", "zero width joiner, U+200D NEW RFC 2070"),
1455 ent!(8206, "lrm", "left-to-right mark, U+200E NEW RFC 2070"),
1456 ent!(8207, "rlm", "right-to-left mark, U+200F NEW RFC 2070"),
1457 ent!(8211, "ndash", "en dash, U+2013 ISOpub"),
1458 ent!(8212, "mdash", "em dash, U+2014 ISOpub"),
1459 ent!(8216, "lsquo", "left single quotation mark, U+2018 ISOnum"),
1460 ent!(8217, "rsquo", "right single quotation mark, U+2019 ISOnum"),
1461 ent!(8218, "sbquo", "single low-9 quotation mark, U+201A NEW"),
1462 ent!(8220, "ldquo", "left double quotation mark, U+201C ISOnum"),
1463 ent!(8221, "rdquo", "right double quotation mark, U+201D ISOnum"),
1464 ent!(8222, "bdquo", "double low-9 quotation mark, U+201E NEW"),
1465 ent!(8224, "dagger", "dagger, U+2020 ISOpub"),
1466 ent!(8225, "Dagger", "double dagger, U+2021 ISOpub"),
1467 ent!(8226, "bull", "bullet = black small circle, U+2022 ISOpub"),
1468 ent!(
1469 8230,
1470 "hellip",
1471 "horizontal ellipsis = three dot leader, U+2026 ISOpub"
1472 ),
1473 ent!(8240, "permil", "per mille sign, U+2030 ISOtech"),
1474 ent!(8242, "prime", "prime = minutes = feet, U+2032 ISOtech"),
1475 ent!(
1476 8243,
1477 "Prime",
1478 "double prime = seconds = inches, U+2033 ISOtech"
1479 ),
1480 ent!(
1481 8249,
1482 "lsaquo",
1483 "single left-pointing angle quotation mark, U+2039 ISO proposed"
1484 ),
1485 ent!(
1486 8250,
1487 "rsaquo",
1488 "single right-pointing angle quotation mark, U+203A ISO proposed"
1489 ),
1490 ent!(8254, "oline", "overline = spacing overscore, U+203E NEW"),
1491 ent!(8260, "frasl", "fraction slash, U+2044 NEW"),
1492 ent!(8364, "euro", "euro sign, U+20AC NEW"),
1493 ent!(
1494 8465,
1495 "image",
1496 "blackletter capital I = imaginary part, U+2111 ISOamso"
1497 ),
1498 ent!(
1499 8472,
1500 "weierp",
1501 "script capital P = power set = Weierstrass p, U+2118 ISOamso"
1502 ),
1503 ent!(
1504 8476,
1505 "real",
1506 "blackletter capital R = real part symbol, U+211C ISOamso"
1507 ),
1508 ent!(8482, "trade", "trade mark sign, U+2122 ISOnum"),
1509 ent!(
1510 8501,
1511 "alefsym",
1512 "alef symbol = first transfinite cardinal, U+2135 NEW"
1513 ),
1514 ent!(8592, "larr", "leftwards arrow, U+2190 ISOnum"),
1515 ent!(8593, "uarr", "upwards arrow, U+2191 ISOnum"),
1516 ent!(8594, "rarr", "rightwards arrow, U+2192 ISOnum"),
1517 ent!(8595, "darr", "downwards arrow, U+2193 ISOnum"),
1518 ent!(8596, "harr", "left right arrow, U+2194 ISOamsa"),
1519 ent!(
1520 8629,
1521 "crarr",
1522 "downwards arrow with corner leftwards = carriage return, U+21B5 NEW"
1523 ),
1524 ent!(8656, "lArr", "leftwards double arrow, U+21D0 ISOtech"),
1525 ent!(8657, "uArr", "upwards double arrow, U+21D1 ISOamsa"),
1526 ent!(8658, "rArr", "rightwards double arrow, U+21D2 ISOtech"),
1527 ent!(8659, "dArr", "downwards double arrow, U+21D3 ISOamsa"),
1528 ent!(8660, "hArr", "left right double arrow, U+21D4 ISOamsa"),
1529 ent!(8704, "forall", "for all, U+2200 ISOtech"),
1530 ent!(8706, "part", "partial differential, U+2202 ISOtech"),
1531 ent!(8707, "exist", "there exists, U+2203 ISOtech"),
1532 ent!(
1533 8709,
1534 "empty",
1535 "empty set = null set = diameter, U+2205 ISOamso"
1536 ),
1537 ent!(8711, "nabla", "nabla = backward difference, U+2207 ISOtech"),
1538 ent!(8712, "isin", "element of, U+2208 ISOtech"),
1539 ent!(8713, "notin", "not an element of, U+2209 ISOtech"),
1540 ent!(8715, "ni", "contains as member, U+220B ISOtech"),
1541 ent!(8719, "prod", "n-ary product = product sign, U+220F ISOamsb"),
1542 ent!(8721, "sum", "n-ary summation, U+2211 ISOamsb"),
1543 ent!(8722, "minus", "minus sign, U+2212 ISOtech"),
1544 ent!(8727, "lowast", "asterisk operator, U+2217 ISOtech"),
1545 ent!(8730, "radic", "square root = radical sign, U+221A ISOtech"),
1546 ent!(8733, "prop", "proportional to, U+221D ISOtech"),
1547 ent!(8734, "infin", "infinity, U+221E ISOtech"),
1548 ent!(8736, "ang", "angle, U+2220 ISOamso"),
1549 ent!(8743, "and", "logical and = wedge, U+2227 ISOtech"),
1550 ent!(8744, "or", "logical or = vee, U+2228 ISOtech"),
1551 ent!(8745, "cap", "intersection = cap, U+2229 ISOtech"),
1552 ent!(8746, "cup", "union = cup, U+222A ISOtech"),
1553 ent!(8747, "int", "integral, U+222B ISOtech"),
1554 ent!(8756, "there4", "therefore, U+2234 ISOtech"),
1555 ent!(
1556 8764,
1557 "sim",
1558 "tilde operator = varies with = similar to, U+223C ISOtech"
1559 ),
1560 ent!(8773, "cong", "approximately equal to, U+2245 ISOtech"),
1561 ent!(
1562 8776,
1563 "asymp",
1564 "almost equal to = asymptotic to, U+2248 ISOamsr"
1565 ),
1566 ent!(8800, "ne", "not equal to, U+2260 ISOtech"),
1567 ent!(8801, "equiv", "identical to, U+2261 ISOtech"),
1568 ent!(8804, "le", "less-than or equal to, U+2264 ISOtech"),
1569 ent!(8805, "ge", "greater-than or equal to, U+2265 ISOtech"),
1570 ent!(8834, "sub", "subset of, U+2282 ISOtech"),
1571 ent!(8835, "sup", "superset of, U+2283 ISOtech"),
1572 ent!(8836, "nsub", "not a subset of, U+2284 ISOamsn"),
1573 ent!(8838, "sube", "subset of or equal to, U+2286 ISOtech"),
1574 ent!(8839, "supe", "superset of or equal to, U+2287 ISOtech"),
1575 ent!(8853, "oplus", "circled plus = direct sum, U+2295 ISOamsb"),
1576 ent!(
1577 8855,
1578 "otimes",
1579 "circled times = vector product, U+2297 ISOamsb"
1580 ),
1581 ent!(
1582 8869,
1583 "perp",
1584 "up tack = orthogonal to = perpendicular, U+22A5 ISOtech"
1585 ),
1586 ent!(8901, "sdot", "dot operator, U+22C5 ISOamsb"),
1587 ent!(8968, "lceil", "left ceiling = apl upstile, U+2308 ISOamsc"),
1588 ent!(8969, "rceil", "right ceiling, U+2309 ISOamsc"),
1589 ent!(8970, "lfloor", "left floor = apl downstile, U+230A ISOamsc"),
1590 ent!(8971, "rfloor", "right floor, U+230B ISOamsc"),
1591 ent!(
1592 9001,
1593 "lang",
1594 "left-pointing angle bracket = bra, U+2329 ISOtech"
1595 ),
1596 ent!(
1597 9002,
1598 "rang",
1599 "right-pointing angle bracket = ket, U+232A ISOtech"
1600 ),
1601 ent!(9674, "loz", "lozenge, U+25CA ISOpub"),
1602 ent!(9824, "spades", "black spade suit, U+2660 ISOpub"),
1603 ent!(9827, "clubs", "black club suit = shamrock, U+2663 ISOpub"),
1604 ent!(
1605 9829,
1606 "hearts",
1607 "black heart suit = valentine, U+2665 ISOpub"
1608 ),
1609 ent!(9830, "diams", "black diamond suit, U+2666 ISOpub"),
1610];
1611
1612#[no_mangle]
1623pub unsafe extern "C" fn htmlEntityLookup(name: *const xmlChar) -> *const _htmlEntityDesc {
1624 if name.is_null() {
1625 return ptr::null();
1626 }
1627 let bytes = unsafe { xmlstr_to_bytes(name) };
1628 for e in HTML40_ENTITIES {
1629 let ename = unsafe { core::ffi::CStr::from_ptr(e.name) }.to_bytes();
1630 if bytes == ename {
1631 return e as *const _htmlEntityDesc;
1632 }
1633 }
1634 ptr::null()
1635}
1636
1637#[no_mangle]
1648pub unsafe extern "C" fn htmlEntityValueLookup(value: c_uint) -> *const _htmlEntityDesc {
1649 for e in HTML40_ENTITIES {
1650 if e.value == value {
1651 return e as *const _htmlEntityDesc;
1652 }
1653 }
1654 ptr::null()
1655}
1656
1657#[inline]
1660unsafe fn html_entity_value_lookup_static(value: c_uint) -> *const _htmlEntityDesc {
1661 for e in HTML40_ENTITIES {
1662 if e.value == value {
1663 return e as *const _htmlEntityDesc;
1664 }
1665 }
1666 ptr::null()
1667}
1668
1669static HTML_START_CLOSE: &[(&str, &str)] = &[
1677 ("a", "a"),
1678 ("a", "fieldset"),
1679 ("a", "table"),
1680 ("a", "td"),
1681 ("a", "th"),
1682 ("address", "dd"),
1683 ("address", "dl"),
1684 ("address", "dt"),
1685 ("address", "form"),
1686 ("address", "li"),
1687 ("address", "ul"),
1688 ("b", "center"),
1689 ("b", "p"),
1690 ("b", "td"),
1691 ("b", "th"),
1692 ("big", "p"),
1693 ("caption", "col"),
1694 ("caption", "colgroup"),
1695 ("caption", "tbody"),
1696 ("caption", "tfoot"),
1697 ("caption", "thead"),
1698 ("caption", "tr"),
1699 ("col", "col"),
1700 ("col", "colgroup"),
1701 ("col", "tbody"),
1702 ("col", "tfoot"),
1703 ("col", "thead"),
1704 ("col", "tr"),
1705 ("colgroup", "colgroup"),
1706 ("colgroup", "tbody"),
1707 ("colgroup", "tfoot"),
1708 ("colgroup", "thead"),
1709 ("colgroup", "tr"),
1710 ("dd", "dt"),
1711 ("dir", "dd"),
1712 ("dir", "dl"),
1713 ("dir", "dt"),
1714 ("dir", "form"),
1715 ("dir", "ul"),
1716 ("dl", "form"),
1717 ("dl", "li"),
1718 ("dt", "dd"),
1719 ("dt", "dl"),
1720 ("font", "center"),
1721 ("font", "td"),
1722 ("font", "th"),
1723 ("form", "form"),
1724 ("h1", "fieldset"),
1725 ("h1", "form"),
1726 ("h1", "li"),
1727 ("h1", "p"),
1728 ("h1", "table"),
1729 ("h2", "fieldset"),
1730 ("h2", "form"),
1731 ("h2", "li"),
1732 ("h2", "p"),
1733 ("h2", "table"),
1734 ("h3", "fieldset"),
1735 ("h3", "form"),
1736 ("h3", "li"),
1737 ("h3", "p"),
1738 ("h3", "table"),
1739 ("h4", "fieldset"),
1740 ("h4", "form"),
1741 ("h4", "li"),
1742 ("h4", "p"),
1743 ("h4", "table"),
1744 ("h5", "fieldset"),
1745 ("h5", "form"),
1746 ("h5", "li"),
1747 ("h5", "p"),
1748 ("h5", "table"),
1749 ("h6", "fieldset"),
1750 ("h6", "form"),
1751 ("h6", "li"),
1752 ("h6", "p"),
1753 ("h6", "table"),
1754 ("head", "a"),
1755 ("head", "abbr"),
1756 ("head", "acronym"),
1757 ("head", "address"),
1758 ("head", "b"),
1759 ("head", "bdo"),
1760 ("head", "big"),
1761 ("head", "blockquote"),
1762 ("head", "body"),
1763 ("head", "br"),
1764 ("head", "center"),
1765 ("head", "cite"),
1766 ("head", "code"),
1767 ("head", "dd"),
1768 ("head", "dfn"),
1769 ("head", "dir"),
1770 ("head", "div"),
1771 ("head", "dl"),
1772 ("head", "dt"),
1773 ("head", "em"),
1774 ("head", "fieldset"),
1775 ("head", "font"),
1776 ("head", "form"),
1777 ("head", "frameset"),
1778 ("head", "h1"),
1779 ("head", "h2"),
1780 ("head", "h3"),
1781 ("head", "h4"),
1782 ("head", "h5"),
1783 ("head", "h6"),
1784 ("head", "hr"),
1785 ("head", "i"),
1786 ("head", "iframe"),
1787 ("head", "img"),
1788 ("head", "kbd"),
1789 ("head", "li"),
1790 ("head", "listing"),
1791 ("head", "map"),
1792 ("head", "menu"),
1793 ("head", "ol"),
1794 ("head", "p"),
1795 ("head", "pre"),
1796 ("head", "q"),
1797 ("head", "s"),
1798 ("head", "samp"),
1799 ("head", "small"),
1800 ("head", "span"),
1801 ("head", "strike"),
1802 ("head", "strong"),
1803 ("head", "sub"),
1804 ("head", "sup"),
1805 ("head", "table"),
1806 ("head", "tt"),
1807 ("head", "u"),
1808 ("head", "ul"),
1809 ("head", "var"),
1810 ("head", "xmp"),
1811 ("hr", "form"),
1812 ("i", "center"),
1813 ("i", "p"),
1814 ("i", "td"),
1815 ("i", "th"),
1816 ("legend", "fieldset"),
1817 ("li", "li"),
1818 ("link", "body"),
1819 ("link", "frameset"),
1820 ("listing", "dd"),
1821 ("listing", "dl"),
1822 ("listing", "dt"),
1823 ("listing", "fieldset"),
1824 ("listing", "form"),
1825 ("listing", "li"),
1826 ("listing", "table"),
1827 ("listing", "ul"),
1828 ("menu", "dd"),
1829 ("menu", "dl"),
1830 ("menu", "dt"),
1831 ("menu", "form"),
1832 ("menu", "ul"),
1833 ("ol", "form"),
1834 ("option", "optgroup"),
1835 ("option", "option"),
1836 ("p", "address"),
1837 ("p", "blockquote"),
1838 ("p", "body"),
1839 ("p", "caption"),
1840 ("p", "center"),
1841 ("p", "col"),
1842 ("p", "colgroup"),
1843 ("p", "dd"),
1844 ("p", "dir"),
1845 ("p", "div"),
1846 ("p", "dl"),
1847 ("p", "dt"),
1848 ("p", "fieldset"),
1849 ("p", "form"),
1850 ("p", "frameset"),
1851 ("p", "h1"),
1852 ("p", "h2"),
1853 ("p", "h3"),
1854 ("p", "h4"),
1855 ("p", "h5"),
1856 ("p", "h6"),
1857 ("p", "head"),
1858 ("p", "hr"),
1859 ("p", "li"),
1860 ("p", "listing"),
1861 ("p", "menu"),
1862 ("p", "ol"),
1863 ("p", "p"),
1864 ("p", "pre"),
1865 ("p", "table"),
1866 ("p", "tbody"),
1867 ("p", "td"),
1868 ("p", "tfoot"),
1869 ("p", "th"),
1870 ("p", "title"),
1871 ("p", "tr"),
1872 ("p", "ul"),
1873 ("p", "xmp"),
1874 ("pre", "dd"),
1875 ("pre", "dl"),
1876 ("pre", "dt"),
1877 ("pre", "fieldset"),
1878 ("pre", "form"),
1879 ("pre", "li"),
1880 ("pre", "table"),
1881 ("pre", "ul"),
1882 ("s", "p"),
1883 ("script", "noscript"),
1884 ("small", "p"),
1885 ("span", "td"),
1886 ("span", "th"),
1887 ("strike", "p"),
1888 ("style", "body"),
1889 ("style", "frameset"),
1890 ("tbody", "tbody"),
1891 ("tbody", "tfoot"),
1892 ("td", "tbody"),
1893 ("td", "td"),
1894 ("td", "tfoot"),
1895 ("td", "th"),
1896 ("td", "tr"),
1897 ("tfoot", "tbody"),
1898 ("th", "tbody"),
1899 ("th", "td"),
1900 ("th", "tfoot"),
1901 ("th", "th"),
1902 ("th", "tr"),
1903 ("thead", "tbody"),
1904 ("thead", "tfoot"),
1905 ("title", "body"),
1906 ("title", "frameset"),
1907 ("tr", "tbody"),
1908 ("tr", "tfoot"),
1909 ("tr", "tr"),
1910 ("tt", "p"),
1911 ("u", "p"),
1912 ("u", "td"),
1913 ("u", "th"),
1914 ("ul", "address"),
1915 ("ul", "form"),
1916 ("ul", "menu"),
1917 ("ul", "pre"),
1918 ("xmp", "dd"),
1919 ("xmp", "dl"),
1920 ("xmp", "dt"),
1921 ("xmp", "fieldset"),
1922 ("xmp", "form"),
1923 ("xmp", "li"),
1924 ("xmp", "table"),
1925 ("xmp", "ul"),
1926];
1927
1928unsafe fn html_check_auto_close(newtag: *const xmlChar, oldtag: *const xmlChar) -> bool {
1932 if newtag.is_null() || oldtag.is_null() {
1933 return false;
1934 }
1935 let new_bytes = unsafe { xmlstr_to_bytes(newtag) };
1936 let old_bytes = unsafe { xmlstr_to_bytes(oldtag) };
1937 HTML_START_CLOSE
1938 .iter()
1939 .any(|(old, new)| old.as_bytes() == old_bytes && new.as_bytes() == new_bytes)
1940}
1941
1942#[no_mangle]
1952pub unsafe extern "C" fn htmlAutoCloseTag(
1953 _doc: *mut _xmlDoc,
1954 name: *const xmlChar,
1955 elem: *mut _xmlNode,
1956) -> c_int {
1957 if elem.is_null() {
1958 return 1;
1959 }
1960 let n = unsafe { &*elem };
1961 if n.name.is_null() {
1962 } else if unsafe { xml_strcmp(name, n.name) } == 0 {
1965 return 0;
1966 }
1967 if unsafe { html_check_auto_close(n.name, name) } {
1968 return 1;
1969 }
1970 let mut child = n.children;
1971 while !child.is_null() {
1972 if unsafe { htmlAutoCloseTag(_doc, name, child) } != 0 {
1973 return 1;
1974 }
1975 child = unsafe { (*child).next };
1976 }
1977 0
1978}
1979
1980#[no_mangle]
1989pub unsafe extern "C" fn htmlIsAutoClosed(doc: *mut _xmlDoc, elem: *mut _xmlNode) -> c_int {
1990 if elem.is_null() {
1991 return 1;
1992 }
1993 let n = unsafe { &*elem };
1994 let mut child = n.children;
1995 while !child.is_null() {
1996 if unsafe { htmlAutoCloseTag(doc, n.name, child) } != 0 {
1997 return 1;
1998 }
1999 child = unsafe { (*child).next };
2000 }
2001 0
2002}
2003
2004static HTML_SCRIPT_ATTRIBUTES: &[&str] = &[
2007 "onclick",
2008 "ondblclick",
2009 "onmousedown",
2010 "onmouseup",
2011 "onmouseover",
2012 "onmousemove",
2013 "onmouseout",
2014 "onkeypress",
2015 "onkeydown",
2016 "onkeyup",
2017 "onload",
2018 "onunload",
2019 "onfocus",
2020 "onblur",
2021 "onsubmit",
2022 "onreset",
2023 "onchange",
2024 "onselect",
2025];
2026
2027#[no_mangle]
2036pub unsafe extern "C" fn htmlIsScriptAttribute(name: *const xmlChar) -> c_int {
2037 if name.is_null() {
2038 return 0;
2039 }
2040 let bytes = unsafe { xmlstr_to_bytes(name) };
2041 if bytes.len() < 3 || bytes[0] != b'o' || bytes[1] != b'n' {
2042 return 0;
2043 }
2044 for cand in HTML_SCRIPT_ATTRIBUTES {
2045 if bytes == cand.as_bytes() {
2046 return 1;
2047 }
2048 }
2049 0
2050}
2051
2052#[no_mangle]
2064pub const unsafe extern "C" fn htmlElementAllowedHere(
2065 _parent: *const _htmlElemDesc,
2066 _elt: *const xmlChar,
2067) -> c_int {
2068 1
2069}
2070
2071#[no_mangle]
2079pub const unsafe extern "C" fn htmlElementStatusHere(
2080 _parent: *const _htmlElemDesc,
2081 _elt: *const _htmlElemDesc,
2082) -> c_int {
2083 HTML_VALID
2084}
2085
2086#[no_mangle]
2094pub const unsafe extern "C" fn htmlAttrAllowed(
2095 _elt: *const _htmlElemDesc,
2096 _attr: *const xmlChar,
2097 _legacy: c_int,
2098) -> c_int {
2099 HTML_VALID
2100}
2101
2102#[no_mangle]
2110pub const unsafe extern "C" fn htmlNodeStatus(_node: *mut _xmlNode, _legacy: c_int) -> c_int {
2111 HTML_VALID
2112}
2113
2114#[no_mangle]
2133pub unsafe extern "C" fn htmlEncodeEntities(
2134 out: *mut u8,
2135 outlen: *mut c_int,
2136 input: *const u8,
2137 inlen: *mut c_int,
2138 quoteChar: c_int,
2139) -> c_int {
2140 if out.is_null() || outlen.is_null() || inlen.is_null() || input.is_null() {
2141 return -1;
2142 }
2143 let outend = (out as usize).wrapping_add((*outlen).max(0) as usize);
2144 let inend = (input as usize).wrapping_add((*inlen).max(0) as usize);
2145 let mut in_ptr = input as usize;
2146 let mut out_ptr = out as usize;
2147 let mut processed = in_ptr;
2148
2149 while in_ptr < inend {
2150 let mut c: c_uint;
2151
2152 let mut trailing: c_int;
2153
2154 let d: c_uint = unsafe { *(in_ptr as *const u8) as c_uint };
2155 in_ptr += 1;
2156 if d < 0x80 {
2157 c = d;
2158 trailing = 0;
2159 } else if d < 0xC0 {
2160 *outlen = (out_ptr - out as usize) as c_int;
2162 *inlen = (processed - input as usize) as c_int;
2163 return -2;
2164 } else if d < 0xE0 {
2165 c = d & 0x1F;
2166 trailing = 1;
2167 } else if d < 0xF0 {
2168 c = d & 0x0F;
2169 trailing = 2;
2170 } else if d < 0xF8 {
2171 c = d & 0x07;
2172 trailing = 3;
2173 } else {
2174 *outlen = (out_ptr - out as usize) as c_int;
2176 *inlen = (processed - input as usize) as c_int;
2177 return -2;
2178 }
2179
2180 if inend - in_ptr < trailing as usize {
2181 break;
2182 }
2183
2184 while trailing > 0 {
2185 let t = unsafe { *(in_ptr as *const u8) as c_uint };
2186 in_ptr += 1;
2187 if (t & 0xC0) != 0x80 {
2188 *outlen = (out_ptr - out as usize) as c_int;
2189 *inlen = (processed - input as usize) as c_int;
2190 return -2;
2191 }
2192 c = (c << 6) | (t & 0x3F);
2193 trailing -= 1;
2194 }
2195
2196 if (c < 0x80)
2198 && (c != quoteChar as c_uint)
2199 && (c != b'&' as c_uint)
2200 && (c != b'<' as c_uint)
2201 && (c != b'>' as c_uint)
2202 {
2203 if out_ptr >= outend {
2204 break;
2205 }
2206 unsafe { *(out_ptr as *mut u8) = c as u8 };
2207 out_ptr += 1;
2208 } else {
2209 let ent = unsafe { html_entity_value_lookup_static(c) };
2210 let mut nbuf = [0u8; 16];
2211 let (cp, len): (*const u8, usize) = if ent.is_null() {
2212 nbuf[0] = b'#';
2214 let mut i = 1usize;
2215 let mut digits = [0u8; 10];
2216 let mut nd = 0usize;
2217 let mut v = c;
2218 if v == 0 {
2219 digits[0] = b'0';
2220 nd = 1;
2221 }
2222 while v > 0 {
2223 digits[nd] = b'0' + (v % 10) as u8;
2224 nd += 1;
2225 v /= 10;
2226 }
2227 while nd > 0 {
2228 nd -= 1;
2229 nbuf[i] = digits[nd];
2230 i += 1;
2231 }
2232 (nbuf.as_ptr(), i)
2233 } else {
2234 (unsafe { (*ent).name } as *const u8, unsafe {
2235 xml_strlen((*ent).name as *const xmlChar)
2236 })
2237 };
2238 if outend - out_ptr < len + 2 {
2239 break;
2240 }
2241 unsafe {
2242 *(out_ptr as *mut u8) = b'&';
2243 ptr::copy_nonoverlapping(cp, (out_ptr + 1) as *mut u8, len);
2244 *((out_ptr + 1 + len) as *mut u8) = b';';
2245 }
2246 out_ptr += len + 2;
2247 }
2248 processed = in_ptr;
2249 }
2250
2251 *outlen = (out_ptr - out as usize) as c_int;
2252 *inlen = (processed - input as usize) as c_int;
2253 0
2254}
2255
2256#[no_mangle]
2269pub unsafe extern "C" fn htmlDecodeEntities(
2270 _ctxt: *mut c_void,
2271 _len: c_int,
2272 _end: xmlChar,
2273 _end2: xmlChar,
2274 _end3: xmlChar,
2275) -> *mut xmlChar {
2276 static DEPRECATED: AtomicBool = AtomicBool::new(false);
2277 if !DEPRECATED.swap(true, Ordering::Relaxed) {
2278 let msg = b"htmlDecodeEntities() deprecated function reached\n";
2280 unsafe {
2281 libc::fwrite(
2282 msg.as_ptr() as *const c_void,
2283 1,
2284 msg.len(),
2285 libc::fdopen(2, b"w\0" as *const u8 as *const c_char),
2286 );
2287 }
2288 }
2289 ptr::null_mut()
2290}
2291
2292#[no_mangle]
2302pub unsafe extern "C" fn htmlIsBooleanAttr(name: *const xmlChar) -> c_int {
2303 if name.is_null() {
2304 return 0;
2305 }
2306 let b = unsafe { xmlstr_to_bytes(name) };
2307 if b.is_empty() {
2308 return 0;
2309 }
2310 let mut i = 0usize;
2311 let mut suffix: Option<&'static [u8]> = None;
2312 match b[i].to_ascii_lowercase() {
2313 b'c' => {
2314 i += 1;
2315 match b.get(i).map(|&x| x.to_ascii_lowercase()) {
2316 Some(b'h') => suffix = Some(b"ecked"),
2317 Some(b'o') => suffix = Some(b"mpact"),
2318 _ => {}
2319 }
2320 }
2321 b'd' => {
2322 i += 1;
2323 match b.get(i).map(|&x| x.to_ascii_lowercase()) {
2324 Some(b'e') => {
2325 i += 1;
2326 match b.get(i).map(|&x| x.to_ascii_lowercase()) {
2327 Some(b'c') => suffix = Some(b"lare"),
2328 Some(b'f') => suffix = Some(b"er"),
2329 _ => {}
2330 }
2331 }
2332 Some(b'i') => suffix = Some(b"sabled"),
2333 _ => {}
2334 }
2335 }
2336 b'i' => suffix = Some(b"smap"),
2337 b'm' => suffix = Some(b"ultiple"),
2338 b'n' => {
2339 i += 1;
2340 if b.get(i).map(|&x| x.to_ascii_lowercase()) == Some(b'o') {
2341 i += 1;
2342 match b.get(i).map(|&x| x.to_ascii_lowercase()) {
2343 Some(b'h') => suffix = Some(b"ref"),
2344 Some(b'r') => suffix = Some(b"esize"),
2345 Some(b's') => suffix = Some(b"hade"),
2346 Some(b'w') => suffix = Some(b"rap"),
2347 _ => {}
2348 }
2349 }
2350 }
2351 b'r' => suffix = Some(b"eadonly"),
2352 b's' => suffix = Some(b"elected"),
2353 _ => {}
2354 }
2355 let Some(suffix) = suffix else {
2356 return 0;
2357 };
2358 if b.len() == i + 1 + suffix.len() && b[i + 1..].eq_ignore_ascii_case(suffix) {
2359 1
2360 } else {
2361 0
2362 }
2363}
2364
2365static HTML_OMITTED_DEFAULT_VALUE: AtomicI32 = AtomicI32::new(1);
2372
2373#[no_mangle]
2381pub unsafe extern "C" fn htmlHandleOmittedElem(val: c_int) -> c_int {
2382 HTML_OMITTED_DEFAULT_VALUE.swap(val, Ordering::Relaxed)
2383}
2384
2385#[no_mangle]
2393pub const unsafe extern "C" fn htmlInitAutoClose() {
2394 }
2396
2397#[no_mangle]
2408pub const unsafe extern "C" fn htmlDefaultSAXHandlerInit() {
2409 }
2411
2412#[no_mangle]
2424pub const unsafe extern "C" fn htmlParseEntityRef(
2425 _ctxt: *mut c_void,
2426 _str: *mut *const xmlChar,
2427) -> *const _htmlEntityDesc {
2428 ptr::null()
2429}
2430
2431#[no_mangle]
2439pub const unsafe extern "C" fn htmlParseCharRef(_ctxt: *mut c_void) -> c_int {
2440 0
2441}
2442
2443#[allow(dead_code)]
2461struct HtmlOpaqueCtxt {
2462 doc: *mut _xmlDoc,
2464 current: *mut _xmlNode,
2465 html: *mut _xmlNode,
2466 head: *mut _xmlNode,
2467 body: *mut _xmlNode,
2468 in_head: bool,
2469 in_body: bool,
2470 html_created: bool,
2471 head_created: bool,
2472 body_created: bool,
2473 seen_body_content: bool,
2474 input: *mut u8,
2476 input_pos: usize,
2477 input_len: usize,
2478 line: c_int,
2479 err: bool,
2480 filename: *mut c_char,
2481 encoding: *mut c_char,
2482 options: c_int,
2484 sax: *mut _xmlSAXHandler,
2485 user_data: *mut c_void,
2486}
2487
2488unsafe fn html_ctxt_alloc() -> *mut HtmlOpaqueCtxt {
2491 let mem = xmlMallocZero(size_of::<HtmlOpaqueCtxt>()) as *mut HtmlOpaqueCtxt;
2492 if mem.is_null() {
2493 return ptr::null_mut();
2494 }
2495 unsafe {
2496 ptr::write(
2497 mem,
2498 HtmlOpaqueCtxt {
2499 doc: ptr::null_mut(),
2500 current: ptr::null_mut(),
2501 html: ptr::null_mut(),
2502 head: ptr::null_mut(),
2503 body: ptr::null_mut(),
2504 in_head: false,
2505 in_body: false,
2506 html_created: false,
2507 head_created: false,
2508 body_created: false,
2509 seen_body_content: false,
2510 input: ptr::null_mut(),
2511 input_pos: 0,
2512 input_len: 0,
2513 line: 1,
2514 err: false,
2515 filename: ptr::null_mut(),
2516 encoding: ptr::null_mut(),
2517 options: 0,
2518 sax: ptr::null_mut(),
2519 user_data: ptr::null_mut(),
2520 },
2521 );
2522 }
2523 mem
2524}
2525
2526unsafe fn html_ctxt_set_input(ctxt: *mut HtmlOpaqueCtxt, buffer: *const c_char, size: c_int) {
2528 if buffer.is_null() || size <= 0 {
2529 return;
2530 }
2531 let len = size as usize;
2532 let nb = xmlMallocImpl(len) as *mut u8;
2533 if nb.is_null() {
2534 return;
2535 }
2536 unsafe {
2537 ptr::copy_nonoverlapping(buffer as *const u8, nb, len);
2538 (*ctxt).input = nb;
2539 (*ctxt).input_len = len;
2540 (*ctxt).input_pos = 0;
2541 }
2542}
2543
2544#[no_mangle]
2552pub unsafe extern "C" fn htmlNewSAXParserCtxt(
2553 sax: *const _xmlSAXHandler,
2554 userData: *mut c_void,
2555) -> *mut c_void {
2556 let ctxt = unsafe { html_ctxt_alloc() };
2557 if ctxt.is_null() {
2558 return ptr::null_mut();
2559 }
2560 unsafe {
2561 (*ctxt).sax = sax as *mut _xmlSAXHandler;
2562 (*ctxt).user_data = userData;
2563 }
2564 ctxt as *mut c_void
2565}
2566
2567#[no_mangle]
2575pub unsafe extern "C" fn htmlNewParserCtxt() -> *mut c_void {
2576 unsafe { htmlNewSAXParserCtxt(ptr::null(), ptr::null_mut()) }
2577}
2578
2579#[no_mangle]
2588pub unsafe extern "C" fn htmlCreateMemoryParserCtxt(
2589 buffer: *const c_char,
2590 size: c_int,
2591) -> *mut c_void {
2592 if buffer.is_null() || size <= 0 {
2593 return ptr::null_mut();
2594 }
2595 let ctxt = unsafe { html_ctxt_alloc() };
2596 if ctxt.is_null() {
2597 return ptr::null_mut();
2598 }
2599 unsafe { html_ctxt_set_input(ctxt, buffer, size) };
2600 if unsafe { (*ctxt).input.is_null() } {
2601 unsafe { crate::xml::html::free_parser_ctxt(ctxt as *mut c_void) };
2602 return ptr::null_mut();
2603 }
2604 ctxt as *mut c_void
2605}
2606
2607#[no_mangle]
2617pub unsafe extern "C" fn htmlCreatePushParserCtxt(
2618 sax: *mut _xmlSAXHandler,
2619 user_data: *mut c_void,
2620 chunk: *const c_char,
2621 size: c_int,
2622 filename: *const c_char,
2623 _enc: xmlCharEncoding,
2624) -> *mut c_void {
2625 let ctxt = unsafe { html_ctxt_alloc() };
2626 if ctxt.is_null() {
2627 return ptr::null_mut();
2628 }
2629 unsafe {
2630 (*ctxt).sax = sax;
2631 (*ctxt).user_data = user_data;
2632 if !filename.is_null() {
2633 (*ctxt).filename = c_strdup(filename);
2634 }
2635 if size > 0 && !chunk.is_null() {
2636 html_ctxt_set_input(ctxt, chunk, size);
2637 } else {
2638 let nb = xmlMallocImpl(1) as *mut u8;
2641 if !nb.is_null() {
2642 (*ctxt).input = nb;
2643 (*ctxt).input_len = 0;
2644 (*ctxt).input_pos = 0;
2645 }
2646 }
2647 }
2648 ctxt as *mut c_void
2649}
2650
2651#[no_mangle]
2659pub unsafe extern "C" fn htmlCtxtReset(ctxt: *mut c_void) {
2660 if ctxt.is_null() {
2661 return;
2662 }
2663 let c = ctxt as *mut HtmlOpaqueCtxt;
2664 unsafe {
2665 if !(*c).input.is_null() {
2666 xmlFreeImpl((*c).input as *mut c_void);
2667 }
2668 (*c).input = ptr::null_mut();
2669 (*c).input_len = 0;
2670 (*c).input_pos = 0;
2671 (*c).doc = ptr::null_mut();
2672 (*c).options = 0;
2673 (*c).line = 1;
2674 (*c).err = false;
2675 }
2676}
2677
2678#[no_mangle]
2689pub unsafe extern "C" fn htmlCtxtUseOptions(ctxt: *mut c_void, options: c_int) -> c_int {
2690 if ctxt.is_null() {
2691 return -1;
2692 }
2693 let c = ctxt as *mut HtmlOpaqueCtxt;
2694 unsafe {
2696 (*c).options = ((*c).options & HTML_OPTIONS_KEEP_MASK) | (options & HTML_OPTIONS_ALL_MASK);
2697 }
2698 options & !HTML_OPTIONS_ALL_MASK & !crate::abi::types::XML_PARSE_NOENT
2701}
2702
2703#[no_mangle]
2712pub unsafe extern "C" fn htmlParseDocument(ctxt: *mut c_void) -> c_int {
2713 if ctxt.is_null() {
2714 return -1;
2715 }
2716 let c = ctxt as *mut HtmlOpaqueCtxt;
2717 if unsafe { (*c).input.is_null() } {
2718 return -1;
2719 }
2720 let doc = unsafe { html::parse_memory((*c).input as *const c_char, (*c).input_len as c_int) };
2721 unsafe { (*c).doc = doc };
2722 if doc.is_null() {
2723 -1
2724 } else {
2725 0
2726 }
2727}
2728
2729#[no_mangle]
2740pub unsafe extern "C" fn htmlParseChunk(
2741 ctxt: *mut c_void,
2742 chunk: *const c_char,
2743 size: c_int,
2744 terminate: c_int,
2745) -> c_int {
2746 if ctxt.is_null() || size < 0 || (size > 0 && chunk.is_null()) {
2747 return XML_ERR_ARGUMENT;
2748 }
2749 let c = ctxt as *mut HtmlOpaqueCtxt;
2750 if unsafe { (*c).input.is_null() } {
2751 return XML_ERR_ARGUMENT;
2752 }
2753
2754 if size > 0 {
2755 let new_len = unsafe { (*c).input_len }.wrapping_add(size as usize);
2756 let nb = unsafe { xmlReallocImpl((*c).input as *mut c_void, new_len) } as *mut u8;
2757 if nb.is_null() {
2758 return XML_ERR_NO_MEMORY;
2759 }
2760 unsafe {
2761 ptr::copy_nonoverlapping(chunk as *const u8, nb.add((*c).input_len), size as usize);
2762 (*c).input = nb;
2763 (*c).input_len = new_len;
2764 }
2765 }
2766
2767 if terminate != 0 {
2768 let doc =
2769 unsafe { html::parse_memory((*c).input as *const c_char, (*c).input_len as c_int) };
2770 unsafe {
2771 (*c).doc = doc;
2772 xmlFreeImpl((*c).input as *mut c_void);
2774 (*c).input = ptr::null_mut();
2775 (*c).input_len = 0;
2776 }
2777 }
2778 XML_ERR_OK
2779}
2780
2781#[no_mangle]
2789pub unsafe extern "C" fn htmlCtxtParseDocument(
2790 ctxt: *mut c_void,
2791 input: *mut _xmlParserInput,
2792) -> *mut _xmlDoc {
2793 if ctxt.is_null() || input.is_null() {
2794 return ptr::null_mut();
2795 }
2796 let cur = unsafe { (*input).cur };
2797 let end = unsafe { (*input).end };
2798 if cur.is_null() {
2799 return ptr::null_mut();
2800 }
2801 let len = (end as usize).wrapping_sub(cur as usize) as c_int;
2802 if len <= 0 {
2803 return ptr::null_mut();
2804 }
2805 let doc = unsafe { html::parse_memory(cur as *const c_char, len) };
2806 let c = ctxt as *mut HtmlOpaqueCtxt;
2807 unsafe {
2808 (*c).doc = doc;
2809 }
2810 doc
2811}
2812
2813unsafe fn html_ctxt_finish_read(
2820 ctxt: *mut c_void,
2821 doc: *mut _xmlDoc,
2822 url: *const c_char,
2823) -> *mut _xmlDoc {
2824 if ctxt.is_null() {
2825 return doc;
2826 }
2827 let c = ctxt as *mut HtmlOpaqueCtxt;
2828 unsafe {
2829 (*c).doc = doc;
2830 if !doc.is_null() && !url.is_null() {
2831 (*doc).URL = c_strdup(url) as *mut xmlChar;
2832 }
2833 }
2834 doc
2835}
2836
2837#[no_mangle]
2846pub unsafe extern "C" fn htmlCtxtReadMemory(
2847 ctxt: *mut c_void,
2848 buffer: *const c_char,
2849 size: c_int,
2850 URL: *const c_char,
2851 _encoding: *const c_char,
2852 options: c_int,
2853) -> *mut _xmlDoc {
2854 if ctxt.is_null() || size < 0 {
2855 return ptr::null_mut();
2856 }
2857 unsafe { htmlCtxtReset(ctxt) };
2858 unsafe { htmlCtxtUseOptions(ctxt, options) };
2859 let doc = unsafe { html::parse_memory(buffer, size) };
2860 unsafe { html_ctxt_finish_read(ctxt, doc, URL) }
2861}
2862
2863#[no_mangle]
2872pub unsafe extern "C" fn htmlCtxtReadDoc(
2873 ctxt: *mut c_void,
2874 str: *const xmlChar,
2875 URL: *const c_char,
2876 encoding: *const c_char,
2877 options: c_int,
2878) -> *mut _xmlDoc {
2879 if ctxt.is_null() {
2880 return ptr::null_mut();
2881 }
2882 unsafe { htmlCtxtReset(ctxt) };
2883 unsafe { htmlCtxtUseOptions(ctxt, options) };
2884 let doc = unsafe { html::parse_doc(str, encoding) };
2885 unsafe { html_ctxt_finish_read(ctxt, doc, URL) }
2886}
2887
2888#[no_mangle]
2898pub unsafe extern "C" fn htmlCtxtReadFile(
2899 ctxt: *mut c_void,
2900 filename: *const c_char,
2901 encoding: *const c_char,
2902 options: c_int,
2903) -> *mut _xmlDoc {
2904 if ctxt.is_null() {
2905 return ptr::null_mut();
2906 }
2907 unsafe { htmlCtxtReset(ctxt) };
2908 unsafe { htmlCtxtUseOptions(ctxt, options) };
2909 let doc = unsafe { html::parse_file(filename, encoding) };
2910 unsafe { html_ctxt_finish_read(ctxt, doc, filename) }
2911}
2912
2913unsafe fn html_read_fd(fd: c_int) -> Vec<u8> {
2915 let mut buf = Vec::new();
2916 let mut tmp = [0u8; 4096];
2917 loop {
2918 let n = libc::read(fd, tmp.as_mut_ptr() as *mut c_void, tmp.len());
2919 if n <= 0 {
2920 break;
2921 }
2922 buf.extend_from_slice(&tmp[..n as usize]);
2923 }
2924 buf
2925}
2926
2927unsafe fn html_read_io(ioread: Option<xmlInputReadCallback>, ioctx: *mut c_void) -> Vec<u8> {
2929 let mut buf = Vec::new();
2930 let mut tmp = [0u8; 4096];
2931 if let Some(read) = ioread {
2932 loop {
2933 let n = unsafe { read(ioctx, tmp.as_mut_ptr() as *mut c_char, tmp.len() as c_int) };
2934 if n <= 0 {
2935 break;
2936 }
2937 buf.extend_from_slice(&tmp[..n as usize]);
2938 }
2939 }
2940 buf
2941}
2942
2943#[no_mangle]
2952pub unsafe extern "C" fn htmlCtxtReadFd(
2953 ctxt: *mut c_void,
2954 fd: c_int,
2955 URL: *const c_char,
2956 _encoding: *const c_char,
2957 options: c_int,
2958) -> *mut _xmlDoc {
2959 if ctxt.is_null() {
2960 return ptr::null_mut();
2961 }
2962 unsafe { htmlCtxtReset(ctxt) };
2963 unsafe { htmlCtxtUseOptions(ctxt, options) };
2964 let data = unsafe { html_read_fd(fd) };
2965 let doc = unsafe { html::parse_memory(data.as_ptr() as *const c_char, data.len() as c_int) };
2966 unsafe { html_ctxt_finish_read(ctxt, doc, URL) }
2967}
2968
2969#[no_mangle]
2979pub unsafe extern "C" fn htmlCtxtReadIO(
2980 ctxt: *mut c_void,
2981 ioread: Option<xmlInputReadCallback>,
2982 _ioclose: Option<xmlInputCloseCallback>,
2983 ioctx: *mut c_void,
2984 URL: *const c_char,
2985 _encoding: *const c_char,
2986 options: c_int,
2987) -> *mut _xmlDoc {
2988 if ctxt.is_null() {
2989 return ptr::null_mut();
2990 }
2991 unsafe { htmlCtxtReset(ctxt) };
2992 unsafe { htmlCtxtUseOptions(ctxt, options) };
2993 let data = unsafe { html_read_io(ioread, ioctx) };
2994 let doc = unsafe { html::parse_memory(data.as_ptr() as *const c_char, data.len() as c_int) };
2995 unsafe { html_ctxt_finish_read(ctxt, doc, URL) }
2996}
2997
2998#[no_mangle]
3007pub unsafe extern "C" fn htmlReadMemory(
3008 buffer: *const c_char,
3009 size: c_int,
3010 url: *const c_char,
3011 encoding: *const c_char,
3012 options: c_int,
3013) -> *mut _xmlDoc {
3014 if size < 0 {
3015 return ptr::null_mut();
3016 }
3017 let ctxt = unsafe { htmlNewParserCtxt() };
3018 if ctxt.is_null() {
3019 return ptr::null_mut();
3020 }
3021 let doc = unsafe { htmlCtxtReadMemory(ctxt, buffer, size, url, encoding, options) };
3022 unsafe { crate::xml::html::free_parser_ctxt(ctxt) };
3023 doc
3024}
3025
3026#[no_mangle]
3036pub unsafe extern "C" fn htmlReadDoc(
3037 str: *const xmlChar,
3038 url: *const c_char,
3039 encoding: *const c_char,
3040 options: c_int,
3041) -> *mut _xmlDoc {
3042 let ctxt = unsafe { htmlNewParserCtxt() };
3043 if ctxt.is_null() {
3044 return ptr::null_mut();
3045 }
3046 let doc = unsafe { htmlCtxtReadDoc(ctxt, str, url, encoding, options) };
3047 unsafe { crate::xml::html::free_parser_ctxt(ctxt) };
3048 doc
3049}
3050
3051#[no_mangle]
3060pub unsafe extern "C" fn htmlReadFile(
3061 filename: *const c_char,
3062 encoding: *const c_char,
3063 options: c_int,
3064) -> *mut _xmlDoc {
3065 let ctxt = unsafe { htmlNewParserCtxt() };
3066 if ctxt.is_null() {
3067 return ptr::null_mut();
3068 }
3069 let doc = unsafe { htmlCtxtReadFile(ctxt, filename, encoding, options) };
3070 unsafe { crate::xml::html::free_parser_ctxt(ctxt) };
3071 doc
3072}
3073
3074#[no_mangle]
3082pub unsafe extern "C" fn htmlReadFd(
3083 fd: c_int,
3084 url: *const c_char,
3085 encoding: *const c_char,
3086 options: c_int,
3087) -> *mut _xmlDoc {
3088 let ctxt = unsafe { htmlNewParserCtxt() };
3089 if ctxt.is_null() {
3090 return ptr::null_mut();
3091 }
3092 let doc = unsafe { htmlCtxtReadFd(ctxt, fd, url, encoding, options) };
3093 unsafe { crate::xml::html::free_parser_ctxt(ctxt) };
3094 doc
3095}
3096
3097#[no_mangle]
3107pub unsafe extern "C" fn htmlReadIO(
3108 ioread: Option<xmlInputReadCallback>,
3109 ioclose: Option<xmlInputCloseCallback>,
3110 ioctx: *mut c_void,
3111 url: *const c_char,
3112 encoding: *const c_char,
3113 options: c_int,
3114) -> *mut _xmlDoc {
3115 let ctxt = unsafe { htmlNewParserCtxt() };
3116 if ctxt.is_null() {
3117 return ptr::null_mut();
3118 }
3119 let doc = unsafe { htmlCtxtReadIO(ctxt, ioread, ioclose, ioctx, url, encoding, options) };
3120 unsafe { crate::xml::html::free_parser_ctxt(ctxt) };
3121 doc
3122}
3123
3124#[no_mangle]
3135pub unsafe extern "C" fn htmlSAXParseDoc(
3136 cur: *const xmlChar,
3137 encoding: *const c_char,
3138 sax: *mut _xmlSAXHandler,
3139 userData: *mut c_void,
3140) -> *mut _xmlDoc {
3141 if cur.is_null() {
3142 return ptr::null_mut();
3143 }
3144 let ctxt = unsafe { htmlNewSAXParserCtxt(sax, userData) };
3145 if ctxt.is_null() {
3146 return ptr::null_mut();
3147 }
3148 let doc = unsafe { htmlCtxtReadDoc(ctxt, cur, ptr::null(), encoding, 0) };
3149 unsafe { crate::xml::html::free_parser_ctxt(ctxt) };
3150 doc
3151}
3152
3153#[no_mangle]
3164pub unsafe extern "C" fn htmlSAXParseFile(
3165 filename: *const c_char,
3166 encoding: *const c_char,
3167 sax: *mut _xmlSAXHandler,
3168 userData: *mut c_void,
3169) -> *mut _xmlDoc {
3170 let ctxt = unsafe { htmlNewSAXParserCtxt(sax, userData) };
3171 if ctxt.is_null() {
3172 return ptr::null_mut();
3173 }
3174 let doc = unsafe { htmlCtxtReadFile(ctxt, filename, encoding, 0) };
3175 unsafe { crate::xml::html::free_parser_ctxt(ctxt) };
3176 doc
3177}
3178
3179#[no_mangle]
3190pub unsafe extern "C" fn htmlParseElement(ctxt: *mut c_void) {
3191 if ctxt.is_null() {
3192 return;
3193 }
3194 let c = ctxt as *mut HtmlOpaqueCtxt;
3195 if unsafe { (*c).input.is_null() } {
3196 return;
3197 }
3198 let doc = unsafe { html::parse_memory((*c).input as *const c_char, (*c).input_len as c_int) };
3199 unsafe {
3200 (*c).doc = doc;
3201 }
3202}
3203
3204#[no_mangle]
3217pub unsafe extern "C" fn htmlNewDocNoDtD(
3218 URI: *const xmlChar,
3219 publicId: *const xmlChar,
3220) -> *mut _xmlDoc {
3221 let doc = unsafe { html::new_doc_no_dtd(ptr::null()) };
3222 if doc.is_null() {
3223 return ptr::null_mut();
3224 }
3225 unsafe {
3226 (*doc).standalone = 1;
3229 (*doc).charset = crate::abi::types::xmlCharEncoding::XML_CHAR_ENCODING_UTF8 as c_int;
3230 (*doc).properties = crate::abi::types::xmlDocProperties::XML_DOC_HTML as c_int
3231 | crate::abi::types::xmlDocProperties::XML_DOC_USERBUILT as c_int;
3232 if !publicId.is_null() || !URI.is_null() {
3233 let dtd = crate::xml::dtd::create_int_subset(
3234 doc,
3235 b"html\0" as *const u8 as *const xmlChar,
3236 publicId,
3237 URI,
3238 );
3239 if dtd.is_null() {
3240 tree::free_doc(doc);
3241 return ptr::null_mut();
3242 }
3243 }
3244 }
3245 doc
3246}
3247
3248#[no_mangle]
3263pub unsafe extern "C" fn htmlNewDoc(
3264 URI: *const xmlChar,
3265 ExternalID: *const xmlChar,
3266) -> *mut _xmlDoc {
3267 let doc = unsafe { html::new_doc(ptr::null()) };
3268 if doc.is_null() {
3269 return ptr::null_mut();
3270 }
3271 unsafe {
3272 (*doc).standalone = 1;
3275 (*doc).charset = crate::abi::types::xmlCharEncoding::XML_CHAR_ENCODING_UTF8 as c_int;
3276 (*doc).properties = crate::abi::types::xmlDocProperties::XML_DOC_HTML as c_int
3277 | crate::abi::types::xmlDocProperties::XML_DOC_USERBUILT as c_int;
3278 if URI.is_null() && ExternalID.is_null() {
3279 let dtd = crate::xml::dtd::create_int_subset(
3280 doc,
3281 b"html\0" as *const u8 as *const xmlChar,
3282 b"-//W3C//DTD HTML 4.0 Transitional//EN\0" as *const u8 as *const xmlChar,
3283 b"http://www.w3.org/TR/REC-html40/loose.dtd\0" as *const u8 as *const xmlChar,
3284 );
3285 if dtd.is_null() {
3286 tree::free_doc(doc);
3287 return ptr::null_mut();
3288 }
3289 } else if !ExternalID.is_null() || !URI.is_null() {
3290 let dtd = crate::xml::dtd::create_int_subset(
3291 doc,
3292 b"html\0" as *const u8 as *const xmlChar,
3293 ExternalID,
3294 URI,
3295 );
3296 if dtd.is_null() {
3297 tree::free_doc(doc);
3298 return ptr::null_mut();
3299 }
3300 }
3301 }
3302 doc
3303}
3304
3305unsafe fn html_find_first_child(node: *mut _xmlNode, name: &[u8]) -> *mut _xmlNode {
3311 let mut c = unsafe { (*node).children };
3312 while !c.is_null() {
3313 let n = unsafe { &*c };
3314 if n.type_ == XML_ELEMENT_NODE as c_int
3315 && !n.name.is_null()
3316 && unsafe { xmlstr_to_bytes(n.name) }.eq_ignore_ascii_case(name)
3317 {
3318 return c;
3319 }
3320 c = unsafe { (*c).next };
3321 }
3322 ptr::null_mut()
3323}
3324
3325unsafe fn html_find_head(doc: *mut _xmlDoc) -> *mut _xmlNode {
3328 if doc.is_null() {
3329 return ptr::null_mut();
3330 }
3331 let html = unsafe { html_find_first_child(doc as *mut _xmlNode, b"html") };
3332 if html.is_null() {
3333 return ptr::null_mut();
3334 }
3335 unsafe { html_find_first_child(html, b"head") }
3336}
3337
3338unsafe fn html_find_meta_encoding_attr(elem: *mut _xmlNode) -> (*mut _xmlAttr, bool) {
3341 let n = unsafe { &*elem };
3342 if n.type_ != XML_ELEMENT_NODE as c_int || n.name.is_null() {
3343 return (ptr::null_mut(), false);
3344 }
3345 if !unsafe { xmlstr_to_bytes(n.name) }.eq_ignore_ascii_case(b"meta") {
3346 return (ptr::null_mut(), false);
3347 }
3348
3349 let mut content_attr: *mut _xmlAttr = ptr::null_mut();
3350 let mut is_content_type = false;
3351 let mut attr = n.properties;
3352 while !attr.is_null() {
3353 let a = unsafe { &*attr };
3354 if a.ns.is_null() && !a.name.is_null() {
3355 let nm = unsafe { xmlstr_to_bytes(a.name) };
3356 if nm.eq_ignore_ascii_case(b"charset") {
3357 return (attr, false);
3358 }
3359 if nm.eq_ignore_ascii_case(b"content") {
3360 content_attr = attr;
3361 }
3362 if nm.eq_ignore_ascii_case(b"http-equiv")
3363 && !a.children.is_null()
3364 && unsafe { (*(a.children)).type_ } == XML_TEXT_NODE as c_int
3365 && unsafe { (*(a.children)).next }.is_null()
3366 && !unsafe { (*(a.children)).content }.is_null()
3367 && unsafe { xmlstr_to_bytes((*(a.children)).content) }
3368 .eq_ignore_ascii_case(b"Content-Type")
3369 {
3370 is_content_type = true;
3371 }
3372 }
3373 attr = unsafe { (*attr).next };
3374 }
3375 if is_content_type && !content_attr.is_null() {
3376 (content_attr, true)
3377 } else {
3378 (ptr::null_mut(), false)
3379 }
3380}
3381
3382unsafe fn html_parse_content_type(val: *const xmlChar) -> Option<(usize, usize, usize)> {
3385 let bytes = unsafe { xmlstr_to_bytes(val) };
3386 let n = bytes.len();
3387 let at = |i: usize| -> u8 {
3388 if i < n {
3389 bytes[i]
3390 } else {
3391 0
3392 }
3393 };
3394
3395 let mut p = 0usize;
3396 loop {
3397 loop {
3399 let ch = at(p);
3400 if ch == b'c' || ch == b'C' {
3401 break;
3402 }
3403 if ch == 0 {
3404 return None;
3405 }
3406 p += 1;
3407 }
3408 p += 1;
3409
3410 let mut ok = true;
3412 for (k, want) in b"harset".iter().enumerate() {
3413 if at(p + k).to_ascii_lowercase() != *want {
3414 ok = false;
3415 break;
3416 }
3417 }
3418 if !ok {
3419 continue;
3420 }
3421 p += 6;
3422 while is_ws_html(at(p)) {
3423 p += 1;
3424 }
3425 if at(p) != b'=' {
3426 continue;
3427 }
3428 p += 1;
3429 while is_ws_html(at(p)) {
3430 p += 1;
3431 }
3432 if at(p) == 0 {
3433 return None;
3434 }
3435
3436 let (start, mut end): (usize, usize);
3437 if at(p) == b'"' || at(p) == b'\'' {
3438 let quote = at(p);
3439 p += 1;
3440 while is_ws_html(at(p)) {
3441 p += 1;
3442 }
3443 start = p;
3444 end = start;
3445 loop {
3446 if at(p) == 0 {
3447 return None;
3448 }
3449 if !is_ws_html(at(p)) {
3450 end = p + 1;
3451 }
3452 if at(p) == quote {
3453 break;
3454 }
3455 p += 1;
3456 }
3457 } else {
3458 start = p;
3459 while at(p) != 0 && at(p) != b';' && !is_ws_html(at(p)) {
3460 p += 1;
3461 }
3462 end = p;
3463 }
3464 let size = n;
3465 return Some((start, end, size));
3466 }
3467}
3468
3469#[no_mangle]
3481pub unsafe extern "C" fn htmlGetMetaEncoding(doc: *mut _xmlDoc) -> *const xmlChar {
3482 let head = unsafe { html_find_head(doc) };
3483 if head.is_null() {
3484 return ptr::null();
3485 }
3486 let mut node = unsafe { (*head).children };
3487 while !node.is_null() {
3488 let (attr, is_content_type) = unsafe { html_find_meta_encoding_attr(node) };
3489 if !attr.is_null() {
3490 let a = unsafe { &*attr };
3491 let val = if !a.children.is_null()
3492 && unsafe { (*(a.children)).type_ } == XML_TEXT_NODE as c_int
3493 && unsafe { (*(a.children)).next }.is_null()
3494 && !unsafe { (*(a.children)).content }.is_null()
3495 {
3496 unsafe { (*(a.children)).content }
3497 } else {
3498 b"\0" as *const u8 as *const xmlChar
3499 };
3500 if !is_content_type {
3501 let bytes = unsafe { xmlstr_to_bytes(val) };
3502 let mut start = 0usize;
3503 while start < bytes.len() && is_ws_html(bytes[start]) {
3504 start += 1;
3505 }
3506 return unsafe { val.add(start) };
3507 } else if let Some((start, _, _)) = unsafe { html_parse_content_type(val) } {
3508 return unsafe { val.add(start) };
3509 }
3510 }
3511 node = unsafe { (*node).next };
3512 }
3513 ptr::null()
3514}
3515
3516unsafe fn html_update_meta_encoding(
3519 attr_value: *const xmlChar,
3520 start: usize,
3521 end: usize,
3522 size: usize,
3523 encoding: &[u8],
3524) -> *mut xmlChar {
3525 let enc: &[u8] = if encoding.eq_ignore_ascii_case(b"HTML") {
3527 b"ASCII"
3528 } else {
3529 encoding
3530 };
3531 let bytes = unsafe { xmlstr_to_bytes(attr_value) };
3532 let e = end.min(bytes.len()).min(size);
3533 let s = start.min(e);
3534 let total = size - (e - s) + enc.len();
3535 let new_val = xmlMallocImpl(total + 1) as *mut xmlChar;
3536 if new_val.is_null() {
3537 return ptr::null_mut();
3538 }
3539 unsafe {
3540 let mut p = new_val;
3541 ptr::copy_nonoverlapping(bytes.as_ptr(), p, s);
3542 p = p.add(s);
3543 ptr::copy_nonoverlapping(enc.as_ptr(), p, enc.len());
3544 p = p.add(enc.len());
3545 ptr::copy_nonoverlapping(bytes.as_ptr().add(e), p, size - e);
3546 *new_val.add(total) = 0;
3547 }
3548 new_val
3549}
3550
3551unsafe fn html_set_attr_content(attr: *mut _xmlAttr, content: *const xmlChar) -> c_int {
3554 if attr.is_null() {
3555 return -1;
3556 }
3557 unsafe {
3558 if !(*attr).children.is_null() {
3559 tree::free_node_list((*attr).children);
3560 (*attr).children = ptr::null_mut();
3561 (*attr).last = ptr::null_mut();
3562 }
3563 let text = tree::new_text(content);
3564 if text.is_null() {
3565 return -1;
3566 }
3567 (*text).parent = attr as *mut _xmlNode;
3568 (*text).doc = (*attr).doc;
3569 (*attr).children = text;
3570 (*attr).last = text;
3571 }
3572 0
3573}
3574
3575#[no_mangle]
3583pub unsafe extern "C" fn htmlSetMetaEncoding(doc: *mut _xmlDoc, encoding: *const xmlChar) -> c_int {
3584 if encoding.is_null() {
3585 return 1;
3586 }
3587 let head = unsafe { html_find_head(doc) };
3588 if head.is_null() {
3589 return 1;
3590 }
3591 let enc_bytes = unsafe { xmlstr_to_bytes(encoding) }.to_vec();
3592
3593 let mut found = 0;
3594 let mut meta = unsafe { (*head).children };
3595 while !meta.is_null() {
3596 let (attr, is_content_type) = unsafe { html_find_meta_encoding_attr(meta) };
3597 if !attr.is_null() {
3598 let a = unsafe { &*attr };
3599 let val = if !a.children.is_null()
3600 && unsafe { (*(a.children)).type_ } == XML_TEXT_NODE as c_int
3601 && unsafe { (*(a.children)).next }.is_null()
3602 && !unsafe { (*(a.children)).content }.is_null()
3603 {
3604 unsafe { (*(a.children)).content }
3605 } else {
3606 b"\0" as *const u8 as *const xmlChar
3607 };
3608 found = 1;
3609 let off = if is_content_type {
3610 unsafe { html_parse_content_type(val) }
3611 } else {
3612 let bytes = unsafe { xmlstr_to_bytes(val) };
3613 let mut start = 0usize;
3614 let mut end = bytes.len();
3615 while start < end && is_ws_html(bytes[start]) {
3616 start += 1;
3617 }
3618 while end > start && is_ws_html(bytes[end - 1]) {
3619 end -= 1;
3620 }
3621 Some((start, end, bytes.len()))
3622 };
3623 if let Some((start, end, size)) = off {
3624 let new_val =
3625 unsafe { html_update_meta_encoding(val, start, end, size, &enc_bytes) };
3626 if new_val.is_null() {
3627 return -1;
3628 }
3629 let ret = unsafe { html_set_attr_content(attr, new_val) };
3630 unsafe { xmlFreeImpl(new_val as *mut c_void) };
3631 if ret < 0 {
3632 return -1;
3633 }
3634 } else {
3635 return -1;
3636 }
3637 }
3638 meta = unsafe { (*meta).next };
3639 }
3640
3641 if found != 0 {
3642 return 0;
3643 }
3644
3645 let meta_node =
3647 unsafe { tree::new_node(ptr::null_mut(), b"meta\0" as *const u8 as *const xmlChar) };
3648 if meta_node.is_null() {
3649 return -1;
3650 }
3651 unsafe {
3652 (*meta_node).doc = (*head).doc;
3653 }
3654 let prop = unsafe {
3655 tree::set_prop(
3656 meta_node,
3657 b"charset\0" as *const u8 as *const xmlChar,
3658 encoding,
3659 )
3660 };
3661 if prop.is_null() {
3662 unsafe { tree::free_node(meta_node) };
3663 return -1;
3664 }
3665 if unsafe { (*head).children }.is_null() {
3666 unsafe { tree::add_child(head, meta_node) };
3667 } else {
3668 unsafe { tree::add_sibling_before((*head).children, meta_node) };
3669 }
3670 0
3671}
3672
3673unsafe fn html_serialize_to_buffer(node: *mut _xmlNode, format: c_int) -> *mut _xmlBuffer {
3680 let buf = io::buf_create(0);
3681 if buf.is_null() {
3682 return ptr::null_mut();
3683 }
3684 unsafe { html::serialize_node(node, buf, format, 0) };
3685 buf
3686}
3687
3688unsafe fn html_serialize_to_obuf(obuf: *mut _xmlOutputBuffer, node: *mut _xmlNode, format: c_int) {
3691 if obuf.is_null() || node.is_null() {
3692 return;
3693 }
3694 let buf = unsafe { html_serialize_to_buffer(node, format) };
3695 if buf.is_null() {
3696 return;
3697 }
3698 let len = io::buf_length(buf);
3699 if len > 0 {
3700 let content = io::buf_content(buf);
3701 unsafe {
3702 io::output_buffer_write(obuf, len, content as *const c_char);
3703 }
3704 }
3705 io::buf_free(buf);
3706}
3707
3708#[no_mangle]
3716pub unsafe extern "C" fn htmlNodeDump(
3717 buf: *mut _xmlBuffer,
3718 _doc: *mut _xmlDoc,
3719 cur: *mut _xmlNode,
3720) -> c_int {
3721 if buf.is_null() || cur.is_null() {
3722 return -1;
3723 }
3724 let before = io::buf_length(buf);
3725 unsafe { html::serialize_node(cur, buf, 1, 0) };
3726 let after = io::buf_length(buf);
3727 if after < 0 || before < 0 {
3728 return -1;
3729 }
3730 after - before
3731}
3732
3733#[no_mangle]
3741pub unsafe extern "C" fn htmlNodeDumpFile(out: *mut c_void, doc: *mut _xmlDoc, cur: *mut _xmlNode) {
3742 unsafe { htmlNodeDumpFileFormat(out, doc, cur, ptr::null(), 1) };
3743}
3744
3745#[no_mangle]
3754pub unsafe extern "C" fn htmlNodeDumpFileFormat(
3755 out: *mut c_void,
3756 _doc: *mut _xmlDoc,
3757 cur: *mut _xmlNode,
3758 _encoding: *const c_char,
3759 format: c_int,
3760) -> c_int {
3761 let obuf = io::output_buffer_create_file(out as *mut libc::FILE, ptr::null_mut());
3762 if obuf.is_null() {
3763 return -1;
3764 }
3765 unsafe { html_serialize_to_obuf(obuf, cur, format) };
3766 io::output_buffer_close(obuf)
3767}
3768
3769#[no_mangle]
3778pub unsafe extern "C" fn htmlNodeDumpOutput(
3779 buf: *mut _xmlOutputBuffer,
3780 _doc: *mut _xmlDoc,
3781 cur: *mut _xmlNode,
3782 _encoding: *const c_char,
3783) {
3784 unsafe { html_serialize_to_obuf(buf, cur, 1) };
3785}
3786
3787#[no_mangle]
3796pub unsafe extern "C" fn htmlNodeDumpFormatOutput(
3797 buf: *mut _xmlOutputBuffer,
3798 _doc: *mut _xmlDoc,
3799 cur: *mut _xmlNode,
3800 _encoding: *const c_char,
3801 format: c_int,
3802) {
3803 unsafe { html_serialize_to_obuf(buf, cur, format) };
3804}
3805
3806#[no_mangle]
3815pub unsafe extern "C" fn htmlDocContentDumpOutput(
3816 buf: *mut _xmlOutputBuffer,
3817 cur: *mut _xmlDoc,
3818 _encoding: *const c_char,
3819) {
3820 unsafe { html_serialize_to_obuf(buf, cur as *mut _xmlNode, 1) };
3821}
3822
3823#[no_mangle]
3832pub unsafe extern "C" fn htmlDocContentDumpFormatOutput(
3833 buf: *mut _xmlOutputBuffer,
3834 cur: *mut _xmlDoc,
3835 _encoding: *const c_char,
3836 format: c_int,
3837) {
3838 unsafe { html_serialize_to_obuf(buf, cur as *mut _xmlNode, format) };
3839}
3840
3841#[no_mangle]
3851pub unsafe extern "C" fn htmlDocDumpMemoryFormat(
3852 cur: *mut _xmlDoc,
3853 mem: *mut *mut xmlChar,
3854 size: *mut c_int,
3855 format: c_int,
3856) {
3857 if mem.is_null() || size.is_null() {
3858 return;
3859 }
3860 unsafe {
3861 *mem = ptr::null_mut();
3862 *size = 0;
3863 }
3864 if cur.is_null() {
3865 return;
3866 }
3867 let buf = unsafe { html_serialize_to_buffer(cur as *mut _xmlNode, format) };
3868 if buf.is_null() {
3869 return;
3870 }
3871 let len = io::buf_length(buf);
3872 if len > 0 {
3873 let content = io::buf_content(buf);
3874 unsafe {
3875 *mem = xml_strndup(content, len as usize);
3876 if !(*mem).is_null() {
3877 *size = len;
3878 }
3879 }
3880 }
3881 io::buf_free(buf);
3882}
3883
3884#[no_mangle]
3892pub unsafe extern "C" fn htmlDocDumpMemory(
3893 cur: *mut _xmlDoc,
3894 mem: *mut *mut xmlChar,
3895 size: *mut c_int,
3896) {
3897 unsafe { htmlDocDumpMemoryFormat(cur, mem, size, 1) };
3898}
3899
3900#[no_mangle]
3908pub unsafe extern "C" fn htmlDocDump(f: *mut c_void, cur: *mut _xmlDoc) -> c_int {
3909 if f.is_null() || cur.is_null() {
3910 return -1;
3911 }
3912 let obuf = io::output_buffer_create_file(f as *mut libc::FILE, ptr::null_mut());
3913 if obuf.is_null() {
3914 return -1;
3915 }
3916 unsafe { html_serialize_to_obuf(obuf, cur as *mut _xmlNode, 1) };
3917 io::output_buffer_close(obuf)
3918}
3919
3920#[no_mangle]
3929pub unsafe extern "C" fn htmlSaveFileFormat(
3930 filename: *const c_char,
3931 cur: *mut _xmlDoc,
3932 _encoding: *const c_char,
3933 format: c_int,
3934) -> c_int {
3935 if cur.is_null() || filename.is_null() {
3936 return -1;
3937 }
3938 let obuf = io::output_buffer_create_filename(filename, ptr::null_mut(), 0);
3939 if obuf.is_null() {
3940 return 0;
3942 }
3943 unsafe { html_serialize_to_obuf(obuf, cur as *mut _xmlNode, format) };
3944 io::output_buffer_close(obuf)
3945}
3946
3947#[no_mangle]
3956pub unsafe extern "C" fn htmlSaveFile(filename: *const c_char, cur: *mut _xmlDoc) -> c_int {
3957 unsafe { htmlSaveFileFormat(filename, cur, ptr::null(), 1) }
3958}
3959
3960#[no_mangle]
3968pub unsafe extern "C" fn htmlSaveFileEnc(
3969 filename: *const c_char,
3970 cur: *mut _xmlDoc,
3971 encoding: *const c_char,
3972) -> c_int {
3973 unsafe { htmlSaveFileFormat(filename, cur, encoding, 1) }
3974}
3975
3976#[no_mangle]
3984pub unsafe extern "C" fn htmlCtxtSetOptions(ctxt: *mut c_void, options: c_int) -> c_int {
3985 if ctxt.is_null() {
3986 return -1;
3987 }
3988 let c = ctxt as *mut HtmlOpaqueCtxt;
3989 unsafe {
3990 (*c).options = options & HTML_OPTIONS_ALL_MASK;
3991 }
3992 options & !HTML_OPTIONS_ALL_MASK & !crate::abi::types::XML_PARSE_NOENT
3993}
3994
3995#[no_mangle]
4005pub unsafe extern "C" fn htmlUTF8ToHtml(
4006 out: *mut u8,
4007 outlen: *mut c_int,
4008 input: *const u8,
4009 inlen: *mut c_int,
4010) -> c_int {
4011 const XML_ENC_ERR_INTERNAL: c_int = -1;
4013 const XML_ENC_ERR_SUCCESS: c_int = 0;
4014 const XML_ENC_ERR_SPACE: c_int = -2;
4015 unsafe {
4016 if out.is_null() || outlen.is_null() || inlen.is_null() {
4017 return XML_ENC_ERR_INTERNAL;
4018 }
4019 if input.is_null() {
4020 *outlen = 0;
4021 *inlen = 0;
4022 return XML_ENC_ERR_SUCCESS;
4023 }
4024 let mut in_pos: usize = 0;
4025 let mut out_pos: usize = 0;
4026 let in_end = *inlen as usize;
4027 let out_cap = *outlen as usize;
4028 let mut ret = XML_ENC_ERR_SPACE;
4029 while in_pos < in_end {
4030 let d = *input.add(in_pos);
4031 if d < 0x80 {
4032 if out_pos >= out_cap {
4033 break;
4034 }
4035 *out.add(out_pos) = d;
4036 out_pos += 1;
4037 in_pos += 1;
4038 continue;
4039 }
4040 let (mut c, seqlen) = if d < 0xE0 {
4041 ((d & 0x1F) as u32, 2usize)
4042 } else if d < 0xF0 {
4043 ((d & 0x0F) as u32, 3usize)
4044 } else {
4045 ((d & 0x07) as u32, 4usize)
4046 };
4047 if in_end - in_pos < seqlen {
4048 break;
4049 }
4050 for i in 1..seqlen {
4051 let dd = *input.add(in_pos + i);
4052 c = (c << 6) | ((dd & 0x3F) as u32);
4053 }
4054 let ent = htmlEntityValueLookup(c);
4055 let mut nbuf = [0u8; 16];
4056 let cp: *const u8;
4057 let mut owned_len: usize = 0;
4058 if ent.is_null() {
4059 let s = format!("#{}", c);
4060 let bytes = s.as_bytes();
4061 nbuf[..bytes.len()].copy_from_slice(bytes);
4062 cp = nbuf.as_ptr();
4063 owned_len = bytes.len();
4064 } else {
4065 cp = (*ent).name as *const u8;
4066 let mut l = 0;
4067 while *cp.add(l) != 0 {
4068 l += 1;
4069 }
4070 owned_len = l;
4071 }
4072 let len = owned_len;
4073 if out_cap - out_pos < len + 2 {
4074 break;
4075 }
4076 *out.add(out_pos) = b'&';
4077 out_pos += 1;
4078 core::ptr::copy_nonoverlapping(cp, out.add(out_pos), len);
4079 out_pos += len;
4080 *out.add(out_pos) = b';';
4081 out_pos += 1;
4082 in_pos += seqlen;
4083 }
4084 ret = out_pos as c_int;
4085 *outlen = out_pos as c_int;
4086 *inlen = in_pos as c_int;
4087 ret
4088 }
4089}