ucf 0.0.1 → 0.0.2

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.
@@ -1,5 +1,22 @@
1
1
  = Changes log for the UCF Ruby Gem
2
2
 
3
+ == Version 0.0.2
4
+
5
+ * Update the main ReadMe file.
6
+ * Add support for multiple reserved names and fix checks.
7
+ * Ensure UCF document is closed after verifying it.
8
+ * Expose the "each" method for enumerating UCF entries.
9
+ * Expose the "size" method to count UCF entries.
10
+ * Add an example program to list UCF contents.
11
+ * Add a method to directly iterate over UCF entries.
12
+
13
+ == Version 0.0.1
14
+
15
+ * Very basic UCF facilities complete (plus examples).
16
+ * Two ways of verifying UCF files.
17
+ * API documentation added.
18
+ * Add tests.
19
+
3
20
  == About this Changes file
4
21
 
5
22
  This file is, at least in part, generated by the following command:
data/Rakefile CHANGED
@@ -48,7 +48,7 @@ Jeweler::Tasks.new do |s|
48
48
  s.version = UCF::Version::STRING
49
49
  s.authors = ["Robert Haines"]
50
50
  s.email = ["support@mygrid.org.uk"]
51
- s.homepage = "http://www.taverna.org.uk/"
51
+ s.homepage = "http://mygrid.github.io/ruby-ucf/"
52
52
  s.platform = Gem::Platform::RUBY
53
53
  s.summary = "Universal Container Format (UCF) Ruby Library"
54
54
  s.description = "A Ruby library for working with Universal Container "\
@@ -2,28 +2,34 @@
2
2
 
3
3
  Authors:: Robert Haines
4
4
  Contact:: mailto:support@mygrid.org.uk
5
- URL:: http://www.taverna.org.uk/
5
+ Homepage:: http://mygrid.github.io/ruby-ucf
6
+ Source code:: https://github.com/myGrid/ruby-ucf
6
7
  Licence:: BSD (See Licence file or http://www.opensource.org/licenses/bsd-license.php)
7
8
  Copyright:: (c) 2013 The University of Manchester, UK
8
9
 
9
10
 
10
11
  == Synopsis
11
12
 
12
- This is a Ruby library for working with UCF files.
13
+ This is a Ruby library for working with UCF documents. See
14
+ {the specification}[https://learn.adobe.com/wiki/display/PDFNAV/Universal+Container+Format]
15
+ for more details.
13
16
 
14
- See https://learn.adobe.com/wiki/display/PDFNAV/Universal+Container+Format
17
+ <b>This library is a work in progress!</b> Until we release version 1.0.0 you
18
+ can expect the API to change in incompatible ways, although we will try to
19
+ keep this to an absolute minimum. Once version 1.0.0 is released we will be
20
+ following the principles of {Semantic Versioning}[http://semver.org/] for our
21
+ version numbering scheme.
15
22
 
16
- This library is a work in progress!
17
-
18
- Examples are provided in the examples directory.
23
+ There are some examples of how to use the library provided in the examples
24
+ directory. See the contents of the tests directory for even more.
19
25
 
20
26
  == What this library can not do yet
21
27
 
22
- The basic requirements of a UCF file are all implemented but there are a
28
+ The basic requirements of a UCF document are all implemented but there are a
23
29
  number of optional features that are not yet provided.
24
30
 
25
- * In memory operation. Presently all operations are performed on files that
26
- are resident on disk.
31
+ * In memory operation. Presently all operations are performed on documents
32
+ that are resident on disk.
27
33
  * META-INF directory support. Everything within the META-INF directory is
28
34
  optional but will supported in a near future version.
29
35
  * Changing the mimetype. It is not certain that this is a sensible operation
@@ -0,0 +1,69 @@
1
+ #!/usr/bin/env ruby
2
+ # Copyright (c) 2013 The University of Manchester, UK.
3
+ #
4
+ # All rights reserved.
5
+ #
6
+ # Redistribution and use in source and binary forms, with or without
7
+ # modification, are permitted provided that the following conditions are met:
8
+ #
9
+ # * Redistributions of source code must retain the above copyright notice,
10
+ # this list of conditions and the following disclaimer.
11
+ #
12
+ # * Redistributions in binary form must reproduce the above copyright notice,
13
+ # this list of conditions and the following disclaimer in the documentation
14
+ # and/or other materials provided with the distribution.
15
+ #
16
+ # * Neither the names of The University of Manchester nor the names of its
17
+ # contributors may be used to endorse or promote products derived from this
18
+ # software without specific prior written permission.
19
+ #
20
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30
+ # POSSIBILITY OF SUCH DAMAGE.
31
+ #
32
+ # Author: Robert Haines
33
+
34
+ require 'rubygems'
35
+ require 'ucf'
36
+
37
+ def usage
38
+ puts "ucfinfo ucf-file"
39
+ exit 1
40
+ end
41
+
42
+ usage unless ARGV.length == 1
43
+
44
+ ucffile = ARGV[0]
45
+
46
+ begin
47
+ ucf = UCF::Container.open(ucffile)
48
+ rescue UCF::MalformedUCFError, Zip::ZipError => err
49
+ puts err.to_s
50
+ exit 1
51
+ end
52
+
53
+ puts "Archive: #{ucf.to_s}"
54
+ puts "UCF file size: #{File.size(ucffile)} bytes, number of entries: #{ucf.size}"
55
+
56
+ total_size = 0
57
+ total_comp = 0
58
+
59
+ ucf.each do |entry|
60
+ total_size += entry.size
61
+ total_comp += entry.compressed_size
62
+ comp = entry.compression_method == 0 ? "stor" : "defN"
63
+ size = entry.size.to_s.rjust(8)
64
+ puts "#{size} #{comp} #{entry.time} #{entry.name}"
65
+ end
66
+
67
+ ratio = ((total_size - total_comp) / total_size.to_f) * 100
68
+ puts "%d files, %d bytes uncompressed, %d bytes compressed: %.1f%%" %
69
+ [ucf.size, total_size, total_comp, ratio]
@@ -47,9 +47,9 @@ module UCF
47
47
  class Container
48
48
 
49
49
  extend Forwardable
50
- def_delegators :@zipfile, :add, :close, :comment, :commit, :dir, :extract,
51
- :file, :find_entry, :get_entry, :get_input_stream, :get_output_stream,
52
- :glob, :mkdir, :name, :read
50
+ def_delegators :@zipfile, :add, :close, :comment, :commit, :dir, :each,
51
+ :extract, :file, :find_entry, :get_entry, :get_input_stream,
52
+ :get_output_stream, :glob, :mkdir, :name, :read, :size
53
53
 
54
54
  private_class_method :new
55
55
 
@@ -59,7 +59,12 @@ module UCF
59
59
 
60
60
  # :stopdoc:
61
61
  DEFAULT_MIMETYPE = "application/epub+zip"
62
+
63
+ # Reserved root file names. File names in UCF documents are
64
+ # case-insensitive so downcase where required in the reserved list.
62
65
  MIMETYPE_FILE = "mimetype"
66
+ META_INF_DIR = "META-INF"
67
+ RESERVED_ROOT_NAMES = [MIMETYPE_FILE, META_INF_DIR.downcase]
63
68
 
64
69
  ERR_MT_NONE = "Not a UCF file. 'mimetype' file is missing."
65
70
  ERR_MT_BAD_OFF = "Not a UCF file. 'mimetype' file is not at offset 0."
@@ -86,6 +91,27 @@ module UCF
86
91
  Container.open(filename, &block)
87
92
  end
88
93
 
94
+ # :call-seq:
95
+ # Container.each_entry -> Enumerator
96
+ # Container.each_entry {|entry| ...}
97
+ #
98
+ # Iterate over the entries in the UCF document. The entry objects returned
99
+ # by this method are Zip::ZipEntry objects. Please see the rubyzip
100
+ # documentation for details.
101
+ def Container.each_entry(filename, &block)
102
+ c = new(filename)
103
+
104
+ if block_given?
105
+ begin
106
+ c.each(&block)
107
+ ensure
108
+ c.close
109
+ end
110
+ end
111
+
112
+ c.each
113
+ end
114
+
89
115
  # :call-seq:
90
116
  # Container.open(filename) -> container
91
117
  # Container.open(filename) {|container| ...}
@@ -129,28 +155,29 @@ module UCF
129
155
  # This method raises exceptions when errors are found or if there is
130
156
  # something fundamental wrong with the file itself (e.g. not found).
131
157
  def Container.verify!(filename)
132
- new(filename)
158
+ new(filename).close
133
159
  nil
134
160
  end
135
161
 
136
162
  # :call-seq:
137
163
  # remove(entry)
138
164
  #
139
- # Removes the specified entry. If asked to remove the special mimetype
140
- # header file this method will do nothing.
165
+ # Removes the specified entry. If asked to remove any reserved files such
166
+ # as the special mimetype header file this method will do nothing.
141
167
  def remove(entry)
142
- return if mimetype_entry?(entry)
168
+ return if reserved_entry?(entry)
143
169
  @zipfile.remove(entry)
144
170
  end
145
171
 
146
172
  # :call-seq:
147
173
  # rename(entry, new_name, &continueOnExistsProc)
148
174
  #
149
- # Renames the specified entry. If asked to rename the special mimetype
150
- # header file this method will do nothing. See the rubyzip documentation
151
- # for details of the +continue_on_exists_proc+ parameter.
175
+ # Renames the specified entry. If asked to rename any reserved files such
176
+ # as the special mimetype header file this method will do nothing. See the
177
+ # rubyzip documentation for details of the +continue_on_exists_proc+
178
+ # parameter.
152
179
  def rename(entry, new_name, &continue_on_exists_proc)
153
- return if mimetype_entry?(entry)
180
+ return if reserved_entry?(entry)
154
181
  @zipfile.rename(entry, new_name, continue_on_exists_proc)
155
182
  end
156
183
 
@@ -158,10 +185,10 @@ module UCF
158
185
  # replace(entry, src_path)
159
186
  #
160
187
  # Replaces the specified entry with the contents of +src_path+ (from the
161
- # file system). If asked to replace the special mimetype header file this
162
- # method will do nothing.
188
+ # file system). If asked to replace any reserved files such as the special
189
+ # mimetype header file this method will do nothing.
163
190
  def replace(entry, src_path)
164
- return if mimetype_entry?(entry)
191
+ return if reserved_entry?(entry)
165
192
  @zipfile.replace(entry, src_path)
166
193
  end
167
194
 
@@ -193,9 +220,11 @@ module UCF
193
220
  @zipfile.read(MIMETYPE_FILE)
194
221
  end
195
222
 
196
- def mimetype_entry?(entry)
197
- name = entry.kind_of?(ZipEntry) ? entry.name : entry
198
- name == MIMETYPE_FILE
223
+ # Remember that file names in UCF documents are case-insensitive so
224
+ # compare downcased versions.
225
+ def reserved_entry?(entry)
226
+ name = entry.kind_of?(::Zip::ZipEntry) ? entry.name : entry
227
+ RESERVED_ROOT_NAMES.include? name.downcase
199
228
  end
200
229
 
201
230
  public
@@ -245,6 +274,16 @@ module UCF
245
274
  #
246
275
  # See the rubyzip documentation for details.
247
276
 
277
+ ##
278
+ # :method: each
279
+ # :call-seq:
280
+ # each -> Enumerator
281
+ # each {|entry| ...}
282
+ #
283
+ # Iterate over the entries in the UCF document. The entry objects returned
284
+ # by this method are Zip::ZipEntry objects. Please see the rubyzip
285
+ # documentation for details.
286
+
248
287
  ##
249
288
  # :method: extract
250
289
  # :call-seq:
@@ -340,5 +379,12 @@ module UCF
340
379
  #
341
380
  # Returns a string containing the contents of the specified entry.
342
381
 
382
+ ##
383
+ # :method: size
384
+ # :call-seq:
385
+ # size -> int
386
+ #
387
+ # Returns the number of entries in the UCF document.
388
+
343
389
  end
344
390
  end
@@ -0,0 +1,80 @@
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 'ucf'
34
+
35
+ class TestReservedNames < Test::Unit::TestCase
36
+
37
+ # Check that nothing happens when trying to delete the mimetype file.
38
+ def test_delete_mimetype
39
+ UCF::Container.open($ucf_example) do |ucf|
40
+ assert(ucf.file.exists?("mimetype"))
41
+ assert_nil(ucf.remove("mimetype"))
42
+ assert(ucf.file.exists?("mimetype"))
43
+ end
44
+ end
45
+
46
+ # Check that nothing happens when trying to rename the mimetype file.
47
+ def test_rename_mimetype
48
+ UCF::Container.open($ucf_example) do |ucf|
49
+ assert(ucf.file.exists?("mimetype"))
50
+ assert_nil(ucf.rename("mimetype", "something-else"))
51
+ assert(ucf.file.exists?("mimetype"))
52
+ assert(!ucf.file.exists?("something-else"))
53
+ end
54
+ end
55
+
56
+ # Check that nothing happens when trying to replace the contents of the
57
+ # mimetype file.
58
+ def test_replace_mimetype
59
+ UCF::Container.open($ucf_example) do |ucf|
60
+ assert(ucf.file.exists?("mimetype"))
61
+ assert_nil(ucf.replace("mimetype", $zip_empty))
62
+ assert_equal("application/epub+zip", ucf.file.read("mimetype"))
63
+ end
64
+ end
65
+
66
+ # Check that nothing happens when trying to delete the META-INF directory.
67
+ def test_delete_metainf
68
+ UCF::Container.open($ucf_example) do |ucf|
69
+ assert_nil(ucf.remove("META-INF"))
70
+ end
71
+ end
72
+
73
+ # Check that nothing happens when trying to rename the META-INF directory.
74
+ def test_rename_metainf
75
+ UCF::Container.open($ucf_example) do |ucf|
76
+ assert_nil(ucf.rename("META-INF", "something-else"))
77
+ end
78
+ end
79
+
80
+ end
@@ -42,3 +42,4 @@ $ucf_example = "test/data/example.ucf"
42
42
  # Run test cases.
43
43
  require 'tc_create'
44
44
  require 'tc_read'
45
+ require 'tc_reserved_names'
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "ucf"
8
- s.version = "0.0.1"
8
+ s.version = "0.0.2"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Robert Haines"]
12
- s.date = "2013-05-24"
12
+ s.date = "2013-05-29"
13
13
  s.description = "A Ruby library for working with Universal Container Format files. See https://learn.adobe.com/wiki/display/PDFNAV/Universal+Container+Format for the specification."
14
14
  s.email = ["support@mygrid.org.uk"]
15
15
  s.extra_rdoc_files = [
@@ -23,6 +23,7 @@ Gem::Specification.new do |s|
23
23
  "Rakefile",
24
24
  "ReadMe.rdoc",
25
25
  "examples/create_ucf.rb",
26
+ "examples/ucfinfo",
26
27
  "examples/verify_ucf.rb",
27
28
  "lib/ucf.rb",
28
29
  "lib/ucf/container.rb",
@@ -33,11 +34,12 @@ Gem::Specification.new do |s|
33
34
  "test/data/null.file",
34
35
  "test/tc_create.rb",
35
36
  "test/tc_read.rb",
37
+ "test/tc_reserved_names.rb",
36
38
  "test/ts_ucf.rb",
37
39
  "ucf.gemspec",
38
40
  "version.yml"
39
41
  ]
40
- s.homepage = "http://www.taverna.org.uk/"
42
+ s.homepage = "http://mygrid.github.io/ruby-ucf/"
41
43
  s.rdoc_options = ["-N", "--tab-width=2", "--main=ReadMe.rdoc"]
42
44
  s.require_paths = ["lib"]
43
45
  s.rubygems_version = "1.8.21"
@@ -1,4 +1,4 @@
1
1
  ---
2
2
  :major: 0
3
3
  :minor: 0
4
- :patch: 1
4
+ :patch: 2
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ucf
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-05-24 00:00:00.000000000 Z
12
+ date: 2013-05-29 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
@@ -91,6 +91,7 @@ files:
91
91
  - Rakefile
92
92
  - ReadMe.rdoc
93
93
  - examples/create_ucf.rb
94
+ - examples/ucfinfo
94
95
  - examples/verify_ucf.rb
95
96
  - lib/ucf.rb
96
97
  - lib/ucf/container.rb
@@ -101,10 +102,11 @@ files:
101
102
  - test/data/null.file
102
103
  - test/tc_create.rb
103
104
  - test/tc_read.rb
105
+ - test/tc_reserved_names.rb
104
106
  - test/ts_ucf.rb
105
107
  - ucf.gemspec
106
108
  - version.yml
107
- homepage: http://www.taverna.org.uk/
109
+ homepage: http://mygrid.github.io/ruby-ucf/
108
110
  licenses: []
109
111
  post_install_message:
110
112
  rdoc_options: