emf 0.1.2 → 0.2.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 (360) hide show
  1. checksums.yaml +4 -4
  2. data/README.adoc +224 -19
  3. data/exe/emf +12 -0
  4. data/lib/emf/backend.rb +60 -0
  5. data/lib/emf/binary/class_field_accessors.rb +49 -0
  6. data/lib/emf/binary/float32_le.rb +54 -0
  7. data/lib/emf/binary/types.rb +40 -6
  8. data/lib/emf/conformance/context.rb +36 -0
  9. data/lib/emf/conformance/diagnostic.rb +18 -0
  10. data/lib/emf/conformance/manifest/emf_bitmap_misc.yml +622 -0
  11. data/lib/emf/conformance/manifest/emf_control_buffers.yml +61 -0
  12. data/lib/emf/conformance/manifest/emf_core.yml +117 -0
  13. data/lib/emf/conformance/manifest/emf_corpus_rules.yml +21 -0
  14. data/lib/emf/conformance/manifest/emf_objects_geometry.yml +229 -0
  15. data/lib/emf/conformance/manifest/emf_plus.yml +357 -0
  16. data/lib/emf/conformance/manifest/emf_plus_core.yml +33 -0
  17. data/lib/emf/conformance/manifest/emf_state_path.yml +403 -0
  18. data/lib/emf/conformance/manifest/emf_text.yml +97 -0
  19. data/lib/emf/conformance/manifest/wmf.yml +874 -0
  20. data/lib/emf/conformance/manifest.rb +79 -0
  21. data/lib/emf/conformance/profile.rb +35 -0
  22. data/lib/emf/conformance/record_types.rb +24 -0
  23. data/lib/emf/conformance/registry.rb +76 -0
  24. data/lib/emf/conformance/report.rb +83 -0
  25. data/lib/emf/conformance/rule.rb +16 -0
  26. data/lib/emf/conformance/rules/emf_bitmap.rb +357 -0
  27. data/lib/emf/conformance/rules/emf_comment_escape.rb +309 -0
  28. data/lib/emf/conformance/rules/emf_control_buffers.rb +137 -0
  29. data/lib/emf/conformance/rules/emf_corpus_named.rb +83 -0
  30. data/lib/emf/conformance/rules/emf_framing.rb +94 -0
  31. data/lib/emf/conformance/rules/emf_geometry.rb +282 -0
  32. data/lib/emf/conformance/rules/emf_header.rb +114 -0
  33. data/lib/emf/conformance/rules/emf_objects.rb +291 -0
  34. data/lib/emf/conformance/rules/emf_parse_recovery.rb +97 -0
  35. data/lib/emf/conformance/rules/emf_path_clip.rb +165 -0
  36. data/lib/emf/conformance/rules/emf_plus.rb +75 -0
  37. data/lib/emf/conformance/rules/emf_plus_common.rb +58 -0
  38. data/lib/emf/conformance/rules/emf_plus_drawing.rb +78 -0
  39. data/lib/emf/conformance/rules/emf_plus_effects.rb +104 -0
  40. data/lib/emf/conformance/rules/emf_plus_fields.rb +169 -0
  41. data/lib/emf/conformance/rules/emf_plus_fields_b.rb +102 -0
  42. data/lib/emf/conformance/rules/emf_plus_framing.rb +172 -0
  43. data/lib/emf/conformance/rules/emf_plus_objects.rb +97 -0
  44. data/lib/emf/conformance/rules/emf_plus_payloads.rb +320 -0
  45. data/lib/emf/conformance/rules/emf_plus_properties.rb +96 -0
  46. data/lib/emf/conformance/rules/emf_plus_state.rb +77 -0
  47. data/lib/emf/conformance/rules/emf_state.rb +244 -0
  48. data/lib/emf/conformance/rules/emf_text.rb +221 -0
  49. data/lib/emf/conformance/rules/emf_transform.rb +85 -0
  50. data/lib/emf/conformance/rules/wmf_buffers.rb +259 -0
  51. data/lib/emf/conformance/rules/wmf_framing.rb +146 -0
  52. data/lib/emf/conformance/rules/wmf_layout_records.rb +112 -0
  53. data/lib/emf/conformance/rules/wmf_objects.rb +168 -0
  54. data/lib/emf/conformance/rules/wmf_records.rb +191 -0
  55. data/lib/emf/conformance/rules/wmf_rejections.rb +184 -0
  56. data/lib/emf/conformance/runner.rb +61 -0
  57. data/lib/emf/conformance/ternary_raster_operations.rb +52 -0
  58. data/lib/emf/conformance.rb +31 -0
  59. data/lib/emf/emf_plus/effects/blur.rb +24 -0
  60. data/lib/emf/emf_plus/effects/brightness_contrast.rb +22 -0
  61. data/lib/emf/emf_plus/effects/color_balance.rb +24 -0
  62. data/lib/emf/emf_plus/effects/color_curve.rb +24 -0
  63. data/lib/emf/emf_plus/effects/color_lookup_table.rb +26 -0
  64. data/lib/emf/emf_plus/effects/color_matrix.rb +23 -0
  65. data/lib/emf/emf_plus/effects/effect.rb +50 -0
  66. data/lib/emf/emf_plus/effects/hue_saturation_lightness.rb +24 -0
  67. data/lib/emf/emf_plus/effects/levels.rb +24 -0
  68. data/lib/emf/emf_plus/effects/opaque.rb +19 -0
  69. data/lib/emf/emf_plus/effects/red_eye_correction.rb +35 -0
  70. data/lib/emf/emf_plus/effects/sharpen.rb +24 -0
  71. data/lib/emf/emf_plus/effects/tint.rb +22 -0
  72. data/lib/emf/emf_plus/effects.rb +45 -0
  73. data/lib/emf/emf_plus/frame.rb +41 -0
  74. data/lib/emf/emf_plus/links/effect_link.rb +16 -0
  75. data/lib/emf/emf_plus/links/get_dc_span.rb +18 -0
  76. data/lib/emf/emf_plus/links/link_error.rb +15 -0
  77. data/lib/emf/emf_plus/links.rb +77 -0
  78. data/lib/emf/emf_plus/object_chain.rb +108 -0
  79. data/lib/emf/emf_plus/object_table.rb +182 -0
  80. data/lib/emf/emf_plus/objects/brush.rb +296 -0
  81. data/lib/emf/emf_plus/objects/custom_line_cap.rb +106 -0
  82. data/lib/emf/emf_plus/objects/font.rb +47 -0
  83. data/lib/emf/emf_plus/objects/image.rb +68 -0
  84. data/lib/emf/emf_plus/objects/image_attributes.rb +28 -0
  85. data/lib/emf/emf_plus/objects/opaque.rb +19 -0
  86. data/lib/emf/emf_plus/objects/parts.rb +103 -0
  87. data/lib/emf/emf_plus/objects/path.rb +21 -0
  88. data/lib/emf/emf_plus/objects/pen.rb +132 -0
  89. data/lib/emf/emf_plus/objects/region.rb +39 -0
  90. data/lib/emf/emf_plus/objects/string_format.rb +55 -0
  91. data/lib/emf/emf_plus/objects/typed.rb +50 -0
  92. data/lib/emf/emf_plus/objects.rb +46 -0
  93. data/lib/emf/emf_plus/parser.rb +64 -2
  94. data/lib/emf/emf_plus/records/base.rb +107 -0
  95. data/lib/emf/emf_plus/records/begin_container.rb +31 -0
  96. data/lib/emf/emf_plus/records/begin_container_no_params.rb +20 -0
  97. data/lib/emf/emf_plus/records/body.rb +16 -0
  98. data/lib/emf/emf_plus/records/clear.rb +22 -0
  99. data/lib/emf/emf_plus/records/clip_transform_flags.rb +26 -0
  100. data/lib/emf/emf_plus/records/comment.rb +21 -0
  101. data/lib/emf/emf_plus/records/draw_arc.rb +33 -0
  102. data/lib/emf/emf_plus/records/draw_beziers.rb +31 -0
  103. data/lib/emf/emf_plus/records/draw_closed_curve.rb +34 -0
  104. data/lib/emf/emf_plus/records/draw_curve.rb +38 -0
  105. data/lib/emf/emf_plus/records/draw_driver_string.rb +61 -0
  106. data/lib/emf/emf_plus/records/draw_ellipse.rb +28 -0
  107. data/lib/emf/emf_plus/records/draw_image.rb +42 -0
  108. data/lib/emf/emf_plus/records/draw_image_points.rb +62 -0
  109. data/lib/emf/emf_plus/records/draw_lines.rb +34 -0
  110. data/lib/emf/emf_plus/records/draw_path.rb +23 -0
  111. data/lib/emf/emf_plus/records/draw_pie.rb +33 -0
  112. data/lib/emf/emf_plus/records/draw_rects.rb +30 -0
  113. data/lib/emf/emf_plus/records/draw_string.rb +41 -0
  114. data/lib/emf/emf_plus/records/end_container.rb +20 -0
  115. data/lib/emf/emf_plus/records/end_of_file.rb +17 -0
  116. data/lib/emf/emf_plus/records/fill_brush.rb +21 -0
  117. data/lib/emf/emf_plus/records/fill_closed_curve.rb +38 -0
  118. data/lib/emf/emf_plus/records/fill_ellipse.rb +29 -0
  119. data/lib/emf/emf_plus/records/fill_path.rb +23 -0
  120. data/lib/emf/emf_plus/records/fill_pie.rb +34 -0
  121. data/lib/emf/emf_plus/records/fill_polygon.rb +32 -0
  122. data/lib/emf/emf_plus/records/fill_rects.rb +31 -0
  123. data/lib/emf/emf_plus/records/fill_region.rb +23 -0
  124. data/lib/emf/emf_plus/records/get_dc.rb +18 -0
  125. data/lib/emf/emf_plus/records/header.rb +35 -0
  126. data/lib/emf/emf_plus/records/multiply_world_transform.rb +24 -0
  127. data/lib/emf/emf_plus/records/object.rb +32 -0
  128. data/lib/emf/emf_plus/records/offset_clip.rb +24 -0
  129. data/lib/emf/emf_plus/records/primitives/argb.rb +20 -0
  130. data/lib/emf/emf_plus/records/primitives/bitmap.rb +32 -0
  131. data/lib/emf/emf_plus/records/primitives/bitmap_data.rb +21 -0
  132. data/lib/emf/emf_plus/records/primitives/blend_colors.rb +22 -0
  133. data/lib/emf/emf_plus/records/primitives/blend_factors.rb +21 -0
  134. data/lib/emf/emf_plus/records/primitives/bounded_array.rb +38 -0
  135. data/lib/emf/emf_plus/records/primitives/byte_reader.rb +25 -0
  136. data/lib/emf/emf_plus/records/primitives/character_range.rb +20 -0
  137. data/lib/emf/emf_plus/records/primitives/compressed_image.rb +17 -0
  138. data/lib/emf/emf_plus/records/primitives/focus_scale_data.rb +20 -0
  139. data/lib/emf/emf_plus/records/primitives/graphics_version.rb +21 -0
  140. data/lib/emf/emf_plus/records/primitives/language_identifier.rb +22 -0
  141. data/lib/emf/emf_plus/records/primitives/metafile.rb +19 -0
  142. data/lib/emf/emf_plus/records/primitives/palette.rb +21 -0
  143. data/lib/emf/emf_plus/records/primitives/path.rb +89 -0
  144. data/lib/emf/emf_plus/records/primitives/path_point_type.rb +21 -0
  145. data/lib/emf/emf_plus/records/primitives/path_point_type_rle.rb +23 -0
  146. data/lib/emf/emf_plus/records/primitives/point.rb +18 -0
  147. data/lib/emf/emf_plus/records/primitives/point_array.rb +42 -0
  148. data/lib/emf/emf_plus/records/primitives/point_f.rb +19 -0
  149. data/lib/emf/emf_plus/records/primitives/point_r.rb +19 -0
  150. data/lib/emf/emf_plus/records/primitives/rect.rb +20 -0
  151. data/lib/emf/emf_plus/records/primitives/rect_array.rb +24 -0
  152. data/lib/emf/emf_plus/records/primitives/rect_f.rb +21 -0
  153. data/lib/emf/emf_plus/records/primitives/region_node.rb +68 -0
  154. data/lib/emf/emf_plus/records/primitives/region_node_child_nodes.rb +22 -0
  155. data/lib/emf/emf_plus/records/primitives/region_node_path.rb +37 -0
  156. data/lib/emf/emf_plus/records/primitives/relative_coordinate.rb +32 -0
  157. data/lib/emf/emf_plus/records/primitives/string_format_data.rb +23 -0
  158. data/lib/emf/emf_plus/records/primitives/transform_matrix.rb +23 -0
  159. data/lib/emf/emf_plus/records/primitives.rb +41 -0
  160. data/lib/emf/emf_plus/records/reset_clip.rb +17 -0
  161. data/lib/emf/emf_plus/records/reset_world_transform.rb +17 -0
  162. data/lib/emf/emf_plus/records/restore.rb +20 -0
  163. data/lib/emf/emf_plus/records/rotate_world_transform.rb +24 -0
  164. data/lib/emf/emf_plus/records/save.rb +20 -0
  165. data/lib/emf/emf_plus/records/scale_world_transform.rb +26 -0
  166. data/lib/emf/emf_plus/records/serializable_object.rb +32 -0
  167. data/lib/emf/emf_plus/records/set_anti_alias_mode.rb +25 -0
  168. data/lib/emf/emf_plus/records/set_clip_path.rb +20 -0
  169. data/lib/emf/emf_plus/records/set_clip_rect.rb +24 -0
  170. data/lib/emf/emf_plus/records/set_clip_region.rb +20 -0
  171. data/lib/emf/emf_plus/records/set_compositing_mode.rb +21 -0
  172. data/lib/emf/emf_plus/records/set_compositing_quality.rb +21 -0
  173. data/lib/emf/emf_plus/records/set_interpolation_mode.rb +21 -0
  174. data/lib/emf/emf_plus/records/set_page_transform.rb +25 -0
  175. data/lib/emf/emf_plus/records/set_pixel_offset_mode.rb +21 -0
  176. data/lib/emf/emf_plus/records/set_rendering_origin.rb +22 -0
  177. data/lib/emf/emf_plus/records/set_text_contrast.rb +24 -0
  178. data/lib/emf/emf_plus/records/set_text_rendering_hint.rb +21 -0
  179. data/lib/emf/emf_plus/records/set_ts_clip.rb +40 -0
  180. data/lib/emf/emf_plus/records/set_ts_graphics.rb +88 -0
  181. data/lib/emf/emf_plus/records/set_world_transform.rb +22 -0
  182. data/lib/emf/emf_plus/records/shape_flags.rb +23 -0
  183. data/lib/emf/emf_plus/records/translate_world_transform.rb +26 -0
  184. data/lib/emf/emf_plus/records/unknown.rb +20 -0
  185. data/lib/emf/emf_plus/records.rb +107 -0
  186. data/lib/emf/emf_plus/serializer.rb +9 -2
  187. data/lib/emf/emf_plus/stream/conformance.rb +68 -0
  188. data/lib/emf/emf_plus/stream/editor.rb +21 -0
  189. data/lib/emf/emf_plus/stream/emf_gap.rb +20 -0
  190. data/lib/emf/emf_plus/stream/link_index.rb +30 -0
  191. data/lib/emf/emf_plus/stream/rebuild.rb +47 -0
  192. data/lib/emf/emf_plus/stream/record_handle.rb +26 -0
  193. data/lib/emf/emf_plus/stream/segment.rb +70 -0
  194. data/lib/emf/emf_plus/stream.rb +153 -0
  195. data/lib/emf/emf_plus.rb +9 -0
  196. data/lib/emf/emr/binary/dib_header.rb +142 -0
  197. data/lib/emf/emr/binary/ext_text_out_fields.rb +43 -0
  198. data/lib/emf/emr/binary/extended_pen_buffers.rb +23 -0
  199. data/lib/emf/emr/binary/fast_fill.rb +1164 -0
  200. data/lib/emf/emr/binary/font.rb +159 -0
  201. data/lib/emf/emr/binary/lazy_utf16_array.rb +82 -0
  202. data/lib/emf/emr/binary/pack_plan.rb +144 -0
  203. data/lib/emf/emr/binary/pack_plan_check.rb +75 -0
  204. data/lib/emf/emr/binary/pack_plan_exact.rb +130 -0
  205. data/lib/emf/emr/binary/pack_plan_generate.rb +116 -0
  206. data/lib/emf/emr/binary/pack_plan_values.rb +92 -0
  207. data/lib/emf/emr/binary/palette_body.rb +19 -0
  208. data/lib/emf/emr/binary/palette_entry.rb +18 -0
  209. data/lib/emf/emr/binary/record.rb +33 -0
  210. data/lib/emf/emr/binary/records/alpha_blend.rb +43 -0
  211. data/lib/emf/emr/binary/records/angle_arc.rb +2 -2
  212. data/lib/emf/emr/binary/records/bit_blt.rb +14 -0
  213. data/lib/emf/emr/binary/records/color_correct_palette.rb +55 -1
  214. data/lib/emf/emr/binary/records/colormatch_to_target_w.rb +76 -1
  215. data/lib/emf/emr/binary/records/create_colorspace.rb +67 -1
  216. data/lib/emf/emr/binary/records/create_colorspace_w.rb +90 -1
  217. data/lib/emf/emr/binary/records/create_dib_pattern_brush_pt.rb +14 -0
  218. data/lib/emf/emr/binary/records/create_font_indirect_w.rb +6 -2
  219. data/lib/emf/emr/binary/records/create_mono_brush.rb +14 -0
  220. data/lib/emf/emr/binary/records/create_palette.rb +19 -1
  221. data/lib/emf/emr/binary/records/delete_colorspace.rb +22 -1
  222. data/lib/emf/emr/binary/records/draw_escape.rb +45 -1
  223. data/lib/emf/emr/binary/records/ellipse.rb +1 -1
  224. data/lib/emf/emr/binary/records/eof.rb +9 -0
  225. data/lib/emf/emr/binary/records/ext_create_pen.rb +80 -1
  226. data/lib/emf/emr/binary/records/ext_escape.rb +45 -1
  227. data/lib/emf/emr/binary/records/ext_flood_fill.rb +9 -2
  228. data/lib/emf/emr/binary/records/ext_select_clip_rgn.rb +9 -1
  229. data/lib/emf/emr/binary/records/ext_text_out_a.rb +16 -3
  230. data/lib/emf/emr/binary/records/ext_text_out_w.rb +14 -3
  231. data/lib/emf/emr/binary/records/fill_rgn.rb +11 -2
  232. data/lib/emf/emr/binary/records/force_ufi_mapping.rb +38 -1
  233. data/lib/emf/emr/binary/records/frame_rgn.rb +12 -2
  234. data/lib/emf/emr/binary/records/gls_bounded_record.rb +61 -1
  235. data/lib/emf/emr/binary/records/gls_record.rb +42 -1
  236. data/lib/emf/emr/binary/records/gradient_fill.rb +7 -0
  237. data/lib/emf/emr/binary/records/invert_rgn.rb +11 -3
  238. data/lib/emf/emr/binary/records/mask_blt.rb +66 -0
  239. data/lib/emf/emr/binary/records/named_escape.rb +78 -1
  240. data/lib/emf/emr/binary/records/paint_rgn.rb +11 -3
  241. data/lib/emf/emr/binary/records/pixel_format.rb +76 -1
  242. data/lib/emf/emr/binary/records/plg_blt.rb +66 -0
  243. data/lib/emf/emr/binary/records/poly_textout_a.rb +128 -1
  244. data/lib/emf/emr/binary/records/poly_textout_w.rb +128 -1
  245. data/lib/emf/emr/binary/records/raw.rb +3 -0
  246. data/lib/emf/emr/binary/records/realize_palette.rb +1 -0
  247. data/lib/emf/emr/binary/records/rectangle.rb +1 -1
  248. data/lib/emf/emr/binary/records/resize_palette.rb +16 -2
  249. data/lib/emf/emr/binary/records/round_rect.rb +2 -2
  250. data/lib/emf/emr/binary/records/select_palette.rb +1 -0
  251. data/lib/emf/emr/binary/records/set_color_adjustment.rb +136 -0
  252. data/lib/emf/emr/binary/records/set_colorspace.rb +22 -1
  253. data/lib/emf/emr/binary/records/set_dibits_to_device.rb +43 -0
  254. data/lib/emf/emr/binary/records/set_icm_profile_a.rb +71 -1
  255. data/lib/emf/emr/binary/records/set_icm_profile_w.rb +71 -1
  256. data/lib/emf/emr/binary/records/set_linked_ufis.rb +49 -1
  257. data/lib/emf/emr/binary/records/set_miter_limit.rb +1 -1
  258. data/lib/emf/emr/binary/records/set_palette_entries.rb +20 -2
  259. data/lib/emf/emr/binary/records/set_text_justification.rb +8 -2
  260. data/lib/emf/emr/binary/records/small_text_out.rb +55 -4
  261. data/lib/emf/emr/binary/records/stretch_blt.rb +14 -0
  262. data/lib/emf/emr/binary/records/stretch_dibits.rb +14 -0
  263. data/lib/emf/emr/binary/records/transparent_blt.rb +43 -0
  264. data/lib/emf/emr/binary/records.rb +4 -2
  265. data/lib/emf/emr/binary/region_data.rb +33 -0
  266. data/lib/emf/emr/binary/state_record_body.rb +33 -0
  267. data/lib/emf/emr/binary/thin_shell.rb +226 -0
  268. data/lib/emf/emr/binary/value_view/layout.rb +101 -0
  269. data/lib/emf/emr/binary/value_view/reader_source.rb +88 -0
  270. data/lib/emf/emr/binary/value_view.rb +173 -0
  271. data/lib/emf/emr/binary/variable_buffers.rb +87 -0
  272. data/lib/emf/emr/binary.rb +4 -0
  273. data/lib/emf/emr/filled_record.rb +77 -0
  274. data/lib/emf/emr/parser.rb +239 -50
  275. data/lib/emf/emr/serializer.rb +4 -5
  276. data/lib/emf/emr.rb +1 -0
  277. data/lib/emf/error.rb +24 -1
  278. data/lib/emf/model/diagnostic.rb +41 -0
  279. data/lib/emf/model/emr/header.rb +40 -1
  280. data/lib/emf/model/emr/records.rb +142 -6
  281. data/lib/emf/model/emr/wire_values.rb +43 -0
  282. data/lib/emf/model/emr.rb +1 -0
  283. data/lib/emf/model/geometry/color.rb +19 -1
  284. data/lib/emf/model/metafile.rb +22 -2
  285. data/lib/emf/model/wmf/bitmap_records.rb +155 -0
  286. data/lib/emf/model/wmf/brush_records.rb +45 -0
  287. data/lib/emf/model/wmf/dc_escape_records.rb +67 -0
  288. data/lib/emf/model/wmf/font_record.rb +40 -0
  289. data/lib/emf/model/wmf/geometry_records.rb +107 -0
  290. data/lib/emf/model/wmf/header.rb +36 -0
  291. data/lib/emf/model/wmf/object_records.rb +71 -0
  292. data/lib/emf/model/wmf/palette_records.rb +68 -0
  293. data/lib/emf/model/wmf/records.rb +247 -0
  294. data/lib/emf/model/wmf/region_records.rb +112 -0
  295. data/lib/emf/model/wmf/state_records.rb +188 -0
  296. data/lib/emf/model/wmf/text_records.rb +36 -0
  297. data/lib/emf/model/wmf.rb +11 -0
  298. data/lib/emf/model.rb +2 -0
  299. data/lib/emf/native/bitmap_fields.rb +58 -0
  300. data/lib/emf/native/diagnostic_contract.rb +39 -0
  301. data/lib/emf/native/diagnostics.rb +81 -0
  302. data/lib/emf/native/emf_plus_loader.rb +35 -0
  303. data/lib/emf/native/emf_plus_snapshot.rb +96 -0
  304. data/lib/emf/native/emf_plus_source.rb +20 -0
  305. data/lib/emf/native/emf_plus_stream.rb +150 -0
  306. data/lib/emf/native/fields.rb +369 -0
  307. data/lib/emf/native/font_fields.rb +87 -0
  308. data/lib/emf/native/gradient_fields.rb +23 -0
  309. data/lib/emf/native/header.rb +35 -0
  310. data/lib/emf/native/header_errors.rb +30 -0
  311. data/lib/emf/native/hydrator.rb +151 -0
  312. data/lib/emf/native/lazy_wire.rb +100 -0
  313. data/lib/emf/native/legacy_state_fields.rb +22 -0
  314. data/lib/emf/native/library_path.rb +68 -0
  315. data/lib/emf/native/loader.rb +120 -0
  316. data/lib/emf/native/palette_fields.rb +45 -0
  317. data/lib/emf/native/poly_text_fields.rb +116 -0
  318. data/lib/emf/native/resource_failure.rb +28 -0
  319. data/lib/emf/native/small_text_fields.rb +27 -0
  320. data/lib/emf/native/snapshot.rb +102 -0
  321. data/lib/emf/native/wmf_bitmap_fields.rb +58 -0
  322. data/lib/emf/native/wmf_brush_fields.rb +62 -0
  323. data/lib/emf/native/wmf_fields.rb +117 -0
  324. data/lib/emf/native/wmf_hydrator.rb +143 -0
  325. data/lib/emf/native/wmf_loading.rb +49 -0
  326. data/lib/emf/native/wmf_palette_fields.rb +60 -0
  327. data/lib/emf/native/wmf_region_fields.rb +92 -0
  328. data/lib/emf/native/wmf_rejection.rb +84 -0
  329. data/lib/emf/native/wmf_remaining_fields.rb +70 -0
  330. data/lib/emf/native/wmf_snapshot.rb +51 -0
  331. data/lib/emf/native/wmf_text_fields.rb +56 -0
  332. data/lib/emf/native.rb +61 -0
  333. data/lib/emf/parse_evidence.rb +57 -0
  334. data/lib/emf/resource_budget/bitmap.rb +66 -0
  335. data/lib/emf/resource_budget/gradient.rb +30 -0
  336. data/lib/emf/resource_budget/poly_text.rb +85 -0
  337. data/lib/emf/resource_budget.rb +382 -0
  338. data/lib/emf/resource_limits/emf_records.rb +130 -0
  339. data/lib/emf/resource_limits.rb +58 -0
  340. data/lib/emf/version.rb +1 -1
  341. data/lib/emf/visitors/dump.rb +4 -0
  342. data/lib/emf/visitors/stats.rb +6 -5
  343. data/lib/emf/wmf/binary.rb +150 -1
  344. data/lib/emf/wmf/bitmap_codec.rb +118 -0
  345. data/lib/emf/wmf/brush_codec.rb +102 -0
  346. data/lib/emf/wmf/dc_escape_codec.rb +75 -0
  347. data/lib/emf/wmf/dib.rb +187 -0
  348. data/lib/emf/wmf/embedded_emf.rb +137 -0
  349. data/lib/emf/wmf/escape_views.rb +89 -0
  350. data/lib/emf/wmf/evidence.rb +255 -0
  351. data/lib/emf/wmf/geometry_codec.rb +49 -0
  352. data/lib/emf/wmf/palette_codec.rb +85 -0
  353. data/lib/emf/wmf/parser.rb +147 -2
  354. data/lib/emf/wmf/recovery.rb +95 -0
  355. data/lib/emf/wmf/region_codec.rb +151 -0
  356. data/lib/emf/wmf/serializer.rb +164 -2
  357. data/lib/emf/wmf/text_codec.rb +123 -0
  358. data/lib/emf/wmf.rb +7 -0
  359. data/lib/emf.rb +13 -9
  360. metadata +287 -10
