File: html_sax_parser_context.c

package info (click to toggle)
ruby-nokogiri 1.10.0%2Bdfsg1-2
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 5,088 kB
  • sloc: xml: 28,081; ruby: 16,687; java: 13,293; ansic: 4,954; yacc: 265; sh: 76; makefile: 19
file content (116 lines) | stat: -rw-r--r-- 3,079 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#include <html_sax_parser_context.h>

VALUE cNokogiriHtmlSaxParserContext ;

static void deallocate(xmlParserCtxtPtr ctxt)
{
  NOKOGIRI_DEBUG_START(handler);

  ctxt->sax = NULL;

  htmlFreeParserCtxt(ctxt);

  NOKOGIRI_DEBUG_END(handler);
}

static VALUE
parse_memory(VALUE klass, VALUE data, VALUE encoding)
{
    htmlParserCtxtPtr ctxt;

    if (NIL_P(data))
	rb_raise(rb_eArgError, "data cannot be nil");
    if (!(int)RSTRING_LEN(data))
	rb_raise(rb_eRuntimeError, "data cannot be empty");

    ctxt = htmlCreateMemoryParserCtxt(StringValuePtr(data),
				      (int)RSTRING_LEN(data));
    if (ctxt->sax) {
	xmlFree(ctxt->sax);
	ctxt->sax = NULL;
    }

    if (RTEST(encoding)) {
	xmlCharEncodingHandlerPtr enc = xmlFindCharEncodingHandler(StringValueCStr(encoding));
	if (enc != NULL) {
	    xmlSwitchToEncoding(ctxt, enc);
	    if (ctxt->errNo == XML_ERR_UNSUPPORTED_ENCODING) {
		rb_raise(rb_eRuntimeError, "Unsupported encoding %s",
			 StringValueCStr(encoding));
	    }
	}
    }

    return Data_Wrap_Struct(klass, NULL, deallocate, ctxt);
}

static VALUE parse_file(VALUE klass, VALUE filename, VALUE encoding)
{
  htmlParserCtxtPtr ctxt = htmlCreateFileParserCtxt(
      StringValueCStr(filename),
      StringValueCStr(encoding)
  );
  return Data_Wrap_Struct(klass, NULL, deallocate, ctxt);
}

static VALUE
parse_doc(VALUE ctxt_val)
{
    htmlParserCtxtPtr ctxt = (htmlParserCtxtPtr)ctxt_val;
    htmlParseDocument(ctxt);
    return Qnil;
}

static VALUE
parse_doc_finalize(VALUE ctxt_val)
{
    htmlParserCtxtPtr ctxt = (htmlParserCtxtPtr)ctxt_val;

    if (ctxt->myDoc)
	xmlFreeDoc(ctxt->myDoc);

    NOKOGIRI_SAX_TUPLE_DESTROY(ctxt->userData);
    return Qnil;
}

static VALUE
parse_with(VALUE self, VALUE sax_handler)
{
    htmlParserCtxtPtr ctxt;
    htmlSAXHandlerPtr sax;

    if (!rb_obj_is_kind_of(sax_handler, cNokogiriXmlSaxParser))
	rb_raise(rb_eArgError, "argument must be a Nokogiri::XML::SAX::Parser");

    Data_Get_Struct(self, htmlParserCtxt, ctxt);
    Data_Get_Struct(sax_handler, htmlSAXHandler, sax);

    /* Free the sax handler since we'll assign our own */
    if (ctxt->sax && ctxt->sax != (xmlSAXHandlerPtr)&xmlDefaultSAXHandler)
	xmlFree(ctxt->sax);

    ctxt->sax = sax;
    ctxt->userData = (void *)NOKOGIRI_SAX_TUPLE_NEW(ctxt, sax_handler);

    rb_ensure(parse_doc, (VALUE)ctxt, parse_doc_finalize, (VALUE)ctxt);

    return self;
}

void init_html_sax_parser_context()
{
  VALUE nokogiri  = rb_define_module("Nokogiri");
  VALUE xml       = rb_define_module_under(nokogiri, "XML");
  VALUE html      = rb_define_module_under(nokogiri, "HTML");
  VALUE sax       = rb_define_module_under(xml, "SAX");
  VALUE hsax      = rb_define_module_under(html, "SAX");
  VALUE pc        = rb_define_class_under(sax, "ParserContext", rb_cObject);
  VALUE klass     = rb_define_class_under(hsax, "ParserContext", pc);

  cNokogiriHtmlSaxParserContext = klass;

  rb_define_singleton_method(klass, "memory", parse_memory, 2);
  rb_define_singleton_method(klass, "file", parse_file, 2);

  rb_define_method(klass, "parse_with", parse_with, 1);
}