archive-zip 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/HACKING ADDED
@@ -0,0 +1,122 @@
1
+ = Guide to Hacking Archive::Zip
2
+
3
+ == Licensing
4
+
5
+ Contributed code must be licensed under the same license as this project. See
6
+ the included LICENSE file for details. Special consideration MAY be made in
7
+ some cases, but such cases will be rare.
8
+
9
+
10
+ == Dependencies
11
+
12
+ === Runtime
13
+
14
+ * Ruby 1.8.6 or greater
15
+
16
+
17
+ === Build
18
+
19
+ * rubygems 0.9.0 or greater
20
+ * rake 0.8.1 or greater
21
+ * allison 2.0.3 (optional - used for documentation only, if available)
22
+ * rsync (optional - used for publishing documentation)
23
+
24
+
25
+ === Install
26
+
27
+ * rubygems 0.9.0 or greater
28
+
29
+
30
+ == Versioning Policy
31
+
32
+ Version numbers will be in <em>x.y.z</em> format, where <em>x</em>, <em>y</em>,
33
+ and <em>z</em> are integers starting from 0. The version increment rules are
34
+ as follows:
35
+
36
+ <b>x</b>:: Planned releases which implement significant changes and/or break API
37
+ compatibility. An exception is to be made for the transition from
38
+ the <em>0.y.z</em> series to the <em>1.y.z</em> series since the
39
+ <em>0.y.z</em> series is expected to be unstable throughout
40
+ development. When incremented, <em>y</em> and <em>z</em> are reset
41
+ to 0.
42
+ <b>y</b>:: Planned releases which incorporate numerous bug fixes and/or new
43
+ features which do not break backward compatibility. When
44
+ incremented, <em>z</em> is reset to 0.
45
+ <b>z</b>:: Generally, unplanned releases which incorporate a single fix for a
46
+ critical defect.
47
+
48
+ This is the {Rational Versioning Policy}[http://www.rubygems.org/read/chapter/7]
49
+ as outlined in the {RubyGems User Guide}[http://www.rubygems.org/read/book/1].
50
+
51
+
52
+ == Support Policy
53
+
54
+ Due to limitations in resources (time/money/manpower), this project will focus
55
+ primarily upon the development line of the current release at any given time.
56
+ Fixes and new features should be applied first to that development line and then
57
+ backported to earlier releases if necessary and feasible. Long term maintenance
58
+ of previous releases is not planned. Users are generally expected to upgrade to
59
+ the latest release in order to receive updates unless an explicit declaration of
60
+ support for a previous release is made.
61
+
62
+
63
+ == Coding Style
64
+
65
+ The following points are not necessarily set in stone but should rather be used
66
+ as a good guideline. Consistency is the goal of coding style, and changes will
67
+ be more easily accepted if they are consistent with the rest of the code.
68
+
69
+ <b>File Encoding</b>:: UTF-8
70
+ <b>Indentation</b>:: Two spaces; no tabs
71
+ <b>Comments</b>:: Document classes, attributes, methods, and code
72
+ <b>Boolean Operators</b>:: Use <tt>&&</tt> and <tt>||</tt> for boolean tests;
73
+ avoid <tt>and</tt> and <tt>or</tt>
74
+ <b>Method Calls</b>:: Use <tt>a_method(arg, arg, etc)</tt>; <b>not</b>
75
+ <tt>a_method( arg, arg, etc )</tt>,
76
+ <tt>a_method arg, arg, etc</tt>, or any other
77
+ variation
78
+ <b>Blocks</b>:: <tt>do end</tt> for multi-line blocks and
79
+ <tt>{ }</tt> for single-line blocks
80
+ <b>Line length</b>:: Limit lines to a maximum of 80 characters
81
+ <b>General</b>:: Try to follow the flow and style of the rest of the
82
+ code
83
+
84
+
85
+ == Generating Patches
86
+
87
+ Patches should usually be generated against the <em>HEAD</em> revision of the
88
+ <em>master</em> branch. When generating patches, please try to implement only
89
+ a single feature or bug fix per patch. Documentation describing a patch should
90
+ be included along with the patch so that the maintainer can more easily
91
+ determine whether or not a patch is acceptable. Patches lacking the necessary
92
+ documentation will be ignored.
93
+
94
+ Patches will be much more readily accepted if test cases are provided which
95
+ verify correct operation. Such test cases should be provided within the patch
96
+ rather than as a separate patch. Proper documentation, especially for
97
+ user-visible APIs, is highly prized; providing accurate and detailed
98
+ documentation, often in the form of rubydocs, throughout new code contributions
99
+ will also increase the desirability of a patch.
100
+
101
+ If a series of patches is generated which cannot be applied individually, make
102
+ sure to mention the dependency relationships in whatever medium is being used
103
+ to distribute the patches. For instance, if a bug is discovered while
104
+ implementing a new feature, create a patch which fixes the bug followed by a
105
+ separate patch adding the feature. If the feature patch requires the bug fix
106
+ patch in order to work, note that dependency in the comments for the feature
107
+ patch by somehow referencing the bug fix patch.
108
+
109
+ The patch generation process in general:
110
+ $ git clone git://rubyforge.org/archive-zip.git # Clone the repo and check out
111
+ # the master branch.
112
+ $ cd archive-zip # Enter the workspace.
113
+ (make and test changes)
114
+ $ git add file1 file2 .. # Add new/modified files.
115
+ $ git commit # Commit changes.
116
+ $ git format-patch -C HEAD^ # Create a patch for the last
117
+ # commit.
118
+
119
+ Repeat as necessary until all patches are generated. Then either attach them to
120
+ 1 or more email messages addressed to the maintainer or attach them to tickets
121
+ in the issue tracker for the project. Remember to include a brief description
122
+ of the patch and its dependencies, if any.
data/LEGAL ADDED
@@ -0,0 +1,8 @@
1
+ = Other Legalities
2
+
3
+ == Files Licensed Differently
4
+
5
+ The following file(s) are provided under a license or licenses separate from
6
+ this project.
7
+
8
+ None at present
data/LICENSE ADDED
@@ -0,0 +1,57 @@
1
+ LICENSE text follows:
2
+
3
+ Archive::Zip is copyrighted free software by Jeremy Bopp
4
+ <jeremy at bopp dot net>. You can redistribute it and/or modify it under
5
+ either the terms of the GPL (see the included GPL file), or the conditions
6
+ below:
7
+
8
+ 1. You may make and give away verbatim copies of the source form of the
9
+ software without restriction, provided that you duplicate all of the
10
+ original copyright notices and associated disclaimers.
11
+
12
+ 2. You may modify your copy of the software in any way, provided that
13
+ you do at least ONE of the following:
14
+
15
+ a) place your modifications in the Public Domain or otherwise
16
+ make them Freely Available, such as by posting said
17
+ modifications to Usenet or an equivalent medium, or by allowing
18
+ the author to include your modifications in the software.
19
+
20
+ b) use the modified software only within your corporation or
21
+ organization.
22
+
23
+ c) rename any non-standard executables so the names do not conflict
24
+ with standard executables, which must also be provided.
25
+
26
+ d) make other distribution arrangements with the author.
27
+
28
+ 3. You may distribute the software in object code or executable
29
+ form, provided that you do at least ONE of the following:
30
+
31
+ a) distribute the executables and library files of the software,
32
+ together with instructions (in the manual page or equivalent)
33
+ on where to get the original distribution.
34
+
35
+ b) accompany the distribution with the machine-readable source of
36
+ the software.
37
+
38
+ c) give non-standard executables non-standard names, with
39
+ instructions on where to get the original software distribution.
40
+
41
+ d) make other distribution arrangements with the author.
42
+
43
+ 4. You may modify and include the covered part of the software into any
44
+ other software (possibly commercial). But some files in the
45
+ distribution may not be written by the author, such that they are not
46
+ under these terms. (See the file LEGAL for a listing and conditions)
47
+
48
+ 5. The scripts and library files supplied as input to or produced as
49
+ output from the software do not automatically fall under the
50
+ copyright of the software, but belong to whomever generated them,
51
+ and may be sold commercially, and may be aggregated with this
52
+ software.
53
+
54
+ 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
55
+ IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
56
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
57
+ PURPOSE.
data/MANIFEST ADDED
@@ -0,0 +1,26 @@
1
+ CONTRIBUTORS
2
+ GPL
3
+ HACKING
4
+ LEGAL
5
+ LICENSE
6
+ MANIFEST
7
+ NEWS
8
+ README
9
+ lib/archive/support/io-like.rb
10
+ lib/archive/support/io.rb
11
+ lib/archive/support/iowindow.rb
12
+ lib/archive/support/stringio.rb
13
+ lib/archive/support/time.rb
14
+ lib/archive/support/zlib.rb
15
+ lib/archive/zip.rb
16
+ lib/archive/zip/codec.rb
17
+ lib/archive/zip/codec/deflate.rb
18
+ lib/archive/zip/codec/store.rb
19
+ lib/archive/zip/entry.rb
20
+ lib/archive/zip/datadescriptor.rb
21
+ lib/archive/zip/extrafield.rb
22
+ lib/archive/zip/extrafield/extendedtimestamp.rb
23
+ lib/archive/zip/extrafield/raw.rb
24
+ lib/archive/zip/extrafield/unix.rb
25
+ lib/archive/zip/error.rb
26
+ test/test_archive.rb
data/NEWS ADDED
@@ -0,0 +1,22 @@
1
+ = News and Notifications by Version
2
+
3
+ This file lists noteworthy changes which may affect users of this project. More
4
+ detailed information is available in the rest of the documentation.
5
+
6
+ <b>NOTE:</b> Date stamps in the following entries are in YYYY/MM/DD format.
7
+
8
+
9
+ == v0.1.0 (2008/07/10)
10
+
11
+ * Initial release
12
+ * Archive creation and extraction is supported with only a few lines of code
13
+ (See README)
14
+ * Archives can be updated "in place" or dumped out to other files or pipes
15
+ * Files, symlinks, and directories are supported within archives
16
+ * Unix permission/mode bits are supported
17
+ * Unix user and group ownerships are supported.
18
+ * Unix last accessed and last modified times are supported.
19
+ * Entry extension (AKA extra field) implementations can be added on the fly.
20
+ * Unknown entry extension types are preserved during archive processing.
21
+ * Deflate and Store compression codecs supported out of the box
22
+ * More compression codecs can be added on the fly
data/README ADDED
@@ -0,0 +1,130 @@
1
+ = Archive::Zip - ZIP Archival Made Easy
2
+
3
+ The Archive::Zip library intends to provide a simple, yet complete and
4
+ Ruby-esque, interface to working with ZIP archives.
5
+
6
+ Basic archive creation and extraction can be handled using only a few methods.
7
+ More complex operations involving the manipulation of existing archives in place
8
+ (adding, removing, and modifying entries) are also possible with a little more
9
+ work. Even adding advanced features such as new compression codecs are
10
+ supported with a moderate amount of effort.
11
+
12
+
13
+ == License
14
+
15
+ Copyright © 2008 Jeremy Bopp <jeremy at bopp dot net>
16
+
17
+ Licensed under the same terms as Ruby -- See the included LICENSE file for
18
+ details
19
+
20
+
21
+ == Installation/Removal
22
+
23
+ Download the GEM file and install it with:
24
+ % sudo gem install archive-zip-VERSION.gem
25
+
26
+ or directly with:
27
+ % sudo gem install archive-zip
28
+
29
+ Removal is the same in either case:
30
+ % sudo gem uninstall archive-zip
31
+
32
+
33
+ == Example
34
+ More examples can be found in the +examples+ directory of the source
35
+ distribution.
36
+
37
+ Create a few archives:
38
+ gem 'archive-zip' # Use require_gem for rubygems versions older than 0.9.0.
39
+ require 'archive/zip'
40
+
41
+ # Add a_directory and its contents to example1.zip.
42
+ Archive::Zip.archive('example1.zip', 'a_directory')
43
+
44
+ # Add the contents of a_directory to example2.zip.
45
+ Archive::Zip.archive('example2.zip', 'a_directory/.')
46
+
47
+ # Add a_file and a_directory and its contents to example3.zip.
48
+ Archive::Zip.archive('example3.zip', ['a_directory', 'a_file'])
49
+
50
+ # Add only the files and symlinks contained in a_directory under the path
51
+ # a/b/c/a_directory in example4.zip.
52
+ Archive::Zip.archive(
53
+ 'example4.zip',
54
+ 'a_directory',
55
+ :directories => false,
56
+ :path_prefix => 'a/b/c'
57
+ )
58
+
59
+ # Create a new archive which will be written to a pipe.
60
+ # Assume $stdout is the write end a pipe.
61
+ # (ruby example.rb | cat >example.zip)
62
+ Archive::Zip.open(nil, $stdout) do |z|
63
+ z.archive('a_directory')
64
+ end
65
+
66
+ Now extract those archives:
67
+ gem 'archive-zip' # Use require_gem for rubygems versions older than 0.9.0.
68
+ require 'archive/zip'
69
+
70
+ # Extract example1.zip to a_destination.
71
+ Archive::Zip.extract('example1.zip', 'a_destination')
72
+
73
+ # Extract example2.zip to a_destination, skipping directory entries.
74
+ Archive::Zip.extract(
75
+ 'example2.zip',
76
+ 'a_destination',
77
+ :directories => false
78
+ )
79
+
80
+ # Extract example3.zip to a_destination, skipping symlinks.
81
+ Archive::Zip.extract(
82
+ 'example3.zip',
83
+ 'a_destination',
84
+ :symlinks => false
85
+ )
86
+
87
+ # Extract example4.zip to a_destination, skipping entries for which files
88
+ # already exist but are newer or for which files do not exist at all.
89
+ Archive::Zip.extract(
90
+ 'example4.zip',
91
+ 'a_destination',
92
+ :create => false,
93
+ :overwrite => :older
94
+ )
95
+
96
+
97
+ == Features
98
+
99
+ 1. 100% native Ruby. (Well, almost... depends on zlib.)
100
+ 2. Archive creation and extraction is supported with only a few lines of code.
101
+ 3. Archives can be updated "in place" or dumped out to other files or pipes.
102
+ 4. Files, symlinks, and directories are supported within archives.
103
+ 5. Unix permission/mode bits are supported.
104
+ 6. Unix user and group ownerships are supported.
105
+ 7. Unix last accessed and last modified times are supported.
106
+ 8. Entry extension (AKA extra field) implementations can be added on the fly.
107
+ 9. Unknown entry extension types are preserved during archive processing.
108
+ 10. The Deflate and Store compression codecs are supported out of the box.
109
+ 11. More compression codecs can be added on the fly.
110
+
111
+
112
+ == Known Bugs/Limitations
113
+
114
+ 1. More testcases are needed.
115
+ 2. All file entries are archived and extracted in binary mode. No attempt is
116
+ made to normalize text files to the line ending convention of any target
117
+ system.
118
+ 3. Hard links and device files are not currently supported within archives.
119
+ 4. Reading archives from non-seekable IO, such as pipes and sockets, is not
120
+ supported.
121
+ 5. MSDOS permission attributes are not supported.
122
+ 6. Encryption is not supported.
123
+ 7. Zip64 is not supported.
124
+ 8. Digital signatures are not supported.
125
+
126
+
127
+ == Contributing
128
+
129
+ Contributions for bug fixes, documentation, extensions, tests, etc. are
130
+ encouraged. Please read the file HACKING for details.
@@ -0,0 +1,12 @@
1
+ # Try to first load io-like from rubygems and then fall back to assuming a
2
+ # standard installation.
3
+ begin
4
+ require 'rubygems'
5
+ gem 'io-like', '>= 0.1.0'
6
+ rescue LoadError
7
+ # Failed to load via rubygems.
8
+ end
9
+
10
+ # This will work for the gem and standard install assuming io-like is available
11
+ # at all.
12
+ require 'io/like'
@@ -0,0 +1,14 @@
1
+ require 'readbytes'
2
+
3
+ class IO
4
+ # Returns +true+ if the seek method of this IO instance would succeed, +false+
5
+ # otherwise.
6
+ def seekable?
7
+ begin
8
+ pos
9
+ true
10
+ rescue SystemCallError
11
+ false
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,123 @@
1
+ require 'archive/support/io-like'
2
+
3
+ # IOWindow represents an IO object which wraps another one allowing read access
4
+ # to a subset of the data within the stream.
5
+ #
6
+ # <b>NOTE:</b> This object is NOT thread safe.
7
+ class IOWindow
8
+ include IO::Like
9
+
10
+ # Creates a new instance of this class using _io_ as the data source
11
+ # and where _window_position_ and _window_size_ define the location and size
12
+ # of data window respectively.
13
+ #
14
+ # _io_ must be opened for reading and must be seekable. _window_position_
15
+ # must be an integer greater than or equal to 0. _window_size_ must be an
16
+ # integer greater than or equal to 0.
17
+ def initialize(io, window_position, window_size)
18
+ raise ArgumentError, 'non-seekable IO object given' unless io.seekable?
19
+
20
+ @io = io
21
+ @unbuffered_pos = 0
22
+ self.window_position = window_position
23
+ self.window_size = window_size
24
+ end
25
+
26
+ # The file position at which this window begins.
27
+ attr_reader :window_position
28
+
29
+ # Set the file position at which this window begins.
30
+ # _window_position_ must be an integer greater than or equal to 0.
31
+ def window_position=(window_position)
32
+ unless window_position.kind_of?(Fixnum) then
33
+ raise ArgumentError, 'non-integer window position given'
34
+ end
35
+ if window_position < 0 then
36
+ raise ArgumentError, 'non-positive window position given'
37
+ end
38
+
39
+ @window_position = window_position
40
+ end
41
+
42
+ # The size of the window.
43
+ attr_reader :window_size
44
+
45
+ # Set the size of the window.
46
+ # _window_size_ must be an integer greater than or equal to 0.
47
+ def window_size=(window_size)
48
+ unless window_size.kind_of?(Fixnum) then
49
+ raise ArgumentError, 'non-integer window size given'
50
+ end
51
+ raise ArgumentError, 'non-positive window size given' if window_size < 0
52
+
53
+ @window_size = window_size
54
+ end
55
+
56
+ private
57
+
58
+ def unbuffered_read(length)
59
+ restore_self
60
+
61
+ # Error out if the end of the window is reached.
62
+ raise EOFError, 'end of file reached' if @unbuffered_pos >= @window_size
63
+
64
+ # Limit the read operation to the window.
65
+ length = @window_size - @unbuffered_pos if @unbuffered_pos + length > @window_size
66
+
67
+ # Fill a buffer with the data from the delegate.
68
+ buffer = @io.read(length)
69
+ # Error out if the end of the delegate is reached.
70
+ raise EOFError, 'end of file reached' if buffer.nil?
71
+
72
+ # Update the position.
73
+ @unbuffered_pos += buffer.length
74
+
75
+ buffer
76
+ ensure
77
+ restore_delegate
78
+ end
79
+
80
+ def unbuffered_seek(offset, whence = IO::SEEK_SET)
81
+ # Convert the offset and whence into an absolute position.
82
+ case whence
83
+ when IO::SEEK_SET
84
+ new_pos = offset
85
+ when IO::SEEK_CUR
86
+ new_pos = @unbuffered_pos + offset
87
+ when IO::SEEK_END
88
+ new_pos = @window_size + offset
89
+ end
90
+
91
+ # Error out if the position is outside the window.
92
+ raise Errno::EINVAL, 'Invalid argument' if new_pos < 0 or new_pos > @window_size
93
+
94
+ # Set the new position.
95
+ @unbuffered_pos = new_pos
96
+ end
97
+
98
+ def unbuffered_write(string)
99
+ restore_self
100
+
101
+ # Ensure that the outputted string will not extend past the window.
102
+ string = string.slice(0, @window_size - @unbuffered_pos)
103
+ @io.write(string)
104
+ ensure
105
+ restore_delegate
106
+ end
107
+
108
+ # Restores the state of the delegate IO object to that saved by a prior call
109
+ # to #restore_self.
110
+ def restore_delegate
111
+ @io.pos = @delegate_pos
112
+ @io.lineno = @delegate_lineno
113
+ end
114
+
115
+ # Saves the state of the delegate IO object so that it can be restored later
116
+ # using #restore_delegate and then configures the delegate so as to restore
117
+ # the state of this object.
118
+ def restore_self
119
+ @delegate_pos = @io.pos
120
+ @delegate_lineno = @io.lineno
121
+ @io.pos = @window_position + @unbuffered_pos
122
+ end
123
+ end