ruby-lzws 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,192 @@
1
+ # Ruby bindings for lzws library.
2
+ # Copyright (c) 2019 AUTHORS, MIT License.
3
+
4
+ require_relative "../validation"
5
+
6
+ module LZWS
7
+ module Stream
8
+ module ReaderHelpers
9
+ def getbyte
10
+ read 1
11
+ end
12
+
13
+ def each_byte(&block)
14
+ each_string method(:getbyte), &block
15
+ end
16
+
17
+ def readbyte
18
+ readstring method(:getbyte)
19
+ end
20
+
21
+ def ungetbyte(byte)
22
+ Validation.validate_string byte
23
+
24
+ @buffer.prepend byte
25
+
26
+ nil
27
+ end
28
+
29
+ # -- char --
30
+
31
+ def getc
32
+ if @external_encoding.nil?
33
+ byte = getbyte
34
+ return nil if byte.nil?
35
+
36
+ return transcode_to_internal byte
37
+ end
38
+
39
+ char = ::String.new :encoding => ::Encoding::BINARY
40
+
41
+ # Read one byte until valid string will appear.
42
+ loop do
43
+ byte = getbyte
44
+ return nil if byte.nil?
45
+
46
+ char << byte
47
+
48
+ char.force_encoding @external_encoding
49
+ return transcode_to_internal char if char.valid_encoding?
50
+
51
+ char.force_encoding ::Encoding::BINARY
52
+ end
53
+ end
54
+
55
+ def readchar
56
+ readstring method(:getc)
57
+ end
58
+
59
+ def each_char(&block)
60
+ each_string method(:getc), &block
61
+ end
62
+
63
+ def ungetc(char)
64
+ ungetstring char
65
+ end
66
+
67
+ # -- lines --
68
+
69
+ def gets(separator = $OUTPUT_RECORD_SEPARATOR, limit = nil)
70
+ # Limit can be a first argument.
71
+ if separator.is_a? ::Numeric
72
+ limit = separator
73
+ separator = $OUTPUT_RECORD_SEPARATOR
74
+ end
75
+
76
+ line_ending =
77
+ if separator.nil?
78
+ nil
79
+ else
80
+ Validation.validate_string separator
81
+ ::String.new separator, :encoding => target_encoding
82
+ end
83
+
84
+ Validation.validate_positive_integer limit unless limit.nil?
85
+
86
+ line = ::String.new :encoding => target_encoding
87
+
88
+ loop do
89
+ char = getc
90
+
91
+ if char.nil?
92
+ return nil if line.empty?
93
+
94
+ break
95
+ end
96
+
97
+ line << char
98
+
99
+ break if
100
+ (!line_ending.nil? && line.end_with?(line_ending)) ||
101
+ (!limit.nil? && line.length >= limit)
102
+ end
103
+
104
+ @lineno += 1
105
+
106
+ line
107
+ end
108
+
109
+ def readline
110
+ readstring method(:gets)
111
+ end
112
+
113
+ def readlines
114
+ lines = []
115
+ each_line { |line| lines << line }
116
+
117
+ lines
118
+ end
119
+
120
+ def each_line(&block)
121
+ each_string method(:gets), &block
122
+ end
123
+
124
+ alias each each_line
125
+
126
+ def ungetline(line)
127
+ ungetstring line
128
+
129
+ @lineno -= 1
130
+
131
+ nil
132
+ end
133
+
134
+ # -- common --
135
+
136
+ protected def readstring(each_proc)
137
+ string = each_proc.call
138
+ raise ::EOFError if string.nil?
139
+
140
+ string
141
+ end
142
+
143
+ protected def each_string(each_proc, &block)
144
+ return enum_for __method__ unless block.is_a? ::Proc
145
+
146
+ loop do
147
+ string = each_proc.call
148
+ break if string.nil?
149
+
150
+ yield string
151
+ end
152
+
153
+ nil
154
+ end
155
+
156
+ protected def ungetstring(string)
157
+ Validation.validate_string string
158
+
159
+ string = ::String.new string, :encoding => @internal_encoding
160
+ string = transcode_to_external string unless @external_encoding.nil?
161
+
162
+ string.force_encoding ::Encoding::BINARY
163
+ @buffer.prepend string
164
+
165
+ nil
166
+ end
167
+
168
+ # -- etc --
169
+
170
+ module ClassMethods
171
+ def open(file_path, *args, &block)
172
+ Validation.validate_string file_path
173
+ Validation.validate_proc block
174
+
175
+ ::File.open file_path, "rb" do |file|
176
+ reader = new file, *args
177
+
178
+ begin
179
+ yield reader
180
+ ensure
181
+ reader.close
182
+ end
183
+ end
184
+ end
185
+ end
186
+
187
+ def self.included(klass)
188
+ klass.extend ClassMethods
189
+ end
190
+ end
191
+ end
192
+ end
@@ -0,0 +1,78 @@
1
+ # Ruby bindings for lzws library.
2
+ # Copyright (c) 2019 AUTHORS, MIT License.
3
+
4
+ require "forwardable"
5
+
6
+ module LZWS
7
+ module Stream
8
+ class Stat
9
+ # Libraries like minitar tries to access stat to know whether stream is seekable.
10
+ # We need to mark stream as not directory, file, etc, because it is not seekable.
11
+
12
+ # User can use disabled delegates using :io reader.
13
+
14
+ extend ::Forwardable
15
+
16
+ METHODS_RETURNING_FALSE = %i[
17
+ blockdev?
18
+ chardev?
19
+ directory?
20
+ executable?
21
+ executable_real?
22
+ file?
23
+ grpowned?
24
+ owned?
25
+ pipe?
26
+ setgid?
27
+ setuid?
28
+ socket?
29
+ sticky?
30
+ symlink?
31
+ zero?
32
+ ]
33
+ .freeze
34
+
35
+ DELEGATES = %i[
36
+ <=>
37
+ atime
38
+ birthtime
39
+ blksize
40
+ blocks
41
+ ctime
42
+ dev
43
+ dev_major
44
+ dev_minor
45
+ ftype
46
+ gid
47
+ ino
48
+ inspect
49
+ mode
50
+ mtime
51
+ nlink
52
+ rdev
53
+ rdev_major
54
+ rdev_minor
55
+ readable?
56
+ readable_real?
57
+ size
58
+ size?
59
+ uid
60
+ world_readable?
61
+ world_writable?
62
+ writable?
63
+ writable_real?
64
+ ]
65
+ .freeze
66
+
67
+ def initialize(stat)
68
+ @stat = stat
69
+ end
70
+
71
+ METHODS_RETURNING_FALSE.each do |method_name|
72
+ define_method(method_name) { false }
73
+ end
74
+
75
+ def_delegators :@stat, *DELEGATES
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,145 @@
1
+ # Ruby bindings for lzws library.
2
+ # Copyright (c) 2019 AUTHORS, MIT License.
3
+
4
+ require_relative "abstract"
5
+ require_relative "raw/compressor"
6
+ require_relative "writer_helpers"
7
+
8
+ module LZWS
9
+ module Stream
10
+ class Writer < Abstract
11
+ include WriterHelpers
12
+
13
+ def initialize(destination_io, options = {}, *args)
14
+ @options = options
15
+
16
+ super destination_io, *args
17
+ end
18
+
19
+ protected def create_raw_stream
20
+ Raw::Compressor.new @options
21
+ end
22
+
23
+ # -- synchronous --
24
+
25
+ def write(*objects)
26
+ write_remaining_buffer
27
+
28
+ bytes_written = 0
29
+
30
+ objects.each do |object|
31
+ source = transcode object.to_s
32
+ bytes_written += raw_wrapper :write, source
33
+ end
34
+
35
+ @pos += bytes_written
36
+
37
+ bytes_written
38
+ end
39
+
40
+ def flush
41
+ finish :flush
42
+
43
+ @io.flush
44
+
45
+ self
46
+ end
47
+
48
+ def rewind
49
+ finish :close
50
+
51
+ super
52
+ end
53
+
54
+ def close
55
+ finish :close
56
+
57
+ super
58
+ end
59
+
60
+ protected def finish(method_name)
61
+ write_remaining_buffer
62
+
63
+ raw_wrapper method_name
64
+ end
65
+
66
+ protected def write_remaining_buffer
67
+ return nil if @buffer.bytesize == 0
68
+
69
+ @io.write @buffer
70
+
71
+ reset_buffer
72
+ end
73
+
74
+ protected def raw_wrapper(method_name, *args)
75
+ @raw_stream.send(method_name, *args) { |portion| @io.write portion }
76
+ end
77
+
78
+ # -- asynchronous --
79
+
80
+ def write_nonblock(object, *options)
81
+ return 0 unless write_remaining_buffer_nonblock(*options)
82
+
83
+ source = transcode object.to_s
84
+ bytes_written = raw_nonblock_wrapper :write, source
85
+ @pos += bytes_written
86
+
87
+ bytes_written
88
+ end
89
+
90
+ def flush_nonblock(*options)
91
+ return false unless finish_nonblock :flush, *options
92
+
93
+ @io.flush
94
+
95
+ true
96
+ end
97
+
98
+ def rewind_nonblock(*options)
99
+ return false unless finish_nonblock :close, *options
100
+
101
+ method(:rewind).super_method.call
102
+
103
+ true
104
+ end
105
+
106
+ def close_nonblock(*options)
107
+ return false unless finish_nonblock :close, *options
108
+
109
+ method(:close).super_method.call
110
+
111
+ true
112
+ end
113
+
114
+ protected def finish_nonblock(method_name, *options)
115
+ return false unless write_remaining_buffer_nonblock(*options)
116
+
117
+ raw_nonblock_wrapper method_name
118
+
119
+ write_remaining_buffer_nonblock(*options)
120
+ end
121
+
122
+ protected def write_remaining_buffer_nonblock(*options)
123
+ return true if @buffer.bytesize == 0
124
+
125
+ bytes_written = @io.write_nonblock @buffer, *options
126
+ return false if bytes_written == 0
127
+
128
+ @buffer = @buffer.byteslice bytes_written, @buffer.bytesize - bytes_written
129
+
130
+ @buffer.bytesize == 0
131
+ end
132
+
133
+ protected def raw_nonblock_wrapper(method_name, *args)
134
+ @raw_stream.send(method_name, *args) { |portion| @buffer << portion }
135
+ end
136
+
137
+ # -- common --
138
+
139
+ protected def transcode(data)
140
+ data = data.encode @external_encoding, @transcode_options unless @external_encoding.nil?
141
+ data
142
+ end
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,93 @@
1
+ # Ruby bindings for lzws library.
2
+ # Copyright (c) 2019 AUTHORS, MIT License.
3
+
4
+ require_relative "../error"
5
+ require_relative "../validation"
6
+
7
+ module LZWS
8
+ module Stream
9
+ module WriterHelpers
10
+ def <<(object)
11
+ write object
12
+ end
13
+
14
+ def print(*objects)
15
+ if objects.empty?
16
+ write $LAST_READ_LINE unless $LAST_READ_LINE.nil?
17
+ return nil
18
+ end
19
+
20
+ objects.each do |object|
21
+ write object
22
+ write $OUTPUT_FIELD_SEPARATOR unless $OUTPUT_FIELD_SEPARATOR.nil?
23
+ end
24
+
25
+ write $OUTPUT_RECORD_SEPARATOR unless $OUTPUT_RECORD_SEPARATOR.nil?
26
+
27
+ nil
28
+ end
29
+
30
+ def printf(*args)
31
+ write sprintf(*args)
32
+
33
+ nil
34
+ end
35
+
36
+ def putc(object, encoding: ::Encoding::BINARY)
37
+ if object.is_a? ::Numeric
38
+ write object.chr(encoding)
39
+ elsif object.is_a? ::String
40
+ write object[0]
41
+ else
42
+ raise ValidateError, "invalid object: \"#{object}\" for putc"
43
+ end
44
+
45
+ object
46
+ end
47
+
48
+ def puts(*objects)
49
+ objects.each do |object|
50
+ if object.is_a? ::Array
51
+ puts(*object)
52
+ next
53
+ end
54
+
55
+ source = object.to_s
56
+ newline = "\n".encode source.encoding
57
+
58
+ # Do not add newline if source ends with newline.
59
+ if source.end_with? newline
60
+ write source
61
+ else
62
+ write source + newline
63
+ end
64
+ end
65
+
66
+ nil
67
+ end
68
+
69
+ # -- etc --
70
+
71
+ module ClassMethods
72
+ def open(file_path, *args, &block)
73
+ Validation.validate_string file_path
74
+ Validation.validate_proc block
75
+
76
+ ::File.open file_path, "wb" do |file|
77
+ writer = new file, *args
78
+
79
+ begin
80
+ yield writer
81
+ ensure
82
+ writer.close
83
+ end
84
+ end
85
+ end
86
+ end
87
+
88
+ def self.included(klass)
89
+ klass.extend ClassMethods
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,27 @@
1
+ # Ruby bindings for lzws library.
2
+ # Copyright (c) 2019 AUTHORS, MIT License.
3
+
4
+ require "lzws_ext"
5
+
6
+ require_relative "option"
7
+ require_relative "validation"
8
+
9
+ module LZWS
10
+ module String
11
+ def self.compress(source, options = {})
12
+ Validation.validate_string source
13
+
14
+ options = Option.get_compressor_options options
15
+
16
+ LZWS._native_compress_string source, options
17
+ end
18
+
19
+ def self.decompress(source, options = {})
20
+ Validation.validate_string source
21
+
22
+ options = Option.get_decompressor_options options
23
+
24
+ LZWS._native_decompress_string source, options
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,36 @@
1
+ # Ruby bindings for lzws library.
2
+ # Copyright (c) 2019 AUTHORS, MIT License.
3
+
4
+ require_relative "error"
5
+
6
+ module LZWS
7
+ module Validation
8
+ def self.validate_bool(value)
9
+ raise ValidateError, "invalid bool" unless value.is_a?(::TrueClass) || value.is_a?(::FalseClass)
10
+ end
11
+
12
+ def self.validate_positive_integer(value)
13
+ raise ValidateError, "invalid positive integer" unless value.is_a?(::Integer) && value > 0
14
+ end
15
+
16
+ def self.validate_not_negative_integer(value)
17
+ raise ValidateError, "invalid not negative integer" unless value.is_a?(::Integer) && value >= 0
18
+ end
19
+
20
+ def self.validate_string(value)
21
+ raise ValidateError, "invalid string" unless value.is_a? ::String
22
+ end
23
+
24
+ def self.validate_io(value)
25
+ raise ValidateError, "invalid io" unless value.is_a? ::IO
26
+ end
27
+
28
+ def self.validate_hash(value)
29
+ raise ValidateError, "invalid hash" unless value.is_a? ::Hash
30
+ end
31
+
32
+ def self.validate_proc(value)
33
+ raise ValidateError, "invalid proc" unless value.is_a?(::Proc) || value.is_a?(::Method) || value.is_a?(::UnboundMethod)
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,6 @@
1
+ # Ruby bindings for lzws library.
2
+ # Copyright (c) 2019 AUTHORS, MIT License.
3
+
4
+ module LZWS
5
+ VERSION = "1.0.0".freeze
6
+ end
data/lib/lzws.rb ADDED
@@ -0,0 +1,4 @@
1
+ require_relative "lzws/file"
2
+ require_relative "lzws/stream/reader"
3
+ require_relative "lzws/stream/writer"
4
+ require_relative "lzws/string"