ruby-xz 0.2.1 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|