Class: Seafoam::BGV::BGVParser
- Inherits:
-
Object
- Object
- Seafoam::BGV::BGVParser
- Defined in:
- lib/seafoam/bgv/bgv_parser.rb
Overview
A parser for BGV files. It’s a push-pull streaming interface that you need to drive with what you want next from the file. It’s slightly complicated and some code is duplicated in order to support skipping over parts of the file that you don’t need.
Direct Known Subclasses
Instance Method Summary collapse
-
#graph_name(graph_header) ⇒ Object
Produce a flat graph name from a header.
-
#initialize(file) ⇒ BGVParser
constructor
A new instance of BGVParser.
- #read_document_props ⇒ Object
-
#read_file_header(version_check: true) ⇒ Object
Read the file header and return the version.
-
#read_graph ⇒ Object
Read a graph having either read or skipped its headers, producing a Graph object.
-
#read_graph_header ⇒ Object
Read a graph’s headers, having just read its ID.
-
#read_graph_preheader ⇒ Object
Move to the next graph in the file, and return its index and ID, or nil if there are no more graphs.
- #skip_document_props ⇒ Object
-
#skip_graph ⇒ Object
Skip over a graph, having read or skipped its headers.
-
#skip_graph_header ⇒ Object
Skip over a graph’s headers, having just read its ID.
Constructor Details
#initialize(file) ⇒ BGVParser
Returns a new instance of BGVParser.
11 12 13 14 15 16 17 18 19 20 |
# File 'lib/seafoam/bgv/bgv_parser.rb', line 11 def initialize(file) data = File.read(file, encoding: Encoding::ASCII_8BIT) if data[0..1].bytes == [0x1f, 0x8b] data = Zlib.gunzip(data) end @reader = Binary::IOBinaryReader.new(StringIO.new(data)) @group_stack = [] @pool = {} @index = 0 end |
Instance Method Details
#graph_name(graph_header) ⇒ Object
Produce a flat graph name from a header.
157 158 159 160 161 162 163 164 165 166 167 |
# File 'lib/seafoam/bgv/bgv_parser.rb', line 157 def graph_name(graph_header) groups_names = graph_header[:group].map { |g| g[:short_name] } count = 0 name = graph_header[:format].sub(/%s/) do arg = graph_header[:args][count] count += 1 arg end components = groups_names + [name] components.join('/') end |
#read_document_props ⇒ Object
36 37 38 39 40 41 42 43 44 45 |
# File 'lib/seafoam/bgv/bgv_parser.rb', line 36 def read_document_props if @major >= 7 token = @reader.peek_sint8 if token == BEGIN_DOCUMENT @reader.skip_int8 document_props = read_props end end document_props end |
#read_file_header(version_check: true) ⇒ Object
Read the file header and return the version.
23 24 25 26 27 28 29 30 31 32 33 34 |
# File 'lib/seafoam/bgv/bgv_parser.rb', line 23 def read_file_header(version_check: true) raise EncodingError, 'does not appear to be a BGV file - missing header' unless @reader.read_bytes(4) == MAGIC @major = @reader.read_sint8 @minor = @reader.read_sint8 version = [@major, @minor] if version_check && !SUPPORTED_VERSIONS.include?(version) raise NotImplementedError, "unsupported BGV version #{@major}.#{@minor}" end version end |
#read_graph ⇒ Object
Read a graph having either read or skipped its headers, producing a Graph object.
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
# File 'lib/seafoam/bgv/bgv_parser.rb', line 98 def read_graph # Already read BEGIN_GRAPH, id, format, args, and props graph = Graph.new(@graph_props) edge_delay = [] @reader.read_sint32.times do id = @reader.read_sint32 node_class = read_pool_object has_predecessor = read_bool props = read_props props[:id] = id props[:node_class] = node_class props[:has_predecessor] = has_predecessor node = graph.create_node(id, props) edge_delay.push(*read_edges(node, node_class, true)) edge_delay.push(*read_edges(node, node_class, false)) end edge_delay.each do |edge| node = edge[:node] props = edge[:edge] inputs = edge[:inputs] others = edge[:ids].reject(&:nil?).map { |id| graph.nodes[id] || raise(EncodingError, "BGV edge with unknown node #{id}") } others.each_with_index do |other, index| # We need to give each edge their own property as they're annotated separately. props = props.dup props[:index] = index if inputs graph.create_edge other, node, props else graph.create_edge node, other, props end end end # Read block information. @reader.read_sint32.times do block_id = @reader.read_sint32 block_nodes = @reader.read_sint32.times.map { @reader.read_sint32 } # Followers aren't used but could be. @reader.read_sint32.times.map { @reader.read_sint32 } graph.create_block block_id, block_nodes end graph end |
#read_graph_header ⇒ Object
Read a graph’s headers, having just read its ID. This gives you the graph’s properties.
83 84 85 86 87 88 89 90 91 92 93 94 95 |
# File 'lib/seafoam/bgv/bgv_parser.rb', line 83 def read_graph_header # Already read BEGIN_GRAPH and id format = read_string args = read_args props = read_props @graph_props = props { group: @group_stack.dup, format: format, args: args, props: props } end |
#read_graph_preheader ⇒ Object
Move to the next graph in the file, and return its index and ID, or nil if there are no more graphs.
59 60 61 62 63 64 65 66 67 68 69 70 71 |
# File 'lib/seafoam/bgv/bgv_parser.rb', line 59 def read_graph_preheader return nil unless read_groups # Already read BEGIN_GRAPH index = @index id = @reader.read_sint32 if id @index += 1 [index, id] else [nil, nil] end end |
#skip_document_props ⇒ Object
47 48 49 50 51 52 53 54 55 |
# File 'lib/seafoam/bgv/bgv_parser.rb', line 47 def skip_document_props if @major >= 7 token = @reader.peek_sint8 if token == BEGIN_DOCUMENT @reader.skip_int8 skip_props end end end |
#skip_graph ⇒ Object
Skip over a graph, having read or skipped its headers.
143 144 145 146 147 148 149 150 151 152 153 154 |
# File 'lib/seafoam/bgv/bgv_parser.rb', line 143 def skip_graph # Already read BEGIN_GRAPH, id, format, args, and props. @reader.read_sint32.times do @reader.skip_int32 node_class = read_pool_object skip_bool skip_props skip_edges node_class, true skip_edges node_class, false end skip_blocks end |
#skip_graph_header ⇒ Object
Skip over a graph’s headers, having just read its ID.
74 75 76 77 78 79 |
# File 'lib/seafoam/bgv/bgv_parser.rb', line 74 def skip_graph_header # Already read BEGIN_GRAPH and id skip_string skip_args @graph_props = read_props end |