class LZString::Base

Base compression class.

Public Class Methods

compress(uncompressed, bits_per_char, get_char_from_int) click to toggle source

@param uncompressed [String] @param bits_per_char [Integer] @param get_char_from_int [Integer]

# File lib/lz_string/base.rb, line 7
def self.compress(uncompressed, bits_per_char, get_char_from_int)
  return "" if uncompressed.nil?

  i, value, ii = nil
  context_dictionary = {}
  context_dictionary_to_create = {}
  context_c = ""
  context_wc = ""
  context_w = ""
  # Compensate for the first entry which should not count
  context_enlarge_in = 2
  context_dict_size = 3
  context_num_bits = 2
  context_data = []
  context_data_val = 0
  context_data_position = 0

  for ii in 0...uncompressed.length do
    context_c = uncompressed[ii]

    if (!context_dictionary.has_key?(context_c))
      context_dictionary[context_c] = context_dict_size
      context_dictionary_to_create[context_c] = true
      context_dict_size += 1
    end

    context_wc = context_w + context_c
    if (context_dictionary.has_key?(context_wc))
      context_w = context_wc
    else
      if (context_dictionary_to_create.has_key?(context_w))
        if (context_w[0].ord < 256)
          for i in 0...context_num_bits do
            context_data_val = (context_data_val << 1)
            if (context_data_position == bits_per_char - 1)
              context_data_position = 0
              context_data.push(get_char_from_int[context_data_val])
              context_data_val = 0
            else
              context_data_position += 1
            end
          end

          value = context_w[0].ord
          for i in 0...8 do
            context_data_val = (context_data_val << 1) | (value & 1)
            if (context_data_position == bits_per_char - 1)
              context_data_position = 0
              context_data.push(get_char_from_int[context_data_val])
              context_data_val = 0
            else
              context_data_position += 1
            end
            value = value >> 1
          end
        else
          value = 1
          for i in 0...context_num_bits do
            context_data_val = (context_data_val << 1) | value
            if (context_data_position == bits_per_char-1)
              context_data_position = 0
              context_data.push(get_char_from_int[context_data_val])
              context_data_val = 0
            else
              context_data_position += 1
            end
            value = 0
          end
          value = context_w[0].ord
          for i in 0...16 do
            context_data_val = (context_data_val << 1) | (value & 1)
            if (context_data_position == bits_per_char - 1)
              context_data_position = 0
              context_data.push(get_char_from_int[context_data_val])
              context_data_val = 0
            else
              context_data_position += 1
            end
            value = value >> 1
          end
        end
        context_enlarge_in -= 1
        if (context_enlarge_in == 0)
          context_enlarge_in = 2**context_num_bits
          context_num_bits += 1
        end
        context_dictionary_to_create.delete(context_w)
      else
        value = context_dictionary[context_w]
        for i in 0...context_num_bits do
          context_data_val = (context_data_val << 1) | (value & 1)
          if (context_data_position == bits_per_char - 1)
            context_data_position = 0
            context_data.push(get_char_from_int[context_data_val])
            context_data_val = 0
          else
            context_data_position += 1
          end
          value = value >> 1
        end
      end

      context_enlarge_in -= 1

      if (context_enlarge_in == 0)
        context_enlarge_in = 2**context_num_bits
        context_num_bits += 1
      end

      # Add wc to the dictionary.
      context_dictionary[context_wc] = context_dict_size
      context_dict_size += 1
      context_w = context_c.to_s
    end
  end

  # Output the code for w.
  if (context_w != "")
    if (context_dictionary_to_create.has_key?(context_w))
      if (context_w[0].ord < 256)
        for i in 0...context_num_bits do
          context_data_val = (context_data_val << 1)
          if (context_data_position == bits_per_char-1)
            context_data_position = 0
            context_data.push(get_char_from_int[context_data_val])
            context_data_val = 0
          else
            context_data_position += 1
          end
        end
        value = context_w[0].ord
        for i in 0...8 do
          context_data_val = (context_data_val << 1) | (value & 1)
          if (context_data_position == bits_per_char-1)
            context_data_position = 0
            context_data.push(get_char_from_int[context_data_val])
            context_data_val = 0
          else
            context_data_position += 1
          end
          value = value >> 1
        end
      else
        value = 1
        for i in 0...context_num_bits do
          context_data_val = (context_data_val << 1) | value
          if (context_data_position == bits_per_char-1)
            context_data_position = 0
            context_data.push(get_char_from_int[context_data_val])
            context_data_val = 0
          else
            context_data_position += 1
          end
          value = 0
        end
        value = context_w[0].ord
        for i in 0...16 do
          context_data_val = (context_data_val << 1) | (value & 1)
          if (context_data_position == bits_per_char-1)
            context_data_position = 0
            context_data.push(get_char_from_int[context_data_val])
            context_data_val = 0
          else
            context_data_position += 1
          end
          value = value >> 1
        end
      end
      context_enlarge_in -= 1
      if (context_enlarge_in == 0)
        context_enlarge_in = 2**context_num_bits
        context_num_bits += 1
      end
      context_dictionary_to_create.delete(context_w)
    else
      value = context_dictionary[context_w]
      for i in 0...context_num_bits
        context_data_val = (context_data_val << 1) | (value & 1)
        if (context_data_position == bits_per_char-1)
          context_data_position = 0
          context_data.push(get_char_from_int[context_data_val])
          context_data_val = 0
        else
          context_data_position += 1
        end
        value = value >> 1
      end
    end

    context_enlarge_in -= 1
    if (context_enlarge_in == 0)
      context_enlarge_in = 2**context_num_bits
      context_num_bits += 1
    end
  end

  # Mark the end of the stream
  value = 2
  for i in 0...context_num_bits do
    context_data_val = (context_data_val << 1) | (value & 1)
    if (context_data_position == bits_per_char - 1)
      context_data_position = 0
      context_data.push(get_char_from_int[context_data_val])
      context_data_val = 0
    else
      context_data_position += 1
    end
    value = value >> 1
  end

  # Flush the last char
  while (true)
    context_data_val = (context_data_val << 1)
    if (context_data_position == bits_per_char-1)
      context_data.push(get_char_from_int[context_data_val])
      break
    else
      context_data_position += 1
    end
  end

  return context_data.join("")
