aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/zip.cr382
1 files changed, 191 insertions, 191 deletions
diff --git a/src/zip.cr b/src/zip.cr
index ea0142f..dff3014 100644
--- a/src/zip.cr
+++ b/src/zip.cr
@@ -399,6 +399,197 @@ module Zip
end
#
+ # Extra data handlers.
+ #
+ module Extra
+ #
+ # Raw extra data associated with `Entry`.
+ #
+ # You should not need to instantiate this class directly; use
+ # `Zip::Entry#extras` or `Zip::Entry#local_extras` instead.
+ #
+ # Example:
+ #
+ # # open "foo.zip"
+ # Zip.read("foo.zip") do |zip|
+ # # get extra data associated with "bar.txt"
+ # extras = zip["bar.txt"].extras
+ # end
+ #
+ class Base
+ #
+ # Identifier for this extra entry.
+ #
+ property :code
+
+ #
+ # Data for this extra entry.
+ #
+ property :data
+
+ #
+ # Create a new raw extra data entry.
+ #
+ # You should not need to instantiate this class directly; it is
+ # created as-needed by `Writer#add`.
+ #
+ def initialize(@code : UInt16, @data : Bytes)
+ end
+
+ #
+ # Return number of bytes needed for this Extra.
+ #
+ def bytes_needed : UInt16
+ (4 + @data.size).to_u16
+ end
+
+ def to_s(io) : UInt16
+ @code.to_u16.to_io(io, LE)
+ @data.size.to_u16.to_io(io, LE)
+ @data.to_s(io)
+
+ # return number of bytes written
+ bytes_needed
+ end
+ end
+
+ #
+ # ZIP64 extra data associated with `Entry`.
+ #
+ # You should not need to instantiate this class directly; it is
+ # created as-needed by `Writer#add()`.
+ #
+ class Zip64 < Base
+ #
+ # File size (64-bit unsigned integer).
+ #
+ getter :size
+
+ #
+ # Compressed file size (64-bit unsigned integer).
+ #
+ getter :compressed_size
+
+ #
+ # Position in output (optional).
+ #
+ getter :pos
+
+ #
+ # Starting disk (optional).
+ #
+ getter :disk_start
+
+ #
+ # ZIP64 extra code
+ #
+ CODE = 0x0001.to_u16
+
+ #
+ # Create ZIP64 extra data associated with `Entry` from given
+ # attributes.
+ #
+ # You should not need to instantiate this class directly; it is
+ # created as-needed by `Writer#add()`.
+ #
+ def initialize(
+ @size : UInt64 = 0_u64,
+ @compressed_size : UInt64 = 0_u64,
+ @pos : UInt64? = nil,
+ @disk_start : UInt32? = nil,
+ )
+ len = 16_u32
+ len += 8 if @pos
+ len += 4 if @disk_start
+
+ # create backing buffer and mem io
+ buf = Bytes.new(len)
+ io = MemoryIO.new(buf)
+
+ @size.to_u64.to_io(io, LE)
+ @compressed_size.to_u64.to_io(io, LE)
+ @pos.not_nil!.to_u64.to_io(io, LE) if @pos
+ @disk_start.not_nil!.to_u32.to_io(io, LE) if @disk_start
+
+ # close io
+ io.close
+
+ super(CODE, buf)
+ end
+
+ #
+ # Parse ZIP64 extra data from given buffer.
+ #
+ # You should not need to instantiate this class directly; it is
+ # created as-needed by `Archive`.
+ #
+ def initialize(data : Bytes)
+ super(CODE, data)
+
+ # create memory io over buffer
+ io = MemoryIO.new(data, false)
+
+ @size = UInt64.from_io(io, LE).as(UInt64)
+ @compressed_size = UInt64.from_io(io, LE).as(UInt64)
+
+ @pos, @disk_start = case data.size - 16
+ when 12
+ { UInt64.from_io(io, LE), UInt32.from_io(io, LE) }
+ when 8
+ { UInt64.from_io(io, LE), nil }
+ when 4
+ { nil, UInt32.from_io(io, LE) }
+ when 0
+ { nil, nil }
+ else
+ raise Error.new("invalid Zip64 extra data: #{data.size}")
+ end
+ end
+ end
+
+ #
+ # Parse `Extra` data from given IO *io*.
+ #
+ def self.read(io) : Base
+ # read code and length
+ code = UInt16.from_io(io, LE).as(UInt16)
+ len = UInt16.from_io(io, LE).as(UInt16)
+
+ # read buffer
+ data = Bytes.new(len)
+ io.read(data)
+
+ case code
+ when Zip64::CODE
+ Zip64.new(data)
+ else
+ Base.new(code, data)
+ end
+ end
+
+ #
+ # Encode array of `Extra::Base` and return buffer.
+ #
+ def self.pack(extras : Array(Extra::Base)?) : Bytes
+ if extras && extras.size > 0
+ # create backing buffer for extras
+ buf = Bytes.new(extras.reduce(0) { |r, e| r + e.bytes_needed })
+
+ # create io and write each extra data to io
+ io = MemoryIO.new(buf)
+ extras.each { |e| e.to_s(io) }
+ io.close
+
+ # return buffer
+ buf
+ else
+ # return empty slice
+ EMPTY_SLICE
+ end
+ end
+ end
+
+ #
# Helper methods for converting to and from `Time` objects.
#
module TimeHelper
@@ -1596,197 +1787,6 @@ module Zip
end
#
- # Extra data handlers.
- #
- module Extra
- #
- # Raw extra data associated with `Entry`.
- #
- # You should not need to instantiate this class directly; use
- # `Zip::Entry#extras` or `Zip::Entry#local_extras` instead.
- #
- # Example:
- #
- # # open "foo.zip"
- # Zip.read("foo.zip") do |zip|
- # # get extra data associated with "bar.txt"
- # extras = zip["bar.txt"].extras
- # end
- #
- class Base
- #
- # Identifier for this extra entry.
- #
- property :code
-
- #
- # Data for this extra entry.
- #
- property :data
-
- #
- # Create a new raw extra data entry.
- #
- # You should not need to instantiate this class directly; it is
- # created as-needed by `Writer#add`.
- #
- def initialize(@code : UInt16, @data : Bytes)
- end
-
- #
- # Return number of bytes needed for this Extra.
- #
- def bytes_needed : UInt16
- (4 + @data.size).to_u16
- end
-
- def to_s(io) : UInt16
- @code.to_u16.to_io(io, LE)
- @data.size.to_u16.to_io(io, LE)
- @data.to_s(io)
-
- # return number of bytes written
- bytes_needed
- end
- end
-
- #
- # ZIP64 extra data associated with `Entry`.
- #
- # You should not need to instantiate this class directly; it is
- # created as-needed by `Writer#add()`.
- #
- class Zip64 < Base
- #
- # File size (64-bit unsigned integer).
- #
- getter :size
-
- #
- # Compressed file size (64-bit unsigned integer).
- #
- getter :compressed_size
-
- #
- # Position in output (optional).
- #
- getter :pos
-
- #
- # Starting disk (optional).
- #
- getter :disk_start
-
- #
- # ZIP64 extra code
- #
- CODE = 0x0001.to_u16
-
- #
- # Create ZIP64 extra data associated with `Entry` from given
- # attributes.
- #
- # You should not need to instantiate this class directly; it is
- # created as-needed by `Writer#add()`.
- #
- def initialize(
- @size : UInt64 = 0_u64,
- @compressed_size : UInt64 = 0_u64,
- @pos : UInt64? = nil,
- @disk_start : UInt32? = nil,
- )
- len = 16_u32
- len += 8 if @pos
- len += 4 if @disk_start
-
- # create backing buffer and mem io
- buf = Bytes.new(len)
- io = MemoryIO.new(buf)
-
- @size.to_u64.to_io(io, LE)
- @compressed_size.to_u64.to_io(io, LE)
- @pos.not_nil!.to_u64.to_io(io, LE) if @pos
- @disk_start.not_nil!.to_u32.to_io(io, LE) if @disk_start
-
- # close io
- io.close
-
- super(CODE, buf)
- end
-
- #
- # Parse ZIP64 extra data from given buffer.
- #
- # You should not need to instantiate this class directly; it is
- # created as-needed by `Archive`.
- #
- def initialize(data : Bytes)
- super(CODE, data)
-
- # create memory io over buffer
- io = MemoryIO.new(data, false)
-
- @size = UInt64.from_io(io, LE).as(UInt64)
- @compressed_size = UInt64.from_io(io, LE).as(UInt64)
-
- @pos, @disk_start = case data.size - 16
- when 12
- { UInt64.from_io(io, LE), UInt32.from_io(io, LE) }
- when 8
- { UInt64.from_io(io, LE), nil }
- when 4
- { nil, UInt32.from_io(io, LE) }
- when 0
- { nil, nil }
- else
- raise Error.new("invalid Zip64 extra data: #{data.size}")
- end
- end
- end
-
- #
- # Parse `Extra` data from given IO *io*.
- #
- def self.read(io) : Base
- # read code and length
- code = UInt16.from_io(io, LE).as(UInt16)
- len = UInt16.from_io(io, LE).as(UInt16)
-
- # read buffer
- data = Bytes.new(len)
- io.read(data)
-
- case code
- when Zip64::CODE
- Zip64.new(data)
- else
- Base.new(code, data)
- end
- end
-
- #
- # Encode array of `Extra::Base` and return buffer.
- #
- def self.pack(extras : Array(Extra::Base)?) : Bytes
- if extras && extras.size > 0
- # create backing buffer for extras
- buf = Bytes.new(extras.reduce(0) { |r, e| r + e.bytes_needed })
-
- # create io and write each extra data to io
- io = MemoryIO.new(buf)
- extras.each { |e| e.to_s(io) }
- io.close
-
- # return buffer
- buf
- else
- # return empty slice
- EMPTY_SLICE
- end
- end
- end
-
- #
# File entry in `Archive`.
#
# Use `Zip.read()` to read a Zip archive, then `#[]` to fetch a