Compare commits
38 Commits
Author | SHA1 | Date |
---|---|---|
|
6c4b7a9f90 | |
|
3b4c2bfa22 | |
|
e3eb62491b | |
|
c09352b546 | |
|
71bb069049 | |
|
bb06f99b14 | |
|
3d95a8204f | |
|
56954b0b59 | |
|
6ff40f7a78 | |
|
e05dc9b978 | |
|
a4c3f5bddb | |
|
57cff3338f | |
|
0001864cfe | |
|
385ebd054a | |
|
46689d7350 | |
|
ef89a62b70 | |
|
900db76760 | |
|
14efdd1cc4 | |
|
02faddaf44 | |
|
9aa5964262 | |
|
13f4ea766f | |
|
3910870f3a | |
|
07d833ca78 | |
|
6bbda380fe | |
|
a6e6c3c469 | |
|
b691a4b72c | |
|
f68877920a | |
|
13781b20d3 | |
|
4b1cfba9db | |
|
5e9ee53c70 | |
|
cb0505d735 | |
|
49950d924c | |
|
a17da19e0c | |
|
7c1a8fbf8f | |
|
77611045f1 | |
|
2f1c1ea400 | |
|
16de339666 | |
|
84d7a66abc |
|
@ -0,0 +1,81 @@
|
||||||
|
name: Tests
|
||||||
|
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu]
|
||||||
|
ruby: ['2.4', '2.5', '2.6', '2.7', '3.0', '3.1', '3.2', '3.3', '3.4', head, jruby, truffleruby]
|
||||||
|
include:
|
||||||
|
- os: macos
|
||||||
|
ruby: '2.6'
|
||||||
|
runs-on: ${{ matrix.os }}-latest
|
||||||
|
continue-on-error: ${{ endsWith(matrix.ruby, 'head') }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout rubyzip code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Install and set up ruby
|
||||||
|
uses: ruby/setup-ruby@v1
|
||||||
|
with:
|
||||||
|
ruby-version: ${{ matrix.ruby }}
|
||||||
|
rubygems: '3.2.3'
|
||||||
|
bundler-cache: true
|
||||||
|
|
||||||
|
- name: Run the tests
|
||||||
|
env:
|
||||||
|
RUBYOPT: -v
|
||||||
|
JRUBY_OPTS: --debug
|
||||||
|
FULL_ZIP64_TEST: 1
|
||||||
|
run: bundle exec rake
|
||||||
|
|
||||||
|
test-frozen-string-literal:
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu]
|
||||||
|
ruby: ['3.3', '3.4', head]
|
||||||
|
runs-on: ${{ matrix.os }}-latest
|
||||||
|
continue-on-error: true
|
||||||
|
steps:
|
||||||
|
- name: Checkout rubyzip code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Install and set up ruby
|
||||||
|
uses: ruby/setup-ruby@v1
|
||||||
|
with:
|
||||||
|
ruby-version: ${{ matrix.ruby }}
|
||||||
|
bundler-cache: true
|
||||||
|
|
||||||
|
- name: Run the tests
|
||||||
|
env:
|
||||||
|
RUBYOPT: --enable-frozen-string-literal
|
||||||
|
FULL_ZIP64_TEST: 1
|
||||||
|
run: bundle exec rake
|
||||||
|
|
||||||
|
test-yjit:
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu, macos]
|
||||||
|
ruby: ['3.1', '3.2', '3.3', '3.4', head]
|
||||||
|
runs-on: ${{ matrix.os }}-latest
|
||||||
|
continue-on-error: true
|
||||||
|
steps:
|
||||||
|
- name: Checkout rubyzip code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Install and set up ruby
|
||||||
|
uses: ruby/setup-ruby@v1
|
||||||
|
with:
|
||||||
|
ruby-version: ${{ matrix.ruby }}
|
||||||
|
bundler-cache: true
|
||||||
|
|
||||||
|
- name: Run the tests
|
||||||
|
env:
|
||||||
|
RUBYOPT: --enable-yjit -v
|
||||||
|
FULL_ZIP64_TEST: 1
|
||||||
|
run: bundle exec rake
|
|
@ -23,11 +23,6 @@ Lint/SuppressedException:
|
||||||
Exclude:
|
Exclude:
|
||||||
- 'test/**/*.rb'
|
- 'test/**/*.rb'
|
||||||
|
|
||||||
# Allow this "useless" test, as we are testing <=> here.
|
|
||||||
Lint/UselessComparison:
|
|
||||||
Exclude:
|
|
||||||
- 'test/entry_test.rb'
|
|
||||||
|
|
||||||
# Turn off ABC metrics for the tests and set a workable max given
|
# Turn off ABC metrics for the tests and set a workable max given
|
||||||
# the current state of the code.
|
# the current state of the code.
|
||||||
Metrics/AbcSize:
|
Metrics/AbcSize:
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
# Offense count: 15
|
# Offense count: 15
|
||||||
# Configuration parameters: CountComments.
|
# Configuration parameters: CountComments.
|
||||||
Metrics/ClassLength:
|
Metrics/ClassLength:
|
||||||
Max: 580
|
Max: 600
|
||||||
|
|
||||||
# Offense count: 26
|
# Offense count: 26
|
||||||
Metrics/CyclomaticComplexity:
|
Metrics/CyclomaticComplexity:
|
||||||
|
@ -18,7 +18,7 @@ Metrics/CyclomaticComplexity:
|
||||||
# Offense count: 120
|
# Offense count: 120
|
||||||
# Configuration parameters: CountComments, ExcludedMethods.
|
# Configuration parameters: CountComments, ExcludedMethods.
|
||||||
Metrics/MethodLength:
|
Metrics/MethodLength:
|
||||||
Max: 30
|
Max: 32
|
||||||
|
|
||||||
# Offense count: 2
|
# Offense count: 2
|
||||||
# Configuration parameters: CountKeywordArgs.
|
# Configuration parameters: CountKeywordArgs.
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
require 'coveralls'
|
|
||||||
|
|
||||||
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new([
|
|
||||||
SimpleCov::Formatter::HTMLFormatter,
|
|
||||||
Coveralls::SimpleCov::Formatter
|
|
||||||
])
|
|
||||||
SimpleCov.start do
|
|
||||||
add_filter '/test'
|
|
||||||
end
|
|
34
.travis.yml
34
.travis.yml
|
@ -1,34 +0,0 @@
|
||||||
language: ruby
|
|
||||||
dist: xenial
|
|
||||||
cache: bundler
|
|
||||||
rvm:
|
|
||||||
- 2.4
|
|
||||||
- 2.5
|
|
||||||
- 2.6
|
|
||||||
- 2.7
|
|
||||||
- ruby-head
|
|
||||||
matrix:
|
|
||||||
fast_finish: true
|
|
||||||
include:
|
|
||||||
- rvm: jruby-9.2
|
|
||||||
jdk: openjdk8
|
|
||||||
- rvm: jruby-9.2
|
|
||||||
jdk: openjdk11
|
|
||||||
- rvm: jruby-head
|
|
||||||
jdk: openjdk11
|
|
||||||
- rvm: rbx-4
|
|
||||||
allow_failures:
|
|
||||||
- rvm: ruby-head
|
|
||||||
- rvm: rbx-4
|
|
||||||
- rvm: jruby-head
|
|
||||||
before_install:
|
|
||||||
- gem --version
|
|
||||||
before_script:
|
|
||||||
- echo `whereis zip`
|
|
||||||
- echo `whereis unzip`
|
|
||||||
env:
|
|
||||||
global:
|
|
||||||
- JRUBY_OPTS="--debug"
|
|
||||||
- COVERALLS_PARALLEL=true
|
|
||||||
notifications:
|
|
||||||
webhooks: https://coveralls.io/webhook
|
|
31
Changelog.md
31
Changelog.md
|
@ -1,5 +1,36 @@
|
||||||
# X.X.X (Next)
|
# X.X.X (Next)
|
||||||
|
|
||||||
|
# 2.4.1 (2025-01-05)
|
||||||
|
|
||||||
|
*This is a re-release of version 2.4 with a full version number string. We need to move to version 2.4.1 due to the canonical version number 2.4 now being taken in Rubygems.*
|
||||||
|
|
||||||
|
Tooling:
|
||||||
|
|
||||||
|
- Opt-in for MFA requirement explicitly on 2.4 branch.
|
||||||
|
|
||||||
|
# 2.4 (2025-01-04) - Yanked
|
||||||
|
|
||||||
|
*Yanked due to incorrect version number format (2.4 vs 2.4.0).*
|
||||||
|
|
||||||
|
- Ensure compatibility with `--enable-frozen-string-literal`.
|
||||||
|
- Ensure `File.open_buffer` doesn't rewrite unchanged data. This is a backport of the fix on the 3.x branch.
|
||||||
|
- Enable use of the version 3 calling style (mainly named parameters) wherever possible, while retaining version 2.x compatibility.
|
||||||
|
- Add (switchable) warning messages to methods that are changed or removed in version 3.x.
|
||||||
|
|
||||||
|
Tooling:
|
||||||
|
|
||||||
|
- Switch to using GitHub Actions (from Travis).
|
||||||
|
- Update Rubocop versions and configuration.
|
||||||
|
- Update actions with latest rubies.
|
||||||
|
|
||||||
|
# 2.3.2 (2021-07-05)
|
||||||
|
|
||||||
|
- This is a dummy release to warn about breaking changes coming in version 3.0. This updated version uses the Gem `post_install_message` instead of printing to `STDERR`.
|
||||||
|
|
||||||
|
# 2.3.1 (2021-07-03)
|
||||||
|
|
||||||
|
- This is a dummy release to warn about breaking changes coming in version 3.0.
|
||||||
|
|
||||||
# 2.3.0 (2020-03-14)
|
# 2.3.0 (2020-03-14)
|
||||||
|
|
||||||
- Fix frozen string literal error [#431](https://github.com/rubyzip/rubyzip/pull/431)
|
- Fix frozen string literal error [#431](https://github.com/rubyzip/rubyzip/pull/431)
|
||||||
|
|
26
README.md
26
README.md
|
@ -1,7 +1,7 @@
|
||||||
# rubyzip
|
# rubyzip
|
||||||
|
|
||||||
[](http://badge.fury.io/rb/rubyzip)
|
[](http://badge.fury.io/rb/rubyzip)
|
||||||
[](http://travis-ci.org/rubyzip/rubyzip)
|
[](https://github.com/rubyzip/rubyzip/actions/workflows/tests.yml)
|
||||||
[](https://codeclimate.com/github/rubyzip/rubyzip)
|
[](https://codeclimate.com/github/rubyzip/rubyzip)
|
||||||
[](https://coveralls.io/r/rubyzip/rubyzip?branch=master)
|
[](https://coveralls.io/r/rubyzip/rubyzip?branch=master)
|
||||||
|
|
||||||
|
@ -9,18 +9,26 @@ Rubyzip is a ruby library for reading and writing zip files.
|
||||||
|
|
||||||
## Important note
|
## Important note
|
||||||
|
|
||||||
The Rubyzip interface has changed!!! No need to do `require "zip/zip"` and `Zip` prefix in class names removed.
|
Rubyzip 2.4 is intended to be the last release in the 2.x series. Please get ready for version 3.0.
|
||||||
|
|
||||||
If you have issues with any third-party gems that require an old version of rubyzip, you can use this workaround:
|
### Updating to version 3.0
|
||||||
|
|
||||||
```ruby
|
The public API of some classes has been modernized to use named parameters for optional arguments. Also some methods have been changed or removed. Please check your usage of the following Rubyzip classes:
|
||||||
gem 'rubyzip', '>= 1.0.0' # will load new rubyzip version
|
* `File`
|
||||||
gem 'zip-zip' # will load compatibility for old rubyzip API.
|
* `Entry`
|
||||||
```
|
* `InputStream`
|
||||||
|
* `OutputStream`
|
||||||
|
* `DOSTime`
|
||||||
|
|
||||||
|
**Please see [Updating to version 3.x](https://github.com/rubyzip/rubyzip/wiki/Updating-to-version-3.x) in the wiki for details.**
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
- Ruby 2.4 or greater (for rubyzip 2.0; use 1.x for older rubies)
|
Version 3.x requires at least Ruby 3.0.
|
||||||
|
|
||||||
|
Version 2.x requires at least Ruby 2.4, and is known to work on Ruby 3.x.
|
||||||
|
|
||||||
|
It is not recommended to use any versions of Rubyzip earlier than 2.3 due to security issues.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
|
@ -188,7 +196,7 @@ If `::Zip::InputStream` finds such entry in the zip archive it will raise an exc
|
||||||
Rubyzip supports reading/writing zip files with traditional zip encryption (a.k.a. "ZipCrypto"). AES encryption is not yet supported. It can be used with buffer streams, e.g.:
|
Rubyzip supports reading/writing zip files with traditional zip encryption (a.k.a. "ZipCrypto"). AES encryption is not yet supported. It can be used with buffer streams, e.g.:
|
||||||
|
|
||||||
```ruby
|
```ruby
|
||||||
Zip::OutputStream.write_buffer(::StringIO.new(''), Zip::TraditionalEncrypter.new('password')) do |out|
|
Zip::OutputStream.write_buffer(::StringIO.new, Zip::TraditionalEncrypter.new('password')) do |out|
|
||||||
out.put_next_entry("my_file.txt")
|
out.put_next_entry("my_file.txt")
|
||||||
out.write my_data
|
out.write my_data
|
||||||
end.string
|
end.string
|
||||||
|
|
19
lib/zip.rb
19
lib/zip.rb
|
@ -34,6 +34,25 @@ require 'zip/streamable_directory'
|
||||||
require 'zip/errors'
|
require 'zip/errors'
|
||||||
|
|
||||||
module Zip
|
module Zip
|
||||||
|
V3_API_WARNING_MSG = <<~END_MSG
|
||||||
|
You have called '%s' (from %s).
|
||||||
|
This method is changing or deprecated in version 3.0.0. Please see
|
||||||
|
https://github.com/rubyzip/rubyzip/wiki/Updating-to-version-3.x
|
||||||
|
for more information.
|
||||||
|
END_MSG
|
||||||
|
|
||||||
|
def self.warn_about_v3_api(method)
|
||||||
|
return unless ENV['RUBYZIP_V3_API_WARN']
|
||||||
|
|
||||||
|
loc = caller_locations(2, 1)[0]
|
||||||
|
from = "#{loc.path.split('/').last}:#{loc.lineno}"
|
||||||
|
warn format(V3_API_WARNING_MSG, method, from)
|
||||||
|
end
|
||||||
|
|
||||||
|
if ENV['RUBYZIP_V3_API_WARN'] && RUBY_VERSION < '3.0'
|
||||||
|
warn 'RubyZip 3.0 will require Ruby 3.0 or later.'
|
||||||
|
end
|
||||||
|
|
||||||
extend self
|
extend self
|
||||||
attr_accessor :unicode_names,
|
attr_accessor :unicode_names,
|
||||||
:on_exists_proc,
|
:on_exists_proc,
|
||||||
|
|
|
@ -24,9 +24,17 @@ module Zip
|
||||||
((year - 1980) << 9)
|
((year - 1980) << 9)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Dos time is only stored with two seconds accuracy
|
|
||||||
def dos_equals(other)
|
def dos_equals(other)
|
||||||
to_i / 2 == other.to_i / 2
|
Zip.warn_about_v3_api('DOSTime#dos_equals')
|
||||||
|
|
||||||
|
self == other
|
||||||
|
end
|
||||||
|
|
||||||
|
# Dos time is only stored with two seconds accuracy.
|
||||||
|
def <=>(other)
|
||||||
|
return unless other.kind_of?(Time)
|
||||||
|
|
||||||
|
(to_i / 2) <=> (other.to_i / 2)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Create a DOSTime instance from a vanilla Time instance.
|
# Create a DOSTime instance from a vanilla Time instance.
|
||||||
|
@ -41,9 +49,8 @@ module Zip
|
||||||
day = (0b11111 & bin_dos_date)
|
day = (0b11111 & bin_dos_date)
|
||||||
month = (0b111100000 & bin_dos_date) >> 5
|
month = (0b111100000 & bin_dos_date) >> 5
|
||||||
year = ((0b1111111000000000 & bin_dos_date) >> 9) + 1980
|
year = ((0b1111111000000000 & bin_dos_date) >> 9) + 1980
|
||||||
begin
|
|
||||||
local(year, month, day, hour, minute, second)
|
local(year, month, day, hour, minute, second)
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -52,26 +52,41 @@ module Zip
|
||||||
raise ::Zip::EntryNameError, "Illegal ZipEntry name '#{name}', name must not start with /"
|
raise ::Zip::EntryNameError, "Illegal ZipEntry name '#{name}', name must not start with /"
|
||||||
end
|
end
|
||||||
|
|
||||||
def initialize(*args)
|
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
||||||
name = args[1] || ''
|
def initialize(zipfile = nil, name = nil, *args)
|
||||||
|
name ||= ''
|
||||||
check_name(name)
|
check_name(name)
|
||||||
|
|
||||||
set_default_vars_values
|
set_default_vars_values
|
||||||
@fstype = ::Zip::RUNNING_ON_WINDOWS ? ::Zip::FSTYPE_FAT : ::Zip::FSTYPE_UNIX
|
@fstype = ::Zip::RUNNING_ON_WINDOWS ? ::Zip::FSTYPE_FAT : ::Zip::FSTYPE_UNIX
|
||||||
|
|
||||||
@zipfile = args[0] || ''
|
@zipfile = zipfile || ''
|
||||||
@name = name
|
@name = name
|
||||||
@comment = args[2] || ''
|
|
||||||
@extra = args[3] || ''
|
if (args_hash = args.first).kind_of?(::Hash)
|
||||||
@compressed_size = args[4] || 0
|
@comment = args_hash[:comment] || ''
|
||||||
@crc = args[5] || 0
|
@extra = args_hash[:extra] || ''
|
||||||
@compression_method = args[6] || ::Zip::Entry::DEFLATED
|
@compressed_size = args_hash[:compressed_size] || 0
|
||||||
@size = args[7] || 0
|
@crc = args_hash[:crc] || 0
|
||||||
@time = args[8] || ::Zip::DOSTime.now
|
@compression_method = args_hash[:compression_method] || ::Zip::Entry::DEFLATED
|
||||||
|
@size = args_hash[:size] || 0
|
||||||
|
@time = args_hash[:time] || ::Zip::DOSTime.now
|
||||||
|
else
|
||||||
|
Zip.warn_about_v3_api('Zip::Entry.new') unless args.empty?
|
||||||
|
|
||||||
|
@comment = args[0] || ''
|
||||||
|
@extra = args[1] || ''
|
||||||
|
@compressed_size = args[2] || 0
|
||||||
|
@crc = args[3] || 0
|
||||||
|
@compression_method = args[4] || ::Zip::Entry::DEFLATED
|
||||||
|
@size = args[5] || 0
|
||||||
|
@time = args[6] || ::Zip::DOSTime.now
|
||||||
|
end
|
||||||
|
|
||||||
@ftype = name_is_directory? ? :directory : :file
|
@ftype = name_is_directory? ? :directory : :file
|
||||||
@extra = ::Zip::ExtraField.new(@extra.to_s) unless @extra.kind_of?(::Zip::ExtraField)
|
@extra = ::Zip::ExtraField.new(@extra.to_s) unless @extra.kind_of?(::Zip::ExtraField)
|
||||||
end
|
end
|
||||||
|
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
||||||
|
|
||||||
def encrypted?
|
def encrypted?
|
||||||
gp_flags & 1 == 1
|
gp_flags & 1 == 1
|
||||||
|
@ -174,6 +189,8 @@ module Zip
|
||||||
# NB: The caller is responsible for making sure dest_path is safe, if it
|
# NB: The caller is responsible for making sure dest_path is safe, if it
|
||||||
# is passed.
|
# is passed.
|
||||||
def extract(dest_path = nil, &block)
|
def extract(dest_path = nil, &block)
|
||||||
|
Zip.warn_about_v3_api('Zip::Entry#extract')
|
||||||
|
|
||||||
if dest_path.nil? && !name_safe?
|
if dest_path.nil? && !name_safe?
|
||||||
warn "WARNING: skipped '#{@name}' as unsafe."
|
warn "WARNING: skipped '#{@name}' as unsafe."
|
||||||
return self
|
return self
|
||||||
|
@ -188,6 +205,28 @@ module Zip
|
||||||
self
|
self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Extracts this entry to a file at `entry_path`, with
|
||||||
|
# `destination_directory` as the base location in the filesystem.
|
||||||
|
#
|
||||||
|
# NB: The caller is responsible for making sure `destination_directory` is
|
||||||
|
# safe, if it is passed.
|
||||||
|
def extract_v3(entry_path = @name, destination_directory: '.', &block)
|
||||||
|
dest_dir = ::File.absolute_path(destination_directory || '.')
|
||||||
|
extract_path = ::File.absolute_path(::File.join(dest_dir, entry_path))
|
||||||
|
|
||||||
|
unless extract_path.start_with?(dest_dir)
|
||||||
|
warn "WARNING: skipped extracting '#{@name}' to '#{extract_path}' as unsafe."
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
block ||= proc { ::Zip.on_exists_proc }
|
||||||
|
|
||||||
|
raise "unknown file type #{inspect}" unless directory? || file? || symlink?
|
||||||
|
|
||||||
|
__send__(:"create_#{ftype}", extract_path, &block)
|
||||||
|
self
|
||||||
|
end
|
||||||
|
|
||||||
def to_s
|
def to_s
|
||||||
@name
|
@name
|
||||||
end
|
end
|
||||||
|
@ -506,7 +545,7 @@ module Zip
|
||||||
keys_equal = %w[compression_method crc compressed_size size name extra filepath].all? do |k|
|
keys_equal = %w[compression_method crc compressed_size size name extra filepath].all? do |k|
|
||||||
other.__send__(k.to_sym) == __send__(k.to_sym)
|
other.__send__(k.to_sym) == __send__(k.to_sym)
|
||||||
end
|
end
|
||||||
keys_equal && time.dos_equals(other.time)
|
keys_equal && time == other.time
|
||||||
end
|
end
|
||||||
|
|
||||||
def <=>(other)
|
def <=>(other)
|
||||||
|
@ -532,7 +571,7 @@ module Zip
|
||||||
raise "unknown @file_type #{@ftype}"
|
raise "unknown @file_type #{@ftype}"
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
zis = ::Zip::InputStream.new(@zipfile, local_header_offset)
|
zis = ::Zip::InputStream.new(@zipfile, offset: local_header_offset)
|
||||||
zis.instance_variable_set(:@complete_entry, self)
|
zis.instance_variable_set(:@complete_entry, self)
|
||||||
zis.get_next_entry
|
zis.get_next_entry
|
||||||
if block_given?
|
if block_given?
|
||||||
|
|
|
@ -51,7 +51,7 @@ module Zip
|
||||||
# reserved 0 and tag 1
|
# reserved 0 and tag 1
|
||||||
s = [0, 1].pack('Vv')
|
s = [0, 1].pack('Vv')
|
||||||
|
|
||||||
tag1 = ''.force_encoding(Encoding::BINARY)
|
tag1 = ''.b
|
||||||
if @mtime
|
if @mtime
|
||||||
tag1 << [to_ntfs_time(@mtime)].pack('Q<')
|
tag1 << [to_ntfs_time(@mtime)].pack('Q<')
|
||||||
if @atime
|
if @atime
|
||||||
|
|
|
@ -59,7 +59,7 @@ module Zip
|
||||||
|
|
||||||
def pack_for_c_dir
|
def pack_for_c_dir
|
||||||
# central directory entries contain only fields that didn't fit in the main entry part
|
# central directory entries contain only fields that didn't fit in the main entry part
|
||||||
packed = ''.force_encoding('BINARY')
|
packed = ''.b
|
||||||
packed << [@original_size].pack('Q<') if @original_size
|
packed << [@original_size].pack('Q<') if @original_size
|
||||||
packed << [@compressed_size].pack('Q<') if @compressed_size
|
packed << [@compressed_size].pack('Q<') if @compressed_size
|
||||||
packed << [@relative_header_offset].pack('Q<') if @relative_header_offset
|
packed << [@relative_header_offset].pack('Q<') if @relative_header_offset
|
||||||
|
|
|
@ -73,12 +73,17 @@ module Zip
|
||||||
|
|
||||||
# Opens a zip archive. Pass true as the second parameter to create
|
# Opens a zip archive. Pass true as the second parameter to create
|
||||||
# a new archive if it doesn't exist already.
|
# a new archive if it doesn't exist already.
|
||||||
def initialize(path_or_io, create = false, buffer = false, options = {})
|
def initialize(path_or_io, dep_create = false, dep_buffer = false,
|
||||||
|
create: false, buffer: false, **options)
|
||||||
super()
|
super()
|
||||||
|
|
||||||
|
Zip.warn_about_v3_api('File#new') if dep_create || dep_buffer
|
||||||
|
|
||||||
options = DEFAULT_OPTIONS.merge(options)
|
options = DEFAULT_OPTIONS.merge(options)
|
||||||
@name = path_or_io.respond_to?(:path) ? path_or_io.path : path_or_io
|
@name = path_or_io.respond_to?(:path) ? path_or_io.path : path_or_io
|
||||||
@comment = ''
|
@comment = ''
|
||||||
@create = create ? true : false # allow any truthy value to mean true
|
@create = create || dep_create ? true : false # allow any truthy value to mean true
|
||||||
|
buffer ||= dep_buffer
|
||||||
|
|
||||||
if ::File.size?(@name.to_s)
|
if ::File.size?(@name.to_s)
|
||||||
# There is a file, which exists, that is associated with this zip.
|
# There is a file, which exists, that is associated with this zip.
|
||||||
|
@ -94,6 +99,7 @@ module Zip
|
||||||
end
|
end
|
||||||
elsif buffer && path_or_io.size > 0
|
elsif buffer && path_or_io.size > 0
|
||||||
# This zip is probably a non-empty StringIO.
|
# This zip is probably a non-empty StringIO.
|
||||||
|
@create = false
|
||||||
read_from_stream(path_or_io)
|
read_from_stream(path_or_io)
|
||||||
elsif @create
|
elsif @create
|
||||||
# This zip is completely new/empty and is to be created.
|
# This zip is completely new/empty and is to be created.
|
||||||
|
@ -117,8 +123,10 @@ module Zip
|
||||||
# Similar to ::new. If a block is passed the Zip::File object is passed
|
# Similar to ::new. If a block is passed the Zip::File object is passed
|
||||||
# to the block and is automatically closed afterwards, just as with
|
# to the block and is automatically closed afterwards, just as with
|
||||||
# ruby's builtin File::open method.
|
# ruby's builtin File::open method.
|
||||||
def open(file_name, create = false, options = {})
|
def open(file_name, dep_create = false, create: false, **options)
|
||||||
zf = ::Zip::File.new(file_name, create, false, options)
|
Zip.warn_about_v3_api('Zip::File.open') if dep_create
|
||||||
|
|
||||||
|
zf = ::Zip::File.new(file_name, create: (dep_create || create), buffer: false, **options)
|
||||||
return zf unless block_given?
|
return zf unless block_given?
|
||||||
|
|
||||||
begin
|
begin
|
||||||
|
@ -130,7 +138,9 @@ module Zip
|
||||||
|
|
||||||
# Same as #open. But outputs data to a buffer instead of a file
|
# Same as #open. But outputs data to a buffer instead of a file
|
||||||
def add_buffer
|
def add_buffer
|
||||||
io = ::StringIO.new('')
|
Zip.warn_about_v3_api('Zip::File.add_buffer')
|
||||||
|
|
||||||
|
io = ::StringIO.new
|
||||||
zf = ::Zip::File.new(io, true, true)
|
zf = ::Zip::File.new(io, true, true)
|
||||||
yield zf
|
yield zf
|
||||||
zf.write_buffer(io)
|
zf.write_buffer(io)
|
||||||
|
@ -140,7 +150,7 @@ module Zip
|
||||||
# stream, and outputs data to a buffer.
|
# stream, and outputs data to a buffer.
|
||||||
# (This can be used to extract data from a
|
# (This can be used to extract data from a
|
||||||
# downloaded zip archive without first saving it to disk.)
|
# downloaded zip archive without first saving it to disk.)
|
||||||
def open_buffer(io, options = {})
|
def open_buffer(io, **options)
|
||||||
unless IO_METHODS.map { |method| io.respond_to?(method) }.all? || io.kind_of?(String)
|
unless IO_METHODS.map { |method| io.respond_to?(method) }.all? || io.kind_of?(String)
|
||||||
raise "Zip::File.open_buffer expects a String or IO-like argument (responds to #{IO_METHODS.join(', ')}). Found: #{io.class}"
|
raise "Zip::File.open_buffer expects a String or IO-like argument (responds to #{IO_METHODS.join(', ')}). Found: #{io.class}"
|
||||||
end
|
end
|
||||||
|
@ -150,7 +160,7 @@ module Zip
|
||||||
# https://github.com/rubyzip/rubyzip/issues/119
|
# https://github.com/rubyzip/rubyzip/issues/119
|
||||||
io.binmode if io.respond_to?(:binmode)
|
io.binmode if io.respond_to?(:binmode)
|
||||||
|
|
||||||
zf = ::Zip::File.new(io, true, true, options)
|
zf = ::Zip::File.new(io, create: true, buffer: true, **options)
|
||||||
return zf unless block_given?
|
return zf unless block_given?
|
||||||
|
|
||||||
yield zf
|
yield zf
|
||||||
|
@ -228,18 +238,24 @@ module Zip
|
||||||
end
|
end
|
||||||
|
|
||||||
# Splits an archive into parts with segment size
|
# Splits an archive into parts with segment size
|
||||||
def split(zip_file_name, segment_size = MAX_SEGMENT_SIZE, delete_zip_file = true, partial_zip_file_name = nil)
|
def split(zip_file_name,
|
||||||
|
dep_segment_size = MAX_SEGMENT_SIZE, dep_delete_zip_file = true, dep_partial_zip_file_name = nil,
|
||||||
|
segment_size: MAX_SEGMENT_SIZE, delete_zip_file: nil, partial_zip_file_name: nil)
|
||||||
raise Error, "File #{zip_file_name} not found" unless ::File.exist?(zip_file_name)
|
raise Error, "File #{zip_file_name} not found" unless ::File.exist?(zip_file_name)
|
||||||
raise Errno::ENOENT, zip_file_name unless ::File.readable?(zip_file_name)
|
raise Errno::ENOENT, zip_file_name unless ::File.readable?(zip_file_name)
|
||||||
|
|
||||||
|
if dep_segment_size != MAX_SEGMENT_SIZE || !dep_delete_zip_file || dep_partial_zip_file_name
|
||||||
|
Zip.warn_about_v3_api('Zip::File.split')
|
||||||
|
end
|
||||||
|
|
||||||
zip_file_size = ::File.size(zip_file_name)
|
zip_file_size = ::File.size(zip_file_name)
|
||||||
segment_size = get_segment_size_for_split(segment_size)
|
segment_size = get_segment_size_for_split(segment_size || dep_segment_size)
|
||||||
return if zip_file_size <= segment_size
|
return if zip_file_size <= segment_size
|
||||||
|
|
||||||
segment_count = get_segment_count_for_split(zip_file_size, segment_size)
|
segment_count = get_segment_count_for_split(zip_file_size, segment_size)
|
||||||
# Checking for correct zip structure
|
# Checking for correct zip structure
|
||||||
::Zip::File.open(zip_file_name) {}
|
::Zip::File.open(zip_file_name) {}
|
||||||
partial_zip_file_name = get_partial_zip_file_name(zip_file_name, partial_zip_file_name)
|
partial_zip_file_name = get_partial_zip_file_name(zip_file_name, (partial_zip_file_name || dep_partial_zip_file_name))
|
||||||
szip_file_index = 0
|
szip_file_index = 0
|
||||||
::File.open(zip_file_name, 'rb') do |zip_file|
|
::File.open(zip_file_name, 'rb') do |zip_file|
|
||||||
until zip_file.eof?
|
until zip_file.eof?
|
||||||
|
@ -247,6 +263,7 @@ module Zip
|
||||||
save_splited_part(zip_file, partial_zip_file_name, zip_file_size, szip_file_index, segment_size, segment_count)
|
save_splited_part(zip_file, partial_zip_file_name, zip_file_size, szip_file_index, segment_size, segment_count)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
delete_zip_file = delete_zip_file.nil? ? dep_delete_zip_file : delete_zip_file
|
||||||
::File.delete(zip_file_name) if delete_zip_file
|
::File.delete(zip_file_name) if delete_zip_file
|
||||||
szip_file_index
|
szip_file_index
|
||||||
end
|
end
|
||||||
|
@ -264,26 +281,45 @@ module Zip
|
||||||
# specified. If a block is passed the stream object is passed to the block and
|
# specified. If a block is passed the stream object is passed to the block and
|
||||||
# the stream is automatically closed afterwards just as with ruby's builtin
|
# the stream is automatically closed afterwards just as with ruby's builtin
|
||||||
# File.open method.
|
# File.open method.
|
||||||
def get_output_stream(entry, permission_int = nil, comment = nil,
|
# rubocop:disable Metrics/ParameterLists, Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
|
||||||
extra = nil, compressed_size = nil, crc = nil,
|
def get_output_stream(entry,
|
||||||
compression_method = nil, size = nil, time = nil,
|
dep_permission_int = nil, dep_comment = nil,
|
||||||
|
dep_extra = nil, dep_compressed_size = nil, dep_crc = nil,
|
||||||
|
dep_compression_method = nil, dep_size = nil, dep_time = nil,
|
||||||
|
permission_int: nil, comment: nil,
|
||||||
|
extra: nil, compressed_size: nil, crc: nil,
|
||||||
|
compression_method: nil, size: nil, time: nil,
|
||||||
&a_proc)
|
&a_proc)
|
||||||
|
|
||||||
|
unless dep_permission_int.nil? && dep_comment.nil? && dep_extra.nil? &&
|
||||||
|
dep_compressed_size.nil? && dep_crc.nil? && dep_compression_method.nil? &&
|
||||||
|
dep_size.nil? && dep_time.nil?
|
||||||
|
Zip.warn_about_v3_api('Zip::File#get_output_stream')
|
||||||
|
end
|
||||||
|
|
||||||
new_entry =
|
new_entry =
|
||||||
if entry.kind_of?(Entry)
|
if entry.kind_of?(Entry)
|
||||||
entry
|
entry
|
||||||
else
|
else
|
||||||
Entry.new(@name, entry.to_s, comment, extra, compressed_size, crc, compression_method, size, time)
|
Entry.new(@name, entry.to_s,
|
||||||
|
comment: (comment || dep_comment),
|
||||||
|
extra: (extra || dep_extra),
|
||||||
|
compressed_size: (compressed_size || dep_compressed_size),
|
||||||
|
crc: (crc || dep_crc),
|
||||||
|
compression_method: (compression_method || dep_compression_method),
|
||||||
|
size: (size || dep_size),
|
||||||
|
time: (time || dep_time))
|
||||||
end
|
end
|
||||||
if new_entry.directory?
|
if new_entry.directory?
|
||||||
raise ArgumentError,
|
raise ArgumentError,
|
||||||
"cannot open stream to directory entry - '#{new_entry}'"
|
"cannot open stream to directory entry - '#{new_entry}'"
|
||||||
end
|
end
|
||||||
new_entry.unix_perms = permission_int
|
new_entry.unix_perms = (permission_int || dep_permission_int)
|
||||||
zip_streamable_entry = StreamableStream.new(new_entry)
|
zip_streamable_entry = StreamableStream.new(new_entry)
|
||||||
@entry_set << zip_streamable_entry
|
@entry_set << zip_streamable_entry
|
||||||
zip_streamable_entry.get_output_stream(&a_proc)
|
zip_streamable_entry.get_output_stream(&a_proc)
|
||||||
end
|
end
|
||||||
|
# rubocop:enable Metrics/ParameterLists, Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
|
||||||
|
|
||||||
# Returns the name of the zip archive
|
# Returns the name of the zip archive
|
||||||
def to_s
|
def to_s
|
||||||
|
@ -336,11 +372,25 @@ module Zip
|
||||||
|
|
||||||
# Extracts entry to file dest_path.
|
# Extracts entry to file dest_path.
|
||||||
def extract(entry, dest_path, &block)
|
def extract(entry, dest_path, &block)
|
||||||
|
Zip.warn_about_v3_api('Zip::File#extract')
|
||||||
|
|
||||||
block ||= proc { ::Zip.on_exists_proc }
|
block ||= proc { ::Zip.on_exists_proc }
|
||||||
found_entry = get_entry(entry)
|
found_entry = get_entry(entry)
|
||||||
found_entry.extract(dest_path, &block)
|
found_entry.extract(dest_path, &block)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Extracts `entry` to a file at `entry_path`, with `destination_directory`
|
||||||
|
# as the base location in the filesystem.
|
||||||
|
#
|
||||||
|
# NB: The caller is responsible for making sure `destination_directory` is
|
||||||
|
# safe, if it is passed.
|
||||||
|
def extract_v3(entry, entry_path = nil, destination_directory: '.', &block)
|
||||||
|
block ||= proc { ::Zip.on_exists_proc }
|
||||||
|
found_entry = get_entry(entry)
|
||||||
|
entry_path ||= found_entry.name
|
||||||
|
found_entry.extract_v3(entry_path, destination_directory: destination_directory, &block)
|
||||||
|
end
|
||||||
|
|
||||||
# Commits changes that has been made since the previous commit to
|
# Commits changes that has been made since the previous commit to
|
||||||
# the zip archive.
|
# the zip archive.
|
||||||
def commit
|
def commit
|
||||||
|
@ -361,7 +411,9 @@ module Zip
|
||||||
end
|
end
|
||||||
|
|
||||||
# Write buffer write changes to buffer and return
|
# Write buffer write changes to buffer and return
|
||||||
def write_buffer(io = ::StringIO.new(''))
|
def write_buffer(io = ::StringIO.new)
|
||||||
|
return io unless commit_required?
|
||||||
|
|
||||||
::Zip::OutputStream.write_buffer(io) do |zos|
|
::Zip::OutputStream.write_buffer(io) do |zos|
|
||||||
@entry_set.each { |e| e.write_to_zip_output_stream(zos) }
|
@entry_set.each { |e| e.write_to_zip_output_stream(zos) }
|
||||||
zos.comment = comment
|
zos.comment = comment
|
||||||
|
|
|
@ -239,7 +239,7 @@ module Zip
|
||||||
end
|
end
|
||||||
|
|
||||||
def open(filename, mode = 'r', permissions = 0o644, &block)
|
def open(filename, mode = 'r', permissions = 0o644, &block)
|
||||||
mode.delete!('b') # ignore b option
|
mode = mode.delete('b') # ignore b option
|
||||||
case mode
|
case mode
|
||||||
when 'r'
|
when 'r'
|
||||||
@mapped_zip.get_input_stream(filename, &block)
|
@mapped_zip.get_input_stream(filename, &block)
|
||||||
|
@ -619,7 +619,7 @@ module Zip
|
||||||
end
|
end
|
||||||
|
|
||||||
def expand_path(path)
|
def expand_path(path)
|
||||||
expanded = path.start_with?('/') ? path : ::File.join(@pwd, path)
|
expanded = path.start_with?('/') ? path.dup : ::File.join(@pwd, path)
|
||||||
expanded.gsub!(/\/\.(\/|$)/, '')
|
expanded.gsub!(/\/\.(\/|$)/, '')
|
||||||
expanded.gsub!(/[^\/]+\/\.\.(\/|$)/, '')
|
expanded.gsub!(/[^\/]+\/\.\.(\/|$)/, '')
|
||||||
expanded.empty? ? '/' : expanded
|
expanded.empty? ? '/' : expanded
|
||||||
|
|
|
@ -3,11 +3,11 @@ module Zip
|
||||||
def initialize(*args)
|
def initialize(*args)
|
||||||
super
|
super
|
||||||
|
|
||||||
@buffer = +''
|
@buffer = ''.b
|
||||||
@zlib_inflater = ::Zlib::Inflate.new(-Zlib::MAX_WBITS)
|
@zlib_inflater = ::Zlib::Inflate.new(-Zlib::MAX_WBITS)
|
||||||
end
|
end
|
||||||
|
|
||||||
def read(length = nil, outbuf = '')
|
def read(length = nil, outbuf = ''.b)
|
||||||
return (length.nil? || length.zero? ? '' : nil) if eof
|
return (length.nil? || length.zero? ? '' : nil) if eof
|
||||||
|
|
||||||
while length.nil? || (@buffer.bytesize < length)
|
while length.nil? || (@buffer.bytesize < length)
|
||||||
|
|
|
@ -49,11 +49,17 @@ module Zip
|
||||||
#
|
#
|
||||||
# @param context [String||IO||StringIO] file path or IO/StringIO object
|
# @param context [String||IO||StringIO] file path or IO/StringIO object
|
||||||
# @param offset [Integer] offset in the IO/StringIO
|
# @param offset [Integer] offset in the IO/StringIO
|
||||||
def initialize(context, offset = 0, decrypter = nil)
|
def initialize(context, dep_offset = 0, dep_decrypter = nil, offset: 0, decrypter: nil)
|
||||||
super()
|
super()
|
||||||
|
|
||||||
|
if !dep_offset.zero? || !dep_decrypter.nil?
|
||||||
|
Zip.warn_about_v3_api('Zip::InputStream.new')
|
||||||
|
end
|
||||||
|
|
||||||
|
offset = dep_offset if offset.zero?
|
||||||
@archive_io = get_io(context, offset)
|
@archive_io = get_io(context, offset)
|
||||||
@decompressor = ::Zip::NullDecompressor
|
@decompressor = ::Zip::NullDecompressor
|
||||||
@decrypter = decrypter || ::Zip::NullDecrypter.new
|
@decrypter = decrypter || dep_decrypter || ::Zip::NullDecrypter.new
|
||||||
@current_entry = nil
|
@current_entry = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -89,8 +95,14 @@ module Zip
|
||||||
# Same as #initialize but if a block is passed the opened
|
# Same as #initialize but if a block is passed the opened
|
||||||
# stream is passed to the block and closed when the block
|
# stream is passed to the block and closed when the block
|
||||||
# returns.
|
# returns.
|
||||||
def open(filename_or_io, offset = 0, decrypter = nil)
|
def open(filename_or_io, dep_offset = 0, dep_decrypter = nil, offset: 0, decrypter: nil)
|
||||||
zio = new(filename_or_io, offset, decrypter)
|
if !dep_offset.zero? || !dep_decrypter.nil?
|
||||||
|
Zip.warn_about_v3_api('Zip::InputStream.new')
|
||||||
|
end
|
||||||
|
|
||||||
|
offset = dep_offset if offset.zero?
|
||||||
|
|
||||||
|
zio = new(filename_or_io, offset: offset, decrypter: decrypter || dep_decrypter)
|
||||||
return zio unless block_given?
|
return zio unless block_given?
|
||||||
|
|
||||||
begin
|
begin
|
||||||
|
@ -101,7 +113,8 @@ module Zip
|
||||||
end
|
end
|
||||||
|
|
||||||
def open_buffer(filename_or_io, offset = 0)
|
def open_buffer(filename_or_io, offset = 0)
|
||||||
warn 'open_buffer is deprecated!!! Use open instead!'
|
Zip.warn_about_v3_api('Zip::InputStream.open_buffer')
|
||||||
|
|
||||||
::Zip::InputStream.open(filename_or_io, offset)
|
::Zip::InputStream.open(filename_or_io, offset)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -6,14 +6,14 @@ module Zip
|
||||||
|
|
||||||
class << self
|
class << self
|
||||||
def copy_stream(ostream, istream)
|
def copy_stream(ostream, istream)
|
||||||
ostream.write(istream.read(CHUNK_SIZE, '')) until istream.eof?
|
ostream.write(istream.read(CHUNK_SIZE, ''.b)) until istream.eof?
|
||||||
end
|
end
|
||||||
|
|
||||||
def copy_stream_n(ostream, istream, nbytes)
|
def copy_stream_n(ostream, istream, nbytes)
|
||||||
toread = nbytes
|
toread = nbytes
|
||||||
while toread > 0 && !istream.eof?
|
while toread > 0 && !istream.eof?
|
||||||
tr = toread > CHUNK_SIZE ? CHUNK_SIZE : toread
|
tr = toread > CHUNK_SIZE ? CHUNK_SIZE : toread
|
||||||
ostream.write(istream.read(tr, ''))
|
ostream.write(istream.read(tr, ''.b))
|
||||||
toread -= tr
|
toread -= tr
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -11,13 +11,13 @@ module Zip
|
||||||
super
|
super
|
||||||
@lineno = 0
|
@lineno = 0
|
||||||
@pos = 0
|
@pos = 0
|
||||||
@output_buffer = ''
|
@output_buffer = ''.b
|
||||||
end
|
end
|
||||||
|
|
||||||
attr_accessor :lineno
|
attr_accessor :lineno
|
||||||
attr_reader :pos
|
attr_reader :pos
|
||||||
|
|
||||||
def read(number_of_bytes = nil, buf = '')
|
def read(number_of_bytes = nil, buf = ''.b)
|
||||||
tbuf = if @output_buffer.bytesize > 0
|
tbuf = if @output_buffer.bytesize > 0
|
||||||
if number_of_bytes <= @output_buffer.bytesize
|
if number_of_bytes <= @output_buffer.bytesize
|
||||||
@output_buffer.slice!(0, number_of_bytes)
|
@output_buffer.slice!(0, number_of_bytes)
|
||||||
|
@ -26,7 +26,7 @@ module Zip
|
||||||
rbuf = sysread(number_of_bytes, buf)
|
rbuf = sysread(number_of_bytes, buf)
|
||||||
out = @output_buffer
|
out = @output_buffer
|
||||||
out << rbuf if rbuf
|
out << rbuf if rbuf
|
||||||
@output_buffer = ''
|
@output_buffer = ''.b
|
||||||
out
|
out
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
|
@ -93,7 +93,7 @@ module Zip
|
||||||
|
|
||||||
def flush
|
def flush
|
||||||
ret_val = @output_buffer
|
ret_val = @output_buffer
|
||||||
@output_buffer = ''
|
@output_buffer = ''.b
|
||||||
ret_val
|
ret_val
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -24,10 +24,13 @@ module Zip
|
||||||
|
|
||||||
# Opens the indicated zip file. If a file with that name already
|
# Opens the indicated zip file. If a file with that name already
|
||||||
# exists it will be overwritten.
|
# exists it will be overwritten.
|
||||||
def initialize(file_name, stream = false, encrypter = nil)
|
def initialize(file_name, dep_stream = false, dep_encrypter = nil, stream: false, encrypter: nil)
|
||||||
super()
|
super()
|
||||||
|
|
||||||
|
Zip.warn_about_v3_api('Zip::OutputStream.new') if dep_stream || !dep_encrypter.nil?
|
||||||
|
|
||||||
@file_name = file_name
|
@file_name = file_name
|
||||||
@output_stream = if stream
|
@output_stream = if stream || dep_stream
|
||||||
iostream = @file_name.dup
|
iostream = @file_name.dup
|
||||||
iostream.reopen(@file_name)
|
iostream.reopen(@file_name)
|
||||||
iostream.rewind
|
iostream.rewind
|
||||||
|
@ -37,7 +40,7 @@ module Zip
|
||||||
end
|
end
|
||||||
@entry_set = ::Zip::EntrySet.new
|
@entry_set = ::Zip::EntrySet.new
|
||||||
@compressor = ::Zip::NullCompressor.instance
|
@compressor = ::Zip::NullCompressor.instance
|
||||||
@encrypter = encrypter || ::Zip::NullEncrypter.new
|
@encrypter = encrypter || dep_encrypter || ::Zip::NullEncrypter.new
|
||||||
@closed = false
|
@closed = false
|
||||||
@current_entry = nil
|
@current_entry = nil
|
||||||
@comment = nil
|
@comment = nil
|
||||||
|
@ -47,19 +50,23 @@ module Zip
|
||||||
# stream is passed to the block and closed when the block
|
# stream is passed to the block and closed when the block
|
||||||
# returns.
|
# returns.
|
||||||
class << self
|
class << self
|
||||||
def open(file_name, encrypter = nil)
|
def open(file_name, dep_encrypter = nil, encrypter: nil)
|
||||||
return new(file_name) unless block_given?
|
return new(file_name) unless block_given?
|
||||||
|
|
||||||
zos = new(file_name, false, encrypter)
|
Zip.warn_about_v3_api('Zip::OutputStream.open') unless dep_encrypter.nil?
|
||||||
|
|
||||||
|
zos = new(file_name, stream: false, encrypter: (encrypter || dep_encrypter))
|
||||||
yield zos
|
yield zos
|
||||||
ensure
|
ensure
|
||||||
zos.close if zos
|
zos.close if zos
|
||||||
end
|
end
|
||||||
|
|
||||||
# Same as #open but writes to a filestream instead
|
# Same as #open but writes to a filestream instead
|
||||||
def write_buffer(io = ::StringIO.new(''), encrypter = nil)
|
def write_buffer(io = ::StringIO.new, dep_encrypter = nil, encrypter: nil)
|
||||||
|
Zip.warn_about_v3_api('Zip::OutputStream.write_buffer') unless dep_encrypter.nil?
|
||||||
|
|
||||||
io.binmode if io.respond_to?(:binmode)
|
io.binmode if io.respond_to?(:binmode)
|
||||||
zos = new(io, true, encrypter)
|
zos = new(io, stream: true, encrypter: (encrypter || dep_encrypter))
|
||||||
yield zos
|
yield zos
|
||||||
zos.close_buffer
|
zos.close_buffer
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,7 +5,7 @@ module Zip
|
||||||
@read_so_far = 0
|
@read_so_far = 0
|
||||||
end
|
end
|
||||||
|
|
||||||
def read(length = nil, outbuf = '')
|
def read(length = nil, outbuf = ''.b)
|
||||||
return (length.nil? || length.zero? ? '' : nil) if eof
|
return (length.nil? || length.zero? ? '' : nil) if eof
|
||||||
|
|
||||||
if length.nil? || (@read_so_far + length) > decompressed_size
|
if length.nil? || (@read_so_far + length) > decompressed_size
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
module Zip
|
module Zip
|
||||||
VERSION = '2.3.0'
|
VERSION = '2.4.1'
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,8 +5,10 @@ require 'zip/version'
|
||||||
Gem::Specification.new do |s|
|
Gem::Specification.new do |s|
|
||||||
s.name = 'rubyzip'
|
s.name = 'rubyzip'
|
||||||
s.version = ::Zip::VERSION
|
s.version = ::Zip::VERSION
|
||||||
s.authors = ['Alexander Simonov']
|
s.authors = ['Robert Haines', 'John Lees-Miller', 'Alexander Simonov']
|
||||||
s.email = ['alex@simonov.me']
|
s.email = [
|
||||||
|
'hainesr@gmail.com', 'jdleesmiller@gmail.com', 'alex@simonov.me'
|
||||||
|
]
|
||||||
s.homepage = 'http://github.com/rubyzip/rubyzip'
|
s.homepage = 'http://github.com/rubyzip/rubyzip'
|
||||||
s.platform = Gem::Platform::RUBY
|
s.platform = Gem::Platform::RUBY
|
||||||
s.summary = 'rubyzip is a ruby module for reading and writing zip files'
|
s.summary = 'rubyzip is a ruby module for reading and writing zip files'
|
||||||
|
@ -14,16 +16,42 @@ Gem::Specification.new do |s|
|
||||||
s.require_paths = ['lib']
|
s.require_paths = ['lib']
|
||||||
s.license = 'BSD 2-Clause'
|
s.license = 'BSD 2-Clause'
|
||||||
s.metadata = {
|
s.metadata = {
|
||||||
'bug_tracker_uri' => 'https://github.com/rubyzip/rubyzip/issues',
|
'bug_tracker_uri' => 'https://github.com/rubyzip/rubyzip/issues',
|
||||||
'changelog_uri' => "https://github.com/rubyzip/rubyzip/blob/v#{s.version}/Changelog.md",
|
'changelog_uri' => "https://github.com/rubyzip/rubyzip/blob/v#{s.version}/Changelog.md",
|
||||||
'documentation_uri' => "https://www.rubydoc.info/gems/rubyzip/#{s.version}",
|
'documentation_uri' => "https://www.rubydoc.info/gems/rubyzip/#{s.version}",
|
||||||
'source_code_uri' => "https://github.com/rubyzip/rubyzip/tree/v#{s.version}",
|
'source_code_uri' => "https://github.com/rubyzip/rubyzip/tree/v#{s.version}",
|
||||||
'wiki_uri' => 'https://github.com/rubyzip/rubyzip/wiki'
|
'wiki_uri' => 'https://github.com/rubyzip/rubyzip/wiki',
|
||||||
|
'rubygems_mfa_required' => 'true'
|
||||||
}
|
}
|
||||||
s.required_ruby_version = '>= 2.4'
|
s.required_ruby_version = '>= 2.4'
|
||||||
s.add_development_dependency 'coveralls', '~> 0.7'
|
|
||||||
s.add_development_dependency 'minitest', '~> 5.4'
|
s.add_development_dependency 'minitest', '~> 5.4'
|
||||||
s.add_development_dependency 'pry', '~> 0.10'
|
s.add_development_dependency 'pry', '~> 0.10'
|
||||||
s.add_development_dependency 'rake', '~> 12.3', '>= 12.3.3'
|
s.add_development_dependency 'rake', '~> 12.3', '>= 12.3.3'
|
||||||
s.add_development_dependency 'rubocop', '~> 0.79'
|
s.add_development_dependency 'rubocop', '~> 0.79'
|
||||||
|
|
||||||
|
s.post_install_message = <<~ENDBANNER
|
||||||
|
RubyZip 3.0 is coming!
|
||||||
|
**********************
|
||||||
|
|
||||||
|
The public API of some Rubyzip classes has been modernized to use named
|
||||||
|
parameters for optional arguments. Please check your usage of the
|
||||||
|
following classes:
|
||||||
|
* `Zip::File`
|
||||||
|
* `Zip::Entry`
|
||||||
|
* `Zip::InputStream`
|
||||||
|
* `Zip::OutputStream`
|
||||||
|
* `Zip::DOSTime`
|
||||||
|
|
||||||
|
Run your test suite with the `RUBYZIP_V3_API_WARN` environment
|
||||||
|
variable set to see warnings about usage of the old API. This will
|
||||||
|
help you to identify any changes that you need to make to your code.
|
||||||
|
See https://github.com/rubyzip/rubyzip/wiki/Updating-to-version-3.x for
|
||||||
|
more information.
|
||||||
|
|
||||||
|
Please ensure that your Gemfiles and .gemspecs are suitably restrictive
|
||||||
|
to avoid an unexpected breakage when 3.0 is released (e.g. ~> 2.3.0).
|
||||||
|
See https://github.com/rubyzip/rubyzip for details. The Changelog also
|
||||||
|
lists other enhancements and bugfixes that have been implemented since
|
||||||
|
version 2.3.0.
|
||||||
|
ENDBANNER
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,6 +1,12 @@
|
||||||
require 'test_helper'
|
require 'test_helper'
|
||||||
|
|
||||||
class ConstantsTest < MiniTest::Test
|
class ConstantsTest < MiniTest::Test
|
||||||
|
def test_version_number_format
|
||||||
|
# Should at least start with MAJoR.MINOR.PATCH, but
|
||||||
|
# allow for additional version information after that.
|
||||||
|
assert_match(/\A\d+\.\d+\.\d+/, Zip::VERSION)
|
||||||
|
end
|
||||||
|
|
||||||
def test_compression_methods
|
def test_compression_methods
|
||||||
assert_equal(0, Zip::COMPRESSION_METHOD_STORE)
|
assert_equal(0, Zip::COMPRESSION_METHOD_STORE)
|
||||||
assert_equal(1, Zip::COMPRESSION_METHOD_SHRINK)
|
assert_equal(1, Zip::COMPRESSION_METHOD_SHRINK)
|
||||||
|
|
|
@ -19,7 +19,7 @@ class EncryptionTest < MiniTest::Test
|
||||||
@rand = [250, 143, 107, 13, 143, 22, 155, 75, 228, 150, 12]
|
@rand = [250, 143, 107, 13, 143, 22, 155, 75, 228, 150, 12]
|
||||||
@output = ::Zip::DOSTime.stub(:now, ::Zip::DOSTime.new(2014, 12, 17, 15, 56, 24)) do
|
@output = ::Zip::DOSTime.stub(:now, ::Zip::DOSTime.new(2014, 12, 17, 15, 56, 24)) do
|
||||||
Random.stub(:rand, ->(_range) { @rand.shift }) do
|
Random.stub(:rand, ->(_range) { @rand.shift }) do
|
||||||
Zip::OutputStream.write_buffer(::StringIO.new(''), Zip::TraditionalEncrypter.new('password')) do |zos|
|
Zip::OutputStream.write_buffer(::StringIO.new, Zip::TraditionalEncrypter.new('password')) do |zos|
|
||||||
zos.put_next_entry('file1.txt')
|
zos.put_next_entry('file1.txt')
|
||||||
zos.write ::File.open(INPUT_FILE1).read
|
zos.write ::File.open(INPUT_FILE1).read
|
||||||
end.string
|
end.string
|
||||||
|
|
|
@ -104,17 +104,27 @@ class ZipFileTest < MiniTest::Test
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_open_buffer_with_string
|
def test_open_buffer_with_string
|
||||||
string = File.read('test/data/rubycode.zip')
|
data = File.read('test/data/rubycode.zip', mode: 'rb')
|
||||||
|
string = data.dup
|
||||||
|
|
||||||
::Zip::File.open_buffer string do |zf|
|
::Zip::File.open_buffer string do |zf|
|
||||||
assert zf.entries.map(&:name).include?('zippedruby1.rb')
|
assert zf.entries.map(&:name).include?('zippedruby1.rb')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Ensure the buffer hasn't changed.
|
||||||
|
assert_equal(data, string)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_open_buffer_with_stringio
|
def test_open_buffer_with_stringio
|
||||||
string_io = StringIO.new File.read('test/data/rubycode.zip')
|
data = File.read('test/data/rubycode.zip', mode: 'rb')
|
||||||
|
string_io = StringIO.new(data.dup)
|
||||||
|
|
||||||
::Zip::File.open_buffer string_io do |zf|
|
::Zip::File.open_buffer string_io do |zf|
|
||||||
assert zf.entries.map(&:name).include?('zippedruby1.rb')
|
assert zf.entries.map(&:name).include?('zippedruby1.rb')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Ensure the buffer hasn't changed.
|
||||||
|
assert_equal(data, string_io.string)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_close_buffer_with_stringio
|
def test_close_buffer_with_stringio
|
||||||
|
@ -123,6 +133,18 @@ class ZipFileTest < MiniTest::Test
|
||||||
assert_nil zf.close
|
assert_nil zf.close
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_open_buffer_without_block_write_buffer_does_nothing
|
||||||
|
data = File.read('test/data/rubycode.zip', mode: 'rb')
|
||||||
|
string_io = StringIO.new(data.dup)
|
||||||
|
|
||||||
|
zf = ::Zip::File.open_buffer(string_io)
|
||||||
|
assert zf.entries.map(&:name).include?('zippedruby1.rb')
|
||||||
|
|
||||||
|
# Ensure the buffer isn't changed.
|
||||||
|
assert_same string_io, zf.write_buffer(string_io)
|
||||||
|
assert_equal(data, string_io.string)
|
||||||
|
end
|
||||||
|
|
||||||
def test_open_buffer_no_op_does_not_change_file
|
def test_open_buffer_no_op_does_not_change_file
|
||||||
Dir.mktmpdir do |tmp|
|
Dir.mktmpdir do |tmp|
|
||||||
test_zip = File.join(tmp, 'test.zip')
|
test_zip = File.join(tmp, 'test.zip')
|
||||||
|
@ -481,7 +503,7 @@ class ZipFileTest < MiniTest::Test
|
||||||
zf = ::Zip::File.new(TEST_ZIP.zip_name)
|
zf = ::Zip::File.new(TEST_ZIP.zip_name)
|
||||||
old_name = zf.entries.first
|
old_name = zf.entries.first
|
||||||
zf.rename(old_name, new_name)
|
zf.rename(old_name, new_name)
|
||||||
io = ::StringIO.new('')
|
io = ::StringIO.new
|
||||||
buffer = zf.write_buffer(io)
|
buffer = zf.write_buffer(io)
|
||||||
File.open(TEST_ZIP.zip_name, 'wb') { |f| f.write buffer.string }
|
File.open(TEST_ZIP.zip_name, 'wb') { |f| f.write buffer.string }
|
||||||
zf_read = ::Zip::File.new(TEST_ZIP.zip_name)
|
zf_read = ::Zip::File.new(TEST_ZIP.zip_name)
|
||||||
|
@ -630,7 +652,7 @@ class ZipFileTest < MiniTest::Test
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_streaming
|
def test_streaming
|
||||||
fname = ::File.join(::File.expand_path(::File.dirname(__FILE__)), '../README.md')
|
fname = ::File.join(__dir__, '../README.md')
|
||||||
zname = 'test/data/generated/README.zip'
|
zname = 'test/data/generated/README.zip'
|
||||||
Zip::File.open(zname, Zip::File::CREATE) do |zipfile|
|
Zip::File.open(zname, Zip::File::CREATE) do |zipfile|
|
||||||
zipfile.get_output_stream(File.basename(fname)) do |f|
|
zipfile.get_output_stream(File.basename(fname)) do |f|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
require 'test_helper'
|
require 'test_helper'
|
||||||
|
|
||||||
|
require 'forwardable'
|
||||||
|
|
||||||
class ZipInputStreamTest < MiniTest::Test
|
class ZipInputStreamTest < MiniTest::Test
|
||||||
include AssertEntry
|
include AssertEntry
|
||||||
|
|
||||||
|
@ -134,7 +136,7 @@ class ZipInputStreamTest < MiniTest::Test
|
||||||
assert_equal(TestZipFile::TEST_ZIP2.entry_names[0], e.name)
|
assert_equal(TestZipFile::TEST_ZIP2.entry_names[0], e.name)
|
||||||
|
|
||||||
# Do a little reading
|
# Do a little reading
|
||||||
buf = ''
|
buf = ''.b
|
||||||
buf << zis.read(100)
|
buf << zis.read(100)
|
||||||
assert_equal(100, zis.pos)
|
assert_equal(100, zis.pos)
|
||||||
buf << (zis.gets || '')
|
buf << (zis.gets || '')
|
||||||
|
@ -143,7 +145,7 @@ class ZipInputStreamTest < MiniTest::Test
|
||||||
|
|
||||||
zis.rewind
|
zis.rewind
|
||||||
|
|
||||||
buf2 = ''
|
buf2 = ''.b
|
||||||
buf2 << zis.read(100)
|
buf2 << zis.read(100)
|
||||||
buf2 << (zis.gets || '')
|
buf2 << (zis.gets || '')
|
||||||
buf2 << (zis.gets || '')
|
buf2 << (zis.gets || '')
|
||||||
|
|
|
@ -8,7 +8,7 @@ class AbstractOutputStreamTest < MiniTest::Test
|
||||||
attr_accessor :buffer
|
attr_accessor :buffer
|
||||||
|
|
||||||
def initialize
|
def initialize
|
||||||
@buffer = ''
|
@buffer = ''.b
|
||||||
end
|
end
|
||||||
|
|
||||||
def <<(data)
|
def <<(data)
|
||||||
|
@ -58,12 +58,12 @@ class AbstractOutputStreamTest < MiniTest::Test
|
||||||
assert_equal("hello world. You ok out there?\nI sure hope so!\n", @output_stream.buffer)
|
assert_equal("hello world. You ok out there?\nI sure hope so!\n", @output_stream.buffer)
|
||||||
|
|
||||||
$, = 'X'
|
$, = 'X'
|
||||||
@output_stream.buffer = ''
|
@output_stream.buffer = ''.b
|
||||||
@output_stream.print('monkey', 'duck', 'zebra')
|
@output_stream.print('monkey', 'duck', 'zebra')
|
||||||
assert_equal("monkeyXduckXzebra\n", @output_stream.buffer)
|
assert_equal("monkeyXduckXzebra\n", @output_stream.buffer)
|
||||||
|
|
||||||
$\ = nil
|
$\ = nil
|
||||||
@output_stream.buffer = ''
|
@output_stream.buffer = ''.b
|
||||||
@output_stream.print(20)
|
@output_stream.print(20)
|
||||||
assert_equal('20', @output_stream.buffer)
|
assert_equal('20', @output_stream.buffer)
|
||||||
end
|
end
|
||||||
|
@ -87,19 +87,19 @@ class AbstractOutputStreamTest < MiniTest::Test
|
||||||
@output_stream.puts('hello', 'world')
|
@output_stream.puts('hello', 'world')
|
||||||
assert_equal("\nhello\nworld\n", @output_stream.buffer)
|
assert_equal("\nhello\nworld\n", @output_stream.buffer)
|
||||||
|
|
||||||
@output_stream.buffer = ''
|
@output_stream.buffer = ''.b
|
||||||
@output_stream.puts("hello\n", "world\n")
|
@output_stream.puts("hello\n", "world\n")
|
||||||
assert_equal("hello\nworld\n", @output_stream.buffer)
|
assert_equal("hello\nworld\n", @output_stream.buffer)
|
||||||
|
|
||||||
@output_stream.buffer = ''
|
@output_stream.buffer = ''.b
|
||||||
@output_stream.puts(%W[hello\n world\n])
|
@output_stream.puts(%W[hello\n world\n])
|
||||||
assert_equal("hello\nworld\n", @output_stream.buffer)
|
assert_equal("hello\nworld\n", @output_stream.buffer)
|
||||||
|
|
||||||
@output_stream.buffer = ''
|
@output_stream.buffer = ''.b
|
||||||
@output_stream.puts(%W[hello\n world\n], 'bingo')
|
@output_stream.puts(%W[hello\n world\n], 'bingo')
|
||||||
assert_equal("hello\nworld\nbingo\n", @output_stream.buffer)
|
assert_equal("hello\nworld\nbingo\n", @output_stream.buffer)
|
||||||
|
|
||||||
@output_stream.buffer = ''
|
@output_stream.buffer = ''.b
|
||||||
@output_stream.puts(16, 20, 50, 'hello')
|
@output_stream.puts(16, 20, 50, 'hello')
|
||||||
assert_equal("16\n20\n50\nhello\n", @output_stream.buffer)
|
assert_equal("16\n20\n50\nhello\n", @output_stream.buffer)
|
||||||
end
|
end
|
||||||
|
|
|
@ -23,7 +23,7 @@ class ZipOutputStreamTest < MiniTest::Test
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_write_buffer
|
def test_write_buffer
|
||||||
io = ::StringIO.new('')
|
io = ::StringIO.new
|
||||||
buffer = ::Zip::OutputStream.write_buffer(io) do |zos|
|
buffer = ::Zip::OutputStream.write_buffer(io) do |zos|
|
||||||
zos.comment = TEST_ZIP.comment
|
zos.comment = TEST_ZIP.comment
|
||||||
write_test_zip(zos)
|
write_test_zip(zos)
|
||||||
|
@ -33,7 +33,7 @@ class ZipOutputStreamTest < MiniTest::Test
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_write_buffer_binmode
|
def test_write_buffer_binmode
|
||||||
io = ::StringIO.new('')
|
io = ::StringIO.new
|
||||||
buffer = ::Zip::OutputStream.write_buffer(io) do |zos|
|
buffer = ::Zip::OutputStream.write_buffer(io) do |zos|
|
||||||
zos.comment = TEST_ZIP.comment
|
zos.comment = TEST_ZIP.comment
|
||||||
write_test_zip(zos)
|
write_test_zip(zos)
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
require 'simplecov'
|
|
||||||
require 'minitest/autorun'
|
require 'minitest/autorun'
|
||||||
require 'minitest/unit'
|
require 'minitest/unit'
|
||||||
require 'fileutils'
|
require 'fileutils'
|
||||||
|
@ -146,7 +145,7 @@ module CrcTest
|
||||||
attr_accessor :buffer
|
attr_accessor :buffer
|
||||||
|
|
||||||
def initialize
|
def initialize
|
||||||
@buffer = ''
|
@buffer = ''.b
|
||||||
end
|
end
|
||||||
|
|
||||||
def <<(data)
|
def <<(data)
|
||||||
|
@ -223,3 +222,21 @@ module ZipEntryData
|
||||||
TEST_ISDIRECTORY = false
|
TEST_ISDIRECTORY = false
|
||||||
TEST_TIME = Time.now
|
TEST_TIME = Time.now
|
||||||
end
|
end
|
||||||
|
|
||||||
|
module ZipV3Assertions
|
||||||
|
def assert_v3_api_warning
|
||||||
|
env_save = ENV['RUBYZIP_V3_API_WARN']
|
||||||
|
ENV['RUBYZIP_V3_API_WARN'] = '1'
|
||||||
|
assert_output('', /^You have called/) { yield }
|
||||||
|
ensure
|
||||||
|
ENV['RUBYZIP_V3_API_WARN'] = env_save
|
||||||
|
end
|
||||||
|
|
||||||
|
def refute_v3_api_warning
|
||||||
|
env_save = ENV['RUBYZIP_V3_API_WARN']
|
||||||
|
ENV['RUBYZIP_V3_API_WARN'] = '1'
|
||||||
|
assert_output('', '') { yield }
|
||||||
|
ensure
|
||||||
|
ENV['RUBYZIP_V3_API_WARN'] = env_save
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
|
@ -0,0 +1,283 @@
|
||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
module Version3APITest
|
||||||
|
class ZipFileTest < MiniTest::Test
|
||||||
|
include CommonZipFileFixture
|
||||||
|
include ZipV3Assertions
|
||||||
|
|
||||||
|
def test_new
|
||||||
|
assert_v3_api_warning do
|
||||||
|
file = ::Zip::File.new(TEST_ZIP.zip_name, true, false, restore_times: true) {}
|
||||||
|
assert(file.restore_times)
|
||||||
|
refute(file.restore_permissions)
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_v3_api_warning do
|
||||||
|
string_io = StringIO.new(File.read('test/data/rubycode.zip'))
|
||||||
|
file = ::Zip::File.new(string_io, false, true, restore_times: true) {}
|
||||||
|
assert(file.restore_times)
|
||||||
|
refute(file.restore_permissions)
|
||||||
|
end
|
||||||
|
|
||||||
|
refute_v3_api_warning do
|
||||||
|
file = ::Zip::File.new(TEST_ZIP.zip_name, create: true, restore_times: true) {}
|
||||||
|
assert(file.restore_times)
|
||||||
|
refute(file.restore_permissions)
|
||||||
|
end
|
||||||
|
|
||||||
|
refute_v3_api_warning do
|
||||||
|
string_io = StringIO.new(File.read('test/data/rubycode.zip'))
|
||||||
|
file = ::Zip::File.new(string_io, buffer: true, restore_times: true) {}
|
||||||
|
assert(file.restore_times)
|
||||||
|
refute(file.restore_permissions)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_open
|
||||||
|
refute_v3_api_warning do
|
||||||
|
file = ::Zip::File.open('test/data/rubycode.zip', restore_permissions: true)
|
||||||
|
assert(file.restore_permissions)
|
||||||
|
refute(file.restore_times)
|
||||||
|
file.close
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_v3_api_warning do
|
||||||
|
file = ::Zip::File.open(TEST_ZIP.zip_name, true, restore_permissions: true)
|
||||||
|
assert(file.restore_permissions)
|
||||||
|
refute(file.restore_times)
|
||||||
|
file.close
|
||||||
|
end
|
||||||
|
|
||||||
|
refute_v3_api_warning do
|
||||||
|
file = ::Zip::File.open(TEST_ZIP.zip_name, create: true, restore_permissions: true)
|
||||||
|
assert(file.restore_permissions)
|
||||||
|
refute(file.restore_times)
|
||||||
|
file.close
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_add_buffer
|
||||||
|
assert_v3_api_warning do
|
||||||
|
Zip::File.add_buffer {}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_get_output_stream
|
||||||
|
refute_v3_api_warning do
|
||||||
|
zf = ::Zip::File.new(EMPTY_FILENAME, create: true)
|
||||||
|
zf.get_output_stream('myFile') { |os| os.write 'myFile contains just this' }
|
||||||
|
zf.close
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_v3_api_warning do
|
||||||
|
zf = ::Zip::File.new(EMPTY_FILENAME, create: true)
|
||||||
|
zf.get_output_stream('myFile', 0o644) { |os| os.write 'myFile contains just this' }
|
||||||
|
zf.close
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class ZipEntryTest < MiniTest::Test
|
||||||
|
include ZipEntryData
|
||||||
|
include ZipV3Assertions
|
||||||
|
|
||||||
|
def test_v3_constructor_and_getters
|
||||||
|
refute_v3_api_warning do
|
||||||
|
entry = ::Zip::Entry.new(TEST_ZIPFILE,
|
||||||
|
TEST_NAME,
|
||||||
|
comment: TEST_COMMENT,
|
||||||
|
extra: TEST_EXTRA,
|
||||||
|
compressed_size: TEST_COMPRESSED_SIZE,
|
||||||
|
crc: TEST_CRC,
|
||||||
|
compression_method: TEST_COMPRESSIONMETHOD,
|
||||||
|
size: TEST_SIZE,
|
||||||
|
time: TEST_TIME)
|
||||||
|
|
||||||
|
assert_equal(TEST_COMMENT, entry.comment)
|
||||||
|
assert_equal(TEST_COMPRESSED_SIZE, entry.compressed_size)
|
||||||
|
assert_equal(TEST_CRC, entry.crc)
|
||||||
|
assert_instance_of(::Zip::ExtraField, entry.extra)
|
||||||
|
assert_equal(TEST_COMPRESSIONMETHOD, entry.compression_method)
|
||||||
|
assert_equal(TEST_NAME, entry.name)
|
||||||
|
assert_equal(TEST_SIZE, entry.size)
|
||||||
|
assert_equal(TEST_TIME, entry.time)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_basic_constructor
|
||||||
|
refute_v3_api_warning do
|
||||||
|
::Zip::Entry.new(TEST_ZIPFILE, TEST_NAME)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_v2_constructor_and_getters
|
||||||
|
assert_v3_api_warning do
|
||||||
|
entry = ::Zip::Entry.new(TEST_ZIPFILE,
|
||||||
|
TEST_NAME,
|
||||||
|
TEST_COMMENT,
|
||||||
|
TEST_EXTRA,
|
||||||
|
TEST_COMPRESSED_SIZE,
|
||||||
|
TEST_CRC,
|
||||||
|
TEST_COMPRESSIONMETHOD,
|
||||||
|
TEST_SIZE,
|
||||||
|
TEST_TIME)
|
||||||
|
|
||||||
|
assert_equal(TEST_COMMENT, entry.comment)
|
||||||
|
assert_equal(TEST_COMPRESSED_SIZE, entry.compressed_size)
|
||||||
|
assert_equal(TEST_CRC, entry.crc)
|
||||||
|
assert_instance_of(::Zip::ExtraField, entry.extra)
|
||||||
|
assert_equal(TEST_COMPRESSIONMETHOD, entry.compression_method)
|
||||||
|
assert_equal(TEST_NAME, entry.name)
|
||||||
|
assert_equal(TEST_SIZE, entry.size)
|
||||||
|
assert_equal(TEST_TIME, entry.time)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class ZipInputStreamTest < MiniTest::Test
|
||||||
|
include ZipV3Assertions
|
||||||
|
|
||||||
|
def test_new_with_old_offset
|
||||||
|
assert_v3_api_warning do
|
||||||
|
zis = ::Zip::InputStream.new(TestZipFile::TEST_ZIP2.zip_name, 100)
|
||||||
|
assert_equal(100, zis.instance_variable_get(:@archive_io).pos)
|
||||||
|
zis.close
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_new_with_new_offset
|
||||||
|
refute_v3_api_warning do
|
||||||
|
zis = ::Zip::InputStream.new(TestZipFile::TEST_ZIP2.zip_name, offset: 100)
|
||||||
|
assert_equal(100, zis.instance_variable_get(:@archive_io).pos)
|
||||||
|
zis.close
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_new_with_clashing_offset
|
||||||
|
assert_v3_api_warning do
|
||||||
|
zis = ::Zip::InputStream.new(TestZipFile::TEST_ZIP2.zip_name, 10, offset: 100)
|
||||||
|
assert_equal(100, zis.instance_variable_get(:@archive_io).pos)
|
||||||
|
zis.close
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_open
|
||||||
|
refute_v3_api_warning do
|
||||||
|
::Zip::InputStream.open(TestZipFile::TEST_ZIP2.zip_name) {}
|
||||||
|
end
|
||||||
|
|
||||||
|
refute_v3_api_warning do
|
||||||
|
::Zip::InputStream.open(TestZipFile::TEST_ZIP2.zip_name, decrypter: true) {}
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_v3_api_warning do
|
||||||
|
::Zip::InputStream.open(TestZipFile::TEST_ZIP2.zip_name, 100, nil) {}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_open_buffer
|
||||||
|
assert_v3_api_warning do
|
||||||
|
::Zip::InputStream.open_buffer(StringIO.new)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class ZipOutputStreamTest < MiniTest::Test
|
||||||
|
include ZipV3Assertions
|
||||||
|
|
||||||
|
TEST_ZIP = TestZipFile::TEST_ZIP2.clone
|
||||||
|
TEST_ZIP.zip_name = 'test/data/generated/output.zip'
|
||||||
|
|
||||||
|
def test_new
|
||||||
|
refute_v3_api_warning do
|
||||||
|
::Zip::OutputStream.new(TEST_ZIP.zip_name)
|
||||||
|
end
|
||||||
|
|
||||||
|
refute_v3_api_warning do
|
||||||
|
::Zip::OutputStream.new(StringIO.new, stream: true)
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_v3_api_warning do
|
||||||
|
::Zip::OutputStream.new(StringIO.new, true)
|
||||||
|
end
|
||||||
|
|
||||||
|
refute_v3_api_warning do
|
||||||
|
::Zip::OutputStream.new(TEST_ZIP.zip_name, stream: false, encrypter: true)
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_v3_api_warning do
|
||||||
|
::Zip::OutputStream.new(TEST_ZIP.zip_name, false, true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_open
|
||||||
|
refute_v3_api_warning do
|
||||||
|
::Zip::OutputStream.open(TEST_ZIP.zip_name) {}
|
||||||
|
end
|
||||||
|
|
||||||
|
refute_v3_api_warning do
|
||||||
|
::Zip::OutputStream.open(TEST_ZIP.zip_name, encrypter: true) {}
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_v3_api_warning do
|
||||||
|
::Zip::OutputStream.open(TEST_ZIP.zip_name, true) {}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_write_buffer
|
||||||
|
refute_v3_api_warning do
|
||||||
|
::Zip::OutputStream.write_buffer(StringIO.new) {}
|
||||||
|
end
|
||||||
|
|
||||||
|
refute_v3_api_warning do
|
||||||
|
::Zip::OutputStream.write_buffer(StringIO.new, encrypter: true) {}
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_v3_api_warning do
|
||||||
|
::Zip::OutputStream.write_buffer(StringIO.new, true) {}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class ZipFileSplitTest < MiniTest::Test
|
||||||
|
include ZipV3Assertions
|
||||||
|
|
||||||
|
TEST_ZIP = TestZipFile::TEST_ZIP2.clone
|
||||||
|
TEST_ZIP.zip_name = 'large_zip_file.zip'
|
||||||
|
|
||||||
|
def setup
|
||||||
|
FileUtils.cp(TestZipFile::TEST_ZIP2.zip_name, TEST_ZIP.zip_name)
|
||||||
|
end
|
||||||
|
|
||||||
|
def teardown
|
||||||
|
File.delete(TEST_ZIP.zip_name)
|
||||||
|
|
||||||
|
Dir["#{TEST_ZIP.zip_name}.*"].each do |zip_file_name|
|
||||||
|
File.delete(zip_file_name) if File.exist?(zip_file_name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_old_split
|
||||||
|
assert_v3_api_warning do
|
||||||
|
Zip::File.split(TEST_ZIP.zip_name, 65_536, false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_new_split
|
||||||
|
refute_v3_api_warning do
|
||||||
|
Zip::File.split(TEST_ZIP.zip_name, segment_size: 65_536, delete_zip_file: false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class ZipDOSTimeTest < MiniTest::Test
|
||||||
|
include ZipV3Assertions
|
||||||
|
|
||||||
|
def test_dos_equals
|
||||||
|
assert_v3_api_warning do
|
||||||
|
time = ::Zip::DOSTime.now
|
||||||
|
assert(time.dos_equals(time))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue