class Origami::Filter::RunLength

Class representing a Filter used to encode and decode data using RLE compression algorithm.

Public Instance Methods

decode(stream) click to toggle source

Decodes data using RLE decompression method.

stream

The data to decode.

# File lib/origami/filters/runlength.rb, line 72
def decode(stream)
    result = "".b

    i = 0
    until i >= stream.length or stream[i].ord == EOD do

        # At least two bytes are required.
        if i > stream.length - 2
            raise InvalidRunLengthDataError.new("Truncated run-length data", input_data: stream, decoded_data: result)
        end

        length = stream[i].ord
        if length < EOD
            result << stream[i + 1, length + 1]
            i = i + length + 2
        else
            result << stream[i + 1] * (257 - length)
            i = i + 2
        end
    end

    # Check if offset is beyond the end of data.
    if i > stream.length
        raise InvalidRunLengthDataError.new("Truncated run-length data", input_data: stream, decoded_data: result)
    end

    result
end
encode(stream) click to toggle source

Encodes data using RLE compression method.

stream

The data to encode.

# File lib/origami/filters/runlength.rb, line 40
def encode(stream)
    result = "".b
    i = 0

    while i < stream.size

        # How many identical bytes coming?
        length = compute_run_length(stream, i)

        # If more than 1, then compress them.
        if length > 1
            result << (257 - length).chr << stream[i]
            i += length

        # Otherwise how many different bytes to copy?
        else
            next_pos = find_next_run(stream, i)
            length = next_pos - i

            result << (length - 1).chr << stream[i, length]

            i += length
        end
    end

    result << EOD.chr
end

Private Instance Methods

compute_run_length(input, pos) click to toggle source

Computes the length of the run at the given position.

# File lib/origami/filters/runlength.rb, line 116
def compute_run_length(input, pos)
    run_length = 1
    while pos + 1 < input.size and run_length < EOD and input[pos] == input[pos + 1]
        run_length += 1
        pos += 1
    end

    run_length
end
find_next_run(input, pos) click to toggle source

Find the position of the next byte at which a new run starts.

# File lib/origami/filters/runlength.rb, line 106
def find_next_run(input, pos)
    start = pos
    pos += 1 while pos + 1 < input.size and (pos - start + 1) < EOD and input[pos] != input[pos + 1]

    pos + 1
end