hamlit 1.7.2 → 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (283) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -3
  3. data/.gitmodules +3 -0
  4. data/.travis.yml +25 -37
  5. data/CHANGELOG.md +18 -0
  6. data/Gemfile +16 -0
  7. data/LICENSE.txt +23 -2
  8. data/README.md +106 -48
  9. data/REFERENCE.md +222 -0
  10. data/Rakefile +77 -19
  11. data/benchmark/boolean_attribute.haml +6 -0
  12. data/benchmark/class_attribute.haml +5 -0
  13. data/benchmark/common_attribute.haml +3 -0
  14. data/benchmark/data_attribute.haml +4 -0
  15. data/benchmark/dynamic_attributes/boolean_attribute.haml +4 -0
  16. data/benchmark/dynamic_attributes/class_attribute.haml +4 -0
  17. data/benchmark/dynamic_attributes/common_attribute.haml +2 -0
  18. data/benchmark/dynamic_attributes/data_attribute.haml +2 -0
  19. data/benchmark/dynamic_attributes/id_attribute.haml +2 -0
  20. data/benchmark/etc/attribute_builder.haml +5 -0
  21. data/benchmark/etc/real_sample.haml +888 -0
  22. data/benchmark/etc/real_sample.rb +11 -0
  23. data/benchmark/etc/static_analyzer.haml +1 -0
  24. data/benchmark/etc/tags.haml +3 -0
  25. data/benchmark/ext/build_data.rb +15 -0
  26. data/benchmark/ext/build_id.rb +13 -0
  27. data/benchmark/id_attribute.haml +3 -0
  28. data/benchmark/plain.haml +4 -0
  29. data/benchmark/script.haml +4 -0
  30. data/benchmark/slim/LICENSE +21 -0
  31. data/{benchmarks → benchmark/slim}/context.rb +2 -4
  32. data/benchmark/slim/run-benchmarks.rb +94 -0
  33. data/{benchmarks → benchmark/slim}/view.erb +3 -3
  34. data/{benchmarks → benchmark/slim}/view.haml +0 -0
  35. data/{benchmarks/view.escaped.slim → benchmark/slim/view.slim} +1 -1
  36. data/benchmark/string_interpolation.haml +2 -0
  37. data/benchmark/utils/benchmark_ips_extension.rb +43 -0
  38. data/bin/bench +85 -0
  39. data/bin/clone +14 -0
  40. data/bin/console +11 -0
  41. data/bin/lineprof +48 -0
  42. data/bin/ruby +3 -0
  43. data/bin/setup +7 -0
  44. data/bin/stackprof +27 -0
  45. data/{test → bin/test} +6 -10
  46. data/{bin → exe}/hamlit +0 -0
  47. data/ext/hamlit/extconf.rb +14 -0
  48. data/ext/hamlit/hamlit.c +512 -0
  49. data/ext/hamlit/houdini/.gitignore +3 -0
  50. data/ext/hamlit/houdini/COPYING +7 -0
  51. data/ext/hamlit/houdini/Makefile +79 -0
  52. data/ext/hamlit/houdini/README.md +59 -0
  53. data/ext/hamlit/houdini/buffer.c +249 -0
  54. data/ext/hamlit/houdini/buffer.h +113 -0
  55. data/ext/hamlit/houdini/houdini.h +46 -0
  56. data/ext/hamlit/houdini/houdini_href_e.c +115 -0
  57. data/ext/hamlit/houdini/houdini_html_e.c +90 -0
  58. data/ext/hamlit/houdini/houdini_html_u.c +122 -0
  59. data/ext/hamlit/houdini/houdini_js_e.c +90 -0
  60. data/ext/hamlit/houdini/houdini_js_u.c +60 -0
  61. data/ext/hamlit/houdini/houdini_uri_e.c +107 -0
  62. data/ext/hamlit/houdini/houdini_uri_u.c +68 -0
  63. data/ext/hamlit/houdini/houdini_xml_e.c +136 -0
  64. data/ext/hamlit/houdini/html_unescape.gperf +258 -0
  65. data/ext/hamlit/houdini/html_unescape.h +754 -0
  66. data/ext/hamlit/houdini/tools/build_table.py +13 -0
  67. data/ext/hamlit/houdini/tools/build_tables.c +51 -0
  68. data/ext/hamlit/houdini/tools/wikipedia_table.txt +2025 -0
  69. data/hamlit.gemspec +30 -31
  70. data/lib/hamlit.rb +3 -1
  71. data/lib/hamlit/attribute_builder.rb +12 -0
  72. data/lib/hamlit/cli.rb +44 -43
  73. data/lib/hamlit/compiler.rb +92 -16
  74. data/lib/hamlit/compiler/attribute_compiler.rb +148 -0
  75. data/lib/hamlit/compiler/children_compiler.rb +111 -0
  76. data/lib/hamlit/compiler/comment_compiler.rb +36 -0
  77. data/lib/hamlit/compiler/doctype_compiler.rb +45 -0
  78. data/lib/hamlit/compiler/script_compiler.rb +97 -0
  79. data/lib/hamlit/compiler/silent_script_compiler.rb +24 -0
  80. data/lib/hamlit/compiler/tag_compiler.rb +69 -0
  81. data/lib/hamlit/engine.rb +12 -7
  82. data/lib/hamlit/error.rb +14 -0
  83. data/lib/hamlit/escapable.rb +12 -0
  84. data/lib/hamlit/filters.rb +65 -0
  85. data/lib/hamlit/filters/base.rb +4 -62
  86. data/lib/hamlit/filters/coffee.rb +9 -7
  87. data/lib/hamlit/filters/css.rb +25 -8
  88. data/lib/hamlit/filters/erb.rb +4 -6
  89. data/lib/hamlit/filters/escaped.rb +11 -9
  90. data/lib/hamlit/filters/javascript.rb +25 -8
  91. data/lib/hamlit/filters/less.rb +9 -7
  92. data/lib/hamlit/filters/markdown.rb +5 -6
  93. data/lib/hamlit/filters/plain.rb +11 -15
  94. data/lib/hamlit/filters/preserve.rb +15 -5
  95. data/lib/hamlit/filters/ruby.rb +3 -5
  96. data/lib/hamlit/filters/sass.rb +9 -7
  97. data/lib/hamlit/filters/scss.rb +9 -7
  98. data/lib/hamlit/filters/text_base.rb +24 -0
  99. data/lib/hamlit/filters/tilt_base.rb +47 -0
  100. data/lib/hamlit/hash_parser.rb +107 -0
  101. data/lib/hamlit/html.rb +9 -6
  102. data/lib/hamlit/identity.rb +12 -0
  103. data/lib/hamlit/object_ref.rb +29 -0
  104. data/lib/hamlit/parser.rb +25 -142
  105. data/lib/hamlit/parser/MIT-LICENSE +20 -0
  106. data/lib/hamlit/parser/README.md +28 -0
  107. data/lib/hamlit/parser/haml_buffer.rb +348 -0
  108. data/lib/hamlit/parser/haml_compiler.rb +553 -0
  109. data/lib/hamlit/parser/haml_error.rb +61 -0
  110. data/lib/hamlit/parser/haml_helpers.rb +727 -0
  111. data/lib/hamlit/parser/haml_options.rb +286 -0
  112. data/lib/hamlit/parser/haml_parser.rb +801 -0
  113. data/lib/hamlit/parser/haml_util.rb +283 -0
  114. data/lib/hamlit/parser/haml_xss_mods.rb +109 -0
  115. data/lib/hamlit/{helpers.rb → rails_helpers.rb} +2 -7
  116. data/lib/hamlit/rails_template.rb +30 -0
  117. data/lib/hamlit/railtie.rb +1 -12
  118. data/lib/hamlit/ruby_expression.rb +31 -0
  119. data/lib/hamlit/static_analyzer.rb +49 -0
  120. data/lib/hamlit/string_interpolation.rb +69 -0
  121. data/lib/hamlit/template.rb +8 -0
  122. data/lib/hamlit/utils.rb +9 -0
  123. data/lib/hamlit/version.rb +1 -1
  124. metadata +116 -324
  125. data/.rspec +0 -2
  126. data/benchmarks/benchmark.rb +0 -110
  127. data/benchmarks/view.slim +0 -17
  128. data/doc/README.md +0 -19
  129. data/doc/engine/indent.md +0 -48
  130. data/doc/engine/new_attribute.md +0 -77
  131. data/doc/engine/old_attributes.md +0 -198
  132. data/doc/engine/silent_script.md +0 -97
  133. data/doc/engine/tag.md +0 -48
  134. data/doc/engine/text.md +0 -64
  135. data/doc/faml/README.md +0 -16
  136. data/doc/faml/engine/indent.md +0 -48
  137. data/doc/faml/engine/old_attributes.md +0 -111
  138. data/doc/faml/engine/silent_script.md +0 -97
  139. data/doc/faml/engine/text.md +0 -59
  140. data/doc/faml/filters/erb.md +0 -24
  141. data/doc/faml/filters/javascript.md +0 -27
  142. data/doc/faml/filters/less.md +0 -57
  143. data/doc/faml/filters/plain.md +0 -25
  144. data/doc/filters/erb.md +0 -31
  145. data/doc/filters/javascript.md +0 -83
  146. data/doc/filters/less.md +0 -57
  147. data/doc/filters/markdown.md +0 -31
  148. data/doc/filters/plain.md +0 -25
  149. data/doc/haml/README.md +0 -15
  150. data/doc/haml/engine/new_attribute.md +0 -77
  151. data/doc/haml/engine/old_attributes.md +0 -142
  152. data/doc/haml/engine/tag.md +0 -48
  153. data/doc/haml/engine/text.md +0 -29
  154. data/doc/haml/filters/erb.md +0 -26
  155. data/doc/haml/filters/javascript.md +0 -76
  156. data/doc/haml/filters/markdown.md +0 -31
  157. data/lib/hamlit/attribute.rb +0 -78
  158. data/lib/hamlit/compilers/attributes.rb +0 -108
  159. data/lib/hamlit/compilers/comment.rb +0 -13
  160. data/lib/hamlit/compilers/doctype.rb +0 -39
  161. data/lib/hamlit/compilers/filter.rb +0 -53
  162. data/lib/hamlit/compilers/new_attribute.rb +0 -115
  163. data/lib/hamlit/compilers/old_attribute.rb +0 -241
  164. data/lib/hamlit/compilers/runtime_attribute.rb +0 -58
  165. data/lib/hamlit/compilers/script.rb +0 -31
  166. data/lib/hamlit/compilers/strip.rb +0 -19
  167. data/lib/hamlit/compilers/text.rb +0 -111
  168. data/lib/hamlit/concerns/attribute_builder.rb +0 -22
  169. data/lib/hamlit/concerns/balanceable.rb +0 -68
  170. data/lib/hamlit/concerns/deprecation.rb +0 -20
  171. data/lib/hamlit/concerns/error.rb +0 -31
  172. data/lib/hamlit/concerns/escapable.rb +0 -17
  173. data/lib/hamlit/concerns/included.rb +0 -28
  174. data/lib/hamlit/concerns/indentable.rb +0 -117
  175. data/lib/hamlit/concerns/lexable.rb +0 -32
  176. data/lib/hamlit/concerns/line_reader.rb +0 -62
  177. data/lib/hamlit/concerns/registerable.rb +0 -24
  178. data/lib/hamlit/concerns/string_interpolation.rb +0 -48
  179. data/lib/hamlit/concerns/whitespace.rb +0 -91
  180. data/lib/hamlit/filters/tilt.rb +0 -41
  181. data/lib/hamlit/parsers/attribute.rb +0 -71
  182. data/lib/hamlit/parsers/comment.rb +0 -30
  183. data/lib/hamlit/parsers/doctype.rb +0 -18
  184. data/lib/hamlit/parsers/filter.rb +0 -18
  185. data/lib/hamlit/parsers/multiline.rb +0 -58
  186. data/lib/hamlit/parsers/script.rb +0 -126
  187. data/lib/hamlit/parsers/tag.rb +0 -83
  188. data/lib/hamlit/parsers/text.rb +0 -28
  189. data/lib/hamlit/temple.rb +0 -9
  190. data/release +0 -6
  191. data/spec/Rakefile +0 -72
  192. data/spec/hamlit/engine/comment_spec.rb +0 -56
  193. data/spec/hamlit/engine/doctype_spec.rb +0 -19
  194. data/spec/hamlit/engine/error_spec.rb +0 -135
  195. data/spec/hamlit/engine/indent_spec.rb +0 -42
  196. data/spec/hamlit/engine/multiline_spec.rb +0 -44
  197. data/spec/hamlit/engine/new_attribute_spec.rb +0 -110
  198. data/spec/hamlit/engine/old_attributes_spec.rb +0 -404
  199. data/spec/hamlit/engine/script_spec.rb +0 -116
  200. data/spec/hamlit/engine/silent_script_spec.rb +0 -213
  201. data/spec/hamlit/engine/tag_spec.rb +0 -295
  202. data/spec/hamlit/engine/text_spec.rb +0 -239
  203. data/spec/hamlit/engine_spec.rb +0 -58
  204. data/spec/hamlit/filters/coffee_spec.rb +0 -60
  205. data/spec/hamlit/filters/css_spec.rb +0 -33
  206. data/spec/hamlit/filters/erb_spec.rb +0 -16
  207. data/spec/hamlit/filters/javascript_spec.rb +0 -82
  208. data/spec/hamlit/filters/less_spec.rb +0 -37
  209. data/spec/hamlit/filters/markdown_spec.rb +0 -30
  210. data/spec/hamlit/filters/plain_spec.rb +0 -15
  211. data/spec/hamlit/filters/ruby_spec.rb +0 -24
  212. data/spec/hamlit/filters/sass_spec.rb +0 -33
  213. data/spec/hamlit/filters/scss_spec.rb +0 -37
  214. data/spec/hamlit/haml_spec.rb +0 -910
  215. data/spec/rails/.gitignore +0 -18
  216. data/spec/rails/.rspec +0 -2
  217. data/spec/rails/Gemfile +0 -19
  218. data/spec/rails/README.rdoc +0 -28
  219. data/spec/rails/Rakefile +0 -6
  220. data/spec/rails/app/assets/images/.keep +0 -0
  221. data/spec/rails/app/assets/javascripts/application.js +0 -15
  222. data/spec/rails/app/assets/stylesheets/application.css +0 -15
  223. data/spec/rails/app/controllers/application_controller.rb +0 -8
  224. data/spec/rails/app/controllers/concerns/.keep +0 -0
  225. data/spec/rails/app/controllers/users_controller.rb +0 -23
  226. data/spec/rails/app/helpers/application_helper.rb +0 -2
  227. data/spec/rails/app/mailers/.keep +0 -0
  228. data/spec/rails/app/models/.keep +0 -0
  229. data/spec/rails/app/models/concerns/.keep +0 -0
  230. data/spec/rails/app/views/application/index.html.haml +0 -18
  231. data/spec/rails/app/views/layouts/application.html.haml +0 -12
  232. data/spec/rails/app/views/users/capture.html.haml +0 -5
  233. data/spec/rails/app/views/users/capture_haml.html.haml +0 -5
  234. data/spec/rails/app/views/users/form.html.haml +0 -2
  235. data/spec/rails/app/views/users/helpers.html.haml +0 -10
  236. data/spec/rails/app/views/users/index.html.haml +0 -9
  237. data/spec/rails/app/views/users/inline.html.haml +0 -6
  238. data/spec/rails/app/views/users/old_attributes.html.haml +0 -5
  239. data/spec/rails/app/views/users/safe_buffer.html.haml +0 -4
  240. data/spec/rails/app/views/users/whitespace.html.haml +0 -4
  241. data/spec/rails/bin/bundle +0 -3
  242. data/spec/rails/bin/rails +0 -8
  243. data/spec/rails/bin/rake +0 -8
  244. data/spec/rails/bin/setup +0 -29
  245. data/spec/rails/bin/spring +0 -15
  246. data/spec/rails/config.ru +0 -4
  247. data/spec/rails/config/application.rb +0 -34
  248. data/spec/rails/config/boot.rb +0 -3
  249. data/spec/rails/config/database.yml +0 -25
  250. data/spec/rails/config/environment.rb +0 -5
  251. data/spec/rails/config/environments/development.rb +0 -41
  252. data/spec/rails/config/environments/production.rb +0 -79
  253. data/spec/rails/config/environments/test.rb +0 -42
  254. data/spec/rails/config/initializers/assets.rb +0 -11
  255. data/spec/rails/config/initializers/backtrace_silencers.rb +0 -7
  256. data/spec/rails/config/initializers/cookies_serializer.rb +0 -3
  257. data/spec/rails/config/initializers/filter_parameter_logging.rb +0 -4
  258. data/spec/rails/config/initializers/inflections.rb +0 -16
  259. data/spec/rails/config/initializers/mime_types.rb +0 -4
  260. data/spec/rails/config/initializers/session_store.rb +0 -3
  261. data/spec/rails/config/initializers/wrap_parameters.rb +0 -14
  262. data/spec/rails/config/locales/en.yml +0 -24
  263. data/spec/rails/config/routes.rb +0 -16
  264. data/spec/rails/config/secrets.yml +0 -22
  265. data/spec/rails/db/schema.rb +0 -16
  266. data/spec/rails/db/seeds.rb +0 -7
  267. data/spec/rails/lib/assets/.keep +0 -0
  268. data/spec/rails/lib/tasks/.keep +0 -0
  269. data/spec/rails/log/.keep +0 -0
  270. data/spec/rails/public/404.html +0 -67
  271. data/spec/rails/public/422.html +0 -67
  272. data/spec/rails/public/500.html +0 -66
  273. data/spec/rails/public/favicon.ico +0 -0
  274. data/spec/rails/public/robots.txt +0 -5
  275. data/spec/rails/spec/hamlit_spec.rb +0 -123
  276. data/spec/rails/spec/rails_helper.rb +0 -56
  277. data/spec/rails/spec/spec_helper.rb +0 -91
  278. data/spec/rails/vendor/assets/javascripts/.keep +0 -0
  279. data/spec/rails/vendor/assets/stylesheets/.keep +0 -0
  280. data/spec/spec_helper.rb +0 -36
  281. data/spec/spec_helper/document_generator.rb +0 -93
  282. data/spec/spec_helper/render_helper.rb +0 -120
  283. data/spec/spec_helper/test_case.rb +0 -55
