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,175 @@
1
+ module Zip
2
+ # ZipOutputStream is the basic class for writing zip files. It is
3
+ # possible to create a ZipOutputStream object directly, passing
4
+ # the zip file name to the constructor, but more often than not
5
+ # the ZipOutputStream 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 ZipOutputStream inherits IOExtras::AbstractOutputStream in order
10
+ # to provide an IO-like interface for writing to a single zip
11
+ # entry. Beyond methods for mimicking an IO-object it contains
12
+ # the method put_next_entry that closes the current entry
13
+ # and creates a new.
14
+ #
15
+ # Please refer to ZipInputStream for example code.
16
+ #
17
+ # java.util.zip.ZipOutputStream is the original inspiration for this
18
+ # class.
19
+
20
+ class OutputStream
21
+ include ::Zip::IOExtras::AbstractOutputStream
22
+
23
+ attr_accessor :comment
24
+
25
+ # Opens the indicated zip file. If a file with that name already
26
+ # exists it will be overwritten.
27
+ def initialize(fileName, stream=false)
28
+ super()
29
+ @fileName = fileName
30
+ if stream
31
+ @output_stream = ::StringIO.new
32
+ else
33
+ @output_stream = ::File.new(@fileName, "wb")
34
+ end
35
+ @entry_set = ::Zip::EntrySet.new
36
+ @compressor = ::Zip::NullCompressor.instance
37
+ @closed = false
38
+ @currentEntry = nil
39
+ @comment = nil
40
+ end
41
+
42
+ # Same as #initialize but if a block is passed the opened
43
+ # stream is passed to the block and closed when the block
44
+ # returns.
45
+ class << self
46
+ def open(fileName)
47
+ return new(fileName) unless block_given?
48
+ zos = new(fileName)
49
+ yield zos
50
+ ensure
51
+ zos.close if zos
52
+ end
53
+
54
+ # Same as #open but writes to a filestream instead
55
+ def write_buffer
56
+ zos = new('', true)
57
+ yield zos
58
+ return zos.close_buffer
59
+ end
60
+ end
61
+
62
+ # Closes the stream and writes the central directory to the zip file
63
+ def close
64
+ return if @closed
65
+ finalize_current_entry
66
+ update_local_headers
67
+ write_central_directory
68
+ @output_stream.close
69
+ @closed = true
70
+ end
71
+
72
+ # Closes the stream and writes the central directory to the zip file
73
+ def close_buffer
74
+ return @output_stream if @closed
75
+ finalize_current_entry
76
+ update_local_headers
77
+ write_central_directory
78
+ @closed = true
79
+ @output_stream
80
+ end
81
+
82
+ # Closes the current entry and opens a new for writing.
83
+ # +entry+ can be a ZipEntry object or a string.
84
+ def put_next_entry(entryname, comment = nil, extra = nil, compression_method = Entry::DEFLATED, level = Zlib::DEFAULT_COMPRESSION)
85
+ raise ZipError, "zip stream is closed" if @closed
86
+ if entryname.kind_of?(Entry)
87
+ new_entry = entryname
88
+ else
89
+ new_entry = Entry.new(@fileName, entryname.to_s)
90
+ end
91
+ new_entry.comment = comment if !comment.nil?
92
+ if (!extra.nil?)
93
+ new_entry.extra = ExtraField === extra ? extra : ExtraField.new(extra.to_s)
94
+ end
95
+ new_entry.compression_method = compression_method if !compression_method.nil?
96
+ init_next_entry(new_entry, level)
97
+ @currentEntry = new_entry
98
+ end
99
+
100
+ def copy_raw_entry(entry)
101
+ entry = entry.dup
102
+ raise ZipError, "zip stream is closed" if @closed
103
+ raise ZipError, "entry is not a ZipEntry" if !entry.kind_of?(Entry)
104
+ finalize_current_entry
105
+ @entry_set << entry
106
+ src_pos = entry.local_entry_offset
107
+ entry.write_local_entry(@output_stream)
108
+ @compressor = NullCompressor.instance
109
+ entry.get_raw_input_stream do |is|
110
+ is.seek(src_pos, IO::SEEK_SET)
111
+ IOExtras.copy_stream_n(@output_stream, is, entry.compressed_size)
112
+ end
113
+ @compressor = NullCompressor.instance
114
+ @currentEntry = nil
115
+ end
116
+
117
+ private
118
+
119
+ def finalize_current_entry
120
+ return unless @currentEntry
121
+ finish
122
+ @currentEntry.compressed_size = @output_stream.tell - @currentEntry.local_header_offset - @currentEntry.calculate_local_header_size
123
+ @currentEntry.size = @compressor.size
124
+ @currentEntry.crc = @compressor.crc
125
+ @currentEntry = nil
126
+ @compressor = NullCompressor.instance
127
+ end
128
+
129
+ def init_next_entry(entry, level = Zlib::DEFAULT_COMPRESSION)
130
+ finalize_current_entry
131
+ @entry_set << entry
132
+ entry.write_local_entry(@output_stream)
133
+ @compressor = get_compressor(entry, level)
134
+ end
135
+
136
+ def get_compressor(entry, level)
137
+ case entry.compression_method
138
+ when Entry::DEFLATED then Deflater.new(@output_stream, level)
139
+ when Entry::STORED then PassThruCompressor.new(@output_stream)
140
+ else raise ZipCompressionMethodError,
141
+ "Invalid compression method: '#{entry.compression_method}'"
142
+ end
143
+ end
144
+
145
+ def update_local_headers
146
+ pos = @output_stream.pos
147
+ @entry_set.each do |entry|
148
+ @output_stream.pos = entry.local_header_offset
149
+ entry.write_local_entry(@output_stream)
150
+ end
151
+ @output_stream.pos = pos
152
+ end
153
+
154
+ def write_central_directory
155
+ cdir = CentralDirectory.new(@entry_set, @comment)
156
+ cdir.write_to_stream(@output_stream)
157
+ end
158
+
159
+ protected
160
+
161
+ def finish
162
+ @compressor.finish
163
+ end
164
+
165
+ public
166
+ # Modeled after IO.<<
167
+ def << (data)
168
+ @compressor << data
169
+ end
170
+ end
171
+ end
172
+
173
+ # Copyright (C) 2002, 2003 Thomas Sondergaard
174
+ # rubyzip is free software; you can redistribute it and/or
175
+ # modify it under the terms of the ruby license.
@@ -0,0 +1,23 @@
1
+ module Zip
2
+ class PassThruCompressor < Compressor #:nodoc:all
3
+ def initialize(outputStream)
4
+ super()
5
+ @output_stream = outputStream
6
+ @crc = Zlib::crc32
7
+ @size = 0
8
+ end
9
+
10
+ def << (data)
11
+ val = data.to_s
12
+ @crc = Zlib::crc32(val, @crc)
13
+ @size += val.bytesize
14
+ @output_stream << val
15
+ end
16
+
17
+ attr_reader :size, :crc
18
+ end
19
+ end
20
+
21
+ # Copyright (C) 2002, 2003 Thomas Sondergaard
22
+ # rubyzip is free software; you can redistribute it and/or
23
+ # modify it under the terms of the ruby license.
@@ -0,0 +1,41 @@
1
+ module Zip
2
+ class PassThruDecompressor < Decompressor #:nodoc:all
3
+
4
+ def initialize(input_stream, chars_to_read)
5
+ super(input_stream)
6
+ @chars_to_read = chars_to_read
7
+ @read_so_far = 0
8
+ @has_returned_empty_string = false
9
+ end
10
+
11
+ def sysread(number_of_bytes = nil, buf = nil)
12
+ if input_finished?
13
+ has_returned_empty_string_val = @has_returned_empty_string
14
+ @has_returned_empty_string = true
15
+ return '' unless has_returned_empty_string_val
16
+ return
17
+ end
18
+
19
+ if (number_of_bytes == nil || @read_so_far + number_of_bytes > @chars_to_read)
20
+ number_of_bytes = @chars_to_read - @read_so_far
21
+ end
22
+ @read_so_far += number_of_bytes
23
+ @input_stream.read(number_of_bytes, buf)
24
+ end
25
+
26
+ def produce_input
27
+ sysread(::Zip::Decompressor::CHUNK_SIZE)
28
+ end
29
+
30
+ def input_finished?
31
+ @read_so_far >= @chars_to_read
32
+ end
33
+
34
+ alias :eof :input_finished?
35
+ alias :eof? :input_finished?
36
+ end
37
+ end
38
+
39
+ # Copyright (C) 2002, 2003 Thomas Sondergaard
40
+ # rubyzip is free software; you can redistribute it and/or
41
+ # modify it under the terms of the ruby license.
@@ -0,0 +1,15 @@
1
+ module Zip
2
+ class StreamableDirectory < Entry
3
+ def initialize(zipfile, entry, srcPath = nil, permissionInt = nil)
4
+ super(zipfile, entry)
5
+
6
+ @ftype = :directory
7
+ entry.get_extra_attributes_from_path(srcPath) if (srcPath)
8
+ @unix_perms = permissionInt if (permissionInt)
9
+ end
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,47 @@
1
+ module Zip
2
+ class StreamableStream < DelegateClass(Entry) #nodoc:all
3
+ def initialize(entry)
4
+ super(entry)
5
+ @tempFile = Tempfile.new(::File.basename(name), ::File.dirname(zipfile))
6
+ @tempFile.binmode
7
+ end
8
+
9
+ def get_output_stream
10
+ if block_given?
11
+ begin
12
+ yield(@tempFile)
13
+ ensure
14
+ @tempFile.close
15
+ end
16
+ else
17
+ @tempFile
18
+ end
19
+ end
20
+
21
+ def get_input_stream
22
+ if ! @tempFile.closed?
23
+ raise StandardError, "cannot open entry for reading while its open for writing - #{name}"
24
+ end
25
+ @tempFile.open # reopens tempfile from top
26
+ @tempFile.binmode
27
+ if block_given?
28
+ begin
29
+ yield(@tempFile)
30
+ ensure
31
+ @tempFile.close
32
+ end
33
+ else
34
+ @tempFile
35
+ end
36
+ end
37
+
38
+ def write_to_zip_output_stream(aZipOutputStream)
39
+ aZipOutputStream.put_next_entry(self)
40
+ get_input_stream { |is| ::Zip::IOExtras.copy_stream(aZipOutputStream, is) }
41
+ end
42
+ end
43
+ end
44
+
45
+ # Copyright (C) 2002, 2003 Thomas Sondergaard
46
+ # rubyzip is free software; you can redistribute it and/or
47
+ # modify it under the terms of the ruby license.
@@ -0,0 +1,3 @@
1
+ module Zip
2
+ VERSION = '0.1.0'
3
+ end
@@ -0,0 +1,91 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $: << "../lib"
4
+ system("zip example.zip example.rb gtkRubyzip.rb")
5
+
6
+ require 'zip/zip'
7
+
8
+ ####### Using ZipInputStream alone: #######
9
+
10
+ Zip::InputStream.open("example.zip") {
11
+ |zis|
12
+ entry = zis.get_next_entry
13
+ print "First line of '#{entry.name} (#{entry.size} bytes): "
14
+ puts "'#{zis.gets.chomp}'"
15
+ entry = zis.get_next_entry
16
+ print "First line of '#{entry.name} (#{entry.size} bytes): "
17
+ puts "'#{zis.gets.chomp}'"
18
+ }
19
+
20
+
21
+ ####### Using ZipFile to read the directory of a zip file: #######
22
+
23
+ zf = Zip::File.new("example.zip")
24
+ zf.each_with_index {
25
+ |entry, index|
26
+
27
+ puts "entry #{index} is #{entry.name}, size = #{entry.size}, compressed size = #{entry.compressed_size}"
28
+ # use zf.get_input_stream(entry) to get a ZipInputStream for the entry
29
+ # entry can be the ZipEntry object or any object which has a to_s method that
30
+ # returns the name of the entry.
31
+ }
32
+
33
+
34
+ ####### Using ZipOutputStream to write a zip file: #######
35
+
36
+ Zip::OutputStream.open("exampleout.zip") {
37
+ |zos|
38
+ zos.put_next_entry("the first little entry")
39
+ zos.puts "Hello hello hello hello hello hello hello hello hello"
40
+
41
+ zos.put_next_entry("the second little entry")
42
+ zos.puts "Hello again"
43
+
44
+ # Use rubyzip or your zip client of choice to verify
45
+ # the contents of exampleout.zip
46
+ }
47
+
48
+ ####### Using ZipFile to change a zip file: #######
49
+
50
+ Zip::File.open("exampleout.zip") {
51
+ |zf|
52
+ zf.add("thisFile.rb", "example.rb")
53
+ zf.rename("thisFile.rb", "ILikeThisName.rb")
54
+ zf.add("Again", "example.rb")
55
+ }
56
+
57
+ # Lets check
58
+ Zip::File.open("exampleout.zip") {
59
+ |zf|
60
+ puts "Changed zip file contains: #{zf.entries.join(', ')}"
61
+ zf.remove("Again")
62
+ puts "Without 'Again': #{zf.entries.join(', ')}"
63
+ }
64
+
65
+ ####### Using ZipFile to split a zip file: #######
66
+
67
+ # Creating large zip file for splitting
68
+ Zip::OutputStream.open("large_zip_file.zip") do |zos|
69
+ puts "Creating zip file..."
70
+ 10.times do |i|
71
+ zos.put_next_entry("large_entry_#{i}.txt")
72
+ zos.puts "Hello" * 104857600
73
+ end
74
+ end
75
+
76
+ # Splitting created large zip file
77
+ part_zips_count = Zip::File.split("large_zip_file.zip", 2097152, false)
78
+ puts "Zip file splitted in #{part_zips_count} parts"
79
+
80
+ # Track splitting an archive
81
+ Zip::File.split("large_zip_file.zip", 1048576, true, 'part_zip_file') do
82
+ |part_count, part_index, chunk_bytes, segment_bytes|
83
+ puts "#{part_index} of #{part_count} part splitting: #{(chunk_bytes.to_f/segment_bytes.to_f * 100).to_i}%"
84
+ end
85
+
86
+
87
+ # For other examples, look at zip.rb and ziptest.rb
88
+
89
+ # Copyright (C) 2002 Thomas Sondergaard
90
+ # rubyzip is free software; you can redistribute it and/or
91
+ # modify it under the terms of the ruby license.
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $: << "../lib"
4
+
5
+ require 'zip/zipfilesystem'
6
+
7
+ EXAMPLE_ZIP = "filesystem.zip"
8
+
9
+ File.delete(EXAMPLE_ZIP) if File.exists?(EXAMPLE_ZIP)
10
+
11
+ Zip::File.open(EXAMPLE_ZIP, Zip::File::CREATE) {
12
+ |zf|
13
+ zf.file.open("file1.txt", "w") { |os| os.write "first file1.txt" }
14
+ zf.dir.mkdir("dir1")
15
+ zf.dir.chdir("dir1")
16
+ zf.file.open("file1.txt", "w") { |os| os.write "second file1.txt" }
17
+ puts zf.file.read("file1.txt")
18
+ puts zf.file.read("../file1.txt")
19
+ zf.dir.chdir("..")
20
+ zf.file.open("file2.txt", "w") { |os| os.write "first file2.txt" }
21
+ puts "Entries: #{zf.entries.join(', ')}"
22
+ }
23
+
24
+ Zip::File.open(EXAMPLE_ZIP) {
25
+ |zf|
26
+ puts "Entries from reloaded zip: #{zf.entries.join(', ')}"
27
+ }
28
+
29
+ # For other examples, look at zip.rb and ziptest.rb
30
+
31
+ # Copyright (C) 2003 Thomas Sondergaard
32
+ # rubyzip is free software; you can redistribute it and/or
33
+ # modify it under the terms of the ruby license.
@@ -0,0 +1,49 @@
1
+ require 'zip/zip'
2
+
3
+ # This is a simple example which uses rubyzip to
4
+ # recursively generate a zip file from the contents of
5
+ # a specified directory. The directory itself is not
6
+ # included in the archive, rather just its contents.
7
+ #
8
+ # Usage:
9
+ # directoryToZip = "/tmp/input"
10
+ # outputFile = "/tmp/out.zip"
11
+ # zf = ZipFileGenerator.new(directoryToZip, outputFile)
12
+ # zf.write()
13
+ class ZipFileGenerator
14
+
15
+ # Initialize with the directory to zip and the location of the output archive.
16
+ def initialize(inputDir, outputFile)
17
+ @inputDir = inputDir
18
+ @outputFile = outputFile
19
+ end
20
+
21
+ # Zip the input directory.
22
+ def write()
23
+ entries = Dir.entries(@inputDir); entries.delete("."); entries.delete("..")
24
+ io = Zip::File.open(@outputFile, Zip::File::CREATE);
25
+
26
+ writeEntries(entries, "", io)
27
+ io.close();
28
+ end
29
+
30
+ # A helper method to make the recursion work.
31
+ private
32
+ def writeEntries(entries, path, io)
33
+
34
+ entries.each { |e|
35
+ zipFilePath = path == "" ? e : File.join(path, e)
36
+ diskFilePath = File.join(@inputDir, zipFilePath)
37
+ puts "Deflating " + diskFilePath
38
+ if File.directory?(diskFilePath)
39
+ io.mkdir(zipFilePath)
40
+ subdir =Dir.entries(diskFilePath); subdir.delete("."); subdir.delete("..")
41
+ writeEntries(subdir, zipFilePath, io)
42
+ else
43
+ io.get_output_stream(zipFilePath) { |f| f.puts(File.open(diskFilePath, "rb").read())}
44
+ end
45
+ }
46
+ end
47
+
48
+ end
49
+