zip-container 0.8.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,88 @@
1
+ # Copyright (c) 2013 The University of Manchester, UK.
2
+ #
3
+ # All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # * Redistributions of source code must retain the above copyright notice,
9
+ # this list of conditions and the following disclaimer.
10
+ #
11
+ # * Redistributions in binary form must reproduce the above copyright notice,
12
+ # this list of conditions and the following disclaimer in the documentation
13
+ # and/or other materials provided with the distribution.
14
+ #
15
+ # * Neither the names of The University of Manchester nor the names of its
16
+ # contributors may be used to endorse or promote products derived from this
17
+ # software without specific prior written permission.
18
+ #
19
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
+ # POSSIBILITY OF SUCH DAMAGE.
30
+ #
31
+ # Author: Robert Haines
32
+
33
+ require 'zip/zip_entry'
34
+
35
+ module ZipContainer
36
+
37
+ # This module provides support for reserved names.
38
+ module ReservedNames
39
+
40
+ # :call-seq:
41
+ # reserved_names -> Array
42
+ #
43
+ # Return a list of reserved file and directory names for this ZipContainer
44
+ # file.
45
+ #
46
+ # Reserved files and directories must be accessed directly by methods
47
+ # within Container (or subclasses of Container). This is because they are
48
+ # fundamental to the format and might need to exhibit certain properties
49
+ # (such as no compression) that must be preserved. The "mimetype" file is
50
+ # an example of such a reserved entry.
51
+ #
52
+ # To add a reserved name to a subclass of Container simply add it to the
53
+ # list in the constructor (you must call the super constructor first!):
54
+ #
55
+ # class MyContainer < ZipContainer::Container
56
+ # def initialize(filename)
57
+ # super(filename)
58
+ #
59
+ # register_reserved_name("my_reserved_name")
60
+ # end
61
+ # end
62
+ def reserved_names
63
+ @reserved_names ||= []
64
+ end
65
+
66
+ # :call-seq:
67
+ # reserved_entry?(entry) -> boolean
68
+ #
69
+ # Is the given entry in the reserved list of names? A String or a
70
+ # Zip::ZipEntry object can be passed in here.
71
+ def reserved_entry?(entry)
72
+ name = entry.kind_of?(::Zip::ZipEntry) ? entry.name : entry
73
+ name.chop! if name.end_with? "/"
74
+ reserved_names.map { |n| n.downcase }.include? name.downcase
75
+ end
76
+
77
+ protected
78
+
79
+ # :call-seq:
80
+ # register_reserved_name(name)
81
+ #
82
+ # Add a reserved name to the list.
83
+ def register_reserved_name(name)
84
+ @reserved_names ||= []
85
+ @reserved_names << name unless @reserved_names.include? name
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,70 @@
1
+ # Copyright (c) 2013 The University of Manchester, UK.
2
+ #
3
+ # All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # * Redistributions of source code must retain the above copyright notice,
9
+ # this list of conditions and the following disclaimer.
10
+ #
11
+ # * Redistributions in binary form must reproduce the above copyright notice,
12
+ # this list of conditions and the following disclaimer in the documentation
13
+ # and/or other materials provided with the distribution.
14
+ #
15
+ # * Neither the names of The University of Manchester nor the names of its
16
+ # contributors may be used to endorse or promote products derived from this
17
+ # software without specific prior written permission.
18
+ #
19
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
+ # POSSIBILITY OF SUCH DAMAGE.
30
+ #
31
+ # Author: Robert Haines
32
+
33
+ #
34
+ module ZipContainer
35
+
36
+ # The base class of all other exceptions raised by this library.
37
+ class ZipContainerError < RuntimeError
38
+ end
39
+
40
+ # This exception is raised when a bad ZipContainer is detected.
41
+ class MalformedZipContainerError < ZipContainerError
42
+
43
+ # :call-seq:
44
+ # new(reason = "")
45
+ #
46
+ # Create a new MalformedZipContainerError with an optional reason for why
47
+ # the ZipContainer file is malformed.
48
+ def initialize(reason = nil)
49
+ if reason.nil?
50
+ super("Malformed ZipContainer File.")
51
+ else
52
+ super("Malformed ZipContainer File: #{reason}")
53
+ end
54
+ end
55
+ end
56
+
57
+ # This exception is raised when a clash occurs with a reserved or managed
58
+ # name.
59
+ class ReservedNameClashError < ZipContainerError
60
+
61
+ # :call-seq:
62
+ # new(name)
63
+ #
64
+ # Create a new ReservedNameClashError with the name of the clash supplied.
65
+ def initialize(name)
66
+ super("'#{name}' is reserved for internal use in this ZipContainer file.")
67
+ end
68
+ end
69
+
70
+ end
Binary file
Binary file
File without changes
@@ -0,0 +1,140 @@
1
+ # Copyright (c) 2013 The University of Manchester, UK.
2
+ #
3
+ # All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # * Redistributions of source code must retain the above copyright notice,
9
+ # this list of conditions and the following disclaimer.
10
+ #
11
+ # * Redistributions in binary form must reproduce the above copyright notice,
12
+ # this list of conditions and the following disclaimer in the documentation
13
+ # and/or other materials provided with the distribution.
14
+ #
15
+ # * Neither the names of The University of Manchester nor the names of its
16
+ # contributors may be used to endorse or promote products derived from this
17
+ # software without specific prior written permission.
18
+ #
19
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
+ # POSSIBILITY OF SUCH DAMAGE.
30
+ #
31
+ # Author: Robert Haines
32
+
33
+ require 'test/unit'
34
+ require 'tmpdir'
35
+ require 'zip-container'
36
+
37
+ class TestCreation < Test::Unit::TestCase
38
+
39
+ # Check creation of standard empty container files.
40
+ def test_create_standard_file
41
+ Dir.mktmpdir do |dir|
42
+ filename = File.join(dir, "test.container")
43
+
44
+ assert_nothing_raised do
45
+ ZipContainer::Container.create(filename, $mimetype) do |c|
46
+ assert(c.on_disk?)
47
+ refute(c.in_memory?)
48
+
49
+ assert(c.find_entry("mimetype").localHeaderOffset == 0)
50
+ end
51
+ end
52
+
53
+ assert_nothing_raised(ZipContainer::MalformedZipContainerError, Zip::ZipError) do
54
+ ZipContainer::Container.verify!(filename)
55
+ end
56
+ end
57
+ end
58
+
59
+ # Check creation of empty container files with a different mimetype.
60
+ def test_create_mimetype_file
61
+ mimetype = "application/x-something-really-odd"
62
+
63
+ Dir.mktmpdir do |dir|
64
+ filename = File.join(dir, "test.container")
65
+
66
+ assert_nothing_raised do
67
+ ZipContainer::Container.create(filename, mimetype) do |c|
68
+ assert(c.on_disk?)
69
+ refute(c.in_memory?)
70
+
71
+ assert(c.find_entry("mimetype").localHeaderOffset == 0)
72
+ end
73
+ end
74
+
75
+ assert_nothing_raised(ZipContainer::MalformedZipContainerError, Zip::ZipError) do
76
+ ZipContainer::Container.verify!(filename)
77
+ end
78
+ end
79
+ end
80
+
81
+ # Check creation of stuff in container files. Check the commit status a few
82
+ # times to ensure that what we expect to happen, happens.
83
+ def test_create_contents_file
84
+ Dir.mktmpdir do |dir|
85
+ filename = File.join(dir, "test.container")
86
+
87
+ assert_nothing_raised do
88
+ ZipContainer::Container.create(filename, $mimetype) do |c|
89
+ assert(c.on_disk?)
90
+ refute(c.in_memory?)
91
+
92
+ c.file.open("test.txt", "w") do |f|
93
+ f.print "testing"
94
+ end
95
+
96
+ assert(c.commit_required?)
97
+ assert(c.commit)
98
+ refute(c.commit_required?)
99
+ refute(c.commit)
100
+
101
+ c.dir.mkdir("dir1")
102
+ c.mkdir("dir2")
103
+
104
+ assert(c.commit_required?)
105
+ assert(c.commit)
106
+ refute(c.commit_required?)
107
+ refute(c.commit)
108
+
109
+ c.comment = "A comment!"
110
+
111
+ assert(c.commit_required?)
112
+ assert(c.commit)
113
+ refute(c.commit_required?)
114
+ refute(c.commit)
115
+ end
116
+ end
117
+
118
+ assert_nothing_raised(ZipContainer::MalformedZipContainerError, Zip::ZipError) do
119
+ ZipContainer::Container.open(filename) do |c|
120
+ assert(c.on_disk?)
121
+ refute(c.in_memory?)
122
+
123
+ assert(c.file.exists?("test.txt"))
124
+ assert(c.file.exists?("dir1"))
125
+ assert(c.file.exists?("dir2"))
126
+ refute(c.file.exists?("dir3"))
127
+
128
+ text = c.file.read("test.txt")
129
+ assert_equal("testing", text)
130
+
131
+ assert_equal("A comment!", c.comment)
132
+
133
+ refute(c.commit_required?)
134
+ refute(c.commit)
135
+ end
136
+ end
137
+ end
138
+ end
139
+
140
+ end
@@ -0,0 +1,230 @@
1
+ # Copyright (c) 2013 The University of Manchester, UK.
2
+ #
3
+ # All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # * Redistributions of source code must retain the above copyright notice,
9
+ # this list of conditions and the following disclaimer.
10
+ #
11
+ # * Redistributions in binary form must reproduce the above copyright notice,
12
+ # this list of conditions and the following disclaimer in the documentation
13
+ # and/or other materials provided with the distribution.
14
+ #
15
+ # * Neither the names of The University of Manchester nor the names of its
16
+ # contributors may be used to endorse or promote products derived from this
17
+ # software without specific prior written permission.
18
+ #
19
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
+ # POSSIBILITY OF SUCH DAMAGE.
30
+ #
31
+ # Author: Robert Haines
32
+
33
+ require 'test/unit'
34
+ require 'tmpdir'
35
+ require 'zip-container'
36
+
37
+ # Classes to test managed entries.
38
+ class ManagedZipContainer < ZipContainer::Container
39
+
40
+ private_class_method :new
41
+
42
+ def initialize(filename)
43
+ super(filename)
44
+ register_managed_entry(ZipContainer::ManagedDirectory.new("src", true))
45
+ register_managed_entry(ZipContainer::ManagedDirectory.new("test"))
46
+ register_managed_entry(ZipContainer::ManagedDirectory.new("lib"))
47
+ register_managed_entry(ZipContainer::ManagedFile.new("index.html", true))
48
+ end
49
+
50
+ end
51
+
52
+ class ExampleZipContainer < ZipContainer::Container
53
+
54
+ private_class_method :new
55
+
56
+ def initialize(filename)
57
+ super(filename)
58
+ register_managed_entry(ZipContainer::ManagedDirectory.new("dir", true))
59
+ register_managed_entry(ZipContainer::ManagedFile.new("greeting.txt", true))
60
+ end
61
+
62
+ end
63
+
64
+ class ExampleZipContainer2 < ZipContainer::Container
65
+
66
+ private_class_method :new
67
+
68
+ def initialize(filename)
69
+ super(filename)
70
+
71
+ valid = Proc.new { |contents| contents.match(/[Hh]ello/) }
72
+ register_managed_entry(ZipContainer::ManagedFile.new("greeting.txt",
73
+ true, valid))
74
+ end
75
+
76
+ def ExampleZipContainer2.create(filename, &block)
77
+ super(filename, "application/example+zip", &block)
78
+ end
79
+
80
+ end
81
+
82
+ class TestManagedEntries < Test::Unit::TestCase
83
+
84
+ # Check that the example ZipContainer file does not validate as a
85
+ # ManagedZipContainer.
86
+ def test_fail_verification
87
+ refute(ManagedZipContainer.verify($example))
88
+
89
+ assert_raises(ZipContainer::MalformedZipContainerError) do
90
+ ManagedZipContainer.verify!($example)
91
+ end
92
+ end
93
+
94
+ # Check that the example ZipContainer file does validate as an
95
+ # ExampleZipContainer.
96
+ def test_pass_verification
97
+ assert(ExampleZipContainer.verify($example))
98
+
99
+ assert_nothing_raised(ZipContainer::MalformedZipContainerError) do
100
+ ExampleZipContainer.verify!($example)
101
+ end
102
+ end
103
+
104
+ # Check that the example ZipContainer file does validate as an
105
+ # ExampleZipContainer2.
106
+ def test_pass_verification_2
107
+ assert(ExampleZipContainer2.verify($example))
108
+
109
+ assert_nothing_raised(ZipContainer::MalformedZipContainerError) do
110
+ ExampleZipContainer2.verify!($example)
111
+ end
112
+ end
113
+
114
+ # Check that a standard Container can be created
115
+ def test_create_standard_container
116
+ Dir.mktmpdir do |dir|
117
+ filename = File.join(dir, "test.container")
118
+
119
+ assert_nothing_raised do
120
+ ZipContainer::Container.create(filename, $mimetype) do |c|
121
+ c.mkdir("META-INF")
122
+ assert(c.file.exists?("META-INF"))
123
+
124
+ c.file.open("META-INF/container.xml", "w") do |f|
125
+ f.puts "<?xml version=\"1.0\"?>"
126
+ end
127
+ assert(c.file.exists?("META-INF/container.xml"))
128
+ end
129
+ end
130
+
131
+ assert_nothing_raised(ZipContainer::MalformedZipContainerError) do
132
+ ZipContainer::Container.verify!(filename)
133
+ end
134
+ end
135
+ end
136
+
137
+ # Check that a ManagedZipContainer does not verify immediately after
138
+ # creation.
139
+ def test_create_bad_subclassed_container
140
+ Dir.mktmpdir do |dir|
141
+ filename = File.join(dir, "test.container")
142
+
143
+ assert_nothing_raised do
144
+ ManagedZipContainer.create(filename, $mimetype) do |c|
145
+ assert_raises(ZipContainer::MalformedZipContainerError) do
146
+ c.verify!
147
+ end
148
+ end
149
+ end
150
+
151
+ refute(ManagedZipContainer.verify(filename))
152
+ assert_raises(ZipContainer::MalformedZipContainerError) do
153
+ ManagedZipContainer.verify!(filename)
154
+ end
155
+ end
156
+ end
157
+
158
+ # Check that a ManagedZipContainer does verify when required objects are
159
+ # added.
160
+ def test_create_subclassed_container
161
+ Dir.mktmpdir do |dir|
162
+ filename = File.join(dir, "test.container")
163
+
164
+ assert_nothing_raised do
165
+ ManagedZipContainer.create(filename, $mimetype) do |c|
166
+ c.dir.mkdir("src")
167
+ c.file.open("index.html", "w") do |f|
168
+ f.puts "<html />"
169
+ end
170
+ end
171
+ end
172
+
173
+ assert(ManagedZipContainer.verify(filename))
174
+ assert_nothing_raised(ZipContainer::MalformedZipContainerError) do
175
+ ManagedZipContainer.verify!(filename)
176
+ end
177
+ end
178
+ end
179
+
180
+ def test_create_subclassed_mimetype
181
+ Dir.mktmpdir do |dir|
182
+ filename = File.join(dir, "test.container")
183
+
184
+ assert_nothing_raised do
185
+ ExampleZipContainer2.create(filename) do |c|
186
+ assert(c.file.exists?("mimetype"))
187
+ assert_equal("application/example+zip", c.file.read("mimetype"))
188
+ end
189
+ end
190
+ end
191
+ end
192
+
193
+ # Check that a ExampleZipContainer2 will only verify when required objects
194
+ # are added with the correct contents.
195
+ def test_create_subclassed_container_with_content_verification
196
+ Dir.mktmpdir do |dir|
197
+ filename = File.join(dir, "test.container")
198
+
199
+ assert_nothing_raised do
200
+ ExampleZipContainer2.create(filename) do |c|
201
+ assert_raises(ZipContainer::MalformedZipContainerError) do
202
+ c.verify!
203
+ end
204
+
205
+ c.file.open("greeting.txt", "w") do |f|
206
+ f.puts "Goodbye!"
207
+ end
208
+
209
+ assert_raises(ZipContainer::MalformedZipContainerError) do
210
+ c.verify!
211
+ end
212
+
213
+ c.file.open("greeting.txt", "w") do |f|
214
+ f.puts "Hello, Y'All!"
215
+ end
216
+
217
+ assert_nothing_raised(ZipContainer::MalformedZipContainerError) do
218
+ c.verify!
219
+ end
220
+ end
221
+ end
222
+
223
+ assert(ExampleZipContainer2.verify(filename))
224
+ assert_nothing_raised(ZipContainer::MalformedZipContainerError) do
225
+ ExampleZipContainer2.verify!(filename)
226
+ end
227
+ end
228
+ end
229
+
230
+ end