@@ -0,0 +1,60 @@
1
+ #include <assert.h>
2
+ #include <stdio.h>
3
+ #include <string.h>
4
+
5
+ #include "houdini.h"
6
+
7
+ int
8
+ houdini_unescape_js(gh_buf *ob, const uint8_t *src, size_t size)
9
+ {
10
+ size_t i = 0, org, ch;
11
+
12
+ while (i < size) {
13
+ org = i;
14
+ while (i < size && src[i] != '\\')
15
+ i++;
16
+
17
+ if (likely(i > org)) {
18
+ if (unlikely(org == 0)) {
19
+ if (i >= size)
20
+ return 0;
21
+
22
+ gh_buf_grow(ob, HOUDINI_UNESCAPED_SIZE(size));
23
+ }
24
+
25
+ gh_buf_put(ob, src + org, i - org);
26
+ }
27
+
28
+ /* escaping */
29
+ if (i == size)
30
+ break;
31
+
32
+ if (++i == size) {
33
+ gh_buf_putc(ob, '\\');
34
+ break;
35
+ }
36
+
37
+ ch = src[i];
38
+
39
+ switch (ch) {
40
+ case 'n':
41
+ ch = '\n';
42
+ /* pass through */
43
+
44
+ case '\\':
45
+ case '\'':
46
+ case '\"':
47
+ case '/':
48
+ gh_buf_putc(ob, ch);
49
+ i++;
50
+ break;
51
+
52
+ default:
53
+ gh_buf_putc(ob, '\\');
54
+ break;
55
+ }
56
+ }
57
+
58
+ return 1;
59
+ }
60
+
@@ -0,0 +1,107 @@
1
+ #include <assert.h>
2
+ #include <stdio.h>
3
+ #include <string.h>
4
+
5
+ #include "houdini.h"
6
+
7
+ static const char URL_SAFE[] = {
8
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,
11
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
12
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
13
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
14
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
15
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
16
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
17
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
18
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
19
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
20
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
21
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
22
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
23
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
24
+ };
25
+
26
+ static const char URI_SAFE[] = {
27
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
28
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
29
+ 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
30
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1,
31
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
32
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1,
33
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
34
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0,
35
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
36
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
37
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
38
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
39
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
40
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
41
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
42
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
43
+ };
44
+
45
+ static int
46
+ escape(gh_buf *ob, const uint8_t *src, size_t size,
47
+ const char *safe_table, bool escape_plus)
48
+ {
49
+ static const uint8_t hex_chars[] = "0123456789ABCDEF";
50
+
51
+ size_t i = 0, org;
52
+ uint8_t hex_str[3];
53
+
54
+ hex_str[0] = '%';
55
+
56
+ while (i < size) {
57
+ org = i;
58
+ while (i < size && safe_table[src[i]] != 0)
59
+ i++;
60
+
61
+ if (likely(i > org)) {
62
+ if (unlikely(org == 0)) {
63
+ if (i >= size)
64
+ return 0;
65
+
66
+ gh_buf_grow(ob, HOUDINI_ESCAPED_SIZE(size));
67
+ }
68
+
69
+ gh_buf_put(ob, src + org, i - org);
70
+ }
71
+
72
+ /* escaping */
73
+ if (i >= size)
74
+ break;
75
+
76
+ if (src[i] == ' ' && escape_plus) {
77
+ gh_buf_putc(ob, '+');
78
+ } else {
79
+ hex_str[1] = hex_chars[(src[i] >> 4) & 0xF];
80
+ hex_str[2] = hex_chars[src[i] & 0xF];
81
+ gh_buf_put(ob, hex_str, 3);
82
+ }
83
+
84
+ i++;
85
+ }
86
+
87
+ return 1;
88
+ }
89
+
90
+ int
91
+ houdini_escape_uri(gh_buf *ob, const uint8_t *src, size_t size)
92
+ {
93
+ return escape(ob, src, size, URI_SAFE, false);
94
+ }
95
+
96
+ int
97
+ houdini_escape_uri_component(gh_buf *ob, const uint8_t *src, size_t size)
98
+ {
99
+ return escape(ob, src, size, URL_SAFE, false);
100
+ }
101
+
102
+ int
103
+ houdini_escape_url(gh_buf *ob, const uint8_t *src, size_t size)
104
+ {
105
+ return escape(ob, src, size, URL_SAFE, true);
106
+ }
107
+
@@ -0,0 +1,68 @@
1
+ #include <assert.h>
2
+ #include <stdio.h>
3
+ #include <string.h>
4
+
5
+ #include "houdini.h"
6
+
7
+ #define hex2c(c) ((c | 32) % 39 - 9)
8
+
9
+ static int
10
+ unescape(gh_buf *ob, const uint8_t *src, size_t size, bool unescape_plus)
11
+ {
12
+ size_t i = 0, org;
13
+
14
+ while (i < size) {
15
+ org = i;
16
+ while (i < size && src[i] != '%' && src[i] != '+')
17
+ i++;
18
+
19
+ if (likely(i > org)) {
20
+ if (unlikely(org == 0)) {
21
+ if (i >= size)
22
+ return 0;
23
+
24
+ gh_buf_grow(ob, HOUDINI_UNESCAPED_SIZE(size));
25
+ }
26
+
27
+ gh_buf_put(ob, src + org, i - org);
28
+ }
29
+
30
+ /* escaping */
31
+ if (i >= size)
32
+ break;
33
+
34
+ if (src[i++] == '+') {
35
+ gh_buf_putc(ob, unescape_plus ? ' ' : '+');
36
+ continue;
37
+ }
38
+
39
+ if (i + 1 < size && _isxdigit(src[i]) && _isxdigit(src[i + 1])) {
40
+ unsigned char new_char = (hex2c(src[i]) << 4) + hex2c(src[i + 1]);
41
+ gh_buf_putc(ob, new_char);
42
+ i += 2;
43
+ } else {
44
+ gh_buf_putc(ob, '%');
45
+ }
46
+ }
47
+
48
+ return 1;
49
+ }
50
+
51
+ int
52
+ houdini_unescape_uri(gh_buf *ob, const uint8_t *src, size_t size)
53
+ {
54
+ return unescape(ob, src, size, false);
55
+ }
56
+
57
+ int
58
+ houdini_unescape_uri_component(gh_buf *ob, const uint8_t *src, size_t size)
59
+ {
60
+ return unescape(ob, src, size, false);
61
+ }
62
+
63
+ int
64
+ houdini_unescape_url(gh_buf *ob, const uint8_t *src, size_t size)
65
+ {
66
+ return unescape(ob, src, size, true);
67
+ }
68
+
@@ -0,0 +1,136 @@
1
+ #include <assert.h>
2
+ #include <stdio.h>
3
+ #include <string.h>
4
+
5
+ #include "houdini.h"
6
+
7
+ /**
8
+ * & --> &amp;
9
+ * < --> &lt;
10
+ * > --> &gt;
11
+ * " --> &quot;
12
+ * ' --> &apos;
13
+ */
14
+ static const char *LOOKUP_CODES[] = {
15
+ "", /* reserved: use literal single character */
16
+ "", /* unused */
17
+ "", /* reserved: 2 character UTF-8 */
18
+ "", /* reserved: 3 character UTF-8 */
19
+ "", /* reserved: 4 character UTF-8 */
20
+ "?", /* invalid UTF-8 character */
21
+ "&quot;",
22
+ "&amp;",
23
+ "&apos;",
24
+ "&lt;",
25
+ "&gt;"
26
+ };
27
+
28
+ static const char CODE_INVALID = 5;
29
+
30
+ static const char XML_LOOKUP_TABLE[] = {
31
+ /* ASCII: 0xxxxxxx */
32
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 5, 5, 0, 5, 5,
33
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
34
+ 0, 0, 6, 0, 0, 0, 7, 8, 0, 0, 0, 0, 0, 0, 0, 0,
35
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0,10, 0,
36
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
37
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
38
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
39
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
40
+
41
+ /* Invalid UTF-8 char start: 10xxxxxx */
42
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
43
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
44
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
45
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
46
+
47
+ /* Multibyte UTF-8 */
48
+
49
+ /* 2 bytes: 110xxxxx */
50
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
51
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
52
+
53
+ /* 3 bytes: 1110xxxx */
54
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
55
+
56
+ /* 4 bytes: 11110xxx */
57
+ 4, 4, 4, 4, 4, 4, 4, 4,
58
+
59
+ /* Invalid UTF-8: 11111xxx */
60
+ 5, 5, 5, 5, 5, 5, 5, 5,
61
+ };
62
+
63
+ int
64
+ houdini_escape_xml(gh_buf *ob, const uint8_t *src, size_t size)
65
+ {
66
+ size_t i = 0;
67
+ unsigned char code = 0;
68
+
69
+ gh_buf_grow(ob, HOUDINI_ESCAPED_SIZE(size));
70
+
71
+ while (i < size) {
72
+ size_t start, end;
73
+
74
+ start = end = i;
75
+
76
+ while (i < size) {
77
+ unsigned int byte;
78
+
79
+ byte = src[i++];
80
+ code = XML_LOOKUP_TABLE[byte];
81
+
82
+ if (!code) {
83
+ /* single character used literally */
84
+ } else if (code >= CODE_INVALID) {
85
+ break; /* insert lookup code string */
86
+ } else if (code > size - end) {
87
+ code = CODE_INVALID; /* truncated UTF-8 character */
88
+ break;
89
+ } else {
90
+ unsigned int chr = byte & (0xff >> code);
91
+
92
+ while (--code) {
93
+ byte = src[i++];
94
+ if ((byte & 0xc0) != 0x80) {
95
+ code = CODE_INVALID;
96
+ break;
97
+ }
98
+ chr = (chr << 6) + (byte & 0x3f);
99
+ }
100
+
101
+ switch (i - end) {
102
+ case 2:
103
+ if (chr < 0x80)
104
+ code = CODE_INVALID;
105
+ break;
106
+ case 3:
107
+ if (chr < 0x800 ||
108
+ (chr > 0xd7ff && chr < 0xe000) ||
109
+ chr > 0xfffd)
110
+ code = CODE_INVALID;
111
+ break;
112
+ case 4:
113
+ if (chr < 0x10000 || chr > 0x10ffff)
114
+ code = CODE_INVALID;
115
+ break;
116
+ default:
117
+ break;
118
+ }
119
+ if (code == CODE_INVALID)
120
+ break;
121
+ }
122
+ end = i;
123
+ }
124
+
125
+ if (end > start)
126
+ gh_buf_put(ob, src + start, end - start);
127
+
128
+ /* escaping */
129
+ if (end >= size)
130
+ break;
131
+
132
+ gh_buf_puts(ob, LOOKUP_CODES[code]);
133
+ }
134
+
135
+ return 1;
136
+ }
@@ -0,0 +1,258 @@
1
+ struct html_ent {
2
+ const char *entity;
3
+ unsigned char utf8_len;
4
+ unsigned char utf8[3];
5
+ };
6
+ %%
7
+ "quot", 1, { 0x22 }
8
+ "amp", 1, { 0x26 }
9
+ "apos", 1, { 0x27 }
10
+ "lt", 1, { 0x3C }
11
+ "gt", 1, { 0x3E }
12
+ "nbsp", 2, { 0xC2, 0xA0 }
13
+ "iexcl", 2, { 0xC2, 0xA1 }
14
+ "cent", 2, { 0xC2, 0xA2 }
15
+ "pound", 2, { 0xC2, 0xA3 }
16
+ "curren", 2, { 0xC2, 0xA4 }
17
+ "yen", 2, { 0xC2, 0xA5 }
18
+ "brvbar", 2, { 0xC2, 0xA6 }
19
+ "sect", 2, { 0xC2, 0xA7 }
20
+ "uml", 2, { 0xC2, 0xA8 }
21
+ "copy", 2, { 0xC2, 0xA9 }
22
+ "ordf", 2, { 0xC2, 0xAA }
23
+ "laquo", 2, { 0xC2, 0xAB }
24
+ "not", 2, { 0xC2, 0xAC }
25
+ "shy", 2, { 0xC2, 0xAD }
26
+ "reg", 2, { 0xC2, 0xAE }
27
+ "macr", 2, { 0xC2, 0xAF }
28
+ "deg", 2, { 0xC2, 0xB0 }
29
+ "plusmn", 2, { 0xC2, 0xB1 }
30
+ "sup2", 2, { 0xC2, 0xB2 }
31
+ "sup3", 2, { 0xC2, 0xB3 }
32
+ "acute", 2, { 0xC2, 0xB4 }
33
+ "micro", 2, { 0xC2, 0xB5 }
34
+ "para", 2, { 0xC2, 0xB6 }
35
+ "middot", 2, { 0xC2, 0xB7 }
36
+ "cedil", 2, { 0xC2, 0xB8 }
37
+ "sup1", 2, { 0xC2, 0xB9 }
38
+ "ordm", 2, { 0xC2, 0xBA }
39
+ "raquo", 2, { 0xC2, 0xBB }
40
+ "frac14", 2, { 0xC2, 0xBC }
41
+ "frac12", 2, { 0xC2, 0xBD }
42
+ "frac34", 2, { 0xC2, 0xBE }
43
+ "iquest", 2, { 0xC2, 0xBF }
44
+ "Agrave", 2, { 0xC3, 0x80 }
45
+ "Aacute", 2, { 0xC3, 0x81 }
46
+ "Acirc", 2, { 0xC3, 0x82 }
47
+ "Atilde", 2, { 0xC3, 0x83 }
48
+ "Auml", 2, { 0xC3, 0x84 }
49
+ "Aring", 2, { 0xC3, 0x85 }
50
+ "AElig", 2, { 0xC3, 0x86 }
51
+ "Ccedil", 2, { 0xC3, 0x87 }
52
+ "Egrave", 2, { 0xC3, 0x88 }
53
+ "Eacute", 2, { 0xC3, 0x89 }
54
+ "Ecirc", 2, { 0xC3, 0x8A }
55
+ "Euml", 2, { 0xC3, 0x8B }
56
+ "Igrave", 2, { 0xC3, 0x8C }
57
+ "Iacute", 2, { 0xC3, 0x8D }
58
+ "Icirc", 2, { 0xC3, 0x8E }
59
+ "Iuml", 2, { 0xC3, 0x8F }
60
+ "ETH", 2, { 0xC3, 0x90 }
61
+ "Ntilde", 2, { 0xC3, 0x91 }
62
+ "Ograve", 2, { 0xC3, 0x92 }
63
+ "Oacute", 2, { 0xC3, 0x93 }
64
+ "Ocirc", 2, { 0xC3, 0x94 }
65
+ "Otilde", 2, { 0xC3, 0x95 }
66
+ "Ouml", 2, { 0xC3, 0x96 }
67
+ "times", 2, { 0xC3, 0x97 }
68
+ "Oslash", 2, { 0xC3, 0x98 }
69
+ "Ugrave", 2, { 0xC3, 0x99 }
70
+ "Uacute", 2, { 0xC3, 0x9A }
71
+ "Ucirc", 2, { 0xC3, 0x9B }
72
+ "Uuml", 2, { 0xC3, 0x9C }
73
+ "Yacute", 2, { 0xC3, 0x9D }
74
+ "THORN", 2, { 0xC3, 0x9E }
75
+ "szlig", 2, { 0xC3, 0x9F }
76
+ "agrave", 2, { 0xC3, 0xA0 }
77
+ "aacute", 2, { 0xC3, 0xA1 }
78
+ "acirc", 2, { 0xC3, 0xA2 }
79
+ "atilde", 2, { 0xC3, 0xA3 }
80
+ "auml", 2, { 0xC3, 0xA4 }
81
+ "aring", 2, { 0xC3, 0xA5 }
82
+ "aelig", 2, { 0xC3, 0xA6 }
83
+ "ccedil", 2, { 0xC3, 0xA7 }
84
+ "egrave", 2, { 0xC3, 0xA8 }
85
+ "eacute", 2, { 0xC3, 0xA9 }
86
+ "ecirc", 2, { 0xC3, 0xAA }
87
+ "euml", 2, { 0xC3, 0xAB }
88
+ "igrave", 2, { 0xC3, 0xAC }
89
+ "iacute", 2, { 0xC3, 0xAD }
90
+ "icirc", 2, { 0xC3, 0xAE }
91
+ "iuml", 2, { 0xC3, 0xAF }
92
+ "eth", 2, { 0xC3, 0xB0 }
93
+ "ntilde", 2, { 0xC3, 0xB1 }
94
+ "ograve", 2, { 0xC3, 0xB2 }
95
+ "oacute", 2, { 0xC3, 0xB3 }
96
+ "ocirc", 2, { 0xC3, 0xB4 }
97
+ "otilde", 2, { 0xC3, 0xB5 }
98
+ "ouml", 2, { 0xC3, 0xB6 }
99
+ "divide", 2, { 0xC3, 0xB7 }
100
+ "oslash", 2, { 0xC3, 0xB8 }
101
+ "ugrave", 2, { 0xC3, 0xB9 }
102
+ "uacute", 2, { 0xC3, 0xBA }
103
+ "ucirc", 2, { 0xC3, 0xBB }
104
+ "uuml", 2, { 0xC3, 0xBC }
105
+ "yacute", 2, { 0xC3, 0xBD }
106
+ "thorn", 2, { 0xC3, 0xBE }
107
+ "yuml", 2, { 0xC3, 0xBF }
108
+ "OElig", 2, { 0xC5, 0x92 }
109
+ "oelig", 2, { 0xC5, 0x93 }
110
+ "Scaron", 2, { 0xC5, 0xA0 }
111
+ "scaron", 2, { 0xC5, 0xA1 }
112
+ "Yuml", 2, { 0xC5, 0xB8 }
113
+ "fnof", 2, { 0xC6, 0x92 }
114
+ "circ", 2, { 0xCB, 0x86 }
115
+ "tilde", 2, { 0xCB, 0x9C }
116
+ "Alpha", 2, { 0xCE, 0x91 }
117
+ "Beta", 2, { 0xCE, 0x92 }
118
+ "Gamma", 2, { 0xCE, 0x93 }
119
+ "Delta", 2, { 0xCE, 0x94 }
120
+ "Epsilon", 2, { 0xCE, 0x95 }
121
+ "Zeta", 2, { 0xCE, 0x96 }
122
+ "Eta", 2, { 0xCE, 0x97 }
123
+ "Theta", 2, { 0xCE, 0x98 }
124
+ "Iota", 2, { 0xCE, 0x99 }
125
+ "Kappa", 2, { 0xCE, 0x9A }
126
+ "Lambda", 2, { 0xCE, 0x9B }
127
+ "Mu", 2, { 0xCE, 0x9C }
128
+ "Nu", 2, { 0xCE, 0x9D }
129
+ "Xi", 2, { 0xCE, 0x9E }
130
+ "Omicron", 2, { 0xCE, 0x9F }
131
+ "Pi", 2, { 0xCE, 0xA0 }
132
+ "Rho", 2, { 0xCE, 0xA1 }
133
+ "Sigma", 2, { 0xCE, 0xA3 }
134
+ "Tau", 2, { 0xCE, 0xA4 }
135
+ "Upsilon", 2, { 0xCE, 0xA5 }
136
+ "Phi", 2, { 0xCE, 0xA6 }
137
+ "Chi", 2, { 0xCE, 0xA7 }
138
+ "Psi", 2, { 0xCE, 0xA8 }
139
+ "Omega", 2, { 0xCE, 0xA9 }
140
+ "alpha", 2, { 0xCE, 0xB1 }
141
+ "beta", 2, { 0xCE, 0xB2 }
142
+ "gamma", 2, { 0xCE, 0xB3 }
143
+ "delta", 2, { 0xCE, 0xB4 }
144
+ "epsilon", 2, { 0xCE, 0xB5 }
145
+ "zeta", 2, { 0xCE, 0xB6 }
146
+ "eta", 2, { 0xCE, 0xB7 }
147
+ "theta", 2, { 0xCE, 0xB8 }
148
+ "iota", 2, { 0xCE, 0xB9 }
149
+ "kappa", 2, { 0xCE, 0xBA }
150
+ "lambda", 2, { 0xCE, 0xBB }
151
+ "mu", 2, { 0xCE, 0xBC }
152
+ "nu", 2, { 0xCE, 0xBD }
153
+ "xi", 2, { 0xCE, 0xBE }
154
+ "omicron", 2, { 0xCE, 0xBF }
155
+ "pi", 2, { 0xCF, 0x80 }
156
+ "rho", 2, { 0xCF, 0x81 }
157
+ "sigmaf", 2, { 0xCF, 0x82 }
158
+ "sigma", 2, { 0xCF, 0x83 }
159
+ "tau", 2, { 0xCF, 0x84 }
160
+ "upsilon", 2, { 0xCF, 0x85 }
161
+ "phi", 2, { 0xCF, 0x86 }
162
+ "chi", 2, { 0xCF, 0x87 }
163
+ "psi", 2, { 0xCF, 0x88 }
164
+ "omega", 2, { 0xCF, 0x89 }
165
+ "thetasym", 2, { 0xCF, 0x91 }
166
+ "piv", 2, { 0xCF, 0x96 }
167
+ "ensp", 3, { 0xE2, 0x80, 0x82 }
168
+ "emsp", 3, { 0xE2, 0x80, 0x83 }
169
+ "thinsp", 3, { 0xE2, 0x80, 0x89 }
170
+ "zwnj", 3, { 0xE2, 0x80, 0x8C }
171
+ "zwj", 3, { 0xE2, 0x80, 0x8D }
172
+ "lrm", 3, { 0xE2, 0x80, 0x8E }
173
+ "rlm", 3, { 0xE2, 0x80, 0x8F }
174
+ "ndash", 3, { 0xE2, 0x80, 0x93 }
175
+ "mdash", 3, { 0xE2, 0x80, 0x94 }
176
+ "lsquo", 3, { 0xE2, 0x80, 0x98 }
177
+ "rsquo", 3, { 0xE2, 0x80, 0x99 }
178
+ "sbquo", 3, { 0xE2, 0x80, 0x9A }
179
+ "ldquo", 3, { 0xE2, 0x80, 0x9C }
180
+ "rdquo", 3, { 0xE2, 0x80, 0x9D }
181
+ "bdquo", 3, { 0xE2, 0x80, 0x9E }
182
+ "dagger", 3, { 0xE2, 0x80, 0xA0 }
183
+ "Dagger", 3, { 0xE2, 0x80, 0xA1 }
184
+ "bull", 3, { 0xE2, 0x80, 0xA2 }
185
+ "hellip", 3, { 0xE2, 0x80, 0xA6 }
186
+ "permil", 3, { 0xE2, 0x80, 0xB0 }
187
+ "prime", 3, { 0xE2, 0x80, 0xB2 }
188
+ "Prime", 3, { 0xE2, 0x80, 0xB3 }
189
+ "lsaquo", 3, { 0xE2, 0x80, 0xB9 }
190
+ "rsaquo", 3, { 0xE2, 0x80, 0xBA }
191
+ "oline", 3, { 0xE2, 0x80, 0xBE }
192
+ "frasl", 3, { 0xE2, 0x81, 0x84 }
193
+ "euro", 3, { 0xE2, 0x82, 0xAC }
194
+ "image", 3, { 0xE2, 0x84, 0x91 }
195
+ "weierp", 3, { 0xE2, 0x84, 0x98 }
196
+ "real", 3, { 0xE2, 0x84, 0x9C }
197
+ "trade", 3, { 0xE2, 0x84, 0xA2 }
198
+ "alefsym", 3, { 0xE2, 0x84, 0xB5 }
199
+ "larr", 3, { 0xE2, 0x86, 0x90 }
200
+ "uarr", 3, { 0xE2, 0x86, 0x91 }
201
+ "rarr", 3, { 0xE2, 0x86, 0x92 }
202
+ "darr", 3, { 0xE2, 0x86, 0x93 }
203
+ "harr", 3, { 0xE2, 0x86, 0x94 }
204
+ "crarr", 3, { 0xE2, 0x86, 0xB5 }
205
+ "lArr", 3, { 0xE2, 0x87, 0x90 }
206
+ "uArr", 3, { 0xE2, 0x87, 0x91 }
207
+ "rArr", 3, { 0xE2, 0x87, 0x92 }
208
+ "dArr", 3, { 0xE2, 0x87, 0x93 }
209
+ "hArr", 3, { 0xE2, 0x87, 0x94 }
210
+ "forall", 3, { 0xE2, 0x88, 0x80 }
211
+ "part", 3, { 0xE2, 0x88, 0x82 }
212
+ "exist", 3, { 0xE2, 0x88, 0x83 }
213
+ "empty", 3, { 0xE2, 0x88, 0x85 }
214
+ "nabla", 3, { 0xE2, 0x88, 0x87 }
215
+ "isin", 3, { 0xE2, 0x88, 0x88 }
216
+ "notin", 3, { 0xE2, 0x88, 0x89 }
217
+ "ni", 3, { 0xE2, 0x88, 0x8B }
218
+ "prod", 3, { 0xE2, 0x88, 0x8F }
219
+ "sum", 3, { 0xE2, 0x88, 0x91 }
220
+ "minus", 3, { 0xE2, 0x88, 0x92 }
221
+ "lowast", 3, { 0xE2, 0x88, 0x97 }
222
+ "radic", 3, { 0xE2, 0x88, 0x9A }
223
+ "prop", 3, { 0xE2, 0x88, 0x9D }
224
+ "infin", 3, { 0xE2, 0x88, 0x9E }
225
+ "ang", 3, { 0xE2, 0x88, 0xA0 }
226
+ "and", 3, { 0xE2, 0x88, 0xA7 }
227
+ "or", 3, { 0xE2, 0x88, 0xA8 }
228
+ "cap", 3, { 0xE2, 0x88, 0xA9 }
229
+ "cup", 3, { 0xE2, 0x88, 0xAA }
230
+ "int", 3, { 0xE2, 0x88, 0xAB }
231
+ "there4", 3, { 0xE2, 0x88, 0xB4 }
232
+ "sim", 3, { 0xE2, 0x88, 0xBC }
233
+ "cong", 3, { 0xE2, 0x89, 0x85 }
234
+ "asymp", 3, { 0xE2, 0x89, 0x88 }
235
+ "ne", 3, { 0xE2, 0x89, 0xA0 }
236
+ "equiv", 3, { 0xE2, 0x89, 0xA1 }
237
+ "le", 3, { 0xE2, 0x89, 0xA4 }
238
+ "ge", 3, { 0xE2, 0x89, 0xA5 }
239
+ "sub", 3, { 0xE2, 0x8A, 0x82 }
240
+ "sup", 3, { 0xE2, 0x8A, 0x83 }
241
+ "nsub", 3, { 0xE2, 0x8A, 0x84 }
242
+ "sube", 3, { 0xE2, 0x8A, 0x86 }
243
+ "supe", 3, { 0xE2, 0x8A, 0x87 }
244
+ "oplus", 3, { 0xE2, 0x8A, 0x95 }
245
+ "otimes", 3, { 0xE2, 0x8A, 0x97 }
246
+ "perp", 3, { 0xE2, 0x8A, 0xA5 }
247
+ "sdot", 3, { 0xE2, 0x8B, 0x85 }
248
+ "lceil", 3, { 0xE2, 0x8C, 0x88 }
249
+ "rceil", 3, { 0xE2, 0x8C, 0x89 }
250
+ "lfloor", 3, { 0xE2, 0x8C, 0x8A }
251
+ "rfloor", 3, { 0xE2, 0x8C, 0x8B }
252
+ "lang", 3, { 0xE2, 0x9F, 0xA8 }
253
+ "rang", 3, { 0xE2, 0x9F, 0xA9 }
254
+ "loz", 3, { 0xE2, 0x97, 0x8A }
255
+ "spades", 3, { 0xE2, 0x99, 0xA0 }
256
+ "clubs", 3, { 0xE2, 0x99, 0xA3 }
257
+ "hearts", 3, { 0xE2, 0x99, 0xA5 }
258
+ "diams", 3, { 0xE2, 0x99, 0xA6 }