ziperu 0.1.1
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/Cargo.lock +879 -0
- data/Cargo.toml +8 -0
- data/LICENSE-rubyzip.txt +24 -0
- data/LICENSE.txt +21 -0
- data/README.md +276 -0
- data/ext/ziperu/Cargo.toml +35 -0
- data/ext/ziperu/build.rs +4 -0
- data/ext/ziperu/extconf.rb +6 -0
- data/ext/ziperu/src/archive.rs +713 -0
- data/ext/ziperu/src/errors.rs +143 -0
- data/ext/ziperu/src/extract.rs +505 -0
- data/ext/ziperu/src/gvl.rs +64 -0
- data/ext/ziperu/src/lib.rs +78 -0
- data/ext/ziperu/src/reader.rs +351 -0
- data/ext/ziperu/src/source.rs +296 -0
- data/ext/ziperu/src/writer.rs +916 -0
- data/ext/ziperu/src/zipcrypto.rs +126 -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/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 +174 -0
|
@@ -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
|