end
decompress(length, reset_value, get_next_value, encoding = "ASCII-8BIT") click to toggle source

@param length [Integer] @param reset_value [Integer] @param get_next_value [Proc]

# File lib/lz_string/base.rb, line 234
def self.decompress(length, reset_value, get_next_value, encoding = "ASCII-8BIT")
  dictionary = [0, 1, 2]
  enlarge_in = 4
  dict_size = 4
  num_bits = 3
  entry = ""
  result = []
  data = {
    val: get_next_value[(0)],
    position: reset_value,
    index: 1
  }
  bits = 0
  maxpower = 2**2
  power = 1
  i, w, resb, c = nil

  while (power != maxpower)
    resb = data[:val] & data[:position]
    data[:position] >>= 1
    if (data[:position] == 0)
      data[:position] = reset_value
      data[:val] = get_next_value[data[:index]]
      data[:index] += 1
    end
    bits |= (resb > 0 ? 1 : 0) * power
    power <<= 1
  end

  case(n = bits)
  when 0
    bits = 0
    maxpower = 2**8
    power = 1
    while power != maxpower
      resb = data[:val] & data[:position]
      data[:position] >>= 1
      if (data[:position] == 0)
        data[:position] = reset_value
        data[:val] = get_next_value[data[:index]]
        data[:index] += 1
      end
      bits |= (resb > 0 ? 1 : 0) * power
      power <<= 1
    end
    c = bits.chr(encoding)
  when 1
    bits = 0
    maxpower = 2*16
    power = 1
    while (power != maxpower)
      resb = data[:val] & data[:position]
      data[:position] >>= 1
      if (data[:position] == 0)
          data[:position] = reset_value
          data[:val] = get_next_value[data[:index]]
          data[:index] += 1
      end
      bits |= (resb > 0 ? 1 : 0) * power
      power <<= 1
    end
    c = bits.chr(encoding)
  when 2
    ""
  end

  dictionary[3] = c
  w = c
  result << c

  while(true)
    return "" if (data[:index] > length)

    bits = 0
    maxpower = 2**num_bits
    power = 1
    while (power != maxpower)
      resb = data[:val] & data[:position]
      data[:position] >>= 1
      if (data[:position] == 0)
        data[:position] = reset_value
        data[:val] = get_next_value[data[:index]]
        data[:index] += 1
      end
      bits |= (resb > 0 ? 1 : 0) * power
      power <<= 1
    end

    case(c = bits)
    when 0
      bits = 0
      maxpower = 2**8
      power = 1
      while (power != maxpower)
        resb = data[:val] & data[:position]
        data[:position] >>= 1
        if (data[:position] == 0)
          data[:position] = reset_value
          data[:val] = get_next_value[data[:index]]
          data[:index] += 1
        end
        bits |= (resb > 0 ? 1 : 0) * power
        power <<= 1
      end

      dictionary[dict_size] = bits.chr(encoding)
      dict_size += 1
      c = dict_size - 1
      enlarge_in -= 1
    when 1
      bits = 0
      maxpower = 2**16
      power = 1
      while (power != maxpower)
        resb = data[:val] & data[:position]
        data[:position] >>= 1
        if (data[:position] == 0)
          data[:position] = reset_value
          data[:val] = get_next_value[data[:index]]
          data[:index] += 1
        end
        bits |= (resb > 0 ? 1 : 0) * power
        power <<= 1
      end
      dictionary[dict_size] = bits.chr(encoding)
      dict_size += 1
      c = dict_size - 1
      enlarge_in -= 1
    when 2
      return result.join("")
    end

    if (enlarge_in == 0)
      enlarge_in = 2**num_bits
      num_bits += 1
    end

    if (dictionary[c])
      entry = dictionary[c]
    else
      if (c === dict_size)
          entry = w + w[0]
      else
        return nil
      end
    end

    result << entry

    # Add w+entry[0] to the dictionary.
    dictionary[dict_size] = w + entry[0]
    dict_size += 1
    enlarge_in -= 1

    w = entry

    if (enlarge_in == 0)
      enlarge_in = 2**num_bits
      num_bits += 1
    end
  end
end