Class: Omnizip::Formats::Rar::Compression::BitStream

Inherits:
Object
  • Object
show all
Defined in:
lib/omnizip/formats/rar/compression/bit_stream.rb

Overview

Bit-level I/O stream for RAR compression algorithms

Provides methods to read and write individual bits from byte streams. This is a shared utility used by PPMd, LZ77+Huffman, and other RAR compression algorithms that need bit-level access.

Responsibilities:

  • ONE responsibility: Bit-level I/O operations
  • Read bits from byte stream
  • Write bits to byte stream
  • Manage bit buffer and byte alignment

Instance Method Summary collapse

Constructor Details

#initialize(io, mode = :read) ⇒ BitStream

Initialize a new bit stream

Parameters:

  • io (IO)

    The underlying byte stream

  • mode (Symbol) (defaults to: :read)

    :read or :write



43
44
45
46
47
48
# File 'lib/omnizip/formats/rar/compression/bit_stream.rb', line 43

def initialize(io, mode = :read)
  @io = io
  @mode = mode
  @buffer = 0
  @bits_in_buffer = 0
end

Instance Method Details

#align_to_bytevoid

This method returns an undefined value.

Align to byte boundary (read mode)



126
127
128
129
130
131
# File 'lib/omnizip/formats/rar/compression/bit_stream.rb', line 126

def align_to_byte
  return unless @mode == :read

  @bits_in_buffer = 0
  @buffer = 0
end

#eof?Boolean

Check if at end of stream

Returns:

  • (Boolean)

    True if no more data available



151
152
153
# File 'lib/omnizip/formats/rar/compression/bit_stream.rb', line 151

def eof?
  @mode == :read && @bits_in_buffer.zero? && @io.eof?
end

#flushvoid

This method returns an undefined value.

Flush any remaining bits (write mode)



136
137
138
139
140
141
142
143
144
145
146
# File 'lib/omnizip/formats/rar/compression/bit_stream.rb', line 136

def flush
  return unless @mode == :write
  return if @bits_in_buffer.zero?

  # Pad with zeros to complete byte
  padding = 8 - @bits_in_buffer
  @buffer <<= padding
  @io.write([@buffer].pack("C"))
  @buffer = 0
  @bits_in_buffer = 0
end

#read_bitInteger

Read a single bit

Returns:

  • (Integer)

    0 or 1



74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/omnizip/formats/rar/compression/bit_stream.rb', line 74

def read_bit
  unless @mode == :read
    raise ArgumentError,
          "Can only read in read mode"
  end

  if @bits_in_buffer.zero?
    fill_buffer
  end

  @bits_in_buffer -= 1
  (@buffer >> @bits_in_buffer) & 1
end

#read_bits(count) ⇒ Integer

Read specified number of bits

Parameters:

  • count (Integer)

    Number of bits to read (1-32)

Returns:

  • (Integer)

    The bits read as an integer

Raises:

  • (ArgumentError)


54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/omnizip/formats/rar/compression/bit_stream.rb', line 54

def read_bits(count)
  unless @mode == :read
    raise ArgumentError,
          "Can only read in read mode"
  end
  raise ArgumentError, "Count must be 1-32" unless count.between?(1,
                                                                  32)

  result = 0

  count.times do
    result = (result << 1) | read_bit
  end

  result
end

#write_bit(bit) ⇒ void

This method returns an undefined value.

Write a single bit

Parameters:

  • bit (Integer)

    0 or 1



111
112
113
114
115
116
117
118
119
120
121
# File 'lib/omnizip/formats/rar/compression/bit_stream.rb', line 111

def write_bit(bit)
  unless @mode == :write
    raise ArgumentError,
          "Can only write in write mode"
  end

  @buffer = (@buffer << 1) | (bit & 1)
  @bits_in_buffer += 1

  flush_buffer if @bits_in_buffer == 8
end

#write_bits(value, count) ⇒ void

This method returns an undefined value.

Write specified number of bits

Parameters:

  • value (Integer)

    The value to write

  • count (Integer)

    Number of bits to write (1-32)

Raises:

  • (ArgumentError)


93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/omnizip/formats/rar/compression/bit_stream.rb', line 93

def write_bits(value, count)
  unless @mode == :write
    raise ArgumentError,
          "Can only write in write mode"
  end
  raise ArgumentError, "Count must be 1-32" unless count.between?(1,
                                                                  32)

  count.times do |i|
    bit = (value >> (count - 1 - i)) & 1
    write_bit(bit)
  end
end