Class: WR::LZSS

Inherits:
Object
  • Object
show all
Defined in:
lib/wrb/lzss.rb

Constant Summary collapse

PatMin =
3
PatMax =

16 pattern (3 to 18)

18

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(str) ⇒ LZSS

Returns a new instance of LZSS.



13
14
15
# File 'lib/wrb/lzss.rb', line 13

def initialize(str)
  @src = str.b
end

Class Method Details

.compress(str) ⇒ Object



10
# File 'lib/wrb/lzss.rb', line 10

def self.compress(str) self.new(str).compress; end

.expand(str) ⇒ Object



11
# File 'lib/wrb/lzss.rb', line 11

def self.expand(str) self.new(str).expand; end

Instance Method Details

#compressObject



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/wrb/lzss.rb', line 17

def compress()
  rp = 0
  ht = {}
  dst = "".b
  def dst.concat_bits(bint, blen)
    raise ArgumentError, "Argument is too big." if bint > 0xffff || blen > 16
    @bit_offset ||= 0
    len = @bit_offset + blen
    ival = bint << (32 - len) 
    n, new_offset = len.divmod(8)
    if @bit_offset==0
      self.concat([ival].pack('N')[0, new_offset==0 ? n : n + 1])
    else
      s = [self[-1].ord << 24 | ival].pack('N')
      self[-1] = s[0]
      self.concat(s[1, new_offset==0 ? n - 1 : n]) if len > 8
    end
    @bit_offset = new_offset
    self
  end
  
  while rp < @src.bytesize
    found = len = nil
    max = @src.size - rp > PatMax ? PatMax : @src.size - rp
    max.downto(PatMin) {|i|  # search pattern.

      s = @src[rp, i]
      if (found = ht[s])
        if rp - found > 4095 # length of offset is 12 bits.

          found = nil        # only replace address of pattern.

        elsif found + i < rp 
          len = i
          break
        else
          found = nil
          break
        end
      end
      ht[s] = rp
    }
    if found
      offset = rp - found
      dst.concat_bits(1, 1)
      dst.concat_bits((offset << 4) + len - 3, 16) # length of pattern is 4bits(3 to 18).

      rp += len
    else
      dst.concat_bits(0, 1)
      dst.concat_bits(@src[rp, 1].ord, 8)
      rp += 1
    end
  end
  dst
end

#expandObject



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/wrb/lzss.rb', line 70

def expand()
  dst = "".b
  bp = 0
  while true
    q, r = bp.divmod(8)
    s = @src[q]        # get 1 byte

    break unless s
    data = s.ord       # convert to 8 bits integer value

    break unless @src[q+1]
    data = (data << 8) + @src[q + 1].ord # join more 1 byte

    if data[15-r] == 0                   # read flag bit

      bp += 9
      dst.concat ((data >> 8 - r - 1) & 0xff).chr # return 1 byte to char

    else
      data = (data << 8) + @src[q + 2].ord # join more 1 byte

      x = (data >> (8 - r - 1)) & 0xffff   # get 16 bits which containes length and offset.

      dic_len = (x & 0xf) + PatMin
      dic_off = x >> 4                     # length of pattern is 4bits(3 to 18).

      bp += 17
      dst.concat dst[dst.size - dic_off, dic_len] # get from dictionary

    end
  end
  dst
end