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