@@ -0,0 +1,159 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bindata"
4
+ require "emf/emr/binary/lazy_utf16_array"
5
+
6
+ module Emf
7
+ module Emr
8
+ module Binary
9
+ # Fixed UTF-16 fields retain code units, including units after a terminator.
10
+ class LogFont < BinData::Record
11
+ endian :little
12
+ int32 :height
13
+ int32 :width
14
+ int32 :escapement
15
+ int32 :orientation
16
+ int32 :weight
17
+ uint8 :italic
18
+ uint8 :underline
19
+ uint8 :strike_out
20
+ uint8 :char_set
21
+ uint8 :out_precision
22
+ uint8 :clip_precision
23
+ uint8 :quality
24
+ uint8 :pitch_and_family
25
+ lazy_utf16_array :facename, initial_length: 32
26
+ end
27
+
28
+ class Panose < BinData::Record
29
+ uint8 :family_type
30
+ uint8 :serif_style
31
+ uint8 :weight
32
+ uint8 :proportion
33
+ uint8 :contrast
34
+ uint8 :stroke_variation
35
+ uint8 :arm_style
36
+ uint8 :letterform
37
+ uint8 :midline
38
+ uint8 :x_height
39
+ end
40
+
41
+ class LogFontPanose < BinData::Record
42
+ endian :little
43
+ log_font :log_font
44
+ lazy_utf16_array :fullname, initial_length: 64
45
+ lazy_utf16_array :style, initial_length: 32
46
+ uint32 :version
47
+ uint32 :style_size
48
+ uint32 :match
49
+ uint32 :reserved
50
+ array :vendor_id, type: :uint8, initial_length: 4
51
+ uint32 :culture
52
+ panose :panose
53
+ array :padding, type: :uint8, initial_length: 2
54
+ end
55
+
56
+ class DesignVector < BinData::Record
57
+ endian :little
58
+ uint32 :signature
59
+ uint32 :num_axes
60
+ array :axis_values, type: :int32, initial_length: :num_axes
61
+ end
62
+
63
+ class LogFontExDv < BinData::Record
64
+ endian :little
65
+ log_font :log_font
66
+ lazy_utf16_array :fullname, initial_length: 64
67
+ lazy_utf16_array :style, initial_length: 32
68
+ lazy_utf16_array :script, initial_length: 32
69
+ design_vector :design_vector
70
+ rest :trailing
71
+ end
72
+
73
+ # The byte snapshot preserves the existing body API; font exposes the fields.
74
+ class FontBody < BinData::BasePrimitive
75
+ mandatory_parameter :byte_length
76
+
77
+ attr_accessor :font
78
+
79
+ def assign(value)
80
+ bytes = value.respond_to?(:snapshot) ? value.snapshot : value
81
+ @font = parse_font(bytes)
82
+ @assigned_size = bytes.bytesize
83
+ super(bytes)
84
+ end
85
+
86
+ def snapshot
87
+ @font ? value_to_binary_string(nil) : super
88
+ end
89
+
90
+ private
91
+
92
+ def read_and_return_value(io)
93
+ length = eval_parameter(:byte_length)
94
+ raise BinData::ValidityError, "font body is shorter than LOGFONT" if length < 92
95
+
96
+ bytes = io.readbytes(length)
97
+ @font = parse_font(bytes)
98
+ bytes
99
+ rescue IOError => e
100
+ raise BinData::ValidityError, e.message
101
+ end
102
+
103
+ def parse_font(bytes)
104
+ size = bytes.bytesize
105
+ raise BinData::ValidityError, "font body is shorter than LOGFONT" if size < 92
106
+
107
+ return LogFont.read(bytes) if size == 92
108
+ return LogFontPanose.read(bytes.ljust(320, "\0")) if size <= 320
109
+
110
+ validate_exdv(bytes)
111
+ LogFontExDv.read(bytes)
112
+ end
113
+
114
+ def validate_exdv(bytes)
115
+ raise BinData::ValidityError, "truncated LOGFONTEXDV" if bytes.bytesize < 356
116
+
117
+ signature, axes = bytes.byteslice(348, 8).unpack("V2")
118
+ raise BinData::ValidityError, "invalid design vector signature" unless signature == 0x08007664
119
+ raise BinData::ValidityError, "invalid design vector axis count" if axes > 16
120
+ raise BinData::ValidityError, "truncated design vector" if bytes.bytesize < 356 + (axes * 4)
121
+ end
122
+
123
+ def value_to_binary_string(value)
124
+ return value unless @font
125
+
126
+ bytes = @font.to_binary_s
127
+ if @font.is_a?(LogFontExDv)
128
+ validate_exdv(bytes)
129
+ unless @font.design_vector.axis_values.length == @font.design_vector.num_axes
130
+ raise BinData::ValidityError, "design vector axis count does not match values"
131
+ end
132
+ end
133
+ length = body_length
134
+ if @font.is_a?(LogFontPanose) && length.between?(93, 319)
135
+ raise BinData::ValidityError, "font edit exceeds partial Panose body" unless bytes.byteslice(length..).bytes.all?(&:zero?)
136
+
137
+ return bytes.byteslice(0, length)
138
+ end
139
+ raise BinData::ValidityError, "font body does not match record size" unless bytes.bytesize == length
140
+
141
+ bytes
142
+ end
143
+
144
+ # A record built in memory can be serialized before its nSize is set:
145
+ # emfsvg assigns a raw LOGFONTW body, then derives n_size from
146
+ # to_binary_s. Until nSize gives a size, the body keeps the size it
147
+ # was assigned; an explicit nSize is still validated.
148
+ def body_length
149
+ length = eval_parameter(:byte_length)
150
+ length.positive? || @assigned_size.nil? ? length : @assigned_size
151
+ end
152
+
153
+ def sensible_default
154
+ "".b
155
+ end
156
+ end
157
+ end
158
+ end
159
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bindata"
4
+
5
+ module Emf
6
+ module Emr
7
+ module Binary
8
+ # A fixed-length array of little-endian uint16 that keeps the bytes it read
9
+ # and builds the per-unit BinData objects only when an element is touched.
10
+ # A font record read and written back untouched never pays for them.
11
+ class LazyUtf16Array < BinData::Array
12
+ UNIT_BYTES = 2
13
+
14
+ default_parameter type: :uint16le
15
+
16
+ # BinData extends each instance with its initial_length plugin, which
17
+ # shadows class methods; extending last puts these in front of it.
18
+ def initialize_shared_instance
19
+ super
20
+ extend Lazy
21
+ end
22
+
23
+ def initialize_instance
24
+ super
25
+ @raw = nil
26
+ end
27
+
28
+ module Lazy
29
+ def do_read(io)
30
+ @elements = nil
31
+ @raw = io.readbytes(eval_parameter(:initial_length) * UNIT_BYTES)
32
+ end
33
+
34
+ def do_write(io)
35
+ @raw ? io.writebytes(@raw) : super
36
+ end
37
+
38
+ def do_num_bytes
39
+ @raw ? @raw.bytesize : super
40
+ end
41
+
42
+ def clear?
43
+ @raw ? @raw.count("\0") == @raw.bytesize : super
44
+ end
45
+
46
+ def length
47
+ @raw ? @raw.bytesize / UNIT_BYTES : super
48
+ end
49
+ alias size length
50
+
51
+ def assign(array)
52
+ return if equal?(array)
53
+
54
+ @raw = nil
55
+ super
56
+ end
57
+
58
+ private
59
+
60
+ def elements
61
+ materialize if @raw
62
+ super
63
+ end
64
+
65
+ # Build the full element list before publishing it, so a concurrent
66
+ # reader sees either the raw bytes or complete elements, never an
67
+ # empty array in between.
68
+ def materialize
69
+ raw = @raw
70
+ list = Array.new(raw.bytesize / UNIT_BYTES) { new_element }
71
+ io = BinData::IO::Read.new(raw)
72
+ list.each { |element| element.do_read(io) }
73
+ @elements = list
74
+ @raw = nil
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
81
+
82
+ BinData::RegisteredClasses.register("lazy_utf16_array", Emf::Emr::Binary::LazyUtf16Array)
@@ -0,0 +1,144 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "pack_plan_check"
4
+ require_relative "pack_plan_exact"
5
+ require_relative "pack_plan_generate"
6
+ require_relative "pack_plan_values"
7
+
8
+ module Emf
9
+ module Emr
10
+ module Binary
11
+ # The bytes of `klass.new(**attrs)` with n_size set to the record's size,
12
+ # computed straight from the attributes, with no wire built. Compiled once
13
+ # per FastFill class from the instantiated template: the leaves in write
14
+ # order with their defaults, directives and ranges. It accepts only
15
+ # attributes whose BinData assignment is the identity: known fields, and
16
+ # in-range Integers (Floats float32 holds exactly, for float32 leaves) given as a
17
+ # symbol-keyed Hash or an instance of the field's own struct class, plus,
18
+ # for a point array record, a list of integer points. Everything else
19
+ # returns nil and the caller builds the wire.
20
+ #
21
+ # A plan is only used once it reproduces BinData's bytes on the leaf
22
+ # values it was compiled from (see `verified?`); otherwise `build`
23
+ # returns nil for the class.
24
+ class PackPlan
25
+ include PackPlanCheck
26
+ include PackPlanValues
27
+ include PackPlanExact
28
+ include PackPlanGenerate
29
+
30
+ LEAVES = {
31
+ "BinData::Uint32le" => ["V", 0, (2**32) - 1],
32
+ "BinData::Int32le" => ["l<", -(2**31), (2**31) - 1],
33
+ "BinData::Uint8" => ["C", 0, 255],
34
+ "Emf::Binary::Float32Le" => ["e", nil, nil]
35
+ }.freeze
36
+ private_constant :LEAVES
37
+
38
+ Leaf = Struct.new(:index)
39
+ Branch = Struct.new(:klass, :children)
40
+
41
+ # A verified plan for the filler's class, or nil.
42
+ def self.build(filler)
43
+ plan = new(filler)
44
+ plan if plan.verified?(filler)
45
+ rescue StandardError
46
+ nil
47
+ end
48
+
49
+ def initialize(filler)
50
+ template = filler.template
51
+ @leaves = []
52
+ @defaults = []
53
+ @tree = {}
54
+ @array = nil
55
+ @plain_leaves = true
56
+ template.field_names.each { |name| @tree[name] = node_of(template.public_send(name), name) }
57
+ @format = @leaves.map(&:first).join
58
+ @lows = @leaves.map { |leaf| leaf[1] }.freeze
59
+ @highs = @leaves.map { |leaf| leaf[2] }.freeze
60
+ @size = filler.size
61
+ @n_size = @tree.fetch(:n_size).index
62
+ @coord_bytes = 0
63
+ finish_points(filler)
64
+ generate_pack
65
+ end
66
+
67
+ # The record's bytes, or nil when any attribute needs BinData. n_size
68
+ # is the record's size unless `size` is false, which leaves it as
69
+ # given (or its default).
70
+ def pack(attrs, size: true)
71
+ pack_interpreted(attrs, size: size)
72
+ end
73
+
74
+ # The same result computed by walking the attributes; the generated
75
+ # `pack` (see PackPlanGenerate) falls back to it for anything but plain
76
+ # in-range attributes.
77
+ def pack_interpreted(attrs, size: true)
78
+ catch(:decline) do
79
+ values = @defaults.dup
80
+ coords = nil
81
+ attrs.each do |name, value|
82
+ node = @tree[name] or throw :decline
83
+ next if value.nil?
84
+
85
+ node.equal?(@array) ? coords = coords_of(value) : (store(values, node, value) or throw :decline)
86
+ end
87
+ finish(values, coords, size)
88
+ end
89
+ end
90
+
91
+ private
92
+
93
+ def node_of(field, name)
94
+ if field.is_a?(BinData::Array)
95
+ @array_name = name
96
+ return @array = Branch.new(field.class, nil)
97
+ end
98
+ return branch_of(field) if field.respond_to?(:field_names)
99
+
100
+ directive, low, high = LEAVES.fetch(field.class.name)
101
+ @plain_leaves &&= !field.has_parameter?(:value)
102
+ @leaves << [directive, low, high]
103
+ @defaults << field.value
104
+ Leaf.new(@leaves.size - 1)
105
+ end
106
+
107
+ def branch_of(struct)
108
+ children = struct.field_names.to_h { |name| [name, node_of(struct.public_send(name), name)] }
109
+ Branch.new(struct.class, children)
110
+ end
111
+
112
+ # The record's one array, which must come last, as `pack` appends it.
113
+ def finish_points(filler)
114
+ return unless @array
115
+
116
+ raise ArgumentError, "array is not the last field" unless @tree.keys.last == @array_name
117
+
118
+ @point_class, @coord_directive, @coord_low, @coord_high, @coord_bytes, count_name = filler.points_layout
119
+ @count_name = count_name
120
+ @count = @tree.fetch(count_name).index
121
+ @points_format = "#{@format}#{@coord_directive}*"
122
+ @plain_leaves &&= plain_point?
123
+ end
124
+
125
+ # A point is a struct of x and y, each a plain stored value, so a
126
+ # point's coordinates can be read from its field objects.
127
+ def plain_point?
128
+ point = @point_class.new
129
+ point.field_names == %i[x y] && %i[x y].none? { |name| point.public_send(name).has_parameter?(:value) }
130
+ end
131
+
132
+ # The wire read back from the bytes must be the wire BinData built,
133
+ # so the count must be the array's length (an absent array is empty).
134
+ def finish(values, coords, size)
135
+ throw :decline if @array && values[@count] != (coords ? coords.size / 2 : 0)
136
+
137
+ values[@n_size] = @size + (coords ? coords.size * @coord_bytes : 0) if size
138
+ values.concat(coords) if coords
139
+ values.pack(coords ? @points_format : @format)
140
+ end
141
+ end
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bindata"
4
+
5
+ module Emf
6
+ module Emr
7
+ module Binary
8
+ # The self-check of a PackPlan: its bytes against BinData's.
9
+ module PackPlanCheck
10
+ # True when the plan's bytes equal BinData's for the defaults, for every
11
+ # leaf set alone, and for every leaf set at once.
12
+ def verified?(filler)
13
+ klass = filler.wire_class
14
+ cases = [{}] + each_leaf_attrs + [all_leaf_attrs, exact_attrs, exact_attrs(structs: true)]
15
+ cases << { @array_name => [{ x: 3, y: -4 }, { x: 5, y: 6 }] } if @array
16
+ return false unless pack({})
17
+
18
+ # A plan may decline a case (nil) but never differ from BinData.
19
+ cases.all? { |attrs| (bytes = pack(attrs)).nil? || bytes == reference(klass, attrs) }
20
+ end
21
+
22
+ private
23
+
24
+ # BinData's own constructor: Record.new would consult this plan.
25
+ BINDATA_NEW = BinData::Base.method(:new).unbind
26
+ private_constant :BINDATA_NEW
27
+
28
+ def reference(klass, attrs)
29
+ wire = BINDATA_NEW.bind_call(klass, **attrs)
30
+ wire.n_size = wire.num_bytes
31
+ wire.to_binary_s
32
+ end
33
+
34
+ def each_leaf_attrs
35
+ @tree.filter_map do |name, node|
36
+ next if node.equal?(@array)
37
+
38
+ { name => sample_value(node, 1) }
39
+ end
40
+ end
41
+
42
+ # Every field but n_size, the shape the generated `pack` takes first;
43
+ # `structs` gives nested structs and points as instances.
44
+ def exact_attrs(structs: false)
45
+ attrs = @tree.reject { |name, _| name == :n_size || name.equal?(@array_name) }
46
+ .to_h { |name, node| [name, sample_value(node, 7)] }
47
+ attrs.each { |name, value| attrs[name] = @tree[name].klass.new(value) if structs && value.is_a?(Hash) }
48
+ return attrs unless @array
49
+
50
+ points = [{ x: 3, y: -4 }, { x: 5, y: 6 }]
51
+ points = points.map { |point| @point_class.new(point) } if structs
52
+ attrs.merge(@array_name => points, @count_name => 2)
53
+ end
54
+
55
+ def all_leaf_attrs
56
+ @tree.reject { |_, node| node.equal?(@array) }.to_h { |name, node| [name, sample_value(node, 7)] }
57
+ end
58
+
59
+ # Hash of distinct in-range values for a field.
60
+ def sample_value(node, seed)
61
+ return leaf_sample(node.index, seed) if node.is_a?(PackPlan::Leaf)
62
+
63
+ node.children.each_with_index.to_h { |(name, child), at| [name, sample_value(child, seed + at + 1)] }
64
+ end
65
+
66
+ def leaf_sample(index, seed)
67
+ _, low, high = @leaves[index]
68
+ return seed + 0.5 unless low # exact in float32
69
+
70
+ (seed * 3).clamp(low, high)
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,130 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Emf
4
+ module Emr
5
+ module Binary
6
+ # The common call shape of `pack`, compiled to one boolean chain: every
7
+ # field but n_size given, nested structs and the point list as plain
8
+ # Hashes and Arrays of Hashes of in-range Integers (or exact Floats). A
9
+ # Hash with exactly as many keys as the struct has fields, every field
10
+ # read non-nil, has exactly the struct's keys, so no per-key bookkeeping
11
+ # is needed; the first value that is not plain makes the chain false and
12
+ # `pack` continues with the general path, which stays the authority on
13
+ # declines and results.
14
+ module PackPlanExact
15
+ private
16
+
17
+ # The source of the `if` that returns the exact shape's bytes, or ""
18
+ # when the record has no n_size to leave out.
19
+ def gen_exact
20
+ return "" unless @tree.key?(:n_size)
21
+
22
+ @exact_depth = 0
23
+ given = @tree.except(:n_size)
24
+ checks = given.map { |name, node| exact_check(name, node, "attrs") }
25
+ checks.unshift("attrs.size == #{given.size}", "attrs[:n_size].nil?")
26
+ <<~RUBY.gsub(/^(?=.)/, " ")
27
+ if #{checks.join(" &&\n ")}
28
+ v#{@n_size} = #{exact_size}
29
+ vals = [#{(0...@leaves.size).map { |index| "v#{index}" }.join(', ')}]
30
+ #{exact_return}end
31
+ RUBY
32
+ end
33
+
34
+ def exact_size
35
+ bytes = @array ? " + pts.size * #{@coord_bytes * 2}" : ""
36
+ "size ? #{@size}#{bytes} : #{@defaults[@n_size].inspect}"
37
+ end
38
+
39
+ def exact_return
40
+ return " return vals.pack(#{@format.inspect})\n" unless @array
41
+
42
+ " return vals.pack(#{@points_format.inspect}) if points_appended?(vals, pts)\n"
43
+ end
44
+
45
+ def exact_check(name, node, container)
46
+ read = "#{container}[#{name.inspect}]"
47
+ return exact_array(read) if node.equal?(@array)
48
+ return exact_leaf(node.index, read) if node.is_a?(PackPlan::Leaf)
49
+
50
+ sub = "h#{@exact_depth += 1}"
51
+ hash = ["#{sub}.instance_of?(Hash)", "#{sub}.size == #{node.children.size}"] +
52
+ node.children.map { |child, n| exact_check(child, n, sub) }
53
+ return "((#{sub} = #{read}).instance_of?(Hash) &&\n #{hash.drop(1).join(" &&\n ")})" unless @plain_leaves
54
+
55
+ "((#{sub} = #{read}; #{hash.first}) &&\n #{hash.drop(1).join(" &&\n ")} ||\n #{exact_struct(sub, node)})"
56
+ end
57
+
58
+ # A nested struct given as an instance of its own class: its leaves
59
+ # are read from the field objects' stored values, in field order.
60
+ # An unmade field, or a value not stored as a plain Integer or
61
+ # Float, makes the chain false.
62
+ def exact_struct(sub, node)
63
+ @gen_classes << node.klass
64
+ fields = "f#{sub}"
65
+ checks = node.children.each_with_index.map do |(_, child), at|
66
+ if child.is_a?(PackPlan::Leaf)
67
+ exact_leaf(child.index, "#{fields}[#{at}]&.instance_variable_get(:@value)")
68
+ else
69
+ exact_nested_struct(child, "#{fields}[#{at}]")
70
+ end
71
+ end
72
+ ["#{sub}.instance_of?(@gen_classes[#{@gen_classes.size - 1}])",
73
+ "(#{fields} = #{sub}.instance_variable_get(:@field_objs))", *checks].join(" &&\n ")
74
+ end
75
+
76
+ def exact_nested_struct(node, read)
77
+ sub = "h#{@exact_depth += 1}"
78
+ "(#{sub} = #{read}) && #{exact_struct(sub, node)}"
79
+ end
80
+
81
+ def exact_array(read)
82
+ "(pts = #{read}).instance_of?(Array) &&\n v#{@count} == pts.size"
83
+ end
84
+
85
+ def exact_leaf(index, read)
86
+ var = "v#{index}"
87
+ low = @lows[index]
88
+ return "float32_exact?(#{var} = #{read})" unless low
89
+
90
+ "(#{var} = #{read}).instance_of?(Integer) &&\n #{var} >= #{low} && #{var} <= #{@highs[index]}"
91
+ end
92
+
93
+ # Appends the flat coordinates of `points`, which must each be a
94
+ # Hash of exactly x and y, or a plain point struct, in the point
95
+ # range; false for any other point, with `vals` then to be dropped.
96
+ def points_appended?(vals, points)
97
+ index = 0
98
+ count = points.size
99
+ while index < count
100
+ point = points[index]
101
+ appended = point.instance_of?(Hash) ? hash_point_appended?(vals, point) : struct_point_appended?(vals, point)
102
+ return false unless appended
103
+
104
+ index += 1
105
+ end
106
+ true
107
+ end
108
+
109
+ def hash_point_appended?(vals, point)
110
+ point.size == 2 && point_appended?(vals, point[:x], point[:y])
111
+ end
112
+
113
+ def struct_point_appended?(vals, point)
114
+ return false unless @plain_leaves && point.instance_of?(@point_class)
115
+
116
+ fields = point.instance_variable_get(:@field_objs) or return false
117
+ point_appended?(vals, fields[0]&.instance_variable_get(:@value), fields[1]&.instance_variable_get(:@value))
118
+ end
119
+
120
+ def point_appended?(vals, x, y)
121
+ return false unless x.instance_of?(Integer) && x >= @coord_low && x <= @coord_high &&
122
+ y.instance_of?(Integer) && y >= @coord_low && y <= @coord_high
123
+
124
+ vals << x << y
125
+ true
126
+ end
127
+ end
128
+ end
129
+ end
130
+ end