ruby-xz 0.2.1 → 0.2.2
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.
- checksums.yaml +4 -4
- data/AUTHORS +8 -0
- data/COPYING +1 -1
- data/HISTORY.rdoc +24 -4
- data/{README.rdoc → README.md} +61 -33
- data/lib/xz.rb +290 -184
- data/lib/xz/lib_lzma.rb +28 -18
- data/lib/xz/stream.rb +24 -22
- data/lib/xz/stream_reader.rb +328 -122
- data/lib/xz/stream_writer.rb +288 -97
- data/lib/xz/version.rb +33 -0
- metadata +36 -46
data/lib/xz/lib_lzma.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
|
+
#--
|
2
3
|
# The MIT License
|
3
4
|
#
|
4
5
|
# Basic liblzma-bindings for Ruby.
|
5
6
|
#
|
6
|
-
# Copyright © 2011,2013 Marvin Gülker et al.
|
7
|
+
# Copyright © 2011,2013,2015 Marvin Gülker et al.
|
7
8
|
#
|
8
9
|
# Permission is hereby granted, free of charge, to any person obtaining a
|
9
10
|
# copy of this software and associated documentation files (the ‘Software’),
|
@@ -22,19 +23,20 @@
|
|
22
23
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
23
24
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
24
25
|
# THE SOFTWARE.
|
26
|
+
#++
|
25
27
|
|
26
28
|
module XZ
|
27
29
|
|
28
|
-
#This module wraps functions and enums used by liblzma.
|
30
|
+
# This module wraps functions and enums used by liblzma.
|
29
31
|
module LibLZMA
|
30
32
|
extend FFI::Library
|
31
33
|
|
32
|
-
#The maximum value of an uint64_t, as defined by liblzma.
|
33
|
-
#Should be the same as
|
34
|
-
#
|
34
|
+
# The maximum value of an uint64_t, as defined by liblzma.
|
35
|
+
# Should be the same as
|
36
|
+
# (2 ** 64) - 1
|
35
37
|
UINT64_MAX = 18446744073709551615
|
36
38
|
|
37
|
-
#Activates extreme compression. Same as xz's "-e" commandline switch.
|
39
|
+
# Activates extreme compression. Same as xz's "-e" commandline switch.
|
38
40
|
LZMA_PRESET_EXTREME = 1 << 31
|
39
41
|
|
40
42
|
LZMA_TELL_NO_CHECK = 0x02
|
@@ -42,22 +44,30 @@ module XZ
|
|
42
44
|
LZMA_TELL_ANY_CHECK = 0x04
|
43
45
|
LZMA_CONCATENATED = 0x08
|
44
46
|
|
45
|
-
#
|
47
|
+
# For access convenience of the above flags.
|
48
|
+
LZMA_DECODE_FLAGS = {
|
49
|
+
:tell_no_check => LZMA_TELL_NO_CHECK,
|
50
|
+
:tell_unsupported_check => LZMA_TELL_UNSUPPORTED_CHECK,
|
51
|
+
:tell_any_check => LZMA_TELL_ANY_CHECK,
|
52
|
+
:concatenated => LZMA_CONCATENATED
|
53
|
+
}.freeze
|
54
|
+
|
55
|
+
# Placeholder enum used by liblzma for later additions.
|
46
56
|
LZMA_RESERVED_ENUM = enum :lzma_reserved_enum, 0
|
47
57
|
|
48
|
-
#Actions that can be passed to the lzma_code() function.
|
58
|
+
# Actions that can be passed to the lzma_code() function.
|
49
59
|
LZMA_ACTION = enum :lzma_run, 0,
|
50
60
|
:lzma_sync_flush,
|
51
61
|
:lzma_full_flush,
|
52
62
|
:lzma_finish
|
53
63
|
|
54
|
-
#Integrity check algorithms supported by liblzma.
|
64
|
+
# Integrity check algorithms supported by liblzma.
|
55
65
|
LZMA_CHECK = enum :lzma_check_none, 0,
|
56
66
|
:lzma_check_crc32, 1,
|
57
67
|
:lzma_check_crc64, 4,
|
58
68
|
:lzma_check_sha256, 10
|
59
69
|
|
60
|
-
#Possible return values of liblzma functions.
|
70
|
+
# Possible return values of liblzma functions.
|
61
71
|
LZMA_RET = enum :lzma_ok, 0,
|
62
72
|
:lzma_stream_end,
|
63
73
|
:lzma_no_check,
|
@@ -80,10 +90,10 @@ module XZ
|
|
80
90
|
|
81
91
|
end
|
82
92
|
|
83
|
-
#The class of the error that this library raises.
|
93
|
+
# The class of the error that this library raises.
|
84
94
|
class LZMAError < StandardError
|
85
95
|
|
86
|
-
#Raises an appropriate exception if +val+ isn't a liblzma success code.
|
96
|
+
# Raises an appropriate exception if +val+ isn't a liblzma success code.
|
87
97
|
def self.raise_if_necessary(val)
|
88
98
|
case LibLZMA::LZMA_RET[val]
|
89
99
|
when :lzma_mem_error then raise(self, "Couldn't allocate memory!")
|
@@ -98,7 +108,7 @@ module XZ
|
|
98
108
|
|
99
109
|
end
|
100
110
|
|
101
|
-
#The main struct of the liblzma library.
|
111
|
+
# The main struct of the liblzma library.
|
102
112
|
class LZMAStream < FFI::Struct
|
103
113
|
layout :next_in, :pointer, #uint8
|
104
114
|
:avail_in, :size_t,
|
@@ -119,11 +129,11 @@ module XZ
|
|
119
129
|
:reserved_enum1, :int,
|
120
130
|
:reserved_enum2, :int
|
121
131
|
|
122
|
-
#This method does basicly the same thing as the
|
123
|
-
#LZMA_STREAM_INIT macro of liblzma. Creates a new LZMAStream
|
124
|
-
#that has been initialized for usage. If any argument is passed,
|
125
|
-
#it is assumed to be a FFI::Pointer to a lzma_stream structure
|
126
|
-
#and that structure is wrapped.
|
132
|
+
# This method does basicly the same thing as the
|
133
|
+
# LZMA_STREAM_INIT macro of liblzma. Creates a new LZMAStream
|
134
|
+
# that has been initialized for usage. If any argument is passed,
|
135
|
+
# it is assumed to be a FFI::Pointer to a lzma_stream structure
|
136
|
+
# and that structure is wrapped.
|
127
137
|
def initialize(*args)
|
128
138
|
if !args.empty? #Got a pointer, want to wrap it
|
129
139
|
super
|
data/lib/xz/stream.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
|
+
#--
|
2
3
|
# (The MIT license)
|
3
4
|
#
|
4
5
|
# Basic liblzma-bindings for Ruby.
|
5
6
|
#
|
6
|
-
# Copyright © 2012 Marvin Gülker
|
7
|
+
# Copyright © 2012, 2015 Marvin Gülker
|
7
8
|
#
|
8
9
|
# Permission is hereby granted, free of charge, to any person obtaining a
|
9
10
|
# copy of this software and associated documentation files (the ‘Software’),
|
@@ -22,30 +23,31 @@
|
|
22
23
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
23
24
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
24
25
|
# THE SOFTWARE.
|
26
|
+
#++
|
25
27
|
|
26
|
-
#The base class for XZ::StreamReader and XZ::StreamWriter.
|
27
|
-
#This is an abstract class that is not meant to be used
|
28
|
-
#directly; if you try, you will soon recognise that you’ve
|
29
|
-
#created a quite limited object ;-). You can, however, test
|
30
|
-
#against this class in <tt>kind_of?</tt> tests.
|
28
|
+
# The base class for XZ::StreamReader and XZ::StreamWriter.
|
29
|
+
# This is an abstract class that is not meant to be used
|
30
|
+
# directly; if you try, you will soon recognise that you’ve
|
31
|
+
# created a quite limited object ;-). You can, however, test
|
32
|
+
# against this class in <tt>kind_of?</tt> tests.
|
31
33
|
#
|
32
|
-
#XZ::StreamReader and XZ::StreamWriter are IO-like classes that
|
33
|
-
#allow you to access XZ-compressed data the same way you access
|
34
|
-
#an IO-object, easily allowing to fool other libraries that expect
|
35
|
-
#IO objects. The most noticable example for this may be reading
|
36
|
-
#and writing XZ-compressed tarballs; see XZ::StreamReader and
|
37
|
-
#XZ::StreamWriter for respective examples.
|
34
|
+
# XZ::StreamReader and XZ::StreamWriter are IO-like classes that
|
35
|
+
# allow you to access XZ-compressed data the same way you access
|
36
|
+
# an IO-object, easily allowing to fool other libraries that expect
|
37
|
+
# IO objects. The most noticable example for this may be reading
|
38
|
+
# and writing XZ-compressed tarballs; see XZ::StreamReader and
|
39
|
+
# XZ::StreamWriter for respective examples.
|
38
40
|
#
|
39
|
-
#Neither this class nor its subclasses document the IO-methods
|
40
|
-
#they contain--this is due to the reason that they include the
|
41
|
-
#great IO::Like module that provides all the necessary IO methods
|
42
|
-
#based on a few methods you define. For all defined IO methods,
|
43
|
-
#see the +io-like+ gem’s documentation.
|
41
|
+
# Neither this class nor its subclasses document the IO-methods
|
42
|
+
# they contain--this is due to the reason that they include the
|
43
|
+
# great IO::Like module that provides all the necessary IO methods
|
44
|
+
# based on a few methods you define. For all defined IO methods,
|
45
|
+
# see the +io-like+ gem’s documentation.
|
44
46
|
class XZ::Stream
|
45
47
|
include IO::Like
|
46
48
|
|
47
|
-
#Creates a new instance of this class. Don’t use this directly,
|
48
|
-
#it’s only called by subclasses’ ::new methods.
|
49
|
+
# Creates a new instance of this class. Don’t use this directly,
|
50
|
+
# it’s only called by subclasses’ ::new methods.
|
49
51
|
def initialize(delegate_io)
|
50
52
|
@delegate_io = delegate_io
|
51
53
|
@lzma_stream = XZ::LZMAStream.new
|
@@ -53,10 +55,10 @@ class XZ::Stream
|
|
53
55
|
|
54
56
|
private
|
55
57
|
|
56
|
-
#This method returns the size of +str+ in bytes.
|
58
|
+
# This method returns the size of +str+ in bytes.
|
57
59
|
def binary_size(str)
|
58
|
-
#Believe it or not, but this is faster than str.bytes.to_a.size.
|
59
|
-
#I benchmarked it, and it is as twice as fast.
|
60
|
+
# Believe it or not, but this is faster than str.bytes.to_a.size.
|
61
|
+
# I benchmarked it, and it is as twice as fast.
|
60
62
|
if str.respond_to? :force_encoding
|
61
63
|
str.dup.force_encoding(Encoding::BINARY).size
|
62
64
|
else
|
data/lib/xz/stream_reader.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
|
+
#--
|
2
3
|
# (The MIT license)
|
3
4
|
#
|
4
5
|
# Basic liblzma-bindings for Ruby.
|
5
6
|
#
|
6
|
-
# Copyright © 2012 Marvin Gülker
|
7
|
+
# Copyright © 2012, 2015 Marvin Gülker
|
7
8
|
#
|
8
9
|
# Permission is hereby granted, free of charge, to any person obtaining a
|
9
10
|
# copy of this software and associated documentation files (the ‘Software’),
|
@@ -22,97 +23,166 @@
|
|
22
23
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
23
24
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
24
25
|
# THE SOFTWARE.
|
26
|
+
#++
|
25
27
|
|
26
|
-
#An IO-like reader class for XZ-compressed data, allowing you to
|
27
|
-
#access XZ-compressed data as if it was a normal IO object, but
|
28
|
-
#please note you can’t seek in the data--this doesn’t make much
|
29
|
-
#sense anyway. Where would you want to seek? The plain or the XZ
|
30
|
-
#data?
|
28
|
+
# An IO-like reader class for XZ-compressed data, allowing you to
|
29
|
+
# access XZ-compressed data as if it was a normal IO object, but
|
30
|
+
# please note you can’t seek in the data--this doesn’t make much
|
31
|
+
# sense anyway. Where would you want to seek? The plain or the XZ
|
32
|
+
# data?
|
31
33
|
#
|
32
|
-
#A StreamReader object actually wraps another IO object it reads
|
33
|
-
#the compressed data from; you can either pass this IO object directly
|
34
|
-
#to the ::new method, effectively allowing you to pass any IO-like thing
|
35
|
-
#you can imagine (just ensure it is readable), or you can pass a path
|
36
|
-
#to a filename to ::
|
37
|
-
#opening and closing the file correctly. You can even take it one step
|
38
|
-
#further and use the block form of ::new which will automatically call
|
39
|
-
#the #close method for you after the block finished. However, if you pass
|
40
|
-
#an IO, remember you have to close:
|
34
|
+
# A StreamReader object actually wraps another IO object it reads
|
35
|
+
# the compressed data from; you can either pass this IO object directly
|
36
|
+
# to the ::new method, effectively allowing you to pass any IO-like thing
|
37
|
+
# you can imagine (just ensure it is readable), or you can pass a path
|
38
|
+
# to a filename to ::open, in which case StreamReader takes care of both
|
39
|
+
# opening and closing the file correctly. You can even take it one step
|
40
|
+
# further and use the block form of ::new and ::open, which will automatically call
|
41
|
+
# the #close method for you after the block finished. However, if you pass
|
42
|
+
# an IO, remember you have to close:
|
41
43
|
#
|
42
|
-
#1. The StreamReader instance.
|
43
|
-
#2. The IO object you passed to ::new.
|
44
|
+
# 1. The StreamReader instance.
|
45
|
+
# 2. The IO object you passed to ::new.
|
44
46
|
#
|
45
|
-
#Do it <b>in exactly that order</b>, otherwise you may lose data.
|
47
|
+
# Do it <b>in exactly that order</b>, otherwise you may lose data.
|
46
48
|
#
|
47
|
-
#
|
48
|
-
#
|
49
|
-
#
|
49
|
+
# *WARNING*: The closing behaviour described above is subject to
|
50
|
+
# change in the next major version. In the future, wrapped IO
|
51
|
+
# objects are automatically closed always, regardless of whether you
|
52
|
+
# passed a filename or an IO instance. This is to sync the API with
|
53
|
+
# Ruby’s own Zlib::GzipReader. To prevent that, call #finish instead
|
54
|
+
# of #close.
|
50
55
|
#
|
51
|
-
|
52
|
-
#
|
53
|
-
|
54
|
-
#together, the two libraries allow us to read XZ-compressed tarballs.
|
56
|
+
# See the +io-like+ gem’s documentation for the IO-reading methods
|
57
|
+
# available for this class (although you’re probably familiar with
|
58
|
+
# them through Ruby’s own IO class ;-)).
|
55
59
|
#
|
56
|
-
#
|
57
|
-
#
|
60
|
+
# ==Example
|
61
|
+
# In this example, we’re going to use ruby-xz together with the
|
62
|
+
# +archive-tar-minitar+ gem that allows to read tarballs. Used
|
63
|
+
# together, the two libraries allow us to read XZ-compressed tarballs.
|
58
64
|
#
|
59
|
-
#
|
60
|
-
#
|
61
|
-
#
|
62
|
-
#
|
65
|
+
# require "xz"
|
66
|
+
# require "archive/tar/minitar"
|
67
|
+
#
|
68
|
+
# XZ::StreamReader.open("foo.tar.xz") do |txz|
|
69
|
+
# # This automatically closes txz
|
70
|
+
# Archive::Tar::Minitar.unpack(txz, "foo")
|
71
|
+
# end
|
63
72
|
class XZ::StreamReader < XZ::Stream
|
64
73
|
|
65
|
-
#The memory limit you set for this reader (in ::new).
|
74
|
+
# The memory limit you set for this reader (in ::new).
|
66
75
|
attr_reader :memory_limit
|
67
|
-
#The flags you set for this reader (in ::new).
|
68
|
-
attr_reader :flags
|
69
76
|
|
70
|
-
#
|
71
|
-
|
72
|
-
# open(delegate, memory_limit = XZ::LibLZMA::UINT64_MAX, flags = [:tell_unsupported_check]) → a_stream_reader
|
73
|
-
#
|
74
|
-
#Creates a new StreamReader instance. If you pass an IO,
|
75
|
-
#remember you have to close *both* the resulting instance
|
76
|
-
#(via the #close method) and the IO object you pass to flush
|
77
|
-
#any internal buffers in order to be able to read all decompressed
|
78
|
-
#data.
|
79
|
-
#==Parameters
|
80
|
-
#[delegate] An IO object to read the data from, or a path
|
81
|
-
# to a file to open. If you’re in an urgent need to
|
82
|
-
# pass a plain string, use StringIO from Ruby’s
|
83
|
-
# standard library. If this is an IO, it must be
|
84
|
-
# opened for reading.
|
85
|
-
#The other parameters are identical to what the XZ::decompress_stream
|
86
|
-
#method expects.
|
87
|
-
#==Return value
|
88
|
-
#The newly created instance.
|
89
|
-
#==Example
|
90
|
-
# # Wrap it around a file
|
91
|
-
# f = File.open("foo.xz")
|
92
|
-
# r = XZ::StreamReader.new(f)
|
93
|
-
#
|
94
|
-
# # Ignore any XZ checksums (may result in invalid data being read!)
|
95
|
-
# File.open("foo.xz") do |f|
|
96
|
-
# r = XZ::StreamReader.new(f, XZ::LibLZMA::UINT64_MAX, [:tell_no_check]
|
97
|
-
# end
|
98
|
-
#
|
99
|
-
# # Let StreamReader handle file closing automatically
|
100
|
-
# XZ::StreamReader.new("myfile.xz"){|r| r.raed}
|
101
|
-
def initialize(delegate, memory_limit = XZ::LibLZMA::UINT64_MAX, flags = [:tell_unsupported_check])
|
102
|
-
raise(ArgumentError, "Invalid memory limit set!") unless (0..XZ::LibLZMA::UINT64_MAX).include?(memory_limit)
|
103
|
-
flags.each do |flag|
|
104
|
-
raise(ArgumentError, "Unknown flag #{flag}!") unless [:tell_no_check, :tell_unsupported_check, :tell_any_check, :concatenated].include?(flag)
|
105
|
-
end
|
77
|
+
# The flags you set for this reader (in ::new).
|
78
|
+
attr_reader :flags
|
106
79
|
|
80
|
+
# call-seq:
|
81
|
+
# new(delegate, opts = {}) → reader
|
82
|
+
# new(delegate, opts = {}){|reader| …} → obj
|
83
|
+
#
|
84
|
+
# Creates a new StreamReader instance. If you pass an IO,
|
85
|
+
# remember you have to close *both* the resulting instance
|
86
|
+
# (via the #close method) and the IO object you pass to flush
|
87
|
+
# any internal buffers in order to be able to read all decompressed
|
88
|
+
# data (beware Deprecations section below).
|
89
|
+
#
|
90
|
+
# === Parameters
|
91
|
+
#
|
92
|
+
# [delegate]
|
93
|
+
# An IO object to read the data from, If you’re in an urgent
|
94
|
+
# need to pass a plain string, use StringIO from Ruby’s
|
95
|
+
# standard library. If this is an IO, it must be
|
96
|
+
# opened for reading.
|
97
|
+
#
|
98
|
+
# [opts]
|
99
|
+
# Options hash accepting these parameters (defaults indicated
|
100
|
+
# in parantheses):
|
101
|
+
#
|
102
|
+
# [:memory_limit (LibLZMA::UINT64_MAX)]
|
103
|
+
# If not XZ::LibLZMA::UINT64_MAX, makes liblzma use
|
104
|
+
# no more memory than this amount of bytes.
|
105
|
+
#
|
106
|
+
# [:flags ([:tell_unsupported_check])]
|
107
|
+
# Additional flags passed to libzlma (an array). Possible
|
108
|
+
# flags are:
|
109
|
+
#
|
110
|
+
# [:tell_no_check]
|
111
|
+
# Spit out a warning if the archive hasn’t an integrity
|
112
|
+
# checksum.
|
113
|
+
# [:tell_unsupported_check]
|
114
|
+
# Spit out a warning if the archive has an unsupported
|
115
|
+
# checksum type.
|
116
|
+
# [:concatenated]
|
117
|
+
# Decompress concatenated archives.
|
118
|
+
#
|
119
|
+
# [reader]
|
120
|
+
# Block argument. self of the new instance.
|
121
|
+
#
|
122
|
+
# === Return value
|
123
|
+
#
|
124
|
+
# The block form returns the block’s last expression, the nonblock
|
125
|
+
# form returns the newly created instance.
|
126
|
+
#
|
127
|
+
# === Deprecations
|
128
|
+
#
|
129
|
+
# The old API for this method as it was documented in version 0.2.1
|
130
|
+
# still works, but is deprecated. Please change to the new API as
|
131
|
+
# soon as possible.
|
132
|
+
#
|
133
|
+
# *WARNING*: The closing behaviour of the block form is subject to
|
134
|
+
# upcoming change. In the next major release the wrapped IO *will*
|
135
|
+
# be automatically closed, unless you call #finish.
|
136
|
+
#
|
137
|
+
# === Example
|
138
|
+
#
|
139
|
+
# # Wrap it around a file
|
140
|
+
# f = File.open("foo.xz")
|
141
|
+
# r = XZ::StreamReader.new(f)
|
142
|
+
#
|
143
|
+
# # Ignore any XZ checksums (may result in invalid
|
144
|
+
# # data being read!)
|
145
|
+
# File.open("foo.xz") do |f|
|
146
|
+
# r = XZ::StreamReader.new(f, :flags => [:tell_no_check])
|
147
|
+
# end
|
148
|
+
def initialize(delegate, *args)
|
107
149
|
if delegate.respond_to?(:to_io)
|
108
|
-
|
150
|
+
# Correct use with IO
|
151
|
+
super(delegate.to_io)
|
152
|
+
@autoclose = false
|
109
153
|
else
|
110
|
-
|
111
|
-
|
154
|
+
# Deprecated use of filename
|
155
|
+
XZ.deprecate "Calling XZ::StreamReader.new with a filename is deprecated, use XZ::StreamReader.open instead."
|
156
|
+
|
157
|
+
@autoclose = true
|
158
|
+
super(File.open(delegate, "rb"))
|
159
|
+
end
|
160
|
+
|
161
|
+
# Flag for calling #finish
|
162
|
+
@finish = false
|
163
|
+
|
164
|
+
opts = {}
|
165
|
+
if args[0].kind_of?(Hash) # New API
|
166
|
+
opts = args[0]
|
167
|
+
opts[:memory_limit] ||= XZ::LibLZMA::UINT64_MAX
|
168
|
+
opts[:flags] ||= [:tell_unsupported_check]
|
169
|
+
else # Old API
|
170
|
+
# no arguments may also happen in new API
|
171
|
+
unless args.empty?
|
172
|
+
XZ.deprecate "Calling XZ::StreamReader.new with explicit arguments is deprecated, use an options hash instead."
|
173
|
+
end
|
174
|
+
|
175
|
+
opts[:memory_limit] = args[0] || XZ::LibLZMA::UINT64_MAX
|
176
|
+
opts[:flags] = args[1] || [:tell_unsupported_check]
|
177
|
+
end
|
178
|
+
|
179
|
+
raise(ArgumentError, "Invalid memory limit set!") unless (0..XZ::LibLZMA::UINT64_MAX).include?(opts[:memory_limit])
|
180
|
+
opts[:flags].each do |flag|
|
181
|
+
raise(ArgumentError, "Unknown flag #{flag}!") unless [:tell_no_check, :tell_unsupported_check, :tell_any_check, :concatenated].include?(flag)
|
112
182
|
end
|
113
183
|
|
114
|
-
@memory_limit = memory_limit
|
115
|
-
@flags = flags
|
184
|
+
@memory_limit = opts[:memory_limit]
|
185
|
+
@flags = opts[:flags]
|
116
186
|
|
117
187
|
res = XZ::LibLZMA.lzma_stream_decoder(@lzma_stream,
|
118
188
|
@memory_limit,
|
@@ -133,17 +203,98 @@ class XZ::StreamReader < XZ::Stream
|
|
133
203
|
end
|
134
204
|
end
|
135
205
|
end
|
136
|
-
|
137
|
-
|
138
|
-
#
|
139
|
-
#
|
140
|
-
|
141
|
-
#
|
142
|
-
|
143
|
-
#
|
144
|
-
|
145
|
-
#
|
146
|
-
#
|
206
|
+
|
207
|
+
# call-seq:
|
208
|
+
# open(filename, opts = {}) → reader
|
209
|
+
# open(filename, opts = {}){|reader| …} → obj
|
210
|
+
#
|
211
|
+
# Opens a file from disk and wraps an XZ::StreamReader instance
|
212
|
+
# around the resulting File IO object. This is a convenience
|
213
|
+
# method that is equivalent to calling
|
214
|
+
#
|
215
|
+
# file = File.open(filename, "rb")
|
216
|
+
# reader = XZ::StreamReader.new(file, opts)
|
217
|
+
#
|
218
|
+
# , except that you don’t have to explicitely close the File
|
219
|
+
# instance, this is done automatically when you call #close.
|
220
|
+
# Beware the Deprecations section in this regard.
|
221
|
+
#
|
222
|
+
# === Parameters
|
223
|
+
#
|
224
|
+
# [filename]
|
225
|
+
# Path to a file on the disk to open. This file should
|
226
|
+
# exist and be readable, otherwise you may get Errno
|
227
|
+
# exceptions.
|
228
|
+
#
|
229
|
+
# [opts]
|
230
|
+
# Options hash. See ::new for a description of the possible
|
231
|
+
# options.
|
232
|
+
#
|
233
|
+
# [reader]
|
234
|
+
# Block argument. self of the new instance.
|
235
|
+
#
|
236
|
+
# === Return value
|
237
|
+
#
|
238
|
+
# The block form returns the block’s last expression, the nonblock
|
239
|
+
# form returns the newly created XZ::StreamReader instance.
|
240
|
+
#
|
241
|
+
# === Deprecations
|
242
|
+
#
|
243
|
+
# In the API up to and including version 0.2.1 this method was an
|
244
|
+
# alias for ::new. This continues to work for now, but using it
|
245
|
+
# as an alias for ::new is deprecated. The next major version will
|
246
|
+
# only accept a string as a parameter for this method.
|
247
|
+
#
|
248
|
+
# *WARNING*: Future versions of ruby-xz will always close the
|
249
|
+
# wrapped IO, regardless of whether you pass in your own IO or use
|
250
|
+
# this convenience method! To prevent that, call the #finish method.
|
251
|
+
#
|
252
|
+
# === Examples
|
253
|
+
#
|
254
|
+
# XZ::StreamReader.new("myfile.xz"){|r| r.read}
|
255
|
+
def self.open(filename, *args, &block)
|
256
|
+
if filename.respond_to?(:to_io)
|
257
|
+
# Deprecated use of IO
|
258
|
+
XZ.deprecate "Calling XZ::StreamReader.open with an IO is deprecated, use XZ::StreamReader.new instead"
|
259
|
+
new(filename.to_io, *args, &block)
|
260
|
+
else
|
261
|
+
# Correct use with filename
|
262
|
+
file = File.open(filename, "rb")
|
263
|
+
|
264
|
+
obj = new(file, *args)
|
265
|
+
obj.instance_variable_set(:@autoclose, true) # Only needed during deprecation phase (see #close)
|
266
|
+
|
267
|
+
if block_given?
|
268
|
+
begin
|
269
|
+
block.call(obj)
|
270
|
+
ensure
|
271
|
+
obj.close unless obj.closed?
|
272
|
+
end
|
273
|
+
else
|
274
|
+
obj
|
275
|
+
end
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
# Closes this StreamReader instance. Don’t use it afterwards
|
280
|
+
# anymore.
|
281
|
+
#
|
282
|
+
# === Return value
|
283
|
+
#
|
284
|
+
# The total number of bytes decompressed.
|
285
|
+
#
|
286
|
+
# === Example
|
287
|
+
#
|
288
|
+
# r.close #=> 6468
|
289
|
+
#
|
290
|
+
# === Remarks
|
291
|
+
#
|
292
|
+
# If you passed an IO to ::new, this method doesn’t close it, so
|
293
|
+
# you have to close it yourself.
|
294
|
+
#
|
295
|
+
# *WARNING*: The next major release will change this behaviour.
|
296
|
+
# In the future, the wrapped IO object will always be closed.
|
297
|
+
# Use the #finish method for keeping it open.
|
147
298
|
def close
|
148
299
|
super
|
149
300
|
|
@@ -151,43 +302,98 @@ class XZ::StreamReader < XZ::Stream
|
|
151
302
|
res = XZ::LibLZMA.lzma_end(@lzma_stream.pointer)
|
152
303
|
XZ::LZMAError.raise_if_necessary(res)
|
153
304
|
|
154
|
-
|
155
|
-
|
305
|
+
unless @finish
|
306
|
+
# New API: Close the wrapped IO
|
307
|
+
#@delegate_io.close
|
308
|
+
# ↑ uncomment on API break and remove OLD API below. Note that with
|
309
|
+
# the new API that always closes the underlying IO, it is not necessary
|
310
|
+
# to distinguish a self-opened IO from a wrapped preexisting IO.
|
311
|
+
# The variable @autoclose can thus be removed on API break.
|
312
|
+
|
313
|
+
# Old API:
|
314
|
+
#If we created a File object, close this as well.
|
315
|
+
if @autoclose
|
316
|
+
# This does not change in the new API, so no deprecation warning.
|
317
|
+
@delegate_io.close
|
318
|
+
else
|
319
|
+
XZ.deprecate "XZ::StreamReader#close will automatically close the wrapped IO in the future. Use #finish to prevent that."
|
320
|
+
end
|
321
|
+
end
|
156
322
|
|
157
323
|
# Return the number of bytes written in total.
|
158
324
|
@lzma_stream[:total_out]
|
159
325
|
end
|
160
326
|
|
161
|
-
#
|
162
|
-
#
|
163
|
-
#
|
327
|
+
# If called in the block form of ::new or ::open, prevents the
|
328
|
+
# wrapped IO from being closed, only the LZMA stream is closed
|
329
|
+
# then. If called outside the block form of ::new and open, behaves
|
330
|
+
# like #close, but only closes the underlying LZMA stream. The
|
331
|
+
# wrapped IO object is kept open.
|
332
|
+
#
|
333
|
+
# === Return value
|
334
|
+
#
|
335
|
+
# Returns the wrapped IO object. This allows you to wire the File
|
336
|
+
# instance out of a StreamReader instance that was created with
|
337
|
+
# ::open.
|
338
|
+
#
|
339
|
+
# === Example
|
164
340
|
#
|
165
|
-
#
|
341
|
+
# # Nonblock form
|
342
|
+
# f = File.open("foo.xz", "rb")
|
343
|
+
# r = XZ::StreamReader.new(f)
|
344
|
+
# r.finish
|
345
|
+
# # f is still open here!
|
346
|
+
#
|
347
|
+
# # Block form
|
348
|
+
# str = nil
|
349
|
+
# f = XZ::StreamReader.open("foo.xz") do |r|
|
350
|
+
# str = r.read
|
351
|
+
# r.finish
|
352
|
+
# end
|
353
|
+
# # f now is an *open* File instance of mode "rb".
|
354
|
+
def finish
|
355
|
+
# Do not close wrapped IO object in #close
|
356
|
+
@finish = true
|
357
|
+
close
|
358
|
+
|
359
|
+
@delegate_io
|
360
|
+
end
|
361
|
+
|
362
|
+
# call-seq:
|
363
|
+
# pos() → an_integer
|
364
|
+
# tell() → an_integer
|
365
|
+
#
|
366
|
+
# Total number of output bytes provided to you yet.
|
166
367
|
def pos
|
167
368
|
@lzma_stream[:total_out]
|
168
369
|
end
|
169
370
|
alias tell pos
|
170
371
|
|
171
|
-
#Instrcuts liblzma to immediately stop decompression,
|
172
|
-
#rewinds the wrapped IO object and reinitalizes the
|
173
|
-
#StreamReader instance with the same values passed
|
174
|
-
#originally to the ::new method. The wrapped IO object
|
175
|
-
#must support the +rewind+ method for this method to
|
176
|
-
#work; if it doesn’t, this method throws an IOError.
|
177
|
-
#After the exception was thrown, the StreamReader instance
|
178
|
-
#is in an unusable state. You cannot continue using it
|
179
|
-
#(don’t call #close on it either); close the wrapped IO
|
180
|
-
#stream and create another instance of this class.
|
181
|
-
|
182
|
-
#
|
183
|
-
#
|
184
|
-
#
|
185
|
-
|
186
|
-
#
|
187
|
-
#
|
188
|
-
#
|
189
|
-
|
190
|
-
#
|
372
|
+
# Instrcuts liblzma to immediately stop decompression,
|
373
|
+
# rewinds the wrapped IO object and reinitalizes the
|
374
|
+
# StreamReader instance with the same values passed
|
375
|
+
# originally to the ::new method. The wrapped IO object
|
376
|
+
# must support the +rewind+ method for this method to
|
377
|
+
# work; if it doesn’t, this method throws an IOError.
|
378
|
+
# After the exception was thrown, the StreamReader instance
|
379
|
+
# is in an unusable state. You cannot continue using it
|
380
|
+
# (don’t call #close on it either); close the wrapped IO
|
381
|
+
# stream and create another instance of this class.
|
382
|
+
#
|
383
|
+
# === Raises
|
384
|
+
#
|
385
|
+
# [IOError]
|
386
|
+
# The wrapped IO doesn’t support rewinding.
|
387
|
+
# Do not use the StreamReader instance anymore
|
388
|
+
# after receiving this exception.
|
389
|
+
#
|
390
|
+
# ==Remarks
|
391
|
+
#
|
392
|
+
# I don’t really like this method, it uses several dirty
|
393
|
+
# tricks to circumvent both io-like’s and liblzma’s control
|
394
|
+
# mechanisms. I only implemented this because the
|
395
|
+
# <tt>archive-tar-minitar</tt> gem calls this method when
|
396
|
+
# unpacking a TAR archive from a stream.
|
191
397
|
def rewind
|
192
398
|
# HACK: Wipe all data from io-like’s internal read buffer.
|
193
399
|
# This heavily relies on io-like’s internal structure.
|
@@ -206,24 +412,24 @@ class XZ::StreamReader < XZ::Stream
|
|
206
412
|
raise(IOError, "Delegate IO failed to rewind! Original message: #{e.message}")
|
207
413
|
end
|
208
414
|
|
209
|
-
# Reinitialize everything. Note this doesn’t affect @
|
415
|
+
# Reinitialize everything. Note this doesn’t affect @autofile as it
|
210
416
|
# is already set and stays so (we don’t pass a filename here,
|
211
417
|
# but rather an IO)
|
212
|
-
initialize(@delegate_io, @memory_limit, @flags)
|
418
|
+
initialize(@delegate_io, :memory_limit => @memory_limit, :flags => @flags)
|
213
419
|
end
|
214
420
|
|
215
|
-
#NO, you CANNOT seek in this object!!
|
216
|
-
#io-like’s default behaviour is to raise Errno::ESPIPE
|
217
|
-
#when calling a non-defined seek, which is not what some
|
218
|
-
#libraries such as RubyGem’s TarReader expect (they expect
|
219
|
-
#a NoMethodError/NameError instead).
|
421
|
+
# NO, you CANNOT seek in this object!!
|
422
|
+
# io-like’s default behaviour is to raise Errno::ESPIPE
|
423
|
+
# when calling a non-defined seek, which is not what some
|
424
|
+
# libraries such as RubyGem’s TarReader expect (they expect
|
425
|
+
# a NoMethodError/NameError instead).
|
220
426
|
undef seek
|
221
427
|
|
222
428
|
private
|
223
429
|
|
224
|
-
#Called by io-like’s read methods such as #read. Does the heavy work
|
225
|
-
#of feeding liblzma the compressed data and reading the returned
|
226
|
-
#uncompressed data.
|
430
|
+
# Called by io-like’s read methods such as #read. Does the heavy work
|
431
|
+
# of feeding liblzma the compressed data and reading the returned
|
432
|
+
# uncompressed data.
|
227
433
|
def unbuffered_read(length)
|
228
434
|
raise(EOFError, "Input data completely processed!") if @__lzma_finished
|
229
435
|
|