ziperu 0.1.1-aarch64-linux-musl
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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +24 -0
- data/LICENSE-rubyzip.txt +24 -0
- data/LICENSE.txt +21 -0
- data/README.md +276 -0
- data/lib/rubyzip.rb +4 -0
- data/lib/zip/central_directory.rb +5 -0
- data/lib/zip/compressor.rb +5 -0
- data/lib/zip/constants.rb +5 -0
- data/lib/zip/crypto/aes_encryption.rb +5 -0
- data/lib/zip/crypto/decrypted_io.rb +5 -0
- data/lib/zip/crypto/encryption.rb +5 -0
- data/lib/zip/crypto/null_encryption.rb +5 -0
- data/lib/zip/crypto/traditional_encryption.rb +5 -0
- data/lib/zip/crypto.rb +5 -0
- data/lib/zip/decompressor.rb +5 -0
- data/lib/zip/deflater.rb +5 -0
- data/lib/zip/dirtyable.rb +5 -0
- data/lib/zip/dos_time.rb +5 -0
- data/lib/zip/entry.rb +5 -0
- data/lib/zip/entry_set.rb +5 -0
- data/lib/zip/errors.rb +5 -0
- data/lib/zip/extra_field/aes.rb +5 -0
- data/lib/zip/extra_field/generic.rb +5 -0
- data/lib/zip/extra_field/ntfs.rb +5 -0
- data/lib/zip/extra_field/old_unix.rb +5 -0
- data/lib/zip/extra_field/universal_time.rb +5 -0
- data/lib/zip/extra_field/unix.rb +5 -0
- data/lib/zip/extra_field/unknown.rb +5 -0
- data/lib/zip/extra_field/zip64.rb +5 -0
- data/lib/zip/extra_field.rb +5 -0
- data/lib/zip/file.rb +5 -0
- data/lib/zip/file_split.rb +5 -0
- data/lib/zip/filesystem/dir.rb +5 -0
- data/lib/zip/filesystem/directory_iterator.rb +5 -0
- data/lib/zip/filesystem/file.rb +5 -0
- data/lib/zip/filesystem/file_stat.rb +5 -0
- data/lib/zip/filesystem/zip_file_name_mapper.rb +5 -0
- data/lib/zip/filesystem.rb +5 -0
- data/lib/zip/inflater.rb +5 -0
- data/lib/zip/input_stream.rb +5 -0
- data/lib/zip/ioextras/abstract_input_stream.rb +5 -0
- data/lib/zip/ioextras/abstract_output_stream.rb +5 -0
- data/lib/zip/ioextras/fake_io.rb +5 -0
- data/lib/zip/ioextras.rb +5 -0
- data/lib/zip/null_compressor.rb +5 -0
- data/lib/zip/null_decompressor.rb +5 -0
- data/lib/zip/null_input_stream.rb +5 -0
- data/lib/zip/output_stream.rb +5 -0
- data/lib/zip/pass_thru_compressor.rb +5 -0
- data/lib/zip/pass_thru_decompressor.rb +5 -0
- data/lib/zip/streamable_directory.rb +5 -0
- data/lib/zip/streamable_stream.rb +5 -0
- data/lib/zip/version.rb +5 -0
- data/lib/zip.rb +19 -0
- data/lib/ziperu/3.1/ziperu.so +0 -0
- data/lib/ziperu/3.2/ziperu.so +0 -0
- data/lib/ziperu/3.3/ziperu.so +0 -0
- data/lib/ziperu/3.4/ziperu.so +0 -0
- data/lib/ziperu/4.0/ziperu.so +0 -0
- data/lib/ziperu/central_directory.rb +136 -0
- data/lib/ziperu/compressor.rb +14 -0
- data/lib/ziperu/constants.rb +148 -0
- data/lib/ziperu/crypto.rb +72 -0
- data/lib/ziperu/decompressor.rb +35 -0
- data/lib/ziperu/deflater.rb +41 -0
- data/lib/ziperu/dirtyable.rb +48 -0
- data/lib/ziperu/dos_time.rb +87 -0
- data/lib/ziperu/entry.rb +760 -0
- data/lib/ziperu/entry_set.rb +147 -0
- data/lib/ziperu/errors.rb +154 -0
- data/lib/ziperu/extra_field/aes.rb +52 -0
- data/lib/ziperu/extra_field/generic.rb +45 -0
- data/lib/ziperu/extra_field/ntfs.rb +98 -0
- data/lib/ziperu/extra_field/old_unix.rb +52 -0
- data/lib/ziperu/extra_field/universal_time.rb +81 -0
- data/lib/ziperu/extra_field/unix.rb +45 -0
- data/lib/ziperu/extra_field/unknown.rb +37 -0
- data/lib/ziperu/extra_field/zip64.rb +86 -0
- data/lib/ziperu/extra_field.rb +109 -0
- data/lib/ziperu/file.rb +614 -0
- data/lib/ziperu/file_split.rb +93 -0
- data/lib/ziperu/filesystem/dir.rb +88 -0
- data/lib/ziperu/filesystem/directory_iterator.rb +50 -0
- data/lib/ziperu/filesystem/file.rb +265 -0
- data/lib/ziperu/filesystem/file_stat.rb +112 -0
- data/lib/ziperu/filesystem/zip_file_name_mapper.rb +83 -0
- data/lib/ziperu/filesystem.rb +76 -0
- data/lib/ziperu/inflater.rb +60 -0
- data/lib/ziperu/input_stream.rb +296 -0
- data/lib/ziperu/ioextras/abstract_input_stream.rb +137 -0
- data/lib/ziperu/ioextras/abstract_output_stream.rb +57 -0
- data/lib/ziperu/ioextras/fake_io.rb +41 -0
- data/lib/ziperu/ioextras.rb +42 -0
- data/lib/ziperu/null_compressor.rb +20 -0
- data/lib/ziperu/null_decompressor.rb +25 -0
- data/lib/ziperu/null_input_stream.rb +55 -0
- data/lib/ziperu/output_stream.rb +223 -0
- data/lib/ziperu/pass_thru_compressor.rb +29 -0
- data/lib/ziperu/pass_thru_decompressor.rb +37 -0
- data/lib/ziperu/streamable_directory.rb +15 -0
- data/lib/ziperu/streamable_stream.rb +59 -0
- data/lib/ziperu/version.rb +7 -0
- data/lib/ziperu.rb +116 -0
- metadata +156 -0
data/lib/zip/version.rb
ADDED
data/lib/zip.rb
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# rubyzip's entry point. Loading ziperu this way makes `Zip` an alias of
|
|
4
|
+
# `Ziperu`, so code written against rubyzip (`Zip::File`, `Zip.setup`, ...)
|
|
5
|
+
# runs unchanged. If another library already defines `Zip` (rubyzip itself,
|
|
6
|
+
# most likely), the two cannot share the name: load ziperu with
|
|
7
|
+
# `require "ziperu"` and use `Ziperu::` directly instead.
|
|
8
|
+
if defined?(::Zip) && !(defined?(::Ziperu) && ::Zip.equal?(::Ziperu))
|
|
9
|
+
raise LoadError, "ziperu cannot alias Zip = Ziperu: a Zip constant is already defined " \
|
|
10
|
+
"(by #{Object.const_source_location(:Zip)&.first || 'another library'}). " \
|
|
11
|
+
"Remove rubyzip, or require \"ziperu\" and use Ziperu:: instead."
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
require "ziperu"
|
|
15
|
+
Zip = Ziperu unless defined?(::Zip)
|
|
16
|
+
|
|
17
|
+
# The `zip/...` paths rubyzip's files live at (`require "zip/filesystem"`
|
|
18
|
+
# is the common one) are kept under lib/zip/ as one-line shims onto the
|
|
19
|
+
# matching lib/ziperu/ file.
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# The end-of-central-directory parsing is ported from rubyzip
|
|
4
|
+
# (Copyright (C) 2002-2026 the rubyzip authors).
|
|
5
|
+
|
|
6
|
+
module Ziperu
|
|
7
|
+
# Reads just the end-of-central-directory records of an archive, in Ruby.
|
|
8
|
+
#
|
|
9
|
+
# The native core refuses archives whose EOCD declares more entries than
|
|
10
|
+
# the central directory holds, so `Ziperu::File.open` raises on them
|
|
11
|
+
# where rubyzip warns (or raises `EntryNumberMismatchError` when
|
|
12
|
+
# `Ziperu.validate_declared_number_of_entries` is set). This gives
|
|
13
|
+
# `Ziperu::File.count_entries` rubyzip's behaviour at least.
|
|
14
|
+
class CentralDirectory # :nodoc:all
|
|
15
|
+
END_OF_CD_SIG = 0x06054b50
|
|
16
|
+
ZIP64_END_OF_CD_SIG = 0x06064b50
|
|
17
|
+
ZIP64_EOCD_LOCATOR_SIG = 0x07064b50
|
|
18
|
+
|
|
19
|
+
STATIC_EOCD_SIZE = 22
|
|
20
|
+
ZIP64_STATIC_EOCD_SIZE = 56
|
|
21
|
+
ZIP64_EOCD_LOC_SIZE = 20
|
|
22
|
+
MAX_FILE_COMMENT_SIZE = (1 << 16) - 1
|
|
23
|
+
MAX_END_OF_CD_SIZE =
|
|
24
|
+
MAX_FILE_COMMENT_SIZE + STATIC_EOCD_SIZE + ZIP64_EOCD_LOC_SIZE
|
|
25
|
+
|
|
26
|
+
attr_reader :size, :cdir_offset, :comment
|
|
27
|
+
|
|
28
|
+
# Number of entries declared by the EOCD of `path_or_io`.
|
|
29
|
+
def self.count_entries(path_or_io)
|
|
30
|
+
if path_or_io.respond_to?(:read)
|
|
31
|
+
new.count_entries(path_or_io)
|
|
32
|
+
else
|
|
33
|
+
::File.open(path_or_io.to_s, 'rb') { |io| new.count_entries(io) }
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def count_entries(io)
|
|
38
|
+
read_eocds(io)
|
|
39
|
+
@size
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
def unpack_64_e_o_c_d(buffer)
|
|
45
|
+
_, # ZIP64_END_OF_CD_SIG. We know we have this at this point.
|
|
46
|
+
_size_of_zip64_e_o_c_d,
|
|
47
|
+
_version_made_by,
|
|
48
|
+
_version_needed_for_extract,
|
|
49
|
+
_number_of_this_disk,
|
|
50
|
+
_number_of_disk_with_start_of_cdir,
|
|
51
|
+
_total_number_of_entries_in_cdir_on_this_disk,
|
|
52
|
+
@size,
|
|
53
|
+
size_in_bytes,
|
|
54
|
+
@cdir_offset = buffer.unpack('VQ<vvVVQ<Q<Q<Q<')
|
|
55
|
+
|
|
56
|
+
validate_size!(@size, size_in_bytes)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def unpack_64_eocd_locator(buffer)
|
|
60
|
+
_, _, zip64_eocd_offset, = buffer.unpack('VVQ<V')
|
|
61
|
+
zip64_eocd_offset
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Returns true when the plain EOCD was complete (no zip64 needed).
|
|
65
|
+
def unpack_e_o_c_d(buffer)
|
|
66
|
+
_, # END_OF_CD_SIG. We know we have this at this point.
|
|
67
|
+
number_of_this_disk,
|
|
68
|
+
number_of_disk_with_start_of_cdir,
|
|
69
|
+
total_number_of_entries_in_cdir_on_this_disk,
|
|
70
|
+
@size,
|
|
71
|
+
size_in_bytes,
|
|
72
|
+
@cdir_offset,
|
|
73
|
+
comment_length = buffer.unpack('VvvvvVVv')
|
|
74
|
+
|
|
75
|
+
complete = !([number_of_this_disk, number_of_disk_with_start_of_cdir,
|
|
76
|
+
total_number_of_entries_in_cdir_on_this_disk, @size].any?(0xFFFF) ||
|
|
77
|
+
size_in_bytes == 0xFFFFFFFF || @cdir_offset == 0xFFFFFFFF)
|
|
78
|
+
|
|
79
|
+
validate_size!(@size, size_in_bytes) if complete
|
|
80
|
+
|
|
81
|
+
@comment = comment_length.positive? ? buffer.slice(STATIC_EOCD_SIZE, comment_length) : ''
|
|
82
|
+
complete
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def read_eocds(io)
|
|
86
|
+
base_location, data = eocd_data(io)
|
|
87
|
+
|
|
88
|
+
eocd_location = data.rindex([END_OF_CD_SIG].pack('V'))
|
|
89
|
+
raise Error, 'Zip end of central directory signature not found' unless eocd_location
|
|
90
|
+
|
|
91
|
+
return if unpack_e_o_c_d(data.slice(eocd_location..-1))
|
|
92
|
+
|
|
93
|
+
zip64_eocd_locator = data.rindex([ZIP64_EOCD_LOCATOR_SIG].pack('V'), eocd_location)
|
|
94
|
+
unless zip64_eocd_locator
|
|
95
|
+
raise Error, 'Zip64 end of central directory locator signature expected but not found'
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
zip64_eocd_location = data.rindex([ZIP64_END_OF_CD_SIG].pack('V'), zip64_eocd_locator)
|
|
99
|
+
|
|
100
|
+
zip64_eocd_data =
|
|
101
|
+
if zip64_eocd_location
|
|
102
|
+
data.slice(zip64_eocd_location..zip64_eocd_locator)
|
|
103
|
+
else
|
|
104
|
+
zip64_eocd_location = unpack_64_eocd_locator(
|
|
105
|
+
data.slice(zip64_eocd_locator..eocd_location)
|
|
106
|
+
)
|
|
107
|
+
raise Error, 'Zip64 end of central directory signature not found' unless zip64_eocd_location
|
|
108
|
+
|
|
109
|
+
io.seek(zip64_eocd_location, IO::SEEK_SET)
|
|
110
|
+
io.read(base_location + zip64_eocd_locator - zip64_eocd_location)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
unpack_64_e_o_c_d(zip64_eocd_data)
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def eocd_data(io)
|
|
117
|
+
io.binmode if io.respond_to?(:binmode)
|
|
118
|
+
begin
|
|
119
|
+
io.seek(-MAX_END_OF_CD_SIZE, IO::SEEK_END)
|
|
120
|
+
rescue Errno::EINVAL
|
|
121
|
+
io.seek(0, IO::SEEK_SET)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
[io.tell, io.read.to_s.b]
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def validate_size!(size, size_in_bytes)
|
|
128
|
+
return if size * CDIR_ENTRY_STATIC_HEADER_LENGTH <= size_in_bytes
|
|
129
|
+
|
|
130
|
+
error = EntryNumberMismatchError.new(size, size_in_bytes)
|
|
131
|
+
raise error if Ziperu.validate_declared_number_of_entries
|
|
132
|
+
|
|
133
|
+
warn error.message
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Ported verbatim from rubyzip (Copyright (C) 2002-2026 the rubyzip authors).
|
|
4
|
+
# Not on any ziperu code path: the Rust core compresses and decompresses.
|
|
5
|
+
# Kept so that code which references these classes keeps loading.
|
|
6
|
+
module Ziperu
|
|
7
|
+
class Compressor # :nodoc:all
|
|
8
|
+
def finish; end
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Copyright (C) 2002, 2003 Thomas Sondergaard
|
|
13
|
+
# rubyzip is free software; you can redistribute it and/or
|
|
14
|
+
# modify it under the terms of the ruby license.
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# rubyzip's constants, verbatim, plus the newer compression methods the Rust
|
|
4
|
+
# core can read.
|
|
5
|
+
module Ziperu
|
|
6
|
+
# :stopdoc:
|
|
7
|
+
|
|
8
|
+
RUNNING_ON_WINDOWS = RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/i
|
|
9
|
+
|
|
10
|
+
CENTRAL_DIRECTORY_ENTRY_SIGNATURE = 0x02014b50
|
|
11
|
+
CDIR_ENTRY_STATIC_HEADER_LENGTH = 46
|
|
12
|
+
|
|
13
|
+
LOCAL_ENTRY_SIGNATURE = 0x04034b50
|
|
14
|
+
LOCAL_ENTRY_STATIC_HEADER_LENGTH = 30
|
|
15
|
+
LOCAL_ENTRY_TRAILING_DESCRIPTOR_LENGTH = 4 + 4 + 4
|
|
16
|
+
VERSION_MADE_BY = 52
|
|
17
|
+
VERSION_NEEDED_TO_EXTRACT = 20
|
|
18
|
+
VERSION_NEEDED_TO_EXTRACT_ZIP64 = 45
|
|
19
|
+
VERSION_NEEDED_TO_EXTRACT_AES = 51
|
|
20
|
+
|
|
21
|
+
SPLIT_FILE_SIGNATURE = 0x08074b50
|
|
22
|
+
|
|
23
|
+
FILE_TYPE_FILE = 0o10
|
|
24
|
+
FILE_TYPE_DIR = 0o04
|
|
25
|
+
FILE_TYPE_SYMLINK = 0o12
|
|
26
|
+
|
|
27
|
+
FSTYPE_FAT = 0
|
|
28
|
+
FSTYPE_AMIGA = 1
|
|
29
|
+
FSTYPE_VMS = 2
|
|
30
|
+
FSTYPE_UNIX = 3
|
|
31
|
+
FSTYPE_VM_CMS = 4
|
|
32
|
+
FSTYPE_ATARI = 5
|
|
33
|
+
FSTYPE_HPFS = 6
|
|
34
|
+
FSTYPE_MAC = 7
|
|
35
|
+
FSTYPE_Z_SYSTEM = 8
|
|
36
|
+
FSTYPE_CPM = 9
|
|
37
|
+
FSTYPE_TOPS20 = 10
|
|
38
|
+
FSTYPE_NTFS = 11
|
|
39
|
+
FSTYPE_QDOS = 12
|
|
40
|
+
FSTYPE_ACORN = 13
|
|
41
|
+
FSTYPE_VFAT = 14
|
|
42
|
+
FSTYPE_MVS = 15
|
|
43
|
+
FSTYPE_BEOS = 16
|
|
44
|
+
FSTYPE_TANDEM = 17
|
|
45
|
+
FSTYPE_THEOS = 18
|
|
46
|
+
FSTYPE_MAC_OSX = 19
|
|
47
|
+
FSTYPE_ATHEOS = 30
|
|
48
|
+
|
|
49
|
+
FSTYPES = {
|
|
50
|
+
FSTYPE_FAT => 'FAT',
|
|
51
|
+
FSTYPE_AMIGA => 'Amiga',
|
|
52
|
+
FSTYPE_VMS => 'VMS (Vax or Alpha AXP)',
|
|
53
|
+
FSTYPE_UNIX => 'Unix',
|
|
54
|
+
FSTYPE_VM_CMS => 'VM/CMS',
|
|
55
|
+
FSTYPE_ATARI => 'Atari ST',
|
|
56
|
+
FSTYPE_HPFS => 'OS/2 or NT HPFS',
|
|
57
|
+
FSTYPE_MAC => 'Macintosh',
|
|
58
|
+
FSTYPE_Z_SYSTEM => 'Z-System',
|
|
59
|
+
FSTYPE_CPM => 'CP/M',
|
|
60
|
+
FSTYPE_TOPS20 => 'TOPS-20',
|
|
61
|
+
FSTYPE_NTFS => 'NTFS',
|
|
62
|
+
FSTYPE_QDOS => 'SMS/QDOS',
|
|
63
|
+
FSTYPE_ACORN => 'Acorn RISC OS',
|
|
64
|
+
FSTYPE_VFAT => 'Win32 VFAT',
|
|
65
|
+
FSTYPE_MVS => 'MVS',
|
|
66
|
+
FSTYPE_BEOS => 'BeOS',
|
|
67
|
+
FSTYPE_TANDEM => 'Tandem NSK',
|
|
68
|
+
FSTYPE_THEOS => 'Theos',
|
|
69
|
+
FSTYPE_MAC_OSX => 'Mac OS/X (Darwin)',
|
|
70
|
+
FSTYPE_ATHEOS => 'AtheOS'
|
|
71
|
+
}.freeze
|
|
72
|
+
|
|
73
|
+
COMPRESSION_METHOD_STORE = 0
|
|
74
|
+
COMPRESSION_METHOD_SHRINK = 1
|
|
75
|
+
COMPRESSION_METHOD_REDUCE_1 = 2
|
|
76
|
+
COMPRESSION_METHOD_REDUCE_2 = 3
|
|
77
|
+
COMPRESSION_METHOD_REDUCE_3 = 4
|
|
78
|
+
COMPRESSION_METHOD_REDUCE_4 = 5
|
|
79
|
+
COMPRESSION_METHOD_IMPLODE = 6
|
|
80
|
+
COMPRESSION_METHOD_DEFLATE = 8
|
|
81
|
+
COMPRESSION_METHOD_DEFLATE_64 = 9
|
|
82
|
+
COMPRESSION_METHOD_DEFLATE64 = COMPRESSION_METHOD_DEFLATE_64
|
|
83
|
+
COMPRESSION_METHOD_PKWARE_DCLI = 10
|
|
84
|
+
COMPRESSION_METHOD_BZIP2 = 12
|
|
85
|
+
COMPRESSION_METHOD_LZMA = 14
|
|
86
|
+
COMPRESSION_METHOD_IBM_CMPSC = 16
|
|
87
|
+
COMPRESSION_METHOD_IBM_TERSE = 18
|
|
88
|
+
COMPRESSION_METHOD_IBM_LZ77 = 19
|
|
89
|
+
COMPRESSION_METHOD_ZSTD = 93
|
|
90
|
+
COMPRESSION_METHOD_XZ = 95
|
|
91
|
+
COMPRESSION_METHOD_JPEG = 96
|
|
92
|
+
COMPRESSION_METHOD_WAVPACK = 97
|
|
93
|
+
COMPRESSION_METHOD_PPMD = 98
|
|
94
|
+
COMPRESSION_METHOD_AES = 99
|
|
95
|
+
|
|
96
|
+
COMPRESSION_METHODS = {
|
|
97
|
+
COMPRESSION_METHOD_STORE => 'Store (no compression)',
|
|
98
|
+
COMPRESSION_METHOD_SHRINK => 'Shrink',
|
|
99
|
+
COMPRESSION_METHOD_REDUCE_1 => 'Reduce with compression factor 1',
|
|
100
|
+
COMPRESSION_METHOD_REDUCE_2 => 'Reduce with compression factor 2',
|
|
101
|
+
COMPRESSION_METHOD_REDUCE_3 => 'Reduce with compression factor 3',
|
|
102
|
+
COMPRESSION_METHOD_REDUCE_4 => 'Reduce with compression factor 4',
|
|
103
|
+
COMPRESSION_METHOD_IMPLODE => 'Implode',
|
|
104
|
+
COMPRESSION_METHOD_DEFLATE => 'Deflate',
|
|
105
|
+
COMPRESSION_METHOD_DEFLATE_64 => 'Deflate64(tm)',
|
|
106
|
+
COMPRESSION_METHOD_PKWARE_DCLI => 'PKWARE Data Compression Library Imploding (old IBM TERSE)',
|
|
107
|
+
COMPRESSION_METHOD_BZIP2 => 'BZIP2',
|
|
108
|
+
COMPRESSION_METHOD_LZMA => 'LZMA',
|
|
109
|
+
COMPRESSION_METHOD_IBM_CMPSC => 'IBM z/OS CMPSC Compression',
|
|
110
|
+
COMPRESSION_METHOD_IBM_TERSE => 'IBM TERSE (new)',
|
|
111
|
+
COMPRESSION_METHOD_IBM_LZ77 => 'IBM LZ77 z Architecture (PFS)',
|
|
112
|
+
COMPRESSION_METHOD_ZSTD => 'Zstandard',
|
|
113
|
+
COMPRESSION_METHOD_XZ => 'XZ',
|
|
114
|
+
COMPRESSION_METHOD_JPEG => 'JPEG variant',
|
|
115
|
+
COMPRESSION_METHOD_WAVPACK => 'WavPack compressed data',
|
|
116
|
+
COMPRESSION_METHOD_PPMD => 'PPMd version I, Rev 1',
|
|
117
|
+
COMPRESSION_METHOD_AES => 'AES encryption'
|
|
118
|
+
}.freeze
|
|
119
|
+
|
|
120
|
+
# Methods the Rust core can decompress.
|
|
121
|
+
READABLE_COMPRESSION_METHODS = [
|
|
122
|
+
COMPRESSION_METHOD_STORE,
|
|
123
|
+
COMPRESSION_METHOD_SHRINK,
|
|
124
|
+
COMPRESSION_METHOD_REDUCE_1,
|
|
125
|
+
COMPRESSION_METHOD_REDUCE_2,
|
|
126
|
+
COMPRESSION_METHOD_REDUCE_3,
|
|
127
|
+
COMPRESSION_METHOD_REDUCE_4,
|
|
128
|
+
COMPRESSION_METHOD_IMPLODE,
|
|
129
|
+
COMPRESSION_METHOD_DEFLATE,
|
|
130
|
+
COMPRESSION_METHOD_DEFLATE_64,
|
|
131
|
+
COMPRESSION_METHOD_BZIP2,
|
|
132
|
+
COMPRESSION_METHOD_LZMA,
|
|
133
|
+
COMPRESSION_METHOD_ZSTD,
|
|
134
|
+
COMPRESSION_METHOD_XZ,
|
|
135
|
+
COMPRESSION_METHOD_PPMD,
|
|
136
|
+
COMPRESSION_METHOD_AES
|
|
137
|
+
].freeze
|
|
138
|
+
|
|
139
|
+
# Methods the Rust core can compress with.
|
|
140
|
+
WRITABLE_COMPRESSION_METHODS = [
|
|
141
|
+
COMPRESSION_METHOD_STORE,
|
|
142
|
+
COMPRESSION_METHOD_DEFLATE,
|
|
143
|
+
COMPRESSION_METHOD_BZIP2,
|
|
144
|
+
COMPRESSION_METHOD_ZSTD
|
|
145
|
+
].freeze
|
|
146
|
+
|
|
147
|
+
# :startdoc:
|
|
148
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ziperu
|
|
4
|
+
# The encrypter/decrypter objects rubyzip's API passes around
|
|
5
|
+
# (`encrypter:` / `decrypter:` keywords). The Rust core does the actual
|
|
6
|
+
# ZipCrypto/AES work, so these are typed password holders.
|
|
7
|
+
class Decrypter # :nodoc:
|
|
8
|
+
attr_reader :password
|
|
9
|
+
|
|
10
|
+
def initialize(password)
|
|
11
|
+
@password = password.to_s
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
class TraditionalDecrypter < Decrypter; end
|
|
16
|
+
|
|
17
|
+
class AESDecrypter < Decrypter
|
|
18
|
+
def initialize(password, _strength = nil)
|
|
19
|
+
super(password)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
module AESEncryption # :nodoc:
|
|
24
|
+
STRENGTH_128_BIT = 0x01
|
|
25
|
+
STRENGTH_192_BIT = 0x02
|
|
26
|
+
STRENGTH_256_BIT = 0x03
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
class Encrypter # :nodoc:
|
|
30
|
+
attr_reader :password
|
|
31
|
+
|
|
32
|
+
def initialize(password)
|
|
33
|
+
@password = password.to_s
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Options for the native writer.
|
|
37
|
+
def native_options # :nodoc:
|
|
38
|
+
{}
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
class NullEncrypter < Encrypter
|
|
43
|
+
def initialize
|
|
44
|
+
super(nil)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# ZipCrypto, the weak legacy cipher that Windows Explorer and other
|
|
49
|
+
# AES-less tools can open. Entries are written with general purpose bits
|
|
50
|
+
# 0 and 3 set, as rubyzip writes them; only Stored and Deflate entries
|
|
51
|
+
# can be encrypted this way.
|
|
52
|
+
class TraditionalEncrypter < Encrypter
|
|
53
|
+
def native_options # :nodoc:
|
|
54
|
+
{ password: @password.b, zipcrypto: true }
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
class AESEncrypter < Encrypter
|
|
59
|
+
include AESEncryption
|
|
60
|
+
|
|
61
|
+
attr_reader :strength
|
|
62
|
+
|
|
63
|
+
def initialize(password, strength = STRENGTH_256_BIT)
|
|
64
|
+
super(password)
|
|
65
|
+
@strength = strength
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def native_options # :nodoc:
|
|
69
|
+
{ password: @password.b, aes_mode: @strength }
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Ported verbatim from rubyzip (Copyright (C) 2002-2026 the rubyzip authors).
|
|
4
|
+
# Not on any ziperu code path: the Rust core compresses and decompresses.
|
|
5
|
+
# Kept so that code which references these classes keeps loading.
|
|
6
|
+
module Ziperu
|
|
7
|
+
class Decompressor # :nodoc:all
|
|
8
|
+
CHUNK_SIZE = 32_768
|
|
9
|
+
|
|
10
|
+
def self.decompressor_classes
|
|
11
|
+
@decompressor_classes ||= {}
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def self.register(compression_method, decompressor_class)
|
|
15
|
+
decompressor_classes[compression_method] = decompressor_class
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def self.find_by_compression_method(compression_method)
|
|
19
|
+
decompressor_classes[compression_method]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
attr_reader :decompressed_size, :input_stream
|
|
23
|
+
|
|
24
|
+
def initialize(input_stream, decompressed_size = nil)
|
|
25
|
+
super()
|
|
26
|
+
|
|
27
|
+
@input_stream = input_stream
|
|
28
|
+
@decompressed_size = decompressed_size
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Copyright (C) 2002, 2003 Thomas Sondergaard
|
|
34
|
+
# rubyzip is free software; you can redistribute it and/or
|
|
35
|
+
# modify it under the terms of the ruby license.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Ported verbatim from rubyzip (Copyright (C) 2002-2026 the rubyzip authors).
|
|
4
|
+
# Not on any ziperu code path: the Rust core compresses and decompresses.
|
|
5
|
+
# Kept so that code which references these classes keeps loading.
|
|
6
|
+
module Ziperu
|
|
7
|
+
class Deflater < Compressor # :nodoc:all
|
|
8
|
+
def initialize(output_stream, level = Ziperu.default_compression, encrypter = NullEncrypter.new)
|
|
9
|
+
super()
|
|
10
|
+
@output_stream = output_stream
|
|
11
|
+
@zlib_deflater = ::Zlib::Deflate.new(level, -::Zlib::MAX_WBITS)
|
|
12
|
+
@size = 0
|
|
13
|
+
@crc = ::Zlib.crc32
|
|
14
|
+
@encrypter = encrypter
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def <<(data)
|
|
18
|
+
val = data.to_s
|
|
19
|
+
@crc = Zlib.crc32(val, @crc)
|
|
20
|
+
@size += val.bytesize
|
|
21
|
+
|
|
22
|
+
# When JRuby#3962 is fixed, we can remove the flushing parameter here.
|
|
23
|
+
buffer = @zlib_deflater.deflate(data, Ziperu::ZLIB_FLUSHING_STRATEGY)
|
|
24
|
+
return @output_stream if buffer.empty?
|
|
25
|
+
|
|
26
|
+
@output_stream << @encrypter.encrypt(buffer)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def finish
|
|
30
|
+
buffer = @zlib_deflater.finish
|
|
31
|
+
@output_stream << @encrypter.encrypt(buffer) unless buffer.empty?
|
|
32
|
+
@zlib_deflater.close
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
attr_reader :size, :crc
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Copyright (C) 2002, 2003 Thomas Sondergaard
|
|
40
|
+
# rubyzip is free software; you can redistribute it and/or
|
|
41
|
+
# modify it under the terms of the ruby license.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Ported from rubyzip (Copyright (C) 2002-2026 the rubyzip authors), with
|
|
4
|
+
# the setters that dirtied the object recorded as well as the flag: an
|
|
5
|
+
# entry whose only change the native raw copy can carry (a rename, or a
|
|
6
|
+
# chmod) need not be recompressed on commit.
|
|
7
|
+
|
|
8
|
+
module Ziperu
|
|
9
|
+
module Dirtyable # :nodoc:all
|
|
10
|
+
def initialize(dirty_on_create: true)
|
|
11
|
+
@dirty = dirty_on_create
|
|
12
|
+
@dirty_fields = []
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def dirty?
|
|
16
|
+
@dirty
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# The setters called since the object was last clean, as symbols.
|
|
20
|
+
def dirty_fields
|
|
21
|
+
@dirty_fields ||= []
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def mark_dirty!(field)
|
|
25
|
+
@dirty = true
|
|
26
|
+
dirty_fields << field unless dirty_fields.include?(field)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
module ClassMethods # :nodoc:
|
|
30
|
+
def mark_dirty(*symbols) # :nodoc:
|
|
31
|
+
# Move the original method and call it after we've set the dirty flag.
|
|
32
|
+
symbols.each do |symbol|
|
|
33
|
+
orig_name = "orig_#{symbol}"
|
|
34
|
+
alias_method orig_name, symbol
|
|
35
|
+
|
|
36
|
+
define_method(symbol) do |param|
|
|
37
|
+
mark_dirty!(symbol)
|
|
38
|
+
send(orig_name, param)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def self.included(base)
|
|
45
|
+
base.extend(ClassMethods)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Ported from rubyzip (Copyright (C) 2002-2026 the rubyzip authors).
|
|
4
|
+
|
|
5
|
+
module Ziperu
|
|
6
|
+
# A Time that knows how to round-trip the MS-DOS date/time packed into a
|
|
7
|
+
# zip header. Mirrors rubyzip's class so `entry.time` behaves identically.
|
|
8
|
+
class DOSTime < Time # :nodoc:all
|
|
9
|
+
# MS-DOS File Date and Time format as used in Interrupt 21H Function 57H:
|
|
10
|
+
#
|
|
11
|
+
# Register CX, the Time:
|
|
12
|
+
# Bits 0-4 2 second increments (0-29)
|
|
13
|
+
# Bits 5-10 minutes (0-59)
|
|
14
|
+
# bits 11-15 hours (0-24)
|
|
15
|
+
#
|
|
16
|
+
# Register DX, the Date:
|
|
17
|
+
# Bits 0-4 day (1-31)
|
|
18
|
+
# bits 5-8 month (1-12)
|
|
19
|
+
# bits 9-15 year (four digit year minus 1980)
|
|
20
|
+
|
|
21
|
+
# The MS-DOS date field is seven bits of "year minus 1980", so only
|
|
22
|
+
# 1980-01-01 00:00:00 through 2107-12-31 23:59:58 can be represented.
|
|
23
|
+
# Times outside that are clamped rather than allowed to wrap: the real
|
|
24
|
+
# time is still carried in the universal time (UT) extra field, but the
|
|
25
|
+
# DOS fields have to stay in range for readers that only look at those.
|
|
26
|
+
DOS_EPOCH_YEAR = 1980
|
|
27
|
+
DOS_MAX_YEAR = 2107
|
|
28
|
+
DOS_MIN_DATE = 0x0021 # 1980-01-01
|
|
29
|
+
DOS_MAX_DATE = 0xff9f # 2107-12-31
|
|
30
|
+
DOS_MIN_TIME = 0x0000 # 00:00:00
|
|
31
|
+
DOS_MAX_TIME = 0xbf7d # 23:59:58
|
|
32
|
+
|
|
33
|
+
attr_writer :absolute_time # :nodoc:
|
|
34
|
+
|
|
35
|
+
# Times built from a DOS field carry no timezone; everything else does.
|
|
36
|
+
def absolute_time?
|
|
37
|
+
@absolute_time.nil? || @absolute_time
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def to_binary_dos_time
|
|
41
|
+
return DOS_MIN_TIME if year < DOS_EPOCH_YEAR
|
|
42
|
+
return DOS_MAX_TIME if year > DOS_MAX_YEAR
|
|
43
|
+
|
|
44
|
+
(sec / 2) + (min << 5) + (hour << 11)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def to_binary_dos_date
|
|
48
|
+
return DOS_MIN_DATE if year < DOS_EPOCH_YEAR
|
|
49
|
+
return DOS_MAX_DATE if year > DOS_MAX_YEAR
|
|
50
|
+
|
|
51
|
+
day + (month << 5) + ((year - DOS_EPOCH_YEAR) << 9)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Deprecated. Remove for version 4.
|
|
55
|
+
def dos_equals(other)
|
|
56
|
+
warn 'Ziperu::DOSTime#dos_equals is deprecated. Use `==` instead.'
|
|
57
|
+
self == other
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# DOS time is only stored with two seconds accuracy.
|
|
61
|
+
def <=>(other)
|
|
62
|
+
return unless other.kind_of?(Time)
|
|
63
|
+
|
|
64
|
+
(to_i / 2) <=> (other.to_i / 2)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Create a DOSTime instance from a vanilla Time instance.
|
|
68
|
+
def self.from_time(time)
|
|
69
|
+
local(time.year, time.month, time.day, time.hour, time.min, time.sec)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Raises ArgumentError for fields that don't make a valid date, like
|
|
73
|
+
# rubyzip; callers decide whether to warn.
|
|
74
|
+
def self.parse_binary_dos_format(bin_dos_date, bin_dos_time)
|
|
75
|
+
second = 2 * (0b11111 & bin_dos_time)
|
|
76
|
+
minute = (0b11111100000 & bin_dos_time) >> 5
|
|
77
|
+
hour = (0b1111100000000000 & bin_dos_time) >> 11
|
|
78
|
+
day = (0b11111 & bin_dos_date)
|
|
79
|
+
month = (0b111100000 & bin_dos_date) >> 5
|
|
80
|
+
year = ((0b1111111000000000 & bin_dos_date) >> 9) + 1980
|
|
81
|
+
|
|
82
|
+
time = local(year, month, day, hour, minute, second)
|
|
83
|
+
time.absolute_time = false
|
|
84
|
+
time
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|