makiri 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/conformance.yml +22 -0
  3. data/.github/workflows/libfuzzer.yml +83 -0
  4. data/.github/workflows/release.yml +12 -7
  5. data/.github/workflows/security.yml +88 -3
  6. data/.github/workflows/valgrind.yml +135 -0
  7. data/CHANGELOG.md +152 -15
  8. data/README.md +183 -13
  9. data/Rakefile +294 -7
  10. data/ext/makiri/bridge/bridge.h +28 -0
  11. data/ext/makiri/bridge/ruby_string.c +282 -12
  12. data/ext/makiri/core/mkr_alloc.c +40 -3
  13. data/ext/makiri/core/mkr_alloc.h +28 -5
  14. data/ext/makiri/core/mkr_buf.c +47 -3
  15. data/ext/makiri/core/mkr_buf.h +112 -3
  16. data/ext/makiri/core/mkr_core.c +143 -0
  17. data/ext/makiri/core/mkr_core.h +11 -2
  18. data/ext/makiri/core/mkr_hash.h +1 -1
  19. data/ext/makiri/core/mkr_span.h +186 -0
  20. data/ext/makiri/core/mkr_text.h +8 -8
  21. data/ext/makiri/core/mkr_utf8.c +101 -0
  22. data/ext/makiri/core/mkr_utf8.h +88 -0
  23. data/ext/makiri/extconf.rb +123 -10
  24. data/ext/makiri/fuzz/Makefile +95 -0
  25. data/ext/makiri/fuzz/check_fuzzer.cc +4 -0
  26. data/ext/makiri/fuzz/xml_fuzz.c +24 -0
  27. data/ext/makiri/fuzz/xpath_fuzz.c +109 -0
  28. data/ext/makiri/glue/glue.h +55 -11
  29. data/ext/makiri/glue/ruby_doc.c +129 -59
  30. data/ext/makiri/glue/ruby_html_css.c +292 -0
  31. data/ext/makiri/glue/{ruby_mutate.c → ruby_html_mutate.c} +248 -52
  32. data/ext/makiri/glue/ruby_html_node.c +859 -0
  33. data/ext/makiri/glue/ruby_html_serialize.c +154 -0
  34. data/ext/makiri/glue/ruby_node.c +74 -729
  35. data/ext/makiri/glue/ruby_node_set.c +167 -32
  36. data/ext/makiri/glue/ruby_xml.c +602 -0
  37. data/ext/makiri/glue/ruby_xml_node.c +1373 -0
  38. data/ext/makiri/glue/ruby_xpath.c +63 -30
  39. data/ext/makiri/glue/ruby_xpath.h +19 -0
  40. data/ext/makiri/lexbor_compat/compat.h +42 -9
  41. data/ext/makiri/lexbor_compat/compat_internal.h +1 -1
  42. data/ext/makiri/lexbor_compat/dom_index.c +2 -2
  43. data/ext/makiri/lexbor_compat/post_parse.c +100 -10
  44. data/ext/makiri/lexbor_compat/source_loc.c +15 -13
  45. data/ext/makiri/lexbor_compat/text_index.c +14 -8
  46. data/ext/makiri/lexbor_compat/utf8_input.c +19 -33
  47. data/ext/makiri/makiri.c +184 -6
  48. data/ext/makiri/makiri.h +43 -2
  49. data/ext/makiri/xml/mkr_xml.h +125 -0
  50. data/ext/makiri/xml/mkr_xml_chars.c +195 -0
  51. data/ext/makiri/xml/mkr_xml_index.c +169 -0
  52. data/ext/makiri/xml/mkr_xml_index.h +48 -0
  53. data/ext/makiri/xml/mkr_xml_mutate.c +817 -0
  54. data/ext/makiri/xml/mkr_xml_mutate.h +139 -0
  55. data/ext/makiri/xml/mkr_xml_node.c +399 -0
  56. data/ext/makiri/xml/mkr_xml_node.h +184 -0
  57. data/ext/makiri/xml/mkr_xml_tree.c +1515 -0
  58. data/ext/makiri/xpath/mkr_css.c +1023 -0
  59. data/ext/makiri/xpath/mkr_css.h +65 -0
  60. data/ext/makiri/xpath/mkr_xpath.c +96 -32
  61. data/ext/makiri/xpath/mkr_xpath.h +109 -4
  62. data/ext/makiri/xpath/mkr_xpath_engine_html.c +17 -0
  63. data/ext/makiri/xpath/mkr_xpath_engine_xml.c +12 -0
  64. data/ext/makiri/xpath/{mkr_xpath_eval.c → mkr_xpath_eval_body.h} +551 -241
  65. data/ext/makiri/xpath/{mkr_xpath_funcs.c → mkr_xpath_funcs_body.h} +318 -276
  66. data/ext/makiri/xpath/mkr_xpath_internal.h +177 -206
  67. data/ext/makiri/xpath/mkr_xpath_lex.c +95 -125
  68. data/ext/makiri/xpath/mkr_xpath_node_access_html.h +138 -0
  69. data/ext/makiri/xpath/mkr_xpath_node_access_xml.h +145 -0
  70. data/ext/makiri/xpath/mkr_xpath_number.c +109 -0
  71. data/ext/makiri/xpath/mkr_xpath_parse.c +83 -94
  72. data/ext/makiri/xpath/mkr_xpath_prelude_html.h +30 -0
  73. data/ext/makiri/xpath/mkr_xpath_prelude_xml.h +28 -0
  74. data/ext/makiri/xpath/mkr_xpath_shared.c +609 -0
  75. data/ext/makiri/xpath/mkr_xpath_value_body.h +801 -0
  76. data/ext/makiri/xpath/mkr_xpath_xml_selftest.c +76 -0
  77. data/lib/makiri/{attribute.rb → attr.rb} +7 -3
  78. data/lib/makiri/cdata_section.rb +19 -0
  79. data/lib/makiri/comment.rb +10 -0
  80. data/lib/makiri/compat_aliases.rb +30 -0
  81. data/lib/makiri/document.rb +9 -73
  82. data/lib/makiri/document_fragment.rb +14 -9
  83. data/lib/makiri/element.rb +4 -4
  84. data/lib/makiri/html/document.rb +106 -0
  85. data/lib/makiri/html/node_methods.rb +19 -0
  86. data/lib/makiri/html.rb +12 -0
  87. data/lib/makiri/node.rb +58 -15
  88. data/lib/makiri/node_set.rb +8 -0
  89. data/lib/makiri/processing_instruction.rb +10 -0
  90. data/lib/makiri/text.rb +1 -1
  91. data/lib/makiri/version.rb +1 -1
  92. data/lib/makiri/xml/builder.rb +263 -0
  93. data/lib/makiri/xml/document.rb +24 -0
  94. data/lib/makiri/xml/node_methods.rb +84 -0
  95. data/lib/makiri/xml.rb +10 -0
  96. data/lib/makiri/xpath_context.rb +1 -1
  97. data/lib/makiri.rb +24 -5
  98. data/script/build_native_gem.rb +2 -2
  99. data/script/check_alloc_failures.rb +266 -0
  100. data/script/check_c_safety.rb +77 -2
  101. data/script/check_c_safety_allowlist.yml +102 -0
  102. data/script/check_leaks.rb +64 -0
  103. data/script/leaks_harness.rb +64 -0
  104. data/vendor/lexbor/CMakeLists.txt +6 -0
  105. data/vendor/lexbor/README.md +12 -0
  106. data/vendor/lexbor/config.cmake +1 -1
  107. data/vendor/lexbor/source/lexbor/core/base.h +1 -1
  108. data/vendor/lexbor/source/lexbor/core/config.cmake +9 -1
  109. data/vendor/lexbor/source/lexbor/css/selectors/pseudo_state.c +2 -3
  110. data/vendor/lexbor/source/lexbor/css/selectors/state.c +3 -0
  111. data/vendor/lexbor/source/lexbor/dom/interfaces/element.c +21 -0
  112. data/vendor/lexbor/source/lexbor/dom/interfaces/element.h +5 -0
  113. data/vendor/lexbor/source/lexbor/encoding/decode.c +33 -4
  114. data/vendor/lexbor/source/lexbor/html/base.h +1 -1
  115. data/vendor/lexbor/source/lexbor/html/interfaces/select_element.c +4 -0
  116. data/vendor/lexbor/source/lexbor/html/serialize.c +545 -41
  117. data/vendor/lexbor/source/lexbor/html/serialize.h +2 -1
  118. data/vendor/lexbor/source/lexbor/html/tokenizer.h +2 -2
  119. data/vendor/lexbor/source/lexbor/html/tree/insertion_mode/in_body.c +1 -1
  120. data/vendor/lexbor/source/lexbor/html/tree.c +6 -6
  121. data/vendor/lexbor/source/lexbor/selectors/selectors.c +12 -3
  122. data/vendor/lexbor/source/lexbor/url/base.h +1 -1
  123. data/vendor/lexbor/source/lexbor/url/url.c +5 -2
  124. data/vendor/lexbor/source/lexbor/url/url.h +9 -0
  125. data/vendor/lexbor/version +1 -1
  126. metadata +53 -9
  127. data/ext/makiri/glue/ruby_css.c +0 -185
  128. data/ext/makiri/glue/ruby_serialize.c +0 -92
  129. data/ext/makiri/xpath/mkr_xpath_value.c +0 -1286
  130. data/lib/makiri/cdata.rb +0 -6
