superp-rubyzip 0.1.0

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.
@@ -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
+