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.
13 14 15 16 17 18 19 20 21 22 |
# File 'lib/seafoam/bgv/bgv_parser.rb', line 13 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.
161 162 163 164 165 166 167 168 169 170 |
# File 'lib/seafoam/bgv/bgv_parser.rb', line 161 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 groups_names + [name] end |
#read_document_props ⇒ Object
38 39 40 41 42 43 44 45 46 47 |
# File 'lib/seafoam/bgv/bgv_parser.rb', line 38 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.
25 26 27 28 29 30 31 32 33 34 35 36 |
# File 'lib/seafoam/bgv/bgv_parser.rb', line 25 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.
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 141 142 143 144 |
# File 'lib/seafoam/bgv/bgv_parser.rb', line 100 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 do |id| graph.nodes[id] || raise(EncodingError, "BGV edge with unknown node #{id}") end 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.
85 86 87 88 89 90 91 92 93 94 95 96 97 |
# File 'lib/seafoam/bgv/bgv_parser.rb', line 85 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.
61 62 63 64 65 66 67 68 69 70 71 72 73 |
# File 'lib/seafoam/bgv/bgv_parser.rb', line 61 def read_graph_preheader return 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
49 50 51 52 53 54 55 56 57 |
# File 'lib/seafoam/bgv/bgv_parser.rb', line 49 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.
147 148 149 150 151 152 153 154 155 156 157 158 |
# File 'lib/seafoam/bgv/bgv_parser.rb', line 147 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.
76 77 78 79 80 81 |
# File 'lib/seafoam/bgv/bgv_parser.rb', line 76 def skip_graph_header # Already read BEGIN_GRAPH and id skip_string skip_args @graph_props = read_props end |