@@ -27,7 +27,8 @@ enum lxb_html_serialize_opt {
27
27
  LXB_HTML_SERIALIZE_OPT_WITHOUT_CLOSING = 0x08,
28
28
  LXB_HTML_SERIALIZE_OPT_TAG_WITH_NS = 0x10,
29
29
  LXB_HTML_SERIALIZE_OPT_WITHOUT_TEXT_INDENT = 0x20,
30
- LXB_HTML_SERIALIZE_OPT_FULL_DOCTYPE = 0x40
30
+ LXB_HTML_SERIALIZE_OPT_FULL_DOCTYPE = 0x40,
31
+ LXB_HTML_SERIALIZE_OPT_HTML5TEST = 0x80
31
32
  };
32
33
 
33
34
 
@@ -310,7 +310,7 @@ lxb_html_tokenizer_temp_append_data(lxb_html_tokenizer_t *tkz,
310
310
  {
311
311
  size_t size = data - tkz->begin;
312
312
 
313
- if ((tkz->pos + size) > tkz->end) {
313
+ if (size > (size_t)(tkz->end - tkz->pos)) {
314
314
  if(lxb_html_tokenizer_temp_realloc(tkz, size)) {
315
315
  return tkz->status;
316
316
  }
@@ -325,7 +325,7 @@ lxb_inline lxb_status_t
325
325
  lxb_html_tokenizer_temp_append(lxb_html_tokenizer_t *tkz,
326
326
  const lxb_char_t *data, size_t size)
327
327
  {
328
- if ((tkz->pos + size) > tkz->end) {
328
+ if (size > (size_t)(tkz->end - tkz->pos)) {
329
329
  if(lxb_html_tokenizer_temp_realloc(tkz, size)) {
330
330
  return tkz->status;
331
331
  }
@@ -1691,7 +1691,7 @@ lxb_html_tree_insertion_mode_in_body_rprt(lxb_html_tree_t *tree,
1691
1691
  node = lxb_html_tree_current_node(tree);
1692
1692
 
1693
1693
  if (lxb_html_tree_node_is(node, LXB_TAG_RTC) == false
1694
- || lxb_html_tree_node_is(node, LXB_TAG_RUBY) == false)
1694
+ && lxb_html_tree_node_is(node, LXB_TAG_RUBY) == false)
1695
1695
  {
1696
1696
  lxb_html_tree_parse_error(tree, token,
1697
1697
  LXB_HTML_RULES_ERROR_MIELINOPELST);
@@ -462,8 +462,8 @@ lxb_html_tree_append_attributes(lxb_html_tree_t *tree,
462
462
  doc = lxb_html_interface_document(element->node.owner_document);
463
463
 
464
464
  while (token_attr != NULL) {
465
- attr = lxb_dom_element_attr_by_local_name_data(element,
466
- token_attr->name);
465
+ attr = lxb_dom_element_attr_by_local_name_ns_data(element,
466
+ token_attr->name, ns);
467
467
  if (attr != NULL) {
468
468
  token_attr = token_attr->next;
469
469
  continue;
@@ -1184,7 +1184,7 @@ lxb_html_tree_element_in_scope_h123456(lxb_html_tree_t *tree)
1184
1184
  break;
1185
1185
  }
1186
1186
 
1187
- if (lxb_html_tag_is_category(node->local_name, LXB_NS_HTML,
1187
+ if (lxb_html_tag_is_category(node->local_name, node->ns,
1188
1188
  LXB_HTML_TAG_CATEGORY_SCOPE))
1189
1189
  {
1190
1190
  return NULL;
@@ -1220,7 +1220,7 @@ lxb_html_tree_element_in_scope_tbody_thead_tfoot(lxb_html_tree_t *tree)
1220
1220
  break;
1221
1221
  }
1222
1222
 
1223
- if (lxb_html_tag_is_category(node->local_name, LXB_NS_HTML,
1223
+ if (lxb_html_tag_is_category(node->local_name, node->ns,
1224
1224
  LXB_HTML_TAG_CATEGORY_SCOPE_TABLE))
1225
1225
  {
1226
1226
  return NULL;
@@ -1255,7 +1255,7 @@ lxb_html_tree_element_in_scope_td_th(lxb_html_tree_t *tree)
1255
1255
  break;
1256
1256
  }
1257
1257
 
1258
- if (lxb_html_tag_is_category(node->local_name, LXB_NS_HTML,
1258
+ if (lxb_html_tag_is_category(node->local_name, node->ns,
1259
1259
  LXB_HTML_TAG_CATEGORY_SCOPE_TABLE))
1260
1260
  {
1261
1261
  return NULL;
@@ -1290,7 +1290,7 @@ lxb_html_tree_element_in_scope_option_optgroup(lxb_html_tree_t *tree)
1290
1290
  break;
1291
1291
  }
1292
1292
 
1293
- if (lxb_html_tag_is_category(node->local_name, LXB_NS_HTML,
1293
+ if (lxb_html_tag_is_category(node->local_name, node->ns,
1294
1294
  LXB_HTML_TAG_CATEGORY_SCOPE))
1295
1295
  {
1296
1296
  return NULL;
@@ -1310,7 +1310,9 @@ lxb_selectors_match(lxb_selectors_t *selectors, lxb_selectors_entry_t *entry,
1310
1310
  }
1311
1311
 
1312
1312
  return lxb_selectors_match_class(element->attr_class->value,
1313
- &entry->selector->name, true);
1313
+ &entry->selector->name,
1314
+ node->owner_document->compat_mode
1315
+ == LXB_DOM_DOCUMENT_CMODE_QUIRKS);
1314
1316
 
1315
1317
  case LXB_CSS_SELECTOR_TYPE_ATTRIBUTE:
1316
1318
  return lxb_selectors_match_attribute(entry->selector, node, entry);
@@ -1368,8 +1370,15 @@ lxb_selectors_match_id(const lxb_css_selector_t *selector, lxb_dom_node_t *node)
1368
1370
  trg = element->attr_id->value;
1369
1371
  src = &selector->name;
1370
1372
 
1371
- return trg->length == src->length
1372
- && lexbor_str_data_ncasecmp(trg->data, src->data, src->length);
1373
+ if (trg->length != src->length) {
1374
+ return false;
1375
+ }
1376
+
1377
+ if (node->owner_document->compat_mode == LXB_DOM_DOCUMENT_CMODE_QUIRKS) {
1378
+ return lexbor_str_data_ncasecmp(trg->data, src->data, src->length);
1379
+ }
1380
+
1381
+ return lexbor_str_data_ncmp(trg->data, src->data, src->length);
1373
1382
  }
1374
1383
 
1375
1384
  static bool
@@ -17,7 +17,7 @@ extern "C" {
17
17
 
18
18
 
19
19
  #define LXB_URL_VERSION_MAJOR 0
20
- #define LXB_URL_VERSION_MINOR 4
20
+ #define LXB_URL_VERSION_MINOR 5
21
21
  #define LXB_URL_VERSION_PATCH 0
22
22
 
23
23
  #define LXB_URL_VERSION_STRING LEXBOR_STRINGIZE(LXB_URL_VERSION_MAJOR) "." \
@@ -499,6 +499,7 @@ lxb_url_scheme_length = sizeof(lxb_url_scheme_res) / sizeof(lxb_url_scheme_data_
499
499
  if (tmp == NULL) { \
500
500
  return NULL; \
501
501
  } \
502
+ memcpy(tmp, (sbuf_begin), offset); \
502
503
  } \
503
504
  else { \
504
505
  tmp = lexbor_realloc((sbuf_begin), new_len); \
@@ -509,7 +510,7 @@ lxb_url_scheme_length = sizeof(lxb_url_scheme_res) / sizeof(lxb_url_scheme_data_
509
510
  } \
510
511
  \
511
512
  (sbuf) = tmp + offset; \
512
- (last) = sbuf + lst; \
513
+ (last) = tmp + lst; \
513
514
  (sbuf_begin) = tmp; \
514
515
  (sbuf_end) = tmp + new_len; \
515
516
  } \
@@ -860,7 +861,7 @@ lxb_url_is_url_codepoint(lxb_codepoint_t cp)
860
861
  return lxb_url_codepoint_alphanumeric[(lxb_char_t) cp] != 0xFF;
861
862
  }
862
863
 
863
- lxb_inline bool
864
+ bool
864
865
  lxb_url_is_special(const lxb_url_t *url)
865
866
  {
866
867
  return url->scheme.type != LXB_URL_SCHEMEL_TYPE__UNKNOWN;
@@ -5080,6 +5081,8 @@ lxb_url_search_params_parse(lxb_url_search_params_t *search_params,
5080
5081
  return status;
5081
5082
  }
5082
5083
 
5084
+ last = entry;
5085
+
5083
5086
  lexbor_str_init(&entry->value, mraw, 0);
5084
5087
  if (entry->value.data == NULL) {
5085
5088
  return LXB_STATUS_ERROR_MEMORY_ALLOCATION;
@@ -763,6 +763,15 @@ LXB_API lxb_status_t
763
763
  lxb_url_search_params_serialize(lxb_url_search_params_t *search_params,
764
764
  lexbor_callback_f cb, void *ctx);
765
765
 
766
+ /**
767
+ * Returns whether the URL is special.
768
+ *
769
+ * @param[in] lxb_url_t *. Cannot be NULL.
770
+ * @return true if URL is special, false otherwise.
771
+ */
772
+ LXB_API bool
773
+ lxb_url_is_special(const lxb_url_t *url);
774
+
766
775
  /*
767
776
  * Inline functions.
768
777
  */
@@ -1 +1 @@
1
- LEXBOR_VERSION=3.0.0
1
+ LEXBOR_VERSION=3.1.0
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: makiri
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - takahashim
@@ -65,8 +65,10 @@ extra_rdoc_files: []
65
65
  files:
66
66
  - ".github/workflows/ci.yml"
67
67
  - ".github/workflows/conformance.yml"
68
+ - ".github/workflows/libfuzzer.yml"
68
69
  - ".github/workflows/release.yml"
69
70
  - ".github/workflows/security.yml"
71
+ - ".github/workflows/valgrind.yml"
70
72
  - ".gitmodules"
71
73
  - CHANGELOG.md
72
74
  - LICENSE
@@ -83,16 +85,27 @@ files:
83
85
  - ext/makiri/core/mkr_core.c
84
86
  - ext/makiri/core/mkr_core.h
85
87
  - ext/makiri/core/mkr_hash.h
88
+ - ext/makiri/core/mkr_span.h
86
89
  - ext/makiri/core/mkr_text.h
90
+ - ext/makiri/core/mkr_utf8.c
91
+ - ext/makiri/core/mkr_utf8.h
87
92
  - ext/makiri/extconf.rb
93
+ - ext/makiri/fuzz/Makefile
94
+ - ext/makiri/fuzz/check_fuzzer.cc
95
+ - ext/makiri/fuzz/xml_fuzz.c
96
+ - ext/makiri/fuzz/xpath_fuzz.c
88
97
  - ext/makiri/glue/glue.h
89
- - ext/makiri/glue/ruby_css.c
90
98
  - ext/makiri/glue/ruby_doc.c
91
- - ext/makiri/glue/ruby_mutate.c
99
+ - ext/makiri/glue/ruby_html_css.c
100
+ - ext/makiri/glue/ruby_html_mutate.c
101
+ - ext/makiri/glue/ruby_html_node.c
102
+ - ext/makiri/glue/ruby_html_serialize.c
92
103
  - ext/makiri/glue/ruby_node.c
93
104
  - ext/makiri/glue/ruby_node_set.c
94
- - ext/makiri/glue/ruby_serialize.c
105
+ - ext/makiri/glue/ruby_xml.c
106
+ - ext/makiri/glue/ruby_xml_node.c
95
107
  - ext/makiri/glue/ruby_xpath.c
108
+ - ext/makiri/glue/ruby_xpath.h
96
109
  - ext/makiri/lexbor_compat/compat.h
97
110
  - ext/makiri/lexbor_compat/compat_internal.h
98
111
  - ext/makiri/lexbor_compat/dom_index.c
@@ -102,33 +115,64 @@ files:
102
115
  - ext/makiri/lexbor_compat/utf8_input.c
103
116
  - ext/makiri/makiri.c
104
117
  - ext/makiri/makiri.h
118
+ - ext/makiri/xml/mkr_xml.h
119
+ - ext/makiri/xml/mkr_xml_chars.c
120
+ - ext/makiri/xml/mkr_xml_index.c
121
+ - ext/makiri/xml/mkr_xml_index.h
122
+ - ext/makiri/xml/mkr_xml_mutate.c
123
+ - ext/makiri/xml/mkr_xml_mutate.h
124
+ - ext/makiri/xml/mkr_xml_node.c
125
+ - ext/makiri/xml/mkr_xml_node.h
126
+ - ext/makiri/xml/mkr_xml_tree.c
127
+ - ext/makiri/xpath/mkr_css.c
128
+ - ext/makiri/xpath/mkr_css.h
105
129
  - ext/makiri/xpath/mkr_xpath.c
106
130
  - ext/makiri/xpath/mkr_xpath.h
107
- - ext/makiri/xpath/mkr_xpath_eval.c
108
- - ext/makiri/xpath/mkr_xpath_funcs.c
131
+ - ext/makiri/xpath/mkr_xpath_engine_html.c
132
+ - ext/makiri/xpath/mkr_xpath_engine_xml.c
133
+ - ext/makiri/xpath/mkr_xpath_eval_body.h
134
+ - ext/makiri/xpath/mkr_xpath_funcs_body.h
109
135
  - ext/makiri/xpath/mkr_xpath_internal.h
110
136
  - ext/makiri/xpath/mkr_xpath_lex.c
137
+ - ext/makiri/xpath/mkr_xpath_node_access_html.h
138
+ - ext/makiri/xpath/mkr_xpath_node_access_xml.h
139
+ - ext/makiri/xpath/mkr_xpath_number.c
111
140
  - ext/makiri/xpath/mkr_xpath_parse.c
112
- - ext/makiri/xpath/mkr_xpath_value.c
141
+ - ext/makiri/xpath/mkr_xpath_prelude_html.h
142
+ - ext/makiri/xpath/mkr_xpath_prelude_xml.h
143
+ - ext/makiri/xpath/mkr_xpath_shared.c
144
+ - ext/makiri/xpath/mkr_xpath_value_body.h
145
+ - ext/makiri/xpath/mkr_xpath_xml_selftest.c
113
146
  - lib/makiri.rb
114
- - lib/makiri/attribute.rb
115
- - lib/makiri/cdata.rb
147
+ - lib/makiri/attr.rb
148
+ - lib/makiri/cdata_section.rb
116
149
  - lib/makiri/comment.rb
150
+ - lib/makiri/compat_aliases.rb
117
151
  - lib/makiri/css.rb
118
152
  - lib/makiri/document.rb
119
153
  - lib/makiri/document_fragment.rb
120
154
  - lib/makiri/document_type.rb
121
155
  - lib/makiri/element.rb
156
+ - lib/makiri/html.rb
157
+ - lib/makiri/html/document.rb
158
+ - lib/makiri/html/node_methods.rb
122
159
  - lib/makiri/node.rb
123
160
  - lib/makiri/node_set.rb
124
161
  - lib/makiri/processing_instruction.rb
125
162
  - lib/makiri/text.rb
126
163
  - lib/makiri/version.rb
164
+ - lib/makiri/xml.rb
165
+ - lib/makiri/xml/builder.rb
166
+ - lib/makiri/xml/document.rb
167
+ - lib/makiri/xml/node_methods.rb
127
168
  - lib/makiri/xpath.rb
128
169
  - lib/makiri/xpath_context.rb
129
170
  - script/build_native_gem.rb
171
+ - script/check_alloc_failures.rb
130
172
  - script/check_c_safety.rb
131
173
  - script/check_c_safety_allowlist.yml
174
+ - script/check_leaks.rb
175
+ - script/leaks_harness.rb
132
176
  - sig/makiri.rbs
133
177
  - vendor/lexbor/.travis.yml
134
178
  - vendor/lexbor/CHANGELOG.md
@@ -1,185 +0,0 @@
1
- #include "glue.h"
2
-
3
- #include <lexbor/css/css.h>
4
- #include <lexbor/selectors/selectors.h>
5
-
6
- /*
7
- * CSS selector queries, delegated to Lexbor's lxb_selectors engine.
8
- *
9
- * Node#css(selector) -> NodeSet (descendants matching, document order)
10
- * Node#at_css(selector) -> first matching descendant, or nil
11
- *
12
- * Selectors are compiled per call (a per-context cache is a later concern).
13
- * A malformed selector raises Makiri::CSS::SyntaxError.
14
- */
15
-
16
- typedef struct {
17
- VALUE set;
18
- lxb_dom_node_t *root; /* excluded from results: css is descendant-only */
19
- size_t count;
20
- int overflow;
21
- int first_only;
22
- } mkr_css_ctx_t;
23
-
24
- static lxb_status_t
25
- mkr_css_find_cb(lxb_dom_node_t *node, lxb_css_selector_specificity_t spec,
26
- void *ctx_)
27
- {
28
- (void)spec;
29
- mkr_css_ctx_t *c = (mkr_css_ctx_t *)ctx_;
30
-
31
- if (node == c->root) {
32
- return LXB_STATUS_OK; /* descendant-only, like Nokogiri's node.css */
33
- }
34
- if (c->count >= MKR_NODE_SET_MAX) {
35
- c->overflow = 1;
36
- return LXB_STATUS_STOP; /* fail closed without raising mid-traversal */
37
- }
38
-
39
- mkr_node_set_push(c->set, node);
40
- c->count++;
41
- return c->first_only ? LXB_STATUS_STOP : LXB_STATUS_OK;
42
- }
43
-
44
- /* Callback for matches?: signals that the node matched the selector. */
45
- static lxb_status_t
46
- mkr_css_match_cb(lxb_dom_node_t *node, lxb_css_selector_specificity_t spec,
47
- void *ctx_)
48
- {
49
- (void)node; (void)spec;
50
- *(int *)ctx_ = 1;
51
- return LXB_STATUS_STOP;
52
- }
53
-
54
- /* Compile +rb_selector+, hand the established engine + parsed list to +run+
55
- * (which performs the actual find / match_node against +node+), then tear the
56
- * Lexbor CSS object graph down in the required order and fail closed. Centralises
57
- * the engine lifecycle so the construction/teardown order — a delicate
58
- * Lexbor-specific detail — lives in exactly one place. Raises
59
- * Makiri::CSS::SyntaxError on a bad selector, Makiri::Error on engine init
60
- * failure; any result-specific limits are checked by the caller after return. */
61
- static void
62
- mkr_with_compiled_selector(VALUE rb_selector, lxb_dom_node_t *node,
63
- lxb_status_t (*run)(lxb_selectors_t *, lxb_dom_node_t *,
64
- lxb_css_selector_list_t *, void *),
65
- void *u)
66
- {
67
- mkr_ruby_borrowed_text_t sv = mkr_ruby_verified_text(rb_selector, "CSS selector");
68
- const lxb_char_t *s = (const lxb_char_t *)sv.ptr;
69
- size_t slen = sv.len;
70
-
71
- /* Lexbor CSS object graph: memory arena -> parser -> selector parser, plus
72
- * the traversal engine. All transient; torn down before we return. */
73
- lxb_css_memory_t *mem = lxb_css_memory_create();
74
- lxb_css_parser_t *parser = lxb_css_parser_create();
75
- lxb_css_selectors_t *css_sel = lxb_css_selectors_create();
76
- lxb_selectors_t *selectors = lxb_selectors_create();
77
- lxb_css_selector_list_t *list = NULL;
78
-
79
- int ok = (mem != NULL && parser != NULL && css_sel != NULL && selectors != NULL);
80
- if (ok) {
81
- ok = (lxb_css_memory_init(mem, 128) == LXB_STATUS_OK)
82
- && (lxb_css_parser_init(parser, NULL) == LXB_STATUS_OK)
83
- && (lxb_css_selectors_init(css_sel) == LXB_STATUS_OK)
84
- && (lxb_selectors_init(selectors) == LXB_STATUS_OK);
85
- }
86
-
87
- int syntax_error = 0;
88
- if (ok) {
89
- lxb_css_parser_memory_set(parser, mem);
90
- lxb_css_parser_selectors_set(parser, css_sel);
91
- list = lxb_css_selectors_parse(parser, s, slen);
92
- if (list == NULL || parser->status != LXB_STATUS_OK) {
93
- syntax_error = 1;
94
- } else {
95
- (void)run(selectors, node, list, u);
96
- }
97
- }
98
-
99
- /* Teardown (order mirrors Lexbor's own examples). Destroying the memory
100
- * arena frees the parsed selector list, so we do not free it separately. */
101
- if (selectors != NULL) lxb_selectors_destroy(selectors, true);
102
- if (parser != NULL) lxb_css_parser_destroy(parser, true);
103
- if (mem != NULL) lxb_css_memory_destroy(mem, true);
104
- if (css_sel != NULL) lxb_css_selectors_destroy(css_sel, true);
105
-
106
- if (!ok) {
107
- rb_raise(mkr_eError, "failed to initialise CSS selector engine");
108
- }
109
- if (syntax_error) {
110
- rb_raise(mkr_eCSSSyntaxError, "invalid CSS selector: %" PRIsVALUE, sv.value);
111
- }
112
- RB_GC_GUARD(sv.value);
113
- }
114
-
115
- /* find: collect descendants matching the selector (MATCH_FIRST dedups a node
116
- * that matches several selectors in a comma list). */
117
- static lxb_status_t
118
- mkr_run_find(lxb_selectors_t *selectors, lxb_dom_node_t *root,
119
- lxb_css_selector_list_t *list, void *u)
120
- {
121
- lxb_selectors_opt_set(selectors, LXB_SELECTORS_OPT_MATCH_FIRST);
122
- return lxb_selectors_find(selectors, root, list, mkr_css_find_cb, u);
123
- }
124
-
125
- /* match_node: does THIS node match? */
126
- static lxb_status_t
127
- mkr_run_match(lxb_selectors_t *selectors, lxb_dom_node_t *node,
128
- lxb_css_selector_list_t *list, void *u)
129
- {
130
- return lxb_selectors_match_node(selectors, node, list, mkr_css_match_cb, u);
131
- }
132
-
133
- /* Run +selector+ against self's subtree. first_only stops after one match.
134
- * Raises Makiri::CSS::SyntaxError on a bad selector, Makiri::Error on
135
- * allocation failure or an over-large result. */
136
- static VALUE
137
- mkr_css_query(VALUE self, VALUE rb_selector, int first_only)
138
- {
139
- lxb_dom_node_t *root = mkr_node_unwrap(self);
140
- VALUE document = mkr_node_document(self);
141
- VALUE set = mkr_node_set_new(document);
142
-
143
- mkr_css_ctx_t ctx = { .set = set, .root = root, .count = 0,
144
- .overflow = 0, .first_only = first_only };
145
- mkr_with_compiled_selector(rb_selector, root, mkr_run_find, &ctx);
146
-
147
- if (ctx.overflow) {
148
- rb_raise(mkr_eError, "CSS result set exceeded the node limit (%u)",
149
- MKR_NODE_SET_MAX);
150
- }
151
- return set;
152
- }
153
-
154
- /* Node#matches?(selector): does THIS node match the CSS selector? (Like
155
- * Nokogiri — tested against the node itself, not its descendants.) A malformed
156
- * selector raises Makiri::CSS::SyntaxError. */
157
- static VALUE
158
- mkr_node_matches(VALUE self, VALUE rb_selector)
159
- {
160
- lxb_dom_node_t *node = mkr_node_unwrap(self);
161
- int matched = 0;
162
- mkr_with_compiled_selector(rb_selector, node, mkr_run_match, &matched);
163
- return matched ? Qtrue : Qfalse;
164
- }
165
-
166
- static VALUE
167
- mkr_node_css(VALUE self, VALUE rb_selector)
168
- {
169
- return mkr_css_query(self, rb_selector, 0);
170
- }
171
-
172
- static VALUE
173
- mkr_node_at_css(VALUE self, VALUE rb_selector)
174
- {
175
- VALUE set = mkr_css_query(self, rb_selector, 1);
176
- return rb_funcall(set, rb_intern("first"), 0);
177
- }
178
-
179
- void
180
- mkr_init_css(void)
181
- {
182
- rb_define_method(mkr_cNode, "css", mkr_node_css, 1);
183
- rb_define_method(mkr_cNode, "at_css", mkr_node_at_css, 1);
184
- rb_define_method(mkr_cNode, "matches?", mkr_node_matches, 1);
185
- }
@@ -1,92 +0,0 @@
1
- #include "glue.h"
2
-
3
- #include <lexbor/html/serialize.h>
4
-
5
- /*
6
- * HTML serialization, delegated to Lexbor's serializer.
7
- *
8
- * Node#to_html / #to_s / #outer_html -> the node and its subtree (outer)
9
- * Node#inner_html -> the node's children only (inner)
10
- *
11
- * We use the callback variants so output streams straight into a Ruby String;
12
- * Lexbor emits UTF-8, which is the string's encoding.
13
- *
14
- * Mutating setters (inner_html=, outer_html=) arrive with the v0.2 mutation
15
- * API and are not defined here.
16
- */
17
-
18
- static lxb_status_t
19
- mkr_serialize_cb(const lxb_char_t *data, size_t len, void *ctx)
20
- {
21
- rb_str_cat((VALUE)ctx, (const char *)data, (long)len);
22
- return LXB_STATUS_OK;
23
- }
24
-
25
- /* Read the optional `pretty:` keyword. */
26
- static int
27
- mkr_serialize_pretty_opt(int argc, VALUE *argv)
28
- {
29
- VALUE opts = Qnil;
30
- rb_scan_args(argc, argv, "0:", &opts);
31
- if (NIL_P(opts)) {
32
- return 0;
33
- }
34
- return RTEST(rb_hash_aref(opts, ID2SYM(rb_intern("pretty"))));
35
- }
36
-
37
- /* Outer HTML: the node itself plus its descendants.
38
- * Pass `pretty: true` for indented output. */
39
- static VALUE
40
- mkr_node_to_html(int argc, VALUE *argv, VALUE self)
41
- {
42
- int pretty = mkr_serialize_pretty_opt(argc, argv);
43
- lxb_dom_node_t *node = mkr_node_unwrap(self);
44
- VALUE str = rb_utf8_str_new(NULL, 0);
45
-
46
- /* A document fragment has no tag of its own; "outer" == its children, so
47
- * the deep (children) serializer is the right one (the tree serializer
48
- * rejects a fragment node). */
49
- int deep = (node->type == LXB_DOM_NODE_TYPE_DOCUMENT_FRAGMENT);
50
- lxb_status_t st;
51
- if (deep) {
52
- st = pretty
53
- ? lxb_html_serialize_pretty_deep_cb(node, LXB_HTML_SERIALIZE_OPT_UNDEF,
54
- 0, mkr_serialize_cb, (void *)str)
55
- : lxb_html_serialize_deep_cb(node, mkr_serialize_cb, (void *)str);
56
- } else {
57
- st = pretty
58
- ? lxb_html_serialize_pretty_tree_cb(node, LXB_HTML_SERIALIZE_OPT_UNDEF,
59
- 0, mkr_serialize_cb, (void *)str)
60
- : lxb_html_serialize_tree_cb(node, mkr_serialize_cb, (void *)str);
61
- }
62
- if (st != LXB_STATUS_OK) {
63
- rb_raise(mkr_eError, "HTML serialization failed");
64
- }
65
- return str;
66
- }
67
-
68
- /* Inner HTML: the node's children, without the node's own tag. */
69
- static VALUE
70
- mkr_node_inner_html(int argc, VALUE *argv, VALUE self)
71
- {
72
- int pretty = mkr_serialize_pretty_opt(argc, argv);
73
- lxb_dom_node_t *node = mkr_node_unwrap(self);
74
- VALUE str = rb_utf8_str_new(NULL, 0);
75
- lxb_status_t st = pretty
76
- ? lxb_html_serialize_pretty_deep_cb(node, LXB_HTML_SERIALIZE_OPT_UNDEF,
77
- 0, mkr_serialize_cb, (void *)str)
78
- : lxb_html_serialize_deep_cb(node, mkr_serialize_cb, (void *)str);
79
- if (st != LXB_STATUS_OK) {
80
- rb_raise(mkr_eError, "HTML serialization failed");
81
- }
82
- return str;
83
- }
84
-
85
- void
86
- mkr_init_serialize(void)
87
- {
88
- rb_define_method(mkr_cNode, "to_html", mkr_node_to_html, -1);
89
- rb_define_method(mkr_cNode, "to_s", mkr_node_to_html, -1);
90
- rb_define_method(mkr_cNode, "outer_html", mkr_node_to_html, -1);
91
- rb_define_method(mkr_cNode, "inner_html", mkr_node_inner_html, -1);
92
- }