superp-rubyzip 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,65 @@
1
+ module Zip
2
+ class Inflater < Decompressor #:nodoc:all
3
+ def initialize(input_stream)
4
+ super
5
+ @zlib_inflater = ::Zlib::Inflate.new(-Zlib::MAX_WBITS)
6
+ @output_buffer = ''
7
+ @has_returned_empty_string = false
8
+ end
9
+
10
+ def sysread(number_of_bytes = nil, buf = nil)
11
+ readEverything = number_of_bytes.nil?
12
+ while (readEverything || @output_buffer.bytesize < number_of_bytes)
13
+ break if internal_input_finished?
14
+ @output_buffer << internal_produce_input(buf)
15
+ end
16
+ return value_when_finished if @output_buffer.bytesize == 0 && input_finished?
17
+ end_index = number_of_bytes.nil? ? @output_buffer.bytesize : number_of_bytes
18
+ @output_buffer.slice!(0...end_index)
19
+ end
20
+
21
+ def produce_input
22
+ if (@output_buffer.empty?)
23
+ internal_produce_input
24
+ else
25
+ @output_buffer.slice!(0...(@output_buffer.length))
26
+ end
27
+ end
28
+
29
+ # to be used with produce_input, not read (as read may still have more data cached)
30
+ # is data cached anywhere other than @outputBuffer? the comment above may be wrong
31
+ def input_finished?
32
+ @output_buffer.empty? && internal_input_finished?
33
+ end
34
+
35
+ alias :eof :input_finished?
36
+ alias :eof? :input_finished?
37
+
38
+ private
39
+
40
+ def internal_produce_input(buf = nil)
41
+ retried = 0
42
+ begin
43
+ @zlib_inflater.inflate(@input_stream.read(Decompressor::CHUNK_SIZE, buf))
44
+ rescue Zlib::BufError
45
+ raise if retried >= 5 # how many times should we retry?
46
+ retried += 1
47
+ retry
48
+ end
49
+ end
50
+
51
+ def internal_input_finished?
52
+ @zlib_inflater.finished?
53
+ end
54
+
55
+ def value_when_finished # mimic behaviour of ruby File object.
56
+ return if @has_returned_empty_string
57
+ @has_returned_empty_string = true
58
+ ''
59
+ end
60
+ end
61
+ end
62
+
63
+ # Copyright (C) 2002, 2003 Thomas Sondergaard
64
+ # rubyzip is free software; you can redistribute it and/or
65
+ # modify it under the terms of the ruby license.
@@ -0,0 +1,145 @@
1
+ module Zip
2
+ # ZipInputStream is the basic class for reading zip entries in a
3
+ # zip file. It is possible to create a ZipInputStream object directly,
4
+ # passing the zip file name to the constructor, but more often than not
5
+ # the ZipInputStream will be obtained from a ZipFile (perhaps using the
6
+ # ZipFileSystem interface) object for a particular entry in the zip
7
+ # archive.
8
+ #
9
+ # A ZipInputStream inherits IOExtras::AbstractInputStream in order
10
+ # to provide an IO-like interface for reading from a single zip
11
+ # entry. Beyond methods for mimicking an IO-object it contains
12
+ # the method get_next_entry for iterating through the entries of
13
+ # an archive. get_next_entry returns a ZipEntry object that describes
14
+ # the zip entry the ZipInputStream is currently reading from.
15
+ #
16
+ # Example that creates a zip archive with ZipOutputStream and reads it
17
+ # back again with a ZipInputStream.
18
+ #
19
+ # require 'zip/zip'
20
+ #
21
+ # Zip::ZipOutputStream::open("my.zip") {
22
+ # |io|
23
+ #
24
+ # io.put_next_entry("first_entry.txt")
25
+ # io.write "Hello world!"
26
+ #
27
+ # io.put_next_entry("adir/first_entry.txt")
28
+ # io.write "Hello again!"
29
+ # }
30
+ #
31
+ #
32
+ # Zip::ZipInputStream::open("my.zip") {
33
+ # |io|
34
+ #
35
+ # while (entry = io.get_next_entry)
36
+ # puts "Contents of #{entry.name}: '#{io.read}'"
37
+ # end
38
+ # }
39
+ #
40
+ # java.util.zip.ZipInputStream is the original inspiration for this
41
+ # class.
42
+
43
+ class InputStream
44
+ include ::Zip::IOExtras::AbstractInputStream
45
+
46
+ # Opens the indicated zip file. An exception is thrown
47
+ # if the specified offset in the specified filename is
48
+ # not a local zip entry header.
49
+ def initialize(filename, offset = 0, io = nil)
50
+ super()
51
+ if (io.nil?)
52
+ @archiveIO = ::File.open(filename, "rb")
53
+ @archiveIO.seek(offset, IO::SEEK_SET)
54
+ else
55
+ @archiveIO = io
56
+ end
57
+ @decompressor = NullDecompressor.instance
58
+ @currentEntry = nil
59
+ end
60
+
61
+ def close
62
+ @archiveIO.close
63
+ end
64
+
65
+ # Same as #initialize but if a block is passed the opened
66
+ # stream is passed to the block and closed when the block
67
+ # returns.
68
+ def InputStream.open(filename)
69
+ return new(filename) unless block_given?
70
+
71
+ zio = new(filename)
72
+ yield zio
73
+ ensure
74
+ zio.close if zio
75
+ end
76
+
77
+ def InputStream.open_buffer(io)
78
+ return new('',0,io) unless block_given?
79
+ zio = new('',0,io)
80
+ yield zio
81
+ ensure
82
+ zio.close if zio
83
+ end
84
+
85
+ # Returns a ZipEntry object. It is necessary to call this
86
+ # method on a newly created ZipInputStream before reading from
87
+ # the first entry in the archive. Returns nil when there are
88
+ # no more entries.
89
+
90
+ def get_next_entry
91
+ @archiveIO.seek(@currentEntry.next_header_offset, IO::SEEK_SET) if @currentEntry
92
+ open_entry
93
+ end
94
+
95
+ # Rewinds the stream to the beginning of the current entry
96
+ def rewind
97
+ return if @currentEntry.nil?
98
+ @lineno = 0
99
+ @pos = 0
100
+ @archiveIO.seek(@currentEntry.local_header_offset,
101
+ IO::SEEK_SET)
102
+ open_entry
103
+ end
104
+
105
+ # Modeled after IO.sysread
106
+ def sysread(numberOfBytes = nil, buf = nil)
107
+ @decompressor.sysread(numberOfBytes, buf)
108
+ end
109
+
110
+ def eof
111
+ @output_buffer.empty? && @decompressor.eof
112
+ end
113
+ alias :eof? :eof
114
+
115
+ protected
116
+
117
+ def open_entry
118
+ @currentEntry = Entry.read_local_entry(@archiveIO)
119
+ if @currentEntry.nil?
120
+ @decompressor = NullDecompressor.instance
121
+ elsif @currentEntry.compression_method == Entry::STORED
122
+ @decompressor = PassThruDecompressor.new(@archiveIO, @currentEntry.size)
123
+ elsif @currentEntry.compression_method == Entry::DEFLATED
124
+ @decompressor = Inflater.new(@archiveIO)
125
+ else
126
+ raise ZipCompressionMethodError,
127
+ "Unsupported compression method #{@currentEntry.compression_method}"
128
+ end
129
+ flush
130
+ return @currentEntry
131
+ end
132
+
133
+ def produce_input
134
+ @decompressor.produce_input
135
+ end
136
+
137
+ def input_finished?
138
+ @decompressor.input_finished?
139
+ end
140
+ end
141
+ end
142
+
143
+ # Copyright (C) 2002, 2003 Thomas Sondergaard
144
+ # rubyzip is free software; you can redistribute it and/or
145
+ # modify it under the terms of the ruby license.
@@ -0,0 +1,186 @@
1
+ module Zip
2
+ module IOExtras #:nodoc:
3
+
4
+ CHUNK_SIZE = 131072
5
+
6
+ RANGE_ALL = 0..-1
7
+
8
+ def self.copy_stream(ostream, istream)
9
+ s = ''
10
+ ostream.write(istream.read(CHUNK_SIZE, s)) until istream.eof?
11
+ end
12
+
13
+ def self.copy_stream_n(ostream, istream, nbytes)
14
+ s = ''
15
+ toread = nbytes
16
+ while (toread > 0 && !istream.eof?)
17
+ tr = toread > CHUNK_SIZE ? CHUNK_SIZE : toread
18
+ ostream.write(istream.read(tr, s))
19
+ toread -= tr
20
+ end
21
+ end
22
+
23
+
24
+ # Implements kind_of? in order to pretend to be an IO object
25
+ module FakeIO
26
+ def kind_of?(object)
27
+ object == IO || super
28
+ end
29
+ end
30
+
31
+ # Implements many of the convenience methods of IO
32
+ # such as gets, getc, readline and readlines
33
+ # depends on: input_finished?, produce_input and read
34
+ module AbstractInputStream
35
+ include Enumerable
36
+ include FakeIO
37
+
38
+ def initialize
39
+ super
40
+ @lineno = 0
41
+ @pos = 0
42
+ @output_buffer = ""
43
+ end
44
+
45
+ attr_accessor :lineno
46
+ attr_reader :pos
47
+
48
+ def read(numberOfBytes = nil, buf = nil)
49
+ tbuf = nil
50
+
51
+ if @output_buffer.bytesize > 0
52
+ if numberOfBytes <= @output_buffer.bytesize
53
+ tbuf = @output_buffer.slice!(0, numberOfBytes)
54
+ else
55
+ numberOfBytes -= @output_buffer.bytesize if (numberOfBytes)
56
+ rbuf = sysread(numberOfBytes, buf)
57
+ tbuf = @output_buffer
58
+ tbuf << rbuf if (rbuf)
59
+ @output_buffer = ""
60
+ end
61
+ else
62
+ tbuf = sysread(numberOfBytes, buf)
63
+ end
64
+
65
+ @pos += tbuf.length
66
+
67
+ return nil unless (tbuf)
68
+
69
+ if buf
70
+ buf.replace(tbuf)
71
+ else
72
+ buf = tbuf
73
+ end
74
+
75
+ buf
76
+ end
77
+
78
+ def readlines(aSepString = $/)
79
+ retVal = []
80
+ each_line(aSepString) { |line| retVal << line }
81
+ retVal
82
+ end
83
+
84
+ def gets(aSepString = $/, numberOfBytes = nil)
85
+ @lineno = @lineno.next
86
+
87
+ if numberOfBytes.respond_to?(:to_int)
88
+ numberOfBytes = numberOfBytes.to_int
89
+ aSepString = aSepString.to_str if aSepString
90
+ elsif aSepString.respond_to?(:to_int)
91
+ numberOfBytes = aSepString.to_int
92
+ aSepString = $/
93
+ else
94
+ numberOfBytes = nil
95
+ aSepString = aSepString.to_str if aSepString
96
+ end
97
+
98
+ return read(numberOfBytes) if aSepString.nil?
99
+ aSepString = "#{$/}#{$/}" if aSepString.empty?
100
+
101
+ bufferIndex = 0
102
+ overLimit = (numberOfBytes && @output_buffer.bytesize >= numberOfBytes)
103
+ while ((matchIndex = @output_buffer.index(aSepString, bufferIndex)) == nil && !overLimit)
104
+ bufferIndex = [bufferIndex, @output_buffer.bytesize - aSepString.bytesize].max
105
+ if input_finished?
106
+ return @output_buffer.empty? ? nil : flush
107
+ end
108
+ @output_buffer << produce_input
109
+ overLimit = (numberOfBytes && @output_buffer.bytesize >= numberOfBytes)
110
+ end
111
+ sepIndex = [matchIndex + aSepString.bytesize, numberOfBytes || @output_buffer.bytesize].min
112
+ @pos += sepIndex
113
+ return @output_buffer.slice!(0...sepIndex)
114
+ end
115
+
116
+ def flush
117
+ retVal = @output_buffer
118
+ @output_buffer=""
119
+ return retVal
120
+ end
121
+
122
+ def readline(aSepString = $/)
123
+ retVal = gets(aSepString)
124
+ raise EOFError if retVal == nil
125
+ retVal
126
+ end
127
+
128
+ def each_line(aSepString = $/)
129
+ while true
130
+ yield readline(aSepString)
131
+ end
132
+ rescue EOFError
133
+ end
134
+
135
+ alias_method :each, :each_line
136
+ end
137
+
138
+
139
+ # Implements many of the output convenience methods of IO.
140
+ # relies on <<
141
+ module AbstractOutputStream
142
+ include FakeIO
143
+
144
+ def write(data)
145
+ self << data
146
+ data.to_s.bytesize
147
+ end
148
+
149
+
150
+ def print(*params)
151
+ self << params.join($,) << $\.to_s
152
+ end
153
+
154
+ def printf(aFormatString, *params)
155
+ self << sprintf(aFormatString, *params)
156
+ end
157
+
158
+ def putc(anObject)
159
+ self << case anObject
160
+ when Fixnum then
161
+ anObject.chr
162
+ when String then
163
+ anObject
164
+ else
165
+ raise TypeError, "putc: Only Fixnum and String supported"
166
+ end
167
+ anObject
168
+ end
169
+
170
+ def puts(*params)
171
+ params << "\n" if params.empty?
172
+ params.flatten.each do |element|
173
+ val = element.to_s
174
+ self << val
175
+ self << "\n" unless val[-1, 1] == "\n"
176
+ end
177
+ end
178
+
179
+ end
180
+
181
+ end # IOExtras namespace module
182
+ end
183
+
184
+ # Copyright (C) 2002-2004 Thomas Sondergaard
185
+ # rubyzip is free software; you can redistribute it and/or
186
+ # modify it under the terms of the ruby license.
@@ -0,0 +1,15 @@
1
+ module Zip
2
+ class NullCompressor < Compressor #:nodoc:all
3
+ include Singleton
4
+
5
+ def <<(data)
6
+ raise IOError, "closed stream"
7
+ end
8
+
9
+ attr_reader :size, :compressed_size
10
+ end
11
+ end
12
+
13
+ # Copyright (C) 2002, 2003 Thomas Sondergaard
14
+ # rubyzip is free software; you can redistribute it and/or
15
+ # modify it under the terms of the ruby license.
@@ -0,0 +1,27 @@
1
+ module Zip
2
+ class NullDecompressor #:nodoc:all
3
+ include Singleton
4
+
5
+ def sysread(numberOfBytes = nil, buf = nil)
6
+ nil
7
+ end
8
+
9
+ def produce_input
10
+ nil
11
+ end
12
+
13
+ def input_finished?
14
+ true
15
+ end
16
+
17
+ def eof
18
+ true
19
+ end
20
+
21
+ alias :eof? :eof
22
+ end
23
+ end
24
+
25
+ # Copyright (C) 2002, 2003 Thomas Sondergaard
26
+ # rubyzip is free software; you can redistribute it and/or
27
+ # modify it under the terms of the ruby license.
@@ -0,0 +1,9 @@
1
+ module Zip
2
+ class NullInputStream < NullDecompressor #:nodoc:all
3
+ include ::Zip::IOExtras::AbstractInputStream
4
+ end
5
+ end
6
+
7
+ # Copyright (C) 2002, 2003 Thomas Sondergaard
8
+ # rubyzip is free software; you can redistribute it and/or
9
+ # modify it under the terms of the ruby license.