Module: BinData::Skip::SkipUntilValidPlugin

Defined in:
lib/bindata/skip.rb

Overview

Logic for the :until_valid parameter

Defined Under Namespace

Classes: FastSearch, ReadaheadIO

Constant Summary collapse

SEARCH_SIZE =
100_000

Instance Method Summary collapse

Instance Method Details

#fast_search_for(obj) ⇒ Object



145
146
147
148
149
150
151
# File 'lib/bindata/skip.rb', line 145

def fast_search_for(obj)
  if obj.respond_to?(:asserted_binary_s)
    FastSearch.new(obj.asserted_binary_s, obj.rel_offset)
  else
    nil
  end
end

#fast_search_for_obj(obj) ⇒ Object

If a search object has an asserted_value field then we perform a faster search for a valid object.



155
156
157
158
159
160
161
162
163
164
165
166
# File 'lib/bindata/skip.rb', line 155

def fast_search_for_obj(obj)
  if BinData::Struct === obj
    obj.each_pair(true) do |_, field|
      fs = fast_search_for(field)
      return fs if fs
    end
  elsif BinData::BasePrimitive === obj
    return fast_search_for(obj)
  end

  nil
end

#next_search_index(io, fs) ⇒ Object



170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
# File 'lib/bindata/skip.rb', line 170

def next_search_index(io, fs)
  buffer = binary_string("")

  # start searching at fast_search offset
  pos = fs.offset
  io.skip(fs.offset)

  loop do
    data = io.read(SEARCH_SIZE)
    raise EOFError, "no match" if data.nil?

    buffer << data
    index = buffer.index(fs.pattern)
    if index
      return pos + index - fs.offset
    end

    # advance buffer
    searched = buffer.slice!(0..-fs.pattern.size)
    pos += searched.size
  end
end

#read_and_return_value(io) ⇒ Object



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
# File 'lib/bindata/skip.rb', line 111

def read_and_return_value(io)
  prototype = get_parameter(:until_valid)
  validator = prototype.instantiate(nil, self)
  fs = fast_search_for_obj(validator)

  io.transform(ReadaheadIO.new) do |transformed_io, raw_io|
    pos = 0
    loop do
      seek_to_pos(pos, raw_io)
      validator.clear
      validator.do_read(transformed_io)
      break
    rescue ValidityError
      pos += 1

      if fs
        seek_to_pos(pos, raw_io)
        pos += next_search_index(raw_io, fs)
      end
    end

    seek_to_pos(pos, raw_io)
    @skip_length = pos
  end
end

#seek_to_pos(pos, io) ⇒ Object



137
138
139
140
# File 'lib/bindata/skip.rb', line 137

def seek_to_pos(pos, io)
  io.rollback
  io.skip(pos)
end

#skip_lengthObject



107
108
109
# File 'lib/bindata/skip.rb', line 107

def skip_length
  @skip_length ||= 0
end