1#![allow(
39 missing_docs,
40 non_snake_case,
41 non_camel_case_types,
42 non_upper_case_globals
43)]
44#![allow(unused_variables)]
45#![allow(private_interfaces)]
46#![allow(unused_assignments)]
47#![allow(unused_unsafe)]
48#![allow(clippy::missing_safety_doc)]
49#![allow(clippy::not_unsafe_ptr_arg_deref)]
50
51use core::ffi::c_void;
52use core::ptr;
53use core::sync::atomic::{AtomicBool, AtomicI32, Ordering};
54use std::mem::size_of;
55use std::os::raw::{c_char, c_int, c_uint};
56
57use crate::abi::allocator::{xmlFreeImpl, xmlMallocImpl, xmlMallocZero, xmlReallocImpl};
58use crate::abi::callbacks::{xmlInputCloseCallback, xmlInputReadCallback};
59use crate::abi::structs::*;
60use crate::abi::types::xmlChar;
61use crate::abi::types::xmlCharEncoding;
62use crate::abi::types::xmlElementType::*;
63use crate::xml::html;
64use crate::xml::io;
65use crate::xml::string::{c_strdup, xml_strcmp, xml_strlen, xml_strndup, xmlstr_to_bytes};
66use crate::xml::tree;
67
68const HTML_PARSE_RECOVER: c_int = 1 << 0;
73const HTML_PARSE_NODEFDTD: c_int = 1 << 2;
74const HTML_PARSE_NOERROR: c_int = 1 << 5;
75const HTML_PARSE_NOWARNING: c_int = 1 << 6;
76const HTML_PARSE_PEDANTIC: c_int = 1 << 7;
77const HTML_PARSE_NOBLANKS: c_int = 1 << 8;
78const HTML_PARSE_NONET: c_int = 1 << 11;
79const HTML_PARSE_NOIMPLIED: c_int = 1 << 13;
80const HTML_PARSE_COMPACT: c_int = 1 << 16;
81const HTML_PARSE_HUGE: c_int = 1 << 19;
82const HTML_PARSE_IGNORE_ENC: c_int = 1 << 21;
83const HTML_PARSE_BIG_LINES: c_int = 1 << 22;
84const HTML_PARSE_HTML5: c_int = 1 << 26;
85
86const HTML_OPTIONS_KEEP_MASK: c_int = HTML_PARSE_NODEFDTD
88 | HTML_PARSE_NOERROR
89 | HTML_PARSE_NOWARNING
90 | HTML_PARSE_NOIMPLIED
91 | HTML_PARSE_COMPACT
92 | HTML_PARSE_HUGE
93 | HTML_PARSE_IGNORE_ENC
94 | HTML_PARSE_BIG_LINES;
95
96const HTML_OPTIONS_ALL_MASK: c_int = HTML_PARSE_RECOVER
98 | HTML_PARSE_HTML5
99 | HTML_PARSE_NODEFDTD
100 | HTML_PARSE_NOERROR
101 | HTML_PARSE_NOWARNING
102 | HTML_PARSE_PEDANTIC
103 | HTML_PARSE_NOBLANKS
104 | HTML_PARSE_NONET
105 | HTML_PARSE_NOIMPLIED
106 | HTML_PARSE_COMPACT
107 | HTML_PARSE_HUGE
108 | HTML_PARSE_IGNORE_ENC
109 | HTML_PARSE_BIG_LINES;
110
111const XML_ERR_OK: c_int = 0;
113const XML_ERR_NO_MEMORY: c_int = 2;
114const XML_ERR_ARGUMENT: c_int = 115;
115
116const HTML_VALID: c_int = 0x4;
118
119const DATA_NEUTRAL: c_int = 0;
121const DATA_RCDATA: c_int = 1;
122const DATA_RAWTEXT: c_int = 2;
123const DATA_PLAINTEXT: c_int = 3;
124const DATA_SCRIPT: c_int = 4;
125
126#[inline]
128const fn is_ws_html(c: u8) -> bool {
129 c == 0x20 || (c >= 0x09 && c <= 0x0d && c != 0x0b)
130}
131
132#[derive(Debug)]
141#[repr(C)]
142pub struct _htmlElemDesc {
143 pub name: *const c_char,
144 pub startTag: c_char,
145 pub endTag: c_char,
146 pub saveEndTag: c_char,
147 pub empty: c_char,
148 pub depr: c_char,
149 pub dtd: c_char,
150 pub isinline: c_char,
151 pub desc: *const c_char,
152 pub subelts: *const *const c_char,
153 pub defaultsubelt: *const c_char,
154 pub attrs_opt: *const *const c_char,
155 pub attrs_depr: *const *const c_char,
156 pub attrs_req: *const *const c_char,
157 pub dataMode: c_int,
158}
159
160unsafe impl Sync for _htmlElemDesc {}
162unsafe impl Send for _htmlElemDesc {}
163
164macro_rules! elem {
168 ($name:literal, $startTag:expr, $endTag:expr, $saveEndTag:expr, $empty:expr, $depr:expr, $dtd:expr, $isinline:expr, $desc:literal, $dataMode:expr) => {
169 _htmlElemDesc {
170 name: concat!($name, "\0").as_ptr() as *const c_char,
171 startTag: $startTag,
172 endTag: $endTag,
173 saveEndTag: $saveEndTag,
174 empty: $empty,
175 depr: $depr,
176 dtd: $dtd,
177 isinline: $isinline,
178 desc: concat!($desc, "\0").as_ptr() as *const c_char,
179 subelts: ptr::null(),
180 defaultsubelt: ptr::null(),
181 attrs_opt: ptr::null(),
182 attrs_depr: ptr::null(),
183 attrs_req: ptr::null(),
184 dataMode: $dataMode,
185 }
186 };
187}
188
189static HTML40_ELEMENTS: &[_htmlElemDesc] = &[
192 elem!("a", 0, 0, 0, 0, 0, 0, 1, "anchor ", DATA_NEUTRAL),
193 elem!(
194 "abbr",
195 0,
196 0,
197 0,
198 0,
199 0,
200 0,
201 1,
202 "abbreviated form",
203 DATA_NEUTRAL
204 ),
205 elem!("acronym", 0, 0, 0, 0, 0, 0, 1, "", DATA_NEUTRAL),
206 elem!(
207 "address",
208 0,
209 0,
210 0,
211 0,
212 0,
213 0,
214 0,
215 "information on author ",
216 DATA_NEUTRAL
217 ),
218 elem!("applet", 0, 0, 0, 0, 1, 1, 2, "java applet ", DATA_NEUTRAL),
219 elem!(
220 "area",
221 0,
222 2,
223 2,
224 1,
225 0,
226 0,
227 0,
228 "client-side image map area ",
229 DATA_NEUTRAL
230 ),
231 elem!("b", 0, 3, 0, 0, 0, 0, 1, "bold text style", DATA_NEUTRAL),
232 elem!(
233 "base",
234 0,
235 2,
236 2,
237 1,
238 0,
239 0,
240 0,
241 "document base uri ",
242 DATA_NEUTRAL
243 ),
244 elem!(
245 "basefont",
246 0,
247 2,
248 2,
249 1,
250 1,
251 1,
252 1,
253 "base font size ",
254 DATA_NEUTRAL
255 ),
256 elem!(
257 "bdo",
258 0,
259 0,
260 0,
261 0,
262 0,
263 0,
264 1,
265 "i18n bidi over-ride ",
266 DATA_NEUTRAL
267 ),
268 elem!("bgsound", 0, 0, 2, 1, 0, 0, 0, "", DATA_NEUTRAL),
269 elem!("big", 0, 3, 0, 0, 0, 0, 1, "large text style", DATA_NEUTRAL),
270 elem!(
271 "blockquote",
272 0,
273 0,
274 0,
275 0,
276 0,
277 0,
278 0,
279 "long quotation ",
280 DATA_NEUTRAL
281 ),
282 elem!("body", 1, 1, 0, 0, 0, 0, 0, "document body ", DATA_NEUTRAL),
283 elem!(
284 "br",
285 0,
286 2,
287 2,
288 1,
289 0,
290 0,
291 1,
292 "forced line break ",
293 DATA_NEUTRAL
294 ),
295 elem!("button", 0, 0, 0, 0, 0, 0, 2, "push button ", DATA_NEUTRAL),
296 elem!(
297 "caption",
298 0,
299 0,
300 0,
301 0,
302 0,
303 0,
304 0,
305 "table caption ",
306 DATA_NEUTRAL
307 ),
308 elem!(
309 "center",
310 0,
311 3,
312 0,
313 0,
314 1,
315 1,
316 0,
317 "shorthand for div align=center ",
318 DATA_NEUTRAL
319 ),
320 elem!("cite", 0, 0, 0, 0, 0, 0, 1, "citation", DATA_NEUTRAL),
321 elem!(
322 "code",
323 0,
324 0,
325 0,
326 0,
327 0,
328 0,
329 1,
330 "computer code fragment",
331 DATA_NEUTRAL
332 ),
333 elem!("col", 0, 2, 2, 1, 0, 0, 0, "table column ", DATA_NEUTRAL),
334 elem!(
335 "colgroup",
336 0,
337 1,
338 0,
339 0,
340 0,
341 0,
342 0,
343 "table column group ",
344 DATA_NEUTRAL
345 ),
346 elem!(
347 "dd",
348 0,
349 1,
350 0,
351 0,
352 0,
353 0,
354 0,
355 "definition description ",
356 DATA_NEUTRAL
357 ),
358 elem!("del", 0, 0, 0, 0, 0, 0, 2, "deleted text ", DATA_NEUTRAL),
359 elem!(
360 "dfn",
361 0,
362 0,
363 0,
364 0,
365 0,
366 0,
367 1,
368 "instance definition",
369 DATA_NEUTRAL
370 ),
371 elem!("dir", 0, 0, 0, 0, 1, 1, 0, "directory list", DATA_NEUTRAL),
372 elem!(
373 "div",
374 0,
375 0,
376 0,
377 0,
378 0,
379 0,
380 0,
381 "generic language/style container",
382 DATA_NEUTRAL
383 ),
384 elem!("dl", 0, 0, 0, 0, 0, 0, 0, "definition list ", DATA_NEUTRAL),
385 elem!("dt", 0, 1, 0, 0, 0, 0, 0, "definition term ", DATA_NEUTRAL),
386 elem!("em", 0, 3, 0, 0, 0, 0, 1, "emphasis", DATA_NEUTRAL),
387 elem!(
388 "embed",
389 0,
390 1,
391 2,
392 1,
393 1,
394 1,
395 1,
396 "generic embedded object ",
397 DATA_NEUTRAL
398 ),
399 elem!(
400 "fieldset",
401 0,
402 0,
403 0,
404 0,
405 0,
406 0,
407 0,
408 "form control group ",
409 DATA_NEUTRAL
410 ),
411 elem!(
412 "font",
413 0,
414 3,
415 0,
416 0,
417 1,
418 1,
419 1,
420 "local change to font ",
421 DATA_NEUTRAL
422 ),
423 elem!(
424 "form",
425 0,
426 0,
427 0,
428 0,
429 0,
430 0,
431 0,
432 "interactive form ",
433 DATA_NEUTRAL
434 ),
435 elem!("frame", 0, 2, 2, 1, 0, 2, 0, "subwindow ", DATA_NEUTRAL),
436 elem!(
437 "frameset",
438 0,
439 0,
440 0,
441 0,
442 0,
443 2,
444 0,
445 "window subdivision",
446 DATA_NEUTRAL
447 ),
448 elem!("h1", 0, 0, 0, 0, 0, 0, 0, "heading ", DATA_NEUTRAL),
449 elem!("h2", 0, 0, 0, 0, 0, 0, 0, "heading ", DATA_NEUTRAL),
450 elem!("h3", 0, 0, 0, 0, 0, 0, 0, "heading ", DATA_NEUTRAL),
451 elem!("h4", 0, 0, 0, 0, 0, 0, 0, "heading ", DATA_NEUTRAL),
452 elem!("h5", 0, 0, 0, 0, 0, 0, 0, "heading ", DATA_NEUTRAL),
453 elem!("h6", 0, 0, 0, 0, 0, 0, 0, "heading ", DATA_NEUTRAL),
454 elem!("head", 1, 1, 0, 0, 0, 0, 0, "document head ", DATA_NEUTRAL),
455 elem!("hr", 0, 2, 2, 1, 0, 0, 0, "horizontal rule ", DATA_NEUTRAL),
456 elem!(
457 "html",
458 1,
459 1,
460 0,
461 0,
462 0,
463 0,
464 0,
465 "document root element ",
466 DATA_NEUTRAL
467 ),
468 elem!("i", 0, 3, 0, 0, 0, 0, 1, "italic text style", DATA_NEUTRAL),
469 elem!(
470 "iframe",
471 0,
472 0,
473 0,
474 0,
475 0,
476 1,
477 2,
478 "inline subwindow ",
479 DATA_RAWTEXT
480 ),
481 elem!("img", 0, 2, 2, 1, 0, 0, 1, "embedded image ", DATA_NEUTRAL),
482 elem!("input", 0, 2, 2, 1, 0, 0, 1, "form control ", DATA_NEUTRAL),
483 elem!("ins", 0, 0, 0, 0, 0, 0, 2, "inserted text", DATA_NEUTRAL),
484 elem!(
485 "isindex",
486 0,
487 2,
488 2,
489 1,
490 1,
491 1,
492 0,
493 "single line prompt ",
494 DATA_NEUTRAL
495 ),
496 elem!(
497 "kbd",
498 0,
499 0,
500 0,
501 0,
502 0,
503 0,
504 1,
505 "text to be entered by the user",
506 DATA_NEUTRAL
507 ),
508 elem!("keygen", 0, 0, 2, 1, 0, 0, 0, "", DATA_NEUTRAL),
509 elem!(
510 "label",
511 0,
512 0,
513 0,
514 0,
515 0,
516 0,
517 1,
518 "form field label text ",
519 DATA_NEUTRAL
520 ),
521 elem!(
522 "legend",
523 0,
524 0,
525 0,
526 0,
527 0,
528 0,
529 0,
530 "fieldset legend ",
531 DATA_NEUTRAL
532 ),
533 elem!("li", 0, 1, 1, 0, 0, 0, 0, "list item ", DATA_NEUTRAL),
534 elem!(
535 "link",
536 0,
537 2,
538 2,
539 1,
540 0,
541 0,
542 0,
543 "a media-independent link ",
544 DATA_NEUTRAL
545 ),
546 elem!(
547 "map",
548 0,
549 0,
550 0,
551 0,
552 0,
553 0,
554 2,
555 "client-side image map ",
556 DATA_NEUTRAL
557 ),
558 elem!("menu", 0, 0, 0, 0, 1, 1, 0, "menu list ", DATA_NEUTRAL),
559 elem!(
560 "meta",
561 0,
562 2,
563 2,
564 1,
565 0,
566 0,
567 0,
568 "generic metainformation ",
569 DATA_NEUTRAL
570 ),
571 elem!("noembed", 0, 0, 0, 0, 0, 0, 0, "", DATA_RAWTEXT),
572 elem!(
573 "noframes",
574 0,
575 0,
576 0,
577 0,
578 0,
579 2,
580 0,
581 "alternate content container for non frame-based rendering ",
582 DATA_RAWTEXT
583 ),
584 elem!(
585 "noscript",
586 0,
587 0,
588 0,
589 0,
590 0,
591 0,
592 0,
593 "alternate content container for non script-based rendering ",
594 DATA_NEUTRAL
595 ),
596 elem!(
597 "object",
598 0,
599 0,
600 0,
601 0,
602 0,
603 0,
604 2,
605 "generic embedded object ",
606 DATA_NEUTRAL
607 ),
608 elem!("ol", 0, 0, 0, 0, 0, 0, 0, "ordered list ", DATA_NEUTRAL),
609 elem!(
610 "optgroup",
611 0,
612 0,
613 0,
614 0,
615 0,
616 0,
617 0,
618 "option group ",
619 DATA_NEUTRAL
620 ),
621 elem!(
622 "option",
623 0,
624 1,
625 0,
626 0,
627 0,
628 0,
629 0,
630 "selectable choice ",
631 DATA_NEUTRAL
632 ),
633 elem!("p", 0, 1, 0, 0, 0, 0, 0, "paragraph ", DATA_NEUTRAL),
634 elem!(
635 "param",
636 0,
637 2,
638 2,
639 1,
640 0,
641 0,
642 0,
643 "named property value ",
644 DATA_NEUTRAL
645 ),
646 elem!("plaintext", 0, 0, 0, 0, 0, 0, 0, "", DATA_PLAINTEXT),
647 elem!(
648 "pre",
649 0,
650 0,
651 0,
652 0,
653 0,
654 0,
655 0,
656 "preformatted text ",
657 DATA_NEUTRAL
658 ),
659 elem!(
660 "q",
661 0,
662 0,
663 0,
664 0,
665 0,
666 0,
667 1,
668 "short inline quotation ",
669 DATA_NEUTRAL
670 ),
671 elem!(
672 "s",
673 0,
674 3,
675 0,
676 0,
677 1,
678 1,
679 1,
680 "strike-through text style",
681 DATA_NEUTRAL
682 ),
683 elem!(
684 "samp",
685 0,
686 0,
687 0,
688 0,
689 0,
690 0,
691 1,
692 "sample program output, scripts, etc.",
693 DATA_NEUTRAL
694 ),
695 elem!(
696 "script",
697 0,
698 0,
699 0,
700 0,
701 0,
702 0,
703 2,
704 "script statements ",
705 DATA_SCRIPT
706 ),
707 elem!(
708 "select",
709 0,
710 0,
711 0,
712 0,
713 0,
714 0,
715 1,
716 "option selector ",
717 DATA_NEUTRAL
718 ),
719 elem!(
720 "small",
721 0,
722 3,
723 0,
724 0,
725 0,
726 0,
727 1,
728 "small text style",
729 DATA_NEUTRAL
730 ),
731 elem!("source", 0, 0, 2, 1, 0, 0, 0, "", DATA_NEUTRAL),
732 elem!(
733 "span",
734 0,
735 0,
736 0,
737 0,
738 0,
739 0,
740 1,
741 "generic language/style container ",
742 DATA_NEUTRAL
743 ),
744 elem!(
745 "strike",
746 0,
747 3,
748 0,
749 0,
750 1,
751 1,
752 1,
753 "strike-through text",
754 DATA_NEUTRAL
755 ),
756 elem!(
757 "strong",
758 0,
759 3,
760 0,
761 0,
762 0,
763 0,
764 1,
765 "strong emphasis",
766 DATA_NEUTRAL
767 ),
768 elem!("style", 0, 0, 0, 0, 0, 0, 0, "style info ", DATA_RAWTEXT),
769 elem!("sub", 0, 3, 0, 0, 0, 0, 1, "subscript", DATA_NEUTRAL),
770 elem!("sup", 0, 3, 0, 0, 0, 0, 1, "superscript ", DATA_NEUTRAL),
771 elem!("table", 0, 0, 0, 0, 0, 0, 0, "", DATA_NEUTRAL),
772 elem!("tbody", 1, 0, 0, 0, 0, 0, 0, "table body ", DATA_NEUTRAL),
773 elem!("td", 0, 0, 0, 0, 0, 0, 0, "table data cell", DATA_NEUTRAL),
774 elem!(
775 "textarea",
776 0,
777 0,
778 0,
779 0,
780 0,
781 0,
782 1,
783 "multi-line text field ",
784 DATA_RCDATA
785 ),
786 elem!("tfoot", 0, 1, 0, 0, 0, 0, 0, "table footer ", DATA_NEUTRAL),
787 elem!("th", 0, 1, 0, 0, 0, 0, 0, "table header cell", DATA_NEUTRAL),
788 elem!("thead", 0, 1, 0, 0, 0, 0, 0, "table header ", DATA_NEUTRAL),
789 elem!("title", 0, 0, 0, 0, 0, 0, 0, "document title ", DATA_RCDATA),
790 elem!("tr", 0, 0, 0, 0, 0, 0, 0, "table row ", DATA_NEUTRAL),
791 elem!("track", 0, 0, 2, 1, 0, 0, 0, "", DATA_NEUTRAL),
792 elem!(
793 "tt",
794 0,
795 3,
796 0,
797 0,
798 0,
799 0,
800 1,
801 "teletype or monospaced text style",
802 DATA_NEUTRAL
803 ),
804 elem!(
805 "u",
806 0,
807 3,
808 0,
809 0,
810 1,
811 1,
812 1,
813 "underlined text style",
814 DATA_NEUTRAL
815 ),
816 elem!("ul", 0, 0, 0, 0, 0, 0, 0, "unordered list ", DATA_NEUTRAL),
817 elem!(
818 "var",
819 0,
820 0,
821 0,
822 0,
823 0,
824 0,
825 1,
826 "instance of a variable or program argument",
827 DATA_NEUTRAL
828 ),
829 elem!("wbr", 0, 0, 2, 1, 0, 0, 0, "", DATA_NEUTRAL),
830 elem!("xmp", 0, 0, 0, 0, 0, 0, 1, "", DATA_RAWTEXT),
831];
832
833#[no_mangle]
845pub unsafe extern "C" fn htmlTagLookup(tag: *const xmlChar) -> *const _htmlElemDesc {
846 if tag.is_null() {
847 return ptr::null();
848 }
849 let bytes = unsafe { xmlstr_to_bytes(tag) };
850 for e in HTML40_ELEMENTS {
851 let name = unsafe { core::ffi::CStr::from_ptr(e.name) }.to_bytes();
852 if bytes.eq_ignore_ascii_case(name) {
853 return e as *const _htmlElemDesc;
854 }
855 }
856 ptr::null()
857}
858
859#[derive(Debug)]
865#[repr(C)]
866pub struct _htmlEntityDesc {
867 pub value: c_uint,
868 pub name: *const c_char,
869 pub desc: *const c_char,
870}
871
872unsafe impl Sync for _htmlEntityDesc {}
874unsafe impl Send for _htmlEntityDesc {}
875
876macro_rules! ent {
878 ($value:expr, $name:literal, $desc:literal) => {
879 _htmlEntityDesc {
880 value: $value,
881 name: concat!($name, "\0").as_ptr() as *const c_char,
882 desc: concat!($desc, "\0").as_ptr() as *const c_char,
883 }
884 };
885}
886
887static HTML40_ENTITIES: &[_htmlEntityDesc] = &[
891 ent!(34, "quot", "quotation mark = APL quote, U+0022 ISOnum"),
892 ent!(38, "amp", "ampersand, U+0026 ISOnum"),
893 ent!(39, "apos", "single quote"),
894 ent!(60, "lt", "less-than sign, U+003C ISOnum"),
895 ent!(62, "gt", "greater-than sign, U+003E ISOnum"),
896 ent!(
897 160,
898 "nbsp",
899 "no-break space = non-breaking space, U+00A0 ISOnum"
900 ),
901 ent!(161, "iexcl", "inverted exclamation mark, U+00A1 ISOnum"),
902 ent!(162, "cent", "cent sign, U+00A2 ISOnum"),
903 ent!(163, "pound", "pound sign, U+00A3 ISOnum"),
904 ent!(164, "curren", "currency sign, U+00A4 ISOnum"),
905 ent!(165, "yen", "yen sign = yuan sign, U+00A5 ISOnum"),
906 ent!(
907 166,
908 "brvbar",
909 "broken bar = broken vertical bar, U+00A6 ISOnum"
910 ),
911 ent!(167, "sect", "section sign, U+00A7 ISOnum"),
912 ent!(168, "uml", "diaeresis = spacing diaeresis, U+00A8 ISOdia"),
913 ent!(169, "copy", "copyright sign, U+00A9 ISOnum"),
914 ent!(170, "ordf", "feminine ordinal indicator, U+00AA ISOnum"),
915 ent!(
916 171,
917 "laquo",
918 "left-pointing double angle quotation mark = left pointing guillemet, U+00AB ISOnum"
919 ),
920 ent!(172, "not", "not sign, U+00AC ISOnum"),
921 ent!(
922 173,
923 "shy",
924 "soft hyphen = discretionary hyphen, U+00AD ISOnum"
925 ),
926 ent!(
927 174,
928 "reg",
929 "registered sign = registered trade mark sign, U+00AE ISOnum"
930 ),
931 ent!(
932 175,
933 "macr",
934 "macron = spacing macron = overline = APL overbar, U+00AF ISOdia"
935 ),
936 ent!(176, "deg", "degree sign, U+00B0 ISOnum"),
937 ent!(
938 177,
939 "plusmn",
940 "plus-minus sign = plus-or-minus sign, U+00B1 ISOnum"
941 ),
942 ent!(
943 178,
944 "sup2",
945 "superscript two = superscript digit two = squared, U+00B2 ISOnum"
946 ),
947 ent!(
948 179,
949 "sup3",
950 "superscript three = superscript digit three = cubed, U+00B3 ISOnum"
951 ),
952 ent!(180, "acute", "acute accent = spacing acute, U+00B4 ISOdia"),
953 ent!(181, "micro", "micro sign, U+00B5 ISOnum"),
954 ent!(182, "para", "pilcrow sign = paragraph sign, U+00B6 ISOnum"),
955 ent!(
956 183,
957 "middot",
958 "middle dot = Georgian comma Greek middle dot, U+00B7 ISOnum"
959 ),
960 ent!(184, "cedil", "cedilla = spacing cedilla, U+00B8 ISOdia"),
961 ent!(
962 185,
963 "sup1",
964 "superscript one = superscript digit one, U+00B9 ISOnum"
965 ),
966 ent!(186, "ordm", "masculine ordinal indicator, U+00BA ISOnum"),
967 ent!(
968 187,
969 "raquo",
970 "right-pointing double angle quotation mark right pointing guillemet, U+00BB ISOnum"
971 ),
972 ent!(
973 188,
974 "frac14",
975 "vulgar fraction one quarter = fraction one quarter, U+00BC ISOnum"
976 ),
977 ent!(
978 189,
979 "frac12",
980 "vulgar fraction one half = fraction one half, U+00BD ISOnum"
981 ),
982 ent!(
983 190,
984 "frac34",
985 "vulgar fraction three quarters = fraction three quarters, U+00BE ISOnum"
986 ),
987 ent!(
988 191,
989 "iquest",
990 "inverted question mark = turned question mark, U+00BF ISOnum"
991 ),
992 ent!(
993 192,
994 "Agrave",
995 "latin capital letter A with grave = latin capital letter A grave, U+00C0 ISOlat1"
996 ),
997 ent!(
998 193,
999 "Aacute",
1000 "latin capital letter A with acute, U+00C1 ISOlat1"
1001 ),
1002 ent!(
1003 194,
1004 "Acirc",
1005 "latin capital letter A with circumflex, U+00C2 ISOlat1"
1006 ),
1007 ent!(
1008 195,
1009 "Atilde",
1010 "latin capital letter A with tilde, U+00C3 ISOlat1"
1011 ),
1012 ent!(
1013 196,
1014 "Auml",
1015 "latin capital letter A with diaeresis, U+00C4 ISOlat1"
1016 ),
1017 ent!(
1018 197,
1019 "Aring",
1020 "latin capital letter A with ring above = latin capital letter A ring, U+00C5 ISOlat1"
1021 ),
1022 ent!(
1023 198,
1024 "AElig",
1025 "latin capital letter AE = latin capital ligature AE, U+00C6 ISOlat1"
1026 ),
1027 ent!(
1028 199,
1029 "Ccedil",
1030 "latin capital letter C with cedilla, U+00C7 ISOlat1"
1031 ),
1032 ent!(
1033 200,
1034 "Egrave",
1035 "latin capital letter E with grave, U+00C8 ISOlat1"
1036 ),
1037 ent!(
1038 201,
1039 "Eacute",
1040 "latin capital letter E with acute, U+00C9 ISOlat1"
1041 ),
1042 ent!(
1043 202,
1044 "Ecirc",
1045 "latin capital letter E with circumflex, U+00CA ISOlat1"
1046 ),
1047 ent!(
1048 203,
1049 "Euml",
1050 "latin capital letter E with diaeresis, U+00CB ISOlat1"
1051 ),
1052 ent!(
1053 204,
1054 "Igrave",
1055 "latin capital letter I with grave, U+00CC ISOlat1"
1056 ),
1057 ent!(
1058 205,
1059 "Iacute",
1060 "latin capital letter I with acute, U+00CD ISOlat1"
1061 ),
1062 ent!(
1063 206,
1064 "Icirc",
1065 "latin capital letter I with circumflex, U+00CE ISOlat1"
1066 ),
1067 ent!(
1068 207,
1069 "Iuml",
1070 "latin capital letter I with diaeresis, U+00CF ISOlat1"
1071 ),
1072 ent!(208, "ETH", "latin capital letter ETH, U+00D0 ISOlat1"),
1073 ent!(
1074 209,
1075 "Ntilde",
1076 "latin capital letter N with tilde, U+00D1 ISOlat1"
1077 ),
1078 ent!(
1079 210,
1080 "Ograve",
1081 "latin capital letter O with grave, U+00D2 ISOlat1"
1082 ),
1083 ent!(
1084 211,
1085 "Oacute",
1086 "latin capital letter O with acute, U+00D3 ISOlat1"
1087 ),
1088 ent!(
1089 212,
1090 "Ocirc",
1091 "latin capital letter O with circumflex, U+00D4 ISOlat1"
1092 ),
1093 ent!(
1094 213,
1095 "Otilde",
1096 "latin capital letter O with tilde, U+00D5 ISOlat1"
1097 ),
1098 ent!(
1099 214,
1100 "Ouml",
1101 "latin capital letter O with diaeresis, U+00D6 ISOlat1"
1102 ),
1103 ent!(215, "times", "multiplication sign, U+00D7 ISOnum"),
1104 ent!(
1105 216,
1106 "Oslash",
1107 "latin capital letter O with stroke latin capital letter O slash, U+00D8 ISOlat1"
1108 ),
1109 ent!(
1110 217,
1111 "Ugrave",
1112 "latin capital letter U with grave, U+00D9 ISOlat1"
1113 ),
1114 ent!(
1115 218,
1116 "Uacute",
1117 "latin capital letter U with acute, U+00DA ISOlat1"
1118 ),
1119 ent!(
1120 219,
1121 "Ucirc",
1122 "latin capital letter U with circumflex, U+00DB ISOlat1"
1123 ),
1124 ent!(
1125 220,
1126 "Uuml",
1127 "latin capital letter U with diaeresis, U+00DC ISOlat1"
1128 ),
1129 ent!(
1130 221,
1131 "Yacute",
1132 "latin capital letter Y with acute, U+00DD ISOlat1"
1133 ),
1134 ent!(222, "THORN", "latin capital letter THORN, U+00DE ISOlat1"),
1135 ent!(
1136 223,
1137 "szlig",
1138 "latin small letter sharp s = ess-zed, U+00DF ISOlat1"
1139 ),
1140 ent!(
1141 224,
1142 "agrave",
1143 "latin small letter a with grave = latin small letter a grave, U+00E0 ISOlat1"
1144 ),
1145 ent!(
1146 225,
1147 "aacute",
1148 "latin small letter a with acute, U+00E1 ISOlat1"
1149 ),
1150 ent!(
1151 226,
1152 "acirc",
1153 "latin small letter a with circumflex, U+00E2 ISOlat1"
1154 ),
1155 ent!(
1156 227,
1157 "atilde",
1158 "latin small letter a with tilde, U+00E3 ISOlat1"
1159 ),
1160 ent!(
1161 228,
1162 "auml",
1163 "latin small letter a with diaeresis, U+00E4 ISOlat1"
1164 ),
1165 ent!(
1166 229,
1167 "aring",
1168 "latin small letter a with ring above = latin small letter a ring, U+00E5 ISOlat1"
1169 ),
1170 ent!(
1171 230,
1172 "aelig",
1173 "latin small letter ae = latin small ligature ae, U+00E6 ISOlat1"
1174 ),
1175 ent!(
1176 231,
1177 "ccedil",
1178 "latin small letter c with cedilla, U+00E7 ISOlat1"
1179 ),
1180 ent!(
1181 232,
1182 "egrave",
1183 "latin small letter e with grave, U+00E8 ISOlat1"
1184 ),
1185 ent!(
1186 233,
1187 "eacute",
1188 "latin small letter e with acute, U+00E9 ISOlat1"
1189 ),
1190 ent!(
1191 234,
1192 "ecirc",
1193 "latin small letter e with circumflex, U+00EA ISOlat1"
1194 ),
1195 ent!(
1196 235,
1197 "euml",
1198 "latin small letter e with diaeresis, U+00EB ISOlat1"
1199 ),
1200 ent!(
1201 236,
1202 "igrave",
1203 "latin small letter i with grave, U+00EC ISOlat1"
1204 ),
1205 ent!(
1206 237,
1207 "iacute",
1208 "latin small letter i with acute, U+00ED ISOlat1"
1209 ),
1210 ent!(
1211 238,
1212 "icirc",
1213 "latin small letter i with circumflex, U+00EE ISOlat1"
1214 ),
1215 ent!(
1216 239,
1217 "iuml",
1218 "latin small letter i with diaeresis, U+00EF ISOlat1"
1219 ),
1220 ent!(240, "eth", "latin small letter eth, U+00F0 ISOlat1"),
1221 ent!(
1222 241,
1223 "ntilde",
1224 "latin small letter n with tilde, U+00F1 ISOlat1"
1225 ),
1226 ent!(
1227 242,
1228 "ograve",
1229 "latin small letter o with grave, U+00F2 ISOlat1"
1230 ),
1231 ent!(
1232 243,
1233 "oacute",
1234 "latin small letter o with acute, U+00F3 ISOlat1"
1235 ),
1236 ent!(
1237 244,
1238 "ocirc",
1239 "latin small letter o with circumflex, U+00F4 ISOlat1"
1240 ),
1241 ent!(
1242 245,
1243 "otilde",
1244 "latin small letter o with tilde, U+00F5 ISOlat1"
1245 ),
1246 ent!(
1247 246,
1248 "ouml",
1249 "latin small letter o with diaeresis, U+00F6 ISOlat1"
1250 ),
1251 ent!(247, "divide", "division sign, U+00F7 ISOnum"),
1252 ent!(
1253 248,
1254 "oslash",
1255 "latin small letter o with stroke, = latin small letter o slash, U+00F8 ISOlat1"
1256 ),
1257 ent!(
1258 249,
1259 "ugrave",
1260 "latin small letter u with grave, U+00F9 ISOlat1"
1261 ),
1262 ent!(
1263 250,
1264 "uacute",
1265 "latin small letter u with acute, U+00FA ISOlat1"
1266 ),
1267 ent!(
1268 251,
1269 "ucirc",
1270 "latin small letter u with circumflex, U+00FB ISOlat1"
1271 ),
1272 ent!(
1273 252,
1274 "uuml",
1275 "latin small letter u with diaeresis, U+00FC ISOlat1"
1276 ),
1277 ent!(
1278 253,
1279 "yacute",
1280 "latin small letter y with acute, U+00FD ISOlat1"
1281 ),
1282 ent!(
1283 254,
1284 "thorn",
1285 "latin small letter thorn with, U+00FE ISOlat1"
1286 ),
1287 ent!(
1288 255,
1289 "yuml",
1290 "latin small letter y with diaeresis, U+00FF ISOlat1"
1291 ),
1292 ent!(338, "OElig", "latin capital ligature OE, U+0152 ISOlat2"),
1293 ent!(339, "oelig", "latin small ligature oe, U+0153 ISOlat2"),
1294 ent!(
1295 352,
1296 "Scaron",
1297 "latin capital letter S with caron, U+0160 ISOlat2"
1298 ),
1299 ent!(
1300 353,
1301 "scaron",
1302 "latin small letter s with caron, U+0161 ISOlat2"
1303 ),
1304 ent!(
1305 376,
1306 "Yuml",
1307 "latin capital letter Y with diaeresis, U+0178 ISOlat2"
1308 ),
1309 ent!(
1310 402,
1311 "fnof",
1312 "latin small f with hook = function = florin, U+0192 ISOtech"
1313 ),
1314 ent!(
1315 710,
1316 "circ",
1317 "modifier letter circumflex accent, U+02C6 ISOpub"
1318 ),
1319 ent!(732, "tilde", "small tilde, U+02DC ISOdia"),
1320 ent!(913, "Alpha", "greek capital letter alpha, U+0391"),
1321 ent!(914, "Beta", "greek capital letter beta, U+0392"),
1322 ent!(915, "Gamma", "greek capital letter gamma, U+0393 ISOgrk3"),
1323 ent!(916, "Delta", "greek capital letter delta, U+0394 ISOgrk3"),
1324 ent!(917, "Epsilon", "greek capital letter epsilon, U+0395"),
1325 ent!(918, "Zeta", "greek capital letter zeta, U+0396"),
1326 ent!(919, "Eta", "greek capital letter eta, U+0397"),
1327 ent!(920, "Theta", "greek capital letter theta, U+0398 ISOgrk3"),
1328 ent!(921, "Iota", "greek capital letter iota, U+0399"),
1329 ent!(922, "Kappa", "greek capital letter kappa, U+039A"),
1330 ent!(923, "Lambda", "greek capital letter lambda, U+039B ISOgrk3"),
1331 ent!(924, "Mu", "greek capital letter mu, U+039C"),
1332 ent!(925, "Nu", "greek capital letter nu, U+039D"),
1333 ent!(926, "Xi", "greek capital letter xi, U+039E ISOgrk3"),
1334 ent!(927, "Omicron", "greek capital letter omicron, U+039F"),
1335 ent!(928, "Pi", "greek capital letter pi, U+03A0 ISOgrk3"),
1336 ent!(929, "Rho", "greek capital letter rho, U+03A1"),
1337 ent!(931, "Sigma", "greek capital letter sigma, U+03A3 ISOgrk3"),
1338 ent!(932, "Tau", "greek capital letter tau, U+03A4"),
1339 ent!(
1340 933,
1341 "Upsilon",
1342 "greek capital letter upsilon, U+03A5 ISOgrk3"
1343 ),
1344 ent!(934, "Phi", "greek capital letter phi, U+03A6 ISOgrk3"),
1345 ent!(935, "Chi", "greek capital letter chi, U+03A7"),
1346 ent!(936, "Psi", "greek capital letter psi, U+03A8 ISOgrk3"),
1347 ent!(937, "Omega", "greek capital letter omega, U+03A9 ISOgrk3"),
1348 ent!(945, "alpha", "greek small letter alpha, U+03B1 ISOgrk3"),
1349 ent!(946, "beta", "greek small letter beta, U+03B2 ISOgrk3"),
1350 ent!(947, "gamma", "greek small letter gamma, U+03B3 ISOgrk3"),
1351 ent!(948, "delta", "greek small letter delta, U+03B4 ISOgrk3"),
1352 ent!(949, "epsilon", "greek small letter epsilon, U+03B5 ISOgrk3"),
1353 ent!(950, "zeta", "greek small letter zeta, U+03B6 ISOgrk3"),
1354 ent!(951, "eta", "greek small letter eta, U+03B7 ISOgrk3"),
1355 ent!(952, "theta", "greek small letter theta, U+03B8 ISOgrk3"),
1356 ent!(953, "iota", "greek small letter iota, U+03B9 ISOgrk3"),
1357 ent!(954, "kappa", "greek small letter kappa, U+03BA ISOgrk3"),
1358 ent!(955, "lambda", "greek small letter lambda, U+03BB ISOgrk3"),
1359 ent!(956, "mu", "greek small letter mu, U+03BC ISOgrk3"),
1360 ent!(957, "nu", "greek small letter nu, U+03BD ISOgrk3"),
1361 ent!(958, "xi", "greek small letter xi, U+03BE ISOgrk3"),
1362 ent!(959, "omicron", "greek small letter omicron, U+03BF NEW"),
1363 ent!(960, "pi", "greek small letter pi, U+03C0 ISOgrk3"),
1364 ent!(961, "rho", "greek small letter rho, U+03C1 ISOgrk3"),
1365 ent!(
1366 962,
1367 "sigmaf",
1368 "greek small letter final sigma, U+03C2 ISOgrk3"
1369 ),
1370 ent!(963, "sigma", "greek small letter sigma, U+03C3 ISOgrk3"),
1371 ent!(964, "tau", "greek small letter tau, U+03C4 ISOgrk3"),
1372 ent!(965, "upsilon", "greek small letter upsilon, U+03C5 ISOgrk3"),
1373 ent!(966, "phi", "greek small letter phi, U+03C6 ISOgrk3"),
1374 ent!(967, "chi", "greek small letter chi, U+03C7 ISOgrk3"),
1375 ent!(968, "psi", "greek small letter psi, U+03C8 ISOgrk3"),
1376 ent!(969, "omega", "greek small letter omega, U+03C9 ISOgrk3"),
1377 ent!(
1378 977,
1379 "thetasym",
1380 "greek small letter theta symbol, U+03D1 NEW"
1381 ),
1382 ent!(978, "upsih", "greek upsilon with hook symbol, U+03D2 NEW"),
1383 ent!(982, "piv", "greek pi symbol, U+03D6 ISOgrk3"),
1384 ent!(8194, "ensp", "en space, U+2002 ISOpub"),
1385 ent!(8195, "emsp", "em space, U+2003 ISOpub"),
1386 ent!(8201, "thinsp", "thin space, U+2009 ISOpub"),
1387 ent!(8204, "zwnj", "zero width non-joiner, U+200C NEW RFC 2070"),
1388 ent!(8205, "zwj", "zero width joiner, U+200D NEW RFC 2070"),
1389 ent!(8206, "lrm", "left-to-right mark, U+200E NEW RFC 2070"),
1390 ent!(8207, "rlm", "right-to-left mark, U+200F NEW RFC 2070"),
1391 ent!(8211, "ndash", "en dash, U+2013 ISOpub"),
1392 ent!(8212, "mdash", "em dash, U+2014 ISOpub"),
1393 ent!(8216, "lsquo", "left single quotation mark, U+2018 ISOnum"),
1394 ent!(8217, "rsquo", "right single quotation mark, U+2019 ISOnum"),
1395 ent!(8218, "sbquo", "single low-9 quotation mark, U+201A NEW"),
1396 ent!(8220, "ldquo", "left double quotation mark, U+201C ISOnum"),
1397 ent!(8221, "rdquo", "right double quotation mark, U+201D ISOnum"),
1398 ent!(8222, "bdquo", "double low-9 quotation mark, U+201E NEW"),
1399 ent!(8224, "dagger", "dagger, U+2020 ISOpub"),
1400 ent!(8225, "Dagger", "double dagger, U+2021 ISOpub"),
1401 ent!(8226, "bull", "bullet = black small circle, U+2022 ISOpub"),
1402 ent!(
1403 8230,
1404 "hellip",
1405 "horizontal ellipsis = three dot leader, U+2026 ISOpub"
1406 ),
1407 ent!(8240, "permil", "per mille sign, U+2030 ISOtech"),
1408 ent!(8242, "prime", "prime = minutes = feet, U+2032 ISOtech"),
1409 ent!(
1410 8243,
1411 "Prime",
1412 "double prime = seconds = inches, U+2033 ISOtech"
1413 ),
1414 ent!(
1415 8249,
1416 "lsaquo",
1417 "single left-pointing angle quotation mark, U+2039 ISO proposed"
1418 ),
1419 ent!(
1420 8250,
1421 "rsaquo",
1422 "single right-pointing angle quotation mark, U+203A ISO proposed"
1423 ),
1424 ent!(8254, "oline", "overline = spacing overscore, U+203E NEW"),
1425 ent!(8260, "frasl", "fraction slash, U+2044 NEW"),
1426 ent!(8364, "euro", "euro sign, U+20AC NEW"),
1427 ent!(
1428 8465,
1429 "image",
1430 "blackletter capital I = imaginary part, U+2111 ISOamso"
1431 ),
1432 ent!(
1433 8472,
1434 "weierp",
1435 "script capital P = power set = Weierstrass p, U+2118 ISOamso"
1436 ),
1437 ent!(
1438 8476,
1439 "real",
1440 "blackletter capital R = real part symbol, U+211C ISOamso"
1441 ),
1442 ent!(8482, "trade", "trade mark sign, U+2122 ISOnum"),
1443 ent!(
1444 8501,
1445 "alefsym",
1446 "alef symbol = first transfinite cardinal, U+2135 NEW"
1447 ),
1448 ent!(8592, "larr", "leftwards arrow, U+2190 ISOnum"),
1449 ent!(8593, "uarr", "upwards arrow, U+2191 ISOnum"),
1450 ent!(8594, "rarr", "rightwards arrow, U+2192 ISOnum"),
1451 ent!(8595, "darr", "downwards arrow, U+2193 ISOnum"),
1452 ent!(8596, "harr", "left right arrow, U+2194 ISOamsa"),
1453 ent!(
1454 8629,
1455 "crarr",
1456 "downwards arrow with corner leftwards = carriage return, U+21B5 NEW"
1457 ),
1458 ent!(8656, "lArr", "leftwards double arrow, U+21D0 ISOtech"),
1459 ent!(8657, "uArr", "upwards double arrow, U+21D1 ISOamsa"),
1460 ent!(8658, "rArr", "rightwards double arrow, U+21D2 ISOtech"),
1461 ent!(8659, "dArr", "downwards double arrow, U+21D3 ISOamsa"),
1462 ent!(8660, "hArr", "left right double arrow, U+21D4 ISOamsa"),
1463 ent!(8704, "forall", "for all, U+2200 ISOtech"),
1464 ent!(8706, "part", "partial differential, U+2202 ISOtech"),
1465 ent!(8707, "exist", "there exists, U+2203 ISOtech"),
1466 ent!(
1467 8709,
1468 "empty",
1469 "empty set = null set = diameter, U+2205 ISOamso"
1470 ),
1471 ent!(8711, "nabla", "nabla = backward difference, U+2207 ISOtech"),
1472 ent!(8712, "isin", "element of, U+2208 ISOtech"),
1473 ent!(8713, "notin", "not an element of, U+2209 ISOtech"),
1474 ent!(8715, "ni", "contains as member, U+220B ISOtech"),
1475 ent!(8719, "prod", "n-ary product = product sign, U+220F ISOamsb"),
1476 ent!(8721, "sum", "n-ary summation, U+2211 ISOamsb"),
1477 ent!(8722, "minus", "minus sign, U+2212 ISOtech"),
1478 ent!(8727, "lowast", "asterisk operator, U+2217 ISOtech"),
1479 ent!(8730, "radic", "square root = radical sign, U+221A ISOtech"),
1480 ent!(8733, "prop", "proportional to, U+221D ISOtech"),
1481 ent!(8734, "infin", "infinity, U+221E ISOtech"),
1482 ent!(8736, "ang", "angle, U+2220 ISOamso"),
1483 ent!(8743, "and", "logical and = wedge, U+2227 ISOtech"),
1484 ent!(8744, "or", "logical or = vee, U+2228 ISOtech"),
1485 ent!(8745, "cap", "intersection = cap, U+2229 ISOtech"),
1486 ent!(8746, "cup", "union = cup, U+222A ISOtech"),
1487 ent!(8747, "int", "integral, U+222B ISOtech"),
1488 ent!(8756, "there4", "therefore, U+2234 ISOtech"),
1489 ent!(
1490 8764,
1491 "sim",
1492 "tilde operator = varies with = similar to, U+223C ISOtech"
1493 ),
1494 ent!(8773, "cong", "approximately equal to, U+2245 ISOtech"),
1495 ent!(
1496 8776,
1497 "asymp",
1498 "almost equal to = asymptotic to, U+2248 ISOamsr"
1499 ),
1500 ent!(8800, "ne", "not equal to, U+2260 ISOtech"),
1501 ent!(8801, "equiv", "identical to, U+2261 ISOtech"),
1502 ent!(8804, "le", "less-than or equal to, U+2264 ISOtech"),
1503 ent!(8805, "ge", "greater-than or equal to, U+2265 ISOtech"),
1504 ent!(8834, "sub", "subset of, U+2282 ISOtech"),
1505 ent!(8835, "sup", "superset of, U+2283 ISOtech"),
1506 ent!(8836, "nsub", "not a subset of, U+2284 ISOamsn"),
1507 ent!(8838, "sube", "subset of or equal to, U+2286 ISOtech"),
1508 ent!(8839, "supe", "superset of or equal to, U+2287 ISOtech"),
1509 ent!(8853, "oplus", "circled plus = direct sum, U+2295 ISOamsb"),
1510 ent!(
1511 8855,
1512 "otimes",
1513 "circled times = vector product, U+2297 ISOamsb"
1514 ),
1515 ent!(
1516 8869,
1517 "perp",
1518 "up tack = orthogonal to = perpendicular, U+22A5 ISOtech"
1519 ),
1520 ent!(8901, "sdot", "dot operator, U+22C5 ISOamsb"),
1521 ent!(8968, "lceil", "left ceiling = apl upstile, U+2308 ISOamsc"),
1522 ent!(8969, "rceil", "right ceiling, U+2309 ISOamsc"),
1523 ent!(8970, "lfloor", "left floor = apl downstile, U+230A ISOamsc"),
1524 ent!(8971, "rfloor", "right floor, U+230B ISOamsc"),
1525 ent!(
1526 9001,
1527 "lang",
1528 "left-pointing angle bracket = bra, U+2329 ISOtech"
1529 ),
1530 ent!(
1531 9002,
1532 "rang",
1533 "right-pointing angle bracket = ket, U+232A ISOtech"
1534 ),
1535 ent!(9674, "loz", "lozenge, U+25CA ISOpub"),
1536 ent!(9824, "spades", "black spade suit, U+2660 ISOpub"),
1537 ent!(9827, "clubs", "black club suit = shamrock, U+2663 ISOpub"),
1538 ent!(
1539 9829,
1540 "hearts",
1541 "black heart suit = valentine, U+2665 ISOpub"
1542 ),
1543 ent!(9830, "diams", "black diamond suit, U+2666 ISOpub"),
1544];
1545
1546#[no_mangle]
1557pub unsafe extern "C" fn htmlEntityLookup(name: *const xmlChar) -> *const _htmlEntityDesc {
1558 if name.is_null() {
1559 return ptr::null();
1560 }
1561 let bytes = unsafe { xmlstr_to_bytes(name) };
1562 for e in HTML40_ENTITIES {
1563 let ename = unsafe { core::ffi::CStr::from_ptr(e.name) }.to_bytes();
1564 if bytes == ename {
1565 return e as *const _htmlEntityDesc;
1566 }
1567 }
1568 ptr::null()
1569}
1570
1571#[no_mangle]
1582pub unsafe extern "C" fn htmlEntityValueLookup(value: c_uint) -> *const _htmlEntityDesc {
1583 for e in HTML40_ENTITIES {
1584 if e.value == value {
1585 return e as *const _htmlEntityDesc;
1586 }
1587 }
1588 ptr::null()
1589}
1590
1591#[inline]
1594unsafe fn html_entity_value_lookup_static(value: c_uint) -> *const _htmlEntityDesc {
1595 for e in HTML40_ENTITIES {
1596 if e.value == value {
1597 return e as *const _htmlEntityDesc;
1598 }
1599 }
1600 ptr::null()
1601}
1602
1603static HTML_START_CLOSE: &[(&str, &str)] = &[
1611 ("a", "a"),
1612 ("a", "fieldset"),
1613 ("a", "table"),
1614 ("a", "td"),
1615 ("a", "th"),
1616 ("address", "dd"),
1617 ("address", "dl"),
1618 ("address", "dt"),
1619 ("address", "form"),
1620 ("address", "li"),
1621 ("address", "ul"),
1622 ("b", "center"),
1623 ("b", "p"),
1624 ("b", "td"),
1625 ("b", "th"),
1626 ("big", "p"),
1627 ("caption", "col"),
1628 ("caption", "colgroup"),
1629 ("caption", "tbody"),
1630 ("caption", "tfoot"),
1631 ("caption", "thead"),
1632 ("caption", "tr"),
1633 ("col", "col"),
1634 ("col", "colgroup"),
1635 ("col", "tbody"),
1636 ("col", "tfoot"),
1637 ("col", "thead"),
1638 ("col", "tr"),
1639 ("colgroup", "colgroup"),
1640 ("colgroup", "tbody"),
1641 ("colgroup", "tfoot"),
1642 ("colgroup", "thead"),
1643 ("colgroup", "tr"),
1644 ("dd", "dt"),
1645 ("dir", "dd"),
1646 ("dir", "dl"),
1647 ("dir", "dt"),
1648 ("dir", "form"),
1649 ("dir", "ul"),
1650 ("dl", "form"),
1651 ("dl", "li"),
1652 ("dt", "dd"),
1653 ("dt", "dl"),
1654 ("font", "center"),
1655 ("font", "td"),
1656 ("font", "th"),
1657 ("form", "form"),
1658 ("h1", "fieldset"),
1659 ("h1", "form"),
1660 ("h1", "li"),
1661 ("h1", "p"),
1662 ("h1", "table"),
1663 ("h2", "fieldset"),
1664 ("h2", "form"),
1665 ("h2", "li"),
1666 ("h2", "p"),
1667 ("h2", "table"),
1668 ("h3", "fieldset"),
1669 ("h3", "form"),
1670 ("h3", "li"),
1671 ("h3", "p"),
1672 ("h3", "table"),
1673 ("h4", "fieldset"),
1674 ("h4", "form"),
1675 ("h4", "li"),
1676 ("h4", "p"),
1677 ("h4", "table"),
1678 ("h5", "fieldset"),
1679 ("h5", "form"),
1680 ("h5", "li"),
1681 ("h5", "p"),
1682 ("h5", "table"),
1683 ("h6", "fieldset"),
1684 ("h6", "form"),
1685 ("h6", "li"),
1686 ("h6", "p"),
1687 ("h6", "table"),
1688 ("head", "a"),
1689 ("head", "abbr"),
1690 ("head", "acronym"),
1691 ("head", "address"),
1692 ("head", "b"),
1693 ("head", "bdo"),
1694 ("head", "big"),
1695 ("head", "blockquote"),
1696 ("head", "body"),
1697 ("head", "br"),
1698 ("head", "center"),
1699 ("head", "cite"),
1700 ("head", "code"),
1701 ("head", "dd"),
1702 ("head", "dfn"),
1703 ("head", "dir"),
1704 ("head", "div"),
1705 ("head", "dl"),
1706 ("head", "dt"),
1707 ("head", "em"),
1708 ("head", "fieldset"),
1709 ("head", "font"),
1710 ("head", "form"),
1711 ("head", "frameset"),
1712 ("head", "h1"),
1713 ("head", "h2"),
1714 ("head", "h3"),
1715 ("head", "h4"),
1716 ("head", "h5"),
1717 ("head", "h6"),
1718 ("head", "hr"),
1719 ("head", "i"),
1720 ("head", "iframe"),
1721 ("head", "img"),
1722 ("head", "kbd"),
1723 ("head", "li"),
1724 ("head", "listing"),
1725 ("head", "map"),
1726 ("head", "menu"),
1727 ("head", "ol"),
1728 ("head", "p"),
1729 ("head", "pre"),
1730 ("head", "q"),
1731 ("head", "s"),
1732 ("head", "samp"),
1733 ("head", "small"),
1734 ("head", "span"),
1735 ("head", "strike"),
1736 ("head", "strong"),
1737 ("head", "sub"),
1738 ("head", "sup"),
1739 ("head", "table"),
1740 ("head", "tt"),
1741 ("head", "u"),
1742 ("head", "ul"),
1743 ("head", "var"),
1744 ("head", "xmp"),
1745 ("hr", "form"),
1746 ("i", "center"),
1747 ("i", "p"),
1748 ("i", "td"),
1749 ("i", "th"),
1750 ("legend", "fieldset"),
1751 ("li", "li"),
1752 ("link", "body"),
1753 ("link", "frameset"),
1754 ("listing", "dd"),
1755 ("listing", "dl"),
1756 ("listing", "dt"),
1757 ("listing", "fieldset"),
1758 ("listing", "form"),
1759 ("listing", "li"),
1760 ("listing", "table"),
1761 ("listing", "ul"),
1762 ("menu", "dd"),
1763 ("menu", "dl"),
1764 ("menu", "dt"),
1765 ("menu", "form"),
1766 ("menu", "ul"),
1767 ("ol", "form"),
1768 ("option", "optgroup"),
1769 ("option", "option"),
1770 ("p", "address"),
1771 ("p", "blockquote"),
1772 ("p", "body"),
1773 ("p", "caption"),
1774 ("p", "center"),
1775 ("p", "col"),
1776 ("p", "colgroup"),
1777 ("p", "dd"),
1778 ("p", "dir"),
1779 ("p", "div"),
1780 ("p", "dl"),
1781 ("p", "dt"),
1782 ("p", "fieldset"),
1783 ("p", "form"),
1784 ("p", "frameset"),
1785 ("p", "h1"),
1786 ("p", "h2"),
1787 ("p", "h3"),
1788 ("p", "h4"),
1789 ("p", "h5"),
1790 ("p", "h6"),
1791 ("p", "head"),
1792 ("p", "hr"),
1793 ("p", "li"),
1794 ("p", "listing"),
1795 ("p", "menu"),
1796 ("p", "ol"),
1797 ("p", "p"),
1798 ("p", "pre"),
1799 ("p", "table"),
1800 ("p", "tbody"),
1801 ("p", "td"),
1802 ("p", "tfoot"),
1803 ("p", "th"),
1804 ("p", "title"),
1805 ("p", "tr"),
1806 ("p", "ul"),
1807 ("p", "xmp"),
1808 ("pre", "dd"),
1809 ("pre", "dl"),
1810 ("pre", "dt"),
1811 ("pre", "fieldset"),
1812 ("pre", "form"),
1813 ("pre", "li"),
1814 ("pre", "table"),
1815 ("pre", "ul"),
1816 ("s", "p"),
1817 ("script", "noscript"),
1818 ("small", "p"),
1819 ("span", "td"),
1820 ("span", "th"),
1821 ("strike", "p"),
1822 ("style", "body"),
1823 ("style", "frameset"),
1824 ("tbody", "tbody"),
1825 ("tbody", "tfoot"),
1826 ("td", "tbody"),
1827 ("td", "td"),
1828 ("td", "tfoot"),
1829 ("td", "th"),
1830 ("td", "tr"),
1831 ("tfoot", "tbody"),
1832 ("th", "tbody"),
1833 ("th", "td"),
1834 ("th", "tfoot"),
1835 ("th", "th"),
1836 ("th", "tr"),
1837 ("thead", "tbody"),
1838 ("thead", "tfoot"),
1839 ("title", "body"),
1840 ("title", "frameset"),
1841 ("tr", "tbody"),
1842 ("tr", "tfoot"),
1843 ("tr", "tr"),
1844 ("tt", "p"),
1845 ("u", "p"),
1846 ("u", "td"),
1847 ("u", "th"),
1848 ("ul", "address"),
1849 ("ul", "form"),
1850 ("ul", "menu"),
1851 ("ul", "pre"),
1852 ("xmp", "dd"),
1853 ("xmp", "dl"),
1854 ("xmp", "dt"),
1855 ("xmp", "fieldset"),
1856 ("xmp", "form"),
1857 ("xmp", "li"),
1858 ("xmp", "table"),
1859 ("xmp", "ul"),
1860];
1861
1862unsafe fn html_check_auto_close(newtag: *const xmlChar, oldtag: *const xmlChar) -> bool {
1866 if newtag.is_null() || oldtag.is_null() {
1867 return false;
1868 }
1869 let new_bytes = unsafe { xmlstr_to_bytes(newtag) };
1870 let old_bytes = unsafe { xmlstr_to_bytes(oldtag) };
1871 HTML_START_CLOSE
1872 .iter()
1873 .any(|(old, new)| old.as_bytes() == old_bytes && new.as_bytes() == new_bytes)
1874}
1875
1876#[no_mangle]
1886pub unsafe extern "C" fn htmlAutoCloseTag(
1887 _doc: *mut _xmlDoc,
1888 name: *const xmlChar,
1889 elem: *mut _xmlNode,
1890) -> c_int {
1891 if elem.is_null() {
1892 return 1;
1893 }
1894 let n = unsafe { &*elem };
1895 if n.name.is_null() {
1896 } else if unsafe { xml_strcmp(name, n.name) } == 0 {
1899 return 0;
1900 }
1901 if unsafe { html_check_auto_close(n.name, name) } {
1902 return 1;
1903 }
1904 let mut child = n.children;
1905 while !child.is_null() {
1906 if unsafe { htmlAutoCloseTag(_doc, name, child) } != 0 {
1907 return 1;
1908 }
1909 child = unsafe { (*child).next };
1910 }
1911 0
1912}
1913
1914#[no_mangle]
1923pub unsafe extern "C" fn htmlIsAutoClosed(doc: *mut _xmlDoc, elem: *mut _xmlNode) -> c_int {
1924 if elem.is_null() {
1925 return 1;
1926 }
1927 let n = unsafe { &*elem };
1928 let mut child = n.children;
1929 while !child.is_null() {
1930 if unsafe { htmlAutoCloseTag(doc, n.name, child) } != 0 {
1931 return 1;
1932 }
1933 child = unsafe { (*child).next };
1934 }
1935 0
1936}
1937
1938static HTML_SCRIPT_ATTRIBUTES: &[&str] = &[
1941 "onclick",
1942 "ondblclick",
1943 "onmousedown",
1944 "onmouseup",
1945 "onmouseover",
1946 "onmousemove",
1947 "onmouseout",
1948 "onkeypress",
1949 "onkeydown",
1950 "onkeyup",
1951 "onload",
1952 "onunload",
1953 "onfocus",
1954 "onblur",
1955 "onsubmit",
1956 "onreset",
1957 "onchange",
1958 "onselect",
1959];
1960
1961#[no_mangle]
1970pub unsafe extern "C" fn htmlIsScriptAttribute(name: *const xmlChar) -> c_int {
1971 if name.is_null() {
1972 return 0;
1973 }
1974 let bytes = unsafe { xmlstr_to_bytes(name) };
1975 if bytes.len() < 3 || bytes[0] != b'o' || bytes[1] != b'n' {
1976 return 0;
1977 }
1978 for cand in HTML_SCRIPT_ATTRIBUTES {
1979 if bytes == cand.as_bytes() {
1980 return 1;
1981 }
1982 }
1983 0
1984}
1985
1986#[no_mangle]
1998pub const unsafe extern "C" fn htmlElementAllowedHere(
1999 _parent: *const _htmlElemDesc,
2000 _elt: *const xmlChar,
2001) -> c_int {
2002 1
2003}
2004
2005#[no_mangle]
2013pub const unsafe extern "C" fn htmlElementStatusHere(
2014 _parent: *const _htmlElemDesc,
2015 _elt: *const _htmlElemDesc,
2016) -> c_int {
2017 HTML_VALID
2018}
2019
2020#[no_mangle]
2028pub const unsafe extern "C" fn htmlAttrAllowed(
2029 _elt: *const _htmlElemDesc,
2030 _attr: *const xmlChar,
2031 _legacy: c_int,
2032) -> c_int {
2033 HTML_VALID
2034}
2035
2036#[no_mangle]
2044pub const unsafe extern "C" fn htmlNodeStatus(_node: *mut _xmlNode, _legacy: c_int) -> c_int {
2045 HTML_VALID
2046}
2047
2048#[no_mangle]
2067pub unsafe extern "C" fn htmlEncodeEntities(
2068 out: *mut u8,
2069 outlen: *mut c_int,
2070 input: *const u8,
2071 inlen: *mut c_int,
2072 quoteChar: c_int,
2073) -> c_int {
2074 if out.is_null() || outlen.is_null() || inlen.is_null() || input.is_null() {
2075 return -1;
2076 }
2077 let outend = (out as usize).wrapping_add((*outlen).max(0) as usize);
2078 let inend = (input as usize).wrapping_add((*inlen).max(0) as usize);
2079 let mut in_ptr = input as usize;
2080 let mut out_ptr = out as usize;
2081 let mut processed = in_ptr;
2082
2083 while in_ptr < inend {
2084 let mut c: c_uint;
2085
2086 let mut trailing: c_int;
2087
2088 let d: c_uint = unsafe { *(in_ptr as *const u8) as c_uint };
2089 in_ptr += 1;
2090 if d < 0x80 {
2091 c = d;
2092 trailing = 0;
2093 } else if d < 0xC0 {
2094 *outlen = (out_ptr - out as usize) as c_int;
2096 *inlen = (processed - input as usize) as c_int;
2097 return -2;
2098 } else if d < 0xE0 {
2099 c = d & 0x1F;
2100 trailing = 1;
2101 } else if d < 0xF0 {
2102 c = d & 0x0F;
2103 trailing = 2;
2104 } else if d < 0xF8 {
2105 c = d & 0x07;
2106 trailing = 3;
2107 } else {
2108 *outlen = (out_ptr - out as usize) as c_int;
2110 *inlen = (processed - input as usize) as c_int;
2111 return -2;
2112 }
2113
2114 if inend - in_ptr < trailing as usize {
2115 break;
2116 }
2117
2118 while trailing > 0 {
2119 let t = unsafe { *(in_ptr as *const u8) as c_uint };
2120 in_ptr += 1;
2121 if (t & 0xC0) != 0x80 {
2122 *outlen = (out_ptr - out as usize) as c_int;
2123 *inlen = (processed - input as usize) as c_int;
2124 return -2;
2125 }
2126 c = (c << 6) | (t & 0x3F);
2127 trailing -= 1;
2128 }
2129
2130 if (c < 0x80)
2132 && (c != quoteChar as c_uint)
2133 && (c != b'&' as c_uint)
2134 && (c != b'<' as c_uint)
2135 && (c != b'>' as c_uint)
2136 {
2137 if out_ptr >= outend {
2138 break;
2139 }
2140 unsafe { *(out_ptr as *mut u8) = c as u8 };
2141 out_ptr += 1;
2142 } else {
2143 let ent = unsafe { html_entity_value_lookup_static(c) };
2144 let mut nbuf = [0u8; 16];
2145 let (cp, len): (*const u8, usize) = if ent.is_null() {
2146 nbuf[0] = b'#';
2148 let mut i = 1usize;
2149 let mut digits = [0u8; 10];
2150 let mut nd = 0usize;
2151 let mut v = c;
2152 if v == 0 {
2153 digits[0] = b'0';
2154 nd = 1;
2155 }
2156 while v > 0 {
2157 digits[nd] = b'0' + (v % 10) as u8;
2158 nd += 1;
2159 v /= 10;
2160 }
2161 while nd > 0 {
2162 nd -= 1;
2163 nbuf[i] = digits[nd];
2164 i += 1;
2165 }
2166 (nbuf.as_ptr(), i)
2167 } else {
2168 (unsafe { (*ent).name } as *const u8, unsafe {
2169 xml_strlen((*ent).name as *const xmlChar)
2170 })
2171 };
2172 if outend - out_ptr < len + 2 {
2173 break;
2174 }
2175 unsafe {
2176 *(out_ptr as *mut u8) = b'&';
2177 ptr::copy_nonoverlapping(cp, (out_ptr + 1) as *mut u8, len);
2178 *((out_ptr + 1 + len) as *mut u8) = b';';
2179 }
2180 out_ptr += len + 2;
2181 }
2182 processed = in_ptr;
2183 }
2184
2185 *outlen = (out_ptr - out as usize) as c_int;
2186 *inlen = (processed - input as usize) as c_int;
2187 0
2188}
2189
2190#[no_mangle]
2203pub unsafe extern "C" fn htmlDecodeEntities(
2204 _ctxt: *mut c_void,
2205 _len: c_int,
2206 _end: xmlChar,
2207 _end2: xmlChar,
2208 _end3: xmlChar,
2209) -> *mut xmlChar {
2210 static DEPRECATED: AtomicBool = AtomicBool::new(false);
2211 if !DEPRECATED.swap(true, Ordering::Relaxed) {
2212 let msg = b"htmlDecodeEntities() deprecated function reached\n";
2214 unsafe {
2215 libc::fwrite(
2216 msg.as_ptr() as *const c_void,
2217 1,
2218 msg.len(),
2219 libc::fdopen(2, b"w\0" as *const u8 as *const c_char),
2220 );
2221 }
2222 }
2223 ptr::null_mut()
2224}
2225
2226#[no_mangle]
2236pub unsafe extern "C" fn htmlIsBooleanAttr(name: *const xmlChar) -> c_int {
2237 if name.is_null() {
2238 return 0;
2239 }
2240 let b = unsafe { xmlstr_to_bytes(name) };
2241 if b.is_empty() {
2242 return 0;
2243 }
2244 let mut i = 0usize;
2245 let mut suffix: Option<&'static [u8]> = None;
2246 match b[i].to_ascii_lowercase() {
2247 b'c' => {
2248 i += 1;
2249 match b.get(i).map(|&x| x.to_ascii_lowercase()) {
2250 Some(b'h') => suffix = Some(b"ecked"),
2251 Some(b'o') => suffix = Some(b"mpact"),
2252 _ => {}
2253 }
2254 }
2255 b'd' => {
2256 i += 1;
2257 match b.get(i).map(|&x| x.to_ascii_lowercase()) {
2258 Some(b'e') => {
2259 i += 1;
2260 match b.get(i).map(|&x| x.to_ascii_lowercase()) {
2261 Some(b'c') => suffix = Some(b"lare"),
2262 Some(b'f') => suffix = Some(b"er"),
2263 _ => {}
2264 }
2265 }
2266 Some(b'i') => suffix = Some(b"sabled"),
2267 _ => {}
2268 }
2269 }
2270 b'i' => suffix = Some(b"smap"),
2271 b'm' => suffix = Some(b"ultiple"),
2272 b'n' => {
2273 i += 1;
2274 if b.get(i).map(|&x| x.to_ascii_lowercase()) == Some(b'o') {
2275 i += 1;
2276 match b.get(i).map(|&x| x.to_ascii_lowercase()) {
2277 Some(b'h') => suffix = Some(b"ref"),
2278 Some(b'r') => suffix = Some(b"esize"),
2279 Some(b's') => suffix = Some(b"hade"),
2280 Some(b'w') => suffix = Some(b"rap"),
2281 _ => {}
2282 }
2283 }
2284 }
2285 b'r' => suffix = Some(b"eadonly"),
2286 b's' => suffix = Some(b"elected"),
2287 _ => {}
2288 }
2289 let Some(suffix) = suffix else {
2290 return 0;
2291 };
2292 if b.len() == i + 1 + suffix.len() && b[i + 1..].eq_ignore_ascii_case(suffix) {
2293 1
2294 } else {
2295 0
2296 }
2297}
2298
2299static HTML_OMITTED_DEFAULT_VALUE: AtomicI32 = AtomicI32::new(1);
2306
2307#[no_mangle]
2315pub unsafe extern "C" fn htmlHandleOmittedElem(val: c_int) -> c_int {
2316 HTML_OMITTED_DEFAULT_VALUE.swap(val, Ordering::Relaxed)
2317}
2318
2319#[no_mangle]
2327pub const unsafe extern "C" fn htmlInitAutoClose() {
2328 }
2330
2331#[no_mangle]
2342pub const unsafe extern "C" fn htmlDefaultSAXHandlerInit() {
2343 }
2345
2346#[no_mangle]
2358pub const unsafe extern "C" fn htmlParseEntityRef(
2359 _ctxt: *mut c_void,
2360 _str: *mut *const xmlChar,
2361) -> *const _htmlEntityDesc {
2362 ptr::null()
2363}
2364
2365#[no_mangle]
2373pub const unsafe extern "C" fn htmlParseCharRef(_ctxt: *mut c_void) -> c_int {
2374 0
2375}
2376
2377#[allow(dead_code)]
2395struct HtmlOpaqueCtxt {
2396 doc: *mut _xmlDoc,
2398 current: *mut _xmlNode,
2399 html: *mut _xmlNode,
2400 head: *mut _xmlNode,
2401 body: *mut _xmlNode,
2402 in_head: bool,
2403 in_body: bool,
2404 html_created: bool,
2405 head_created: bool,
2406 body_created: bool,
2407 seen_body_content: bool,
2408 input: *mut u8,
2410 input_pos: usize,
2411 input_len: usize,
2412 line: c_int,
2413 err: bool,
2414 filename: *mut c_char,
2415 encoding: *mut c_char,
2416 options: c_int,
2418 sax: *mut _xmlSAXHandler,
2419 user_data: *mut c_void,
2420}
2421
2422unsafe fn html_ctxt_alloc() -> *mut HtmlOpaqueCtxt {
2425 let mem = xmlMallocZero(size_of::<HtmlOpaqueCtxt>()) as *mut HtmlOpaqueCtxt;
2426 if mem.is_null() {
2427 return ptr::null_mut();
2428 }
2429 unsafe {
2430 ptr::write(
2431 mem,
2432 HtmlOpaqueCtxt {
2433 doc: ptr::null_mut(),
2434 current: ptr::null_mut(),
2435 html: ptr::null_mut(),
2436 head: ptr::null_mut(),
2437 body: ptr::null_mut(),
2438 in_head: false,
2439 in_body: false,
2440 html_created: false,
2441 head_created: false,
2442 body_created: false,
2443 seen_body_content: false,
2444 input: ptr::null_mut(),
2445 input_pos: 0,
2446 input_len: 0,
2447 line: 1,
2448 err: false,
2449 filename: ptr::null_mut(),
2450 encoding: ptr::null_mut(),
2451 options: 0,
2452 sax: ptr::null_mut(),
2453 user_data: ptr::null_mut(),
2454 },
2455 );
2456 }
2457 mem
2458}
2459
2460unsafe fn html_ctxt_set_input(ctxt: *mut HtmlOpaqueCtxt, buffer: *const c_char, size: c_int) {
2462 if buffer.is_null() || size <= 0 {
2463 return;
2464 }
2465 let len = size as usize;
2466 let nb = xmlMallocImpl(len) as *mut u8;
2467 if nb.is_null() {
2468 return;
2469 }
2470 unsafe {
2471 ptr::copy_nonoverlapping(buffer as *const u8, nb, len);
2472 (*ctxt).input = nb;
2473 (*ctxt).input_len = len;
2474 (*ctxt).input_pos = 0;
2475 }
2476}
2477
2478#[no_mangle]
2486pub unsafe extern "C" fn htmlNewSAXParserCtxt(
2487 sax: *const _xmlSAXHandler,
2488 userData: *mut c_void,
2489) -> *mut c_void {
2490 let ctxt = unsafe { html_ctxt_alloc() };
2491 if ctxt.is_null() {
2492 return ptr::null_mut();
2493 }
2494 unsafe {
2495 (*ctxt).sax = sax as *mut _xmlSAXHandler;
2496 (*ctxt).user_data = userData;
2497 }
2498 ctxt as *mut c_void
2499}
2500
2501#[no_mangle]
2509pub unsafe extern "C" fn htmlNewParserCtxt() -> *mut c_void {
2510 unsafe { htmlNewSAXParserCtxt(ptr::null(), ptr::null_mut()) }
2511}
2512
2513#[no_mangle]
2522pub unsafe extern "C" fn htmlCreateMemoryParserCtxt(
2523 buffer: *const c_char,
2524 size: c_int,
2525) -> *mut c_void {
2526 if buffer.is_null() || size <= 0 {
2527 return ptr::null_mut();
2528 }
2529 let ctxt = unsafe { html_ctxt_alloc() };
2530 if ctxt.is_null() {
2531 return ptr::null_mut();
2532 }
2533 unsafe { html_ctxt_set_input(ctxt, buffer, size) };
2534 if unsafe { (*ctxt).input.is_null() } {
2535 unsafe { crate::xml::html::free_parser_ctxt(ctxt as *mut c_void) };
2536 return ptr::null_mut();
2537 }
2538 ctxt as *mut c_void
2539}
2540
2541#[no_mangle]
2551pub unsafe extern "C" fn htmlCreatePushParserCtxt(
2552 sax: *mut _xmlSAXHandler,
2553 user_data: *mut c_void,
2554 chunk: *const c_char,
2555 size: c_int,
2556 filename: *const c_char,
2557 _enc: xmlCharEncoding,
2558) -> *mut c_void {
2559 let ctxt = unsafe { html_ctxt_alloc() };
2560 if ctxt.is_null() {
2561 return ptr::null_mut();
2562 }
2563 unsafe {
2564 (*ctxt).sax = sax;
2565 (*ctxt).user_data = user_data;
2566 if !filename.is_null() {
2567 (*ctxt).filename = c_strdup(filename);
2568 }
2569 if size > 0 && !chunk.is_null() {
2570 html_ctxt_set_input(ctxt, chunk, size);
2571 } else {
2572 let nb = xmlMallocImpl(1) as *mut u8;
2575 if !nb.is_null() {
2576 (*ctxt).input = nb;
2577 (*ctxt).input_len = 0;
2578 (*ctxt).input_pos = 0;
2579 }
2580 }
2581 }
2582 ctxt as *mut c_void
2583}
2584
2585#[no_mangle]
2593pub unsafe extern "C" fn htmlCtxtReset(ctxt: *mut c_void) {
2594 if ctxt.is_null() {
2595 return;
2596 }
2597 let c = ctxt as *mut HtmlOpaqueCtxt;
2598 unsafe {
2599 if !(*c).input.is_null() {
2600 xmlFreeImpl((*c).input as *mut c_void);
2601 }
2602 (*c).input = ptr::null_mut();
2603 (*c).input_len = 0;
2604 (*c).input_pos = 0;
2605 (*c).doc = ptr::null_mut();
2606 (*c).options = 0;
2607 (*c).line = 1;
2608 (*c).err = false;
2609 }
2610}
2611
2612#[no_mangle]
2623pub unsafe extern "C" fn htmlCtxtUseOptions(ctxt: *mut c_void, options: c_int) -> c_int {
2624 if ctxt.is_null() {
2625 return -1;
2626 }
2627 let c = ctxt as *mut HtmlOpaqueCtxt;
2628 unsafe {
2630 (*c).options = ((*c).options & HTML_OPTIONS_KEEP_MASK) | (options & HTML_OPTIONS_ALL_MASK);
2631 }
2632 options & !HTML_OPTIONS_ALL_MASK & !crate::abi::types::XML_PARSE_NOENT
2635}
2636
2637#[no_mangle]
2646pub unsafe extern "C" fn htmlParseDocument(ctxt: *mut c_void) -> c_int {
2647 if ctxt.is_null() {
2648 return -1;
2649 }
2650 let c = ctxt as *mut HtmlOpaqueCtxt;
2651 if unsafe { (*c).input.is_null() } {
2652 return -1;
2653 }
2654 let doc = unsafe { html::parse_memory((*c).input as *const c_char, (*c).input_len as c_int) };
2655 unsafe { (*c).doc = doc };
2656 if doc.is_null() {
2657 -1
2658 } else {
2659 0
2660 }
2661}
2662
2663#[no_mangle]
2674pub unsafe extern "C" fn htmlParseChunk(
2675 ctxt: *mut c_void,
2676 chunk: *const c_char,
2677 size: c_int,
2678 terminate: c_int,
2679) -> c_int {
2680 if ctxt.is_null() || size < 0 || (size > 0 && chunk.is_null()) {
2681 return XML_ERR_ARGUMENT;
2682 }
2683 let c = ctxt as *mut HtmlOpaqueCtxt;
2684 if unsafe { (*c).input.is_null() } {
2685 return XML_ERR_ARGUMENT;
2686 }
2687
2688 if size > 0 {
2689 let new_len = unsafe { (*c).input_len }.wrapping_add(size as usize);
2690 let nb = unsafe { xmlReallocImpl((*c).input as *mut c_void, new_len) } as *mut u8;
2691 if nb.is_null() {
2692 return XML_ERR_NO_MEMORY;
2693 }
2694 unsafe {
2695 ptr::copy_nonoverlapping(chunk as *const u8, nb.add((*c).input_len), size as usize);
2696 (*c).input = nb;
2697 (*c).input_len = new_len;
2698 }
2699 }
2700
2701 if terminate != 0 {
2702 let doc =
2703 unsafe { html::parse_memory((*c).input as *const c_char, (*c).input_len as c_int) };
2704 unsafe {
2705 (*c).doc = doc;
2706 xmlFreeImpl((*c).input as *mut c_void);
2708 (*c).input = ptr::null_mut();
2709 (*c).input_len = 0;
2710 }
2711 }
2712 XML_ERR_OK
2713}
2714
2715#[no_mangle]
2723pub unsafe extern "C" fn htmlCtxtParseDocument(
2724 ctxt: *mut c_void,
2725 input: *mut _xmlParserInput,
2726) -> *mut _xmlDoc {
2727 if ctxt.is_null() || input.is_null() {
2728 return ptr::null_mut();
2729 }
2730 let cur = unsafe { (*input).cur };
2731 let end = unsafe { (*input).end };
2732 if cur.is_null() {
2733 return ptr::null_mut();
2734 }
2735 let len = (end as usize).wrapping_sub(cur as usize) as c_int;
2736 if len <= 0 {
2737 return ptr::null_mut();
2738 }
2739 let doc = unsafe { html::parse_memory(cur as *const c_char, len) };
2740 let c = ctxt as *mut HtmlOpaqueCtxt;
2741 unsafe {
2742 (*c).doc = doc;
2743 }
2744 doc
2745}
2746
2747unsafe fn html_ctxt_finish_read(
2754 ctxt: *mut c_void,
2755 doc: *mut _xmlDoc,
2756 url: *const c_char,
2757) -> *mut _xmlDoc {
2758 if ctxt.is_null() {
2759 return doc;
2760 }
2761 let c = ctxt as *mut HtmlOpaqueCtxt;
2762 unsafe {
2763 (*c).doc = doc;
2764 if !doc.is_null() && !url.is_null() {
2765 (*doc).URL = c_strdup(url) as *mut xmlChar;
2766 }
2767 }
2768 doc
2769}
2770
2771#[no_mangle]
2780pub unsafe extern "C" fn htmlCtxtReadMemory(
2781 ctxt: *mut c_void,
2782 buffer: *const c_char,
2783 size: c_int,
2784 URL: *const c_char,
2785 _encoding: *const c_char,
2786 options: c_int,
2787) -> *mut _xmlDoc {
2788 if ctxt.is_null() || size < 0 {
2789 return ptr::null_mut();
2790 }
2791 unsafe { htmlCtxtReset(ctxt) };
2792 unsafe { htmlCtxtUseOptions(ctxt, options) };
2793 let doc = unsafe { html::parse_memory(buffer, size) };
2794 unsafe { html_ctxt_finish_read(ctxt, doc, URL) }
2795}
2796
2797#[no_mangle]
2806pub unsafe extern "C" fn htmlCtxtReadDoc(
2807 ctxt: *mut c_void,
2808 str: *const xmlChar,
2809 URL: *const c_char,
2810 encoding: *const c_char,
2811 options: c_int,
2812) -> *mut _xmlDoc {
2813 if ctxt.is_null() {
2814 return ptr::null_mut();
2815 }
2816 unsafe { htmlCtxtReset(ctxt) };
2817 unsafe { htmlCtxtUseOptions(ctxt, options) };
2818 let doc = unsafe { html::parse_doc(str, encoding) };
2819 unsafe { html_ctxt_finish_read(ctxt, doc, URL) }
2820}
2821
2822#[no_mangle]
2832pub unsafe extern "C" fn htmlCtxtReadFile(
2833 ctxt: *mut c_void,
2834 filename: *const c_char,
2835 encoding: *const c_char,
2836 options: c_int,
2837) -> *mut _xmlDoc {
2838 if ctxt.is_null() {
2839 return ptr::null_mut();
2840 }
2841 unsafe { htmlCtxtReset(ctxt) };
2842 unsafe { htmlCtxtUseOptions(ctxt, options) };
2843 let doc = unsafe { html::parse_file(filename, encoding) };
2844 unsafe { html_ctxt_finish_read(ctxt, doc, filename) }
2845}
2846
2847unsafe fn html_read_fd(fd: c_int) -> Vec<u8> {
2849 let mut buf = Vec::new();
2850 let mut tmp = [0u8; 4096];
2851 loop {
2852 let n = libc::read(fd, tmp.as_mut_ptr() as *mut c_void, tmp.len());
2853 if n <= 0 {
2854 break;
2855 }
2856 buf.extend_from_slice(&tmp[..n as usize]);
2857 }
2858 buf
2859}
2860
2861unsafe fn html_read_io(ioread: Option<xmlInputReadCallback>, ioctx: *mut c_void) -> Vec<u8> {
2863 let mut buf = Vec::new();
2864 let mut tmp = [0u8; 4096];
2865 if let Some(read) = ioread {
2866 loop {
2867 let n = unsafe { read(ioctx, tmp.as_mut_ptr() as *mut c_char, tmp.len() as c_int) };
2868 if n <= 0 {
2869 break;
2870 }
2871 buf.extend_from_slice(&tmp[..n as usize]);
2872 }
2873 }
2874 buf
2875}
2876
2877#[no_mangle]
2886pub unsafe extern "C" fn htmlCtxtReadFd(
2887 ctxt: *mut c_void,
2888 fd: c_int,
2889 URL: *const c_char,
2890 _encoding: *const c_char,
2891 options: c_int,
2892) -> *mut _xmlDoc {
2893 if ctxt.is_null() {
2894 return ptr::null_mut();
2895 }
2896 unsafe { htmlCtxtReset(ctxt) };
2897 unsafe { htmlCtxtUseOptions(ctxt, options) };
2898 let data = unsafe { html_read_fd(fd) };
2899 let doc = unsafe { html::parse_memory(data.as_ptr() as *const c_char, data.len() as c_int) };
2900 unsafe { html_ctxt_finish_read(ctxt, doc, URL) }
2901}
2902
2903#[no_mangle]
2913pub unsafe extern "C" fn htmlCtxtReadIO(
2914 ctxt: *mut c_void,
2915 ioread: Option<xmlInputReadCallback>,
2916 _ioclose: Option<xmlInputCloseCallback>,
2917 ioctx: *mut c_void,
2918 URL: *const c_char,
2919 _encoding: *const c_char,
2920 options: c_int,
2921) -> *mut _xmlDoc {
2922 if ctxt.is_null() {
2923 return ptr::null_mut();
2924 }
2925 unsafe { htmlCtxtReset(ctxt) };
2926 unsafe { htmlCtxtUseOptions(ctxt, options) };
2927 let data = unsafe { html_read_io(ioread, ioctx) };
2928 let doc = unsafe { html::parse_memory(data.as_ptr() as *const c_char, data.len() as c_int) };
2929 unsafe { html_ctxt_finish_read(ctxt, doc, URL) }
2930}
2931
2932#[no_mangle]
2941pub unsafe extern "C" fn htmlReadMemory(
2942 buffer: *const c_char,
2943 size: c_int,
2944 url: *const c_char,
2945 encoding: *const c_char,
2946 options: c_int,
2947) -> *mut _xmlDoc {
2948 if size < 0 {
2949 return ptr::null_mut();
2950 }
2951 let ctxt = unsafe { htmlNewParserCtxt() };
2952 if ctxt.is_null() {
2953 return ptr::null_mut();
2954 }
2955 let doc = unsafe { htmlCtxtReadMemory(ctxt, buffer, size, url, encoding, options) };
2956 unsafe { crate::xml::html::free_parser_ctxt(ctxt) };
2957 doc
2958}
2959
2960#[no_mangle]
2970pub unsafe extern "C" fn htmlReadDoc(
2971 str: *const xmlChar,
2972 url: *const c_char,
2973 encoding: *const c_char,
2974 options: c_int,
2975) -> *mut _xmlDoc {
2976 let ctxt = unsafe { htmlNewParserCtxt() };
2977 if ctxt.is_null() {
2978 return ptr::null_mut();
2979 }
2980 let doc = unsafe { htmlCtxtReadDoc(ctxt, str, url, encoding, options) };
2981 unsafe { crate::xml::html::free_parser_ctxt(ctxt) };
2982 doc
2983}
2984
2985#[no_mangle]
2994pub unsafe extern "C" fn htmlReadFile(
2995 filename: *const c_char,
2996 encoding: *const c_char,
2997 options: c_int,
2998) -> *mut _xmlDoc {
2999 let ctxt = unsafe { htmlNewParserCtxt() };
3000 if ctxt.is_null() {
3001 return ptr::null_mut();
3002 }
3003 let doc = unsafe { htmlCtxtReadFile(ctxt, filename, encoding, options) };
3004 unsafe { crate::xml::html::free_parser_ctxt(ctxt) };
3005 doc
3006}
3007
3008#[no_mangle]
3016pub unsafe extern "C" fn htmlReadFd(
3017 fd: c_int,
3018 url: *const c_char,
3019 encoding: *const c_char,
3020 options: c_int,
3021) -> *mut _xmlDoc {
3022 let ctxt = unsafe { htmlNewParserCtxt() };
3023 if ctxt.is_null() {
3024 return ptr::null_mut();
3025 }
3026 let doc = unsafe { htmlCtxtReadFd(ctxt, fd, url, encoding, options) };
3027 unsafe { crate::xml::html::free_parser_ctxt(ctxt) };
3028 doc
3029}
3030
3031#[no_mangle]
3041pub unsafe extern "C" fn htmlReadIO(
3042 ioread: Option<xmlInputReadCallback>,
3043 ioclose: Option<xmlInputCloseCallback>,
3044 ioctx: *mut c_void,
3045 url: *const c_char,
3046 encoding: *const c_char,
3047 options: c_int,
3048) -> *mut _xmlDoc {
3049 let ctxt = unsafe { htmlNewParserCtxt() };
3050 if ctxt.is_null() {
3051 return ptr::null_mut();
3052 }
3053 let doc = unsafe { htmlCtxtReadIO(ctxt, ioread, ioclose, ioctx, url, encoding, options) };
3054 unsafe { crate::xml::html::free_parser_ctxt(ctxt) };
3055 doc
3056}
3057
3058#[no_mangle]
3069pub unsafe extern "C" fn htmlSAXParseDoc(
3070 cur: *const xmlChar,
3071 encoding: *const c_char,
3072 sax: *mut _xmlSAXHandler,
3073 userData: *mut c_void,
3074) -> *mut _xmlDoc {
3075 if cur.is_null() {
3076 return ptr::null_mut();
3077 }
3078 let ctxt = unsafe { htmlNewSAXParserCtxt(sax, userData) };
3079 if ctxt.is_null() {
3080 return ptr::null_mut();
3081 }
3082 let doc = unsafe { htmlCtxtReadDoc(ctxt, cur, ptr::null(), encoding, 0) };
3083 unsafe { crate::xml::html::free_parser_ctxt(ctxt) };
3084 doc
3085}
3086
3087#[no_mangle]
3098pub unsafe extern "C" fn htmlSAXParseFile(
3099 filename: *const c_char,
3100 encoding: *const c_char,
3101 sax: *mut _xmlSAXHandler,
3102 userData: *mut c_void,
3103) -> *mut _xmlDoc {
3104 let ctxt = unsafe { htmlNewSAXParserCtxt(sax, userData) };
3105 if ctxt.is_null() {
3106 return ptr::null_mut();
3107 }
3108 let doc = unsafe { htmlCtxtReadFile(ctxt, filename, encoding, 0) };
3109 unsafe { crate::xml::html::free_parser_ctxt(ctxt) };
3110 doc
3111}
3112
3113#[no_mangle]
3124pub unsafe extern "C" fn htmlParseElement(ctxt: *mut c_void) {
3125 if ctxt.is_null() {
3126 return;
3127 }
3128 let c = ctxt as *mut HtmlOpaqueCtxt;
3129 if unsafe { (*c).input.is_null() } {
3130 return;
3131 }
3132 let doc = unsafe { html::parse_memory((*c).input as *const c_char, (*c).input_len as c_int) };
3133 unsafe {
3134 (*c).doc = doc;
3135 }
3136}
3137
3138#[no_mangle]
3151pub unsafe extern "C" fn htmlNewDocNoDtD(
3152 URI: *const xmlChar,
3153 publicId: *const xmlChar,
3154) -> *mut _xmlDoc {
3155 let doc = unsafe { html::new_doc_no_dtd(ptr::null()) };
3156 if doc.is_null() {
3157 return ptr::null_mut();
3158 }
3159 unsafe {
3160 (*doc).standalone = 1;
3163 (*doc).charset = crate::abi::types::xmlCharEncoding::XML_CHAR_ENCODING_UTF8 as c_int;
3164 (*doc).properties = crate::abi::types::xmlDocProperties::XML_DOC_HTML as c_int
3165 | crate::abi::types::xmlDocProperties::XML_DOC_USERBUILT as c_int;
3166 if !publicId.is_null() || !URI.is_null() {
3167 let dtd = crate::xml::dtd::create_int_subset(
3168 doc,
3169 b"html\0" as *const u8 as *const xmlChar,
3170 publicId,
3171 URI,
3172 );
3173 if dtd.is_null() {
3174 tree::free_doc(doc);
3175 return ptr::null_mut();
3176 }
3177 }
3178 }
3179 doc
3180}
3181
3182#[no_mangle]
3197pub unsafe extern "C" fn htmlNewDoc(
3198 URI: *const xmlChar,
3199 ExternalID: *const xmlChar,
3200) -> *mut _xmlDoc {
3201 let doc = unsafe { html::new_doc(ptr::null()) };
3202 if doc.is_null() {
3203 return ptr::null_mut();
3204 }
3205 unsafe {
3206 (*doc).standalone = 1;
3209 (*doc).charset = crate::abi::types::xmlCharEncoding::XML_CHAR_ENCODING_UTF8 as c_int;
3210 (*doc).properties = crate::abi::types::xmlDocProperties::XML_DOC_HTML as c_int
3211 | crate::abi::types::xmlDocProperties::XML_DOC_USERBUILT as c_int;
3212 if URI.is_null() && ExternalID.is_null() {
3213 let dtd = crate::xml::dtd::create_int_subset(
3214 doc,
3215 b"html\0" as *const u8 as *const xmlChar,
3216 b"-//W3C//DTD HTML 4.0 Transitional//EN\0" as *const u8 as *const xmlChar,
3217 b"http://www.w3.org/TR/REC-html40/loose.dtd\0" as *const u8 as *const xmlChar,
3218 );
3219 if dtd.is_null() {
3220 tree::free_doc(doc);
3221 return ptr::null_mut();
3222 }
3223 } else if !ExternalID.is_null() || !URI.is_null() {
3224 let dtd = crate::xml::dtd::create_int_subset(
3225 doc,
3226 b"html\0" as *const u8 as *const xmlChar,
3227 ExternalID,
3228 URI,
3229 );
3230 if dtd.is_null() {
3231 tree::free_doc(doc);
3232 return ptr::null_mut();
3233 }
3234 }
3235 }
3236 doc
3237}
3238
3239unsafe fn html_find_first_child(node: *mut _xmlNode, name: &[u8]) -> *mut _xmlNode {
3245 let mut c = unsafe { (*node).children };
3246 while !c.is_null() {
3247 let n = unsafe { &*c };
3248 if n.type_ == XML_ELEMENT_NODE as c_int
3249 && !n.name.is_null()
3250 && unsafe { xmlstr_to_bytes(n.name) }.eq_ignore_ascii_case(name)
3251 {
3252 return c;
3253 }
3254 c = unsafe { (*c).next };
3255 }
3256 ptr::null_mut()
3257}
3258
3259unsafe fn html_find_head(doc: *mut _xmlDoc) -> *mut _xmlNode {
3262 if doc.is_null() {
3263 return ptr::null_mut();
3264 }
3265 let html = unsafe { html_find_first_child(doc as *mut _xmlNode, b"html") };
3266 if html.is_null() {
3267 return ptr::null_mut();
3268 }
3269 unsafe { html_find_first_child(html, b"head") }
3270}
3271
3272unsafe fn html_find_meta_encoding_attr(elem: *mut _xmlNode) -> (*mut _xmlAttr, bool) {
3275 let n = unsafe { &*elem };
3276 if n.type_ != XML_ELEMENT_NODE as c_int || n.name.is_null() {
3277 return (ptr::null_mut(), false);
3278 }
3279 if !unsafe { xmlstr_to_bytes(n.name) }.eq_ignore_ascii_case(b"meta") {
3280 return (ptr::null_mut(), false);
3281 }
3282
3283 let mut content_attr: *mut _xmlAttr = ptr::null_mut();
3284 let mut is_content_type = false;
3285 let mut attr = n.properties;
3286 while !attr.is_null() {
3287 let a = unsafe { &*attr };
3288 if a.ns.is_null() && !a.name.is_null() {
3289 let nm = unsafe { xmlstr_to_bytes(a.name) };
3290 if nm.eq_ignore_ascii_case(b"charset") {
3291 return (attr, false);
3292 }
3293 if nm.eq_ignore_ascii_case(b"content") {
3294 content_attr = attr;
3295 }
3296 if nm.eq_ignore_ascii_case(b"http-equiv")
3297 && !a.children.is_null()
3298 && unsafe { (*(a.children)).type_ } == XML_TEXT_NODE as c_int
3299 && unsafe { (*(a.children)).next }.is_null()
3300 && !unsafe { (*(a.children)).content }.is_null()
3301 && unsafe { xmlstr_to_bytes((*(a.children)).content) }
3302 .eq_ignore_ascii_case(b"Content-Type")
3303 {
3304 is_content_type = true;
3305 }
3306 }
3307 attr = unsafe { (*attr).next };
3308 }
3309 if is_content_type && !content_attr.is_null() {
3310 (content_attr, true)
3311 } else {
3312 (ptr::null_mut(), false)
3313 }
3314}
3315
3316unsafe fn html_parse_content_type(val: *const xmlChar) -> Option<(usize, usize, usize)> {
3319 let bytes = unsafe { xmlstr_to_bytes(val) };
3320 let n = bytes.len();
3321 let at = |i: usize| -> u8 {
3322 if i < n {
3323 bytes[i]
3324 } else {
3325 0
3326 }
3327 };
3328
3329 let mut p = 0usize;
3330 loop {
3331 loop {
3333 let ch = at(p);
3334 if ch == b'c' || ch == b'C' {
3335 break;
3336 }
3337 if ch == 0 {
3338 return None;
3339 }
3340 p += 1;
3341 }
3342 p += 1;
3343
3344 let mut ok = true;
3346 for (k, want) in b"harset".iter().enumerate() {
3347 if at(p + k).to_ascii_lowercase() != *want {
3348 ok = false;
3349 break;
3350 }
3351 }
3352 if !ok {
3353 continue;
3354 }
3355 p += 6;
3356 while is_ws_html(at(p)) {
3357 p += 1;
3358 }
3359 if at(p) != b'=' {
3360 continue;
3361 }
3362 p += 1;
3363 while is_ws_html(at(p)) {
3364 p += 1;
3365 }
3366 if at(p) == 0 {
3367 return None;
3368 }
3369
3370 let (start, mut end): (usize, usize);
3371 if at(p) == b'"' || at(p) == b'\'' {
3372 let quote = at(p);
3373 p += 1;
3374 while is_ws_html(at(p)) {
3375 p += 1;
3376 }
3377 start = p;
3378 end = start;
3379 loop {
3380 if at(p) == 0 {
3381 return None;
3382 }
3383 if !is_ws_html(at(p)) {
3384 end = p + 1;
3385 }
3386 if at(p) == quote {
3387 break;
3388 }
3389 p += 1;
3390 }
3391 } else {
3392 start = p;
3393 while at(p) != 0 && at(p) != b';' && !is_ws_html(at(p)) {
3394 p += 1;
3395 }
3396 end = p;
3397 }
3398 let size = n;
3399 return Some((start, end, size));
3400 }
3401}
3402
3403#[no_mangle]
3415pub unsafe extern "C" fn htmlGetMetaEncoding(doc: *mut _xmlDoc) -> *const xmlChar {
3416 let head = unsafe { html_find_head(doc) };
3417 if head.is_null() {
3418 return ptr::null();
3419 }
3420 let mut node = unsafe { (*head).children };
3421 while !node.is_null() {
3422 let (attr, is_content_type) = unsafe { html_find_meta_encoding_attr(node) };
3423 if !attr.is_null() {
3424 let a = unsafe { &*attr };
3425 let val = if !a.children.is_null()
3426 && unsafe { (*(a.children)).type_ } == XML_TEXT_NODE as c_int
3427 && unsafe { (*(a.children)).next }.is_null()
3428 && !unsafe { (*(a.children)).content }.is_null()
3429 {
3430 unsafe { (*(a.children)).content }
3431 } else {
3432 b"\0" as *const u8 as *const xmlChar
3433 };
3434 if !is_content_type {
3435 let bytes = unsafe { xmlstr_to_bytes(val) };
3436 let mut start = 0usize;
3437 while start < bytes.len() && is_ws_html(bytes[start]) {
3438 start += 1;
3439 }
3440 return unsafe { val.add(start) };
3441 } else if let Some((start, _, _)) = unsafe { html_parse_content_type(val) } {
3442 return unsafe { val.add(start) };
3443 }
3444 }
3445 node = unsafe { (*node).next };
3446 }
3447 ptr::null()
3448}
3449
3450unsafe fn html_update_meta_encoding(
3453 attr_value: *const xmlChar,
3454 start: usize,
3455 end: usize,
3456 size: usize,
3457 encoding: &[u8],
3458) -> *mut xmlChar {
3459 let enc: &[u8] = if encoding.eq_ignore_ascii_case(b"HTML") {
3461 b"ASCII"
3462 } else {
3463 encoding
3464 };
3465 let bytes = unsafe { xmlstr_to_bytes(attr_value) };
3466 let e = end.min(bytes.len()).min(size);
3467 let s = start.min(e);
3468 let total = size - (e - s) + enc.len();
3469 let new_val = xmlMallocImpl(total + 1) as *mut xmlChar;
3470 if new_val.is_null() {
3471 return ptr::null_mut();
3472 }
3473 unsafe {
3474 let mut p = new_val;
3475 ptr::copy_nonoverlapping(bytes.as_ptr(), p, s);
3476 p = p.add(s);
3477 ptr::copy_nonoverlapping(enc.as_ptr(), p, enc.len());
3478 p = p.add(enc.len());
3479 ptr::copy_nonoverlapping(bytes.as_ptr().add(e), p, size - e);
3480 *new_val.add(total) = 0;
3481 }
3482 new_val
3483}
3484
3485unsafe fn html_set_attr_content(attr: *mut _xmlAttr, content: *const xmlChar) -> c_int {
3488 if attr.is_null() {
3489 return -1;
3490 }
3491 unsafe {
3492 if !(*attr).children.is_null() {
3493 tree::free_node_list((*attr).children);
3494 (*attr).children = ptr::null_mut();
3495 (*attr).last = ptr::null_mut();
3496 }
3497 let text = tree::new_text(content);
3498 if text.is_null() {
3499 return -1;
3500 }
3501 (*text).parent = attr as *mut _xmlNode;
3502 (*text).doc = (*attr).doc;
3503 (*attr).children = text;
3504 (*attr).last = text;
3505 }
3506 0
3507}
3508
3509#[no_mangle]
3517pub unsafe extern "C" fn htmlSetMetaEncoding(doc: *mut _xmlDoc, encoding: *const xmlChar) -> c_int {
3518 if encoding.is_null() {
3519 return 1;
3520 }
3521 let head = unsafe { html_find_head(doc) };
3522 if head.is_null() {
3523 return 1;
3524 }
3525 let enc_bytes = unsafe { xmlstr_to_bytes(encoding) }.to_vec();
3526
3527 let mut found = 0;
3528 let mut meta = unsafe { (*head).children };
3529 while !meta.is_null() {
3530 let (attr, is_content_type) = unsafe { html_find_meta_encoding_attr(meta) };
3531 if !attr.is_null() {
3532 let a = unsafe { &*attr };
3533 let val = if !a.children.is_null()
3534 && unsafe { (*(a.children)).type_ } == XML_TEXT_NODE as c_int
3535 && unsafe { (*(a.children)).next }.is_null()
3536 && !unsafe { (*(a.children)).content }.is_null()
3537 {
3538 unsafe { (*(a.children)).content }
3539 } else {
3540 b"\0" as *const u8 as *const xmlChar
3541 };
3542 found = 1;
3543 let off = if is_content_type {
3544 unsafe { html_parse_content_type(val) }
3545 } else {
3546 let bytes = unsafe { xmlstr_to_bytes(val) };
3547 let mut start = 0usize;
3548 let mut end = bytes.len();
3549 while start < end && is_ws_html(bytes[start]) {
3550 start += 1;
3551 }
3552 while end > start && is_ws_html(bytes[end - 1]) {
3553 end -= 1;
3554 }
3555 Some((start, end, bytes.len()))
3556 };
3557 if let Some((start, end, size)) = off {
3558 let new_val =
3559 unsafe { html_update_meta_encoding(val, start, end, size, &enc_bytes) };
3560 if new_val.is_null() {
3561 return -1;
3562 }
3563 let ret = unsafe { html_set_attr_content(attr, new_val) };
3564 unsafe { xmlFreeImpl(new_val as *mut c_void) };
3565 if ret < 0 {
3566 return -1;
3567 }
3568 } else {
3569 return -1;
3570 }
3571 }
3572 meta = unsafe { (*meta).next };
3573 }
3574
3575 if found != 0 {
3576 return 0;
3577 }
3578
3579 let meta_node =
3581 unsafe { tree::new_node(ptr::null_mut(), b"meta\0" as *const u8 as *const xmlChar) };
3582 if meta_node.is_null() {
3583 return -1;
3584 }
3585 unsafe {
3586 (*meta_node).doc = (*head).doc;
3587 }
3588 let prop = unsafe {
3589 tree::set_prop(
3590 meta_node,
3591 b"charset\0" as *const u8 as *const xmlChar,
3592 encoding,
3593 )
3594 };
3595 if prop.is_null() {
3596 unsafe { tree::free_node(meta_node) };
3597 return -1;
3598 }
3599 if unsafe { (*head).children }.is_null() {
3600 unsafe { tree::add_child(head, meta_node) };
3601 } else {
3602 unsafe { tree::add_sibling_before((*head).children, meta_node) };
3603 }
3604 0
3605}
3606
3607unsafe fn html_serialize_to_buffer(node: *mut _xmlNode, format: c_int) -> *mut _xmlBuffer {
3614 let buf = io::buf_create(0);
3615 if buf.is_null() {
3616 return ptr::null_mut();
3617 }
3618 unsafe { html::serialize_node(node, buf, format, 0) };
3619 buf
3620}
3621
3622unsafe fn html_serialize_to_obuf(obuf: *mut _xmlOutputBuffer, node: *mut _xmlNode, format: c_int) {
3625 if obuf.is_null() || node.is_null() {
3626 return;
3627 }
3628 let buf = unsafe { html_serialize_to_buffer(node, format) };
3629 if buf.is_null() {
3630 return;
3631 }
3632 let len = io::buf_length(buf);
3633 if len > 0 {
3634 let content = io::buf_content(buf);
3635 unsafe {
3636 io::output_buffer_write(obuf, len, content as *const c_char);
3637 }
3638 }
3639 io::buf_free(buf);
3640}
3641
3642#[no_mangle]
3650pub unsafe extern "C" fn htmlNodeDump(
3651 buf: *mut _xmlBuffer,
3652 _doc: *mut _xmlDoc,
3653 cur: *mut _xmlNode,
3654) -> c_int {
3655 if buf.is_null() || cur.is_null() {
3656 return -1;
3657 }
3658 let before = io::buf_length(buf);
3659 unsafe { html::serialize_node(cur, buf, 1, 0) };
3660 let after = io::buf_length(buf);
3661 if after < 0 || before < 0 {
3662 return -1;
3663 }
3664 after - before
3665}
3666
3667#[no_mangle]
3675pub unsafe extern "C" fn htmlNodeDumpFile(out: *mut c_void, doc: *mut _xmlDoc, cur: *mut _xmlNode) {
3676 unsafe { htmlNodeDumpFileFormat(out, doc, cur, ptr::null(), 1) };
3677}
3678
3679#[no_mangle]
3688pub unsafe extern "C" fn htmlNodeDumpFileFormat(
3689 out: *mut c_void,
3690 _doc: *mut _xmlDoc,
3691 cur: *mut _xmlNode,
3692 _encoding: *const c_char,
3693 format: c_int,
3694) -> c_int {
3695 let obuf = io::output_buffer_create_file(out as *mut libc::FILE, ptr::null_mut());
3696 if obuf.is_null() {
3697 return -1;
3698 }
3699 unsafe { html_serialize_to_obuf(obuf, cur, format) };
3700 io::output_buffer_close(obuf)
3701}
3702
3703#[no_mangle]
3712pub unsafe extern "C" fn htmlNodeDumpOutput(
3713 buf: *mut _xmlOutputBuffer,
3714 _doc: *mut _xmlDoc,
3715 cur: *mut _xmlNode,
3716 _encoding: *const c_char,
3717) {
3718 unsafe { html_serialize_to_obuf(buf, cur, 1) };
3719}
3720
3721#[no_mangle]
3730pub unsafe extern "C" fn htmlNodeDumpFormatOutput(
3731 buf: *mut _xmlOutputBuffer,
3732 _doc: *mut _xmlDoc,
3733 cur: *mut _xmlNode,
3734 _encoding: *const c_char,
3735 format: c_int,
3736) {
3737 unsafe { html_serialize_to_obuf(buf, cur, format) };
3738}
3739
3740#[no_mangle]
3749pub unsafe extern "C" fn htmlDocContentDumpOutput(
3750 buf: *mut _xmlOutputBuffer,
3751 cur: *mut _xmlDoc,
3752 _encoding: *const c_char,
3753) {
3754 unsafe { html_serialize_to_obuf(buf, cur as *mut _xmlNode, 1) };
3755}
3756
3757#[no_mangle]
3766pub unsafe extern "C" fn htmlDocContentDumpFormatOutput(
3767 buf: *mut _xmlOutputBuffer,
3768 cur: *mut _xmlDoc,
3769 _encoding: *const c_char,
3770 format: c_int,
3771) {
3772 unsafe { html_serialize_to_obuf(buf, cur as *mut _xmlNode, format) };
3773}
3774
3775#[no_mangle]
3785pub unsafe extern "C" fn htmlDocDumpMemoryFormat(
3786 cur: *mut _xmlDoc,
3787 mem: *mut *mut xmlChar,
3788 size: *mut c_int,
3789 format: c_int,
3790) {
3791 if mem.is_null() || size.is_null() {
3792 return;
3793 }
3794 unsafe {
3795 *mem = ptr::null_mut();
3796 *size = 0;
3797 }
3798 if cur.is_null() {
3799 return;
3800 }
3801 let buf = unsafe { html_serialize_to_buffer(cur as *mut _xmlNode, format) };
3802 if buf.is_null() {
3803 return;
3804 }
3805 let len = io::buf_length(buf);
3806 if len > 0 {
3807 let content = io::buf_content(buf);
3808 unsafe {
3809 *mem = xml_strndup(content, len as usize);
3810 if !(*mem).is_null() {
3811 *size = len;
3812 }
3813 }
3814 }
3815 io::buf_free(buf);
3816}
3817
3818#[no_mangle]
3826pub unsafe extern "C" fn htmlDocDumpMemory(
3827 cur: *mut _xmlDoc,
3828 mem: *mut *mut xmlChar,
3829 size: *mut c_int,
3830) {
3831 unsafe { htmlDocDumpMemoryFormat(cur, mem, size, 1) };
3832}
3833
3834#[no_mangle]
3842pub unsafe extern "C" fn htmlDocDump(f: *mut c_void, cur: *mut _xmlDoc) -> c_int {
3843 if f.is_null() || cur.is_null() {
3844 return -1;
3845 }
3846 let obuf = io::output_buffer_create_file(f as *mut libc::FILE, ptr::null_mut());
3847 if obuf.is_null() {
3848 return -1;
3849 }
3850 unsafe { html_serialize_to_obuf(obuf, cur as *mut _xmlNode, 1) };
3851 io::output_buffer_close(obuf)
3852}
3853
3854#[no_mangle]
3863pub unsafe extern "C" fn htmlSaveFileFormat(
3864 filename: *const c_char,
3865 cur: *mut _xmlDoc,
3866 _encoding: *const c_char,
3867 format: c_int,
3868) -> c_int {
3869 if cur.is_null() || filename.is_null() {
3870 return -1;
3871 }
3872 let obuf = io::output_buffer_create_filename(filename, ptr::null_mut(), 0);
3873 if obuf.is_null() {
3874 return 0;
3876 }
3877 unsafe { html_serialize_to_obuf(obuf, cur as *mut _xmlNode, format) };
3878 io::output_buffer_close(obuf)
3879}
3880
3881#[no_mangle]
3890pub unsafe extern "C" fn htmlSaveFile(filename: *const c_char, cur: *mut _xmlDoc) -> c_int {
3891 unsafe { htmlSaveFileFormat(filename, cur, ptr::null(), 1) }
3892}
3893
3894#[no_mangle]
3902pub unsafe extern "C" fn htmlSaveFileEnc(
3903 filename: *const c_char,
3904 cur: *mut _xmlDoc,
3905 encoding: *const c_char,
3906) -> c_int {
3907 unsafe { htmlSaveFileFormat(filename, cur, encoding, 1) }
3908}
3909
3910#[no_mangle]
3918pub unsafe extern "C" fn htmlCtxtSetOptions(ctxt: *mut c_void, options: c_int) -> c_int {
3919 if ctxt.is_null() {
3920 return -1;
3921 }
3922 let c = ctxt as *mut HtmlOpaqueCtxt;
3923 unsafe {
3924 (*c).options = options & HTML_OPTIONS_ALL_MASK;
3925 }
3926 options & !HTML_OPTIONS_ALL_MASK & !crate::abi::types::XML_PARSE_NOENT
3927}
3928
3929#[no_mangle]
3939pub unsafe extern "C" fn htmlUTF8ToHtml(
3940 out: *mut u8,
3941 outlen: *mut c_int,
3942 input: *const u8,
3943 inlen: *mut c_int,
3944) -> c_int {
3945 const XML_ENC_ERR_INTERNAL: c_int = -1;
3947 const XML_ENC_ERR_SUCCESS: c_int = 0;
3948 const XML_ENC_ERR_SPACE: c_int = -2;
3949 unsafe {
3950 if out.is_null() || outlen.is_null() || inlen.is_null() {
3951 return XML_ENC_ERR_INTERNAL;
3952 }
3953 if input.is_null() {
3954 *outlen = 0;
3955 *inlen = 0;
3956 return XML_ENC_ERR_SUCCESS;
3957 }
3958 let mut in_pos: usize = 0;
3959 let mut out_pos: usize = 0;
3960 let in_end = *inlen as usize;
3961 let out_cap = *outlen as usize;
3962 let mut ret = XML_ENC_ERR_SPACE;
3963 while in_pos < in_end {
3964 let d = *input.add(in_pos);
3965 if d < 0x80 {
3966 if out_pos >= out_cap {
3967 break;
3968 }
3969 *out.add(out_pos) = d;
3970 out_pos += 1;
3971 in_pos += 1;
3972 continue;
3973 }
3974 let (mut c, seqlen) = if d < 0xE0 {
3975 ((d & 0x1F) as u32, 2usize)
3976 } else if d < 0xF0 {
3977 ((d & 0x0F) as u32, 3usize)
3978 } else {
3979 ((d & 0x07) as u32, 4usize)
3980 };
3981 if in_end - in_pos < seqlen {
3982 break;
3983 }
3984 for i in 1..seqlen {
3985 let dd = *input.add(in_pos + i);
3986 c = (c << 6) | ((dd & 0x3F) as u32);
3987 }
3988 let ent = htmlEntityValueLookup(c);
3989 let mut nbuf = [0u8; 16];
3990 let cp: *const u8;
3991 let mut owned_len: usize = 0;
3992 if ent.is_null() {
3993 let s = format!("#{}", c);
3994 let bytes = s.as_bytes();
3995 nbuf[..bytes.len()].copy_from_slice(bytes);
3996 cp = nbuf.as_ptr();
3997 owned_len = bytes.len();
3998 } else {
3999 cp = (*ent).name as *const u8;
4000 let mut l = 0;
4001 while *cp.add(l) != 0 {
4002 l += 1;
4003 }
4004 owned_len = l;
4005 }
4006 let len = owned_len;
4007 if out_cap - out_pos < len + 2 {
4008 break;
4009 }
4010 *out.add(out_pos) = b'&';
4011 out_pos += 1;
4012 core::ptr::copy_nonoverlapping(cp, out.add(out_pos), len);
4013 out_pos += len;
4014 *out.add(out_pos) = b';';
4015 out_pos += 1;
4016 in_pos += seqlen;
4017 }
4018 ret = out_pos as c_int;
4019 *outlen = out_pos as c_int;
4020 *inlen = in_pos as c_int;
4021 ret
4022 }
4023}