module BinData::Skip::SkipUntilValidPlugin
def fast_search_for(obj)
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
def fast_search_for_obj(obj)
If a search object has an +asserted_value+ field then we
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
def next_search_index(io, fs)
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
def read_and_return_value(io)
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
def seek_to_pos(pos, io)
def seek_to_pos(pos, io) io.rollback io.skip(pos) end
def skip_length
def skip_length @skip_length ||= 0 end