Class: Cabriolet::SZDD::Compressor

Inherits:
Object
  • Object
show all
Defined in:
lib/cabriolet/szdd/compressor.rb

Overview

Compressor creates SZDD compressed files

SZDD files wrap LZSS-compressed data with a header containing metadata about the original file. The compressor supports both NORMAL (used by MS-DOS EXPAND.EXE) and QBASIC formats.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(io_system = nil) ⇒ Compressor

Initialize a new SZDD compressor

Parameters:

  • io_system (System::IOSystem, nil) (defaults to: nil)

    Custom I/O system or nil for default



17
18
19
# File 'lib/cabriolet/szdd/compressor.rb', line 17

def initialize(io_system = nil)
  @io_system = io_system || System::IOSystem.new
end

Instance Attribute Details

#io_systemObject (readonly)

Returns the value of attribute io_system.



11
12
13
# File 'lib/cabriolet/szdd/compressor.rb', line 11

def io_system
  @io_system
end

Instance Method Details

#compress(input_file, output_file, **options) ⇒ Integer

Compress a file to SZDD format

Parameters:

  • input_file (String)

    Path to input file

  • output_file (String)

    Path to output SZDD file

  • options (Hash)

    Compression options

Options Hash (**options):

  • :missing_char (String)

    Last character of original filename for reconstruction

  • :format (Symbol)

    Format to use (:normal or :qbasic, default: :normal)

Returns:

  • (Integer)

    Bytes written to output file

Raises:

  • (Errors::CompressionError)

    if compression fails



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
69
70
71
72
73
74
75
76
77
# File 'lib/cabriolet/szdd/compressor.rb', line 32

def compress(input_file, output_file, **options)
  format = options.fetch(:format, :normal)
  missing_char = options[:missing_char]

  validate_format(format)
  validate_missing_char(missing_char) if missing_char

  input_handle = @io_system.open(input_file, Constants::MODE_READ)
  output_handle = @io_system.open(output_file, Constants::MODE_WRITE)

  begin
    # Get input size
    input_size = @io_system.seek(input_handle, 0, Constants::SEEK_END)
    @io_system.seek(input_handle, 0, Constants::SEEK_START)

    # Write header
    header_bytes = write_header(
      output_handle,
      format,
      input_size,
      missing_char,
    )

    # Compress data using LZSS
    lzss_mode = if format == :normal
                  Compressors::LZSS::MODE_EXPAND
                else
                  Compressors::LZSS::MODE_QBASIC
                end

    compressor = Compressors::LZSS.new(
      @io_system,
      input_handle,
      output_handle,
      2048,
      lzss_mode,
    )

    compressed_bytes = compressor.compress

    header_bytes + compressed_bytes
  ensure
    @io_system.close(input_handle) if input_handle
    @io_system.close(output_handle) if output_handle
  end
end

#compress_data(data, output_file, **options) ⇒ Integer

Compress data from memory to SZDD format

Parameters:

  • data (String)

    Input data to compress

  • output_file (String)

    Path to output SZDD file

  • options (Hash)

    Compression options

Options Hash (**options):

  • :missing_char (String)

    Last character of original filename

  • :format (Symbol)

    Format to use (:normal or :qbasic, default: :normal)

Returns:

  • (Integer)

    Bytes written to output file

Raises:

  • (Errors::CompressionError)

    if compression fails



90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/cabriolet/szdd/compressor.rb', line 90

def compress_data(data, output_file, **options)
  format = options.fetch(:format, :normal)
  missing_char = options[:missing_char]

  validate_format(format)
  validate_missing_char(missing_char) if missing_char

  input_handle = System::MemoryHandle.new(data)
  output_handle = @io_system.open(output_file, Constants::MODE_WRITE)

  begin
    # Write header
    header_bytes = write_header(
      output_handle,
      format,
      data.bytesize,
      missing_char,
    )

    # Compress data using LZSS
    lzss_mode = if format == :normal
                  Compressors::LZSS::MODE_EXPAND
                else
                  Compressors::LZSS::MODE_QBASIC
                end

    compressor = Compressors::LZSS.new(
      @io_system,
      input_handle,
      output_handle,
      2048,
      lzss_mode,
    )

    compressed_bytes = compressor.compress

    header_bytes + compressed_bytes
  ensure
    @io_system.close(output_handle) if output_handle
  end
end