ruby-lzws 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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"