ddn.archive.zip

ddn.archive.zip

ZIP archive reader and writer implementing ddn.api.archive.

Module Initializers 1

shared static this()

Types 6

aliasByteSource = size_t delegate(ubyte[] buffer)

Delegate type for streaming byte source.

Called by ZipStreamReader to request more data from the underlying non-seekable source. The delegate should fill the provided buffer with available bytes.

Parameters

bufferThe buffer to fill with data.

Returns

The number of bytes actually read, or 0 on EOF.
private structCentralDirEntry
Fields
string path
ulong offset
ulong compressedSize
ulong uncompressedSize
ushort compressionMethod
uint crcVal
ushort lastModTime
ushort lastModDate
ushort gpFlags
FilePermissions permissions
string comment
bool isUtf8
Fields
private const(ubyte)[] _data
private ReadOptions _opts
private bool _closed
private CentralDirEntry[] _entries
private size_t _iterIndex
private bool _iterating
private ArchiveProgressCallback _progressCallback
Methods
ArchiveFormat format() @property const
size_t entryCount() @property const
string comment() @property const
bool nextEntry(out EntryInfo info)
bool contains(string path)
EntryInfo getEntry(string path)
void readContent(ref const EntryInfo entry, ContentSink sink)
void extractTo(ref const EntryInfo entry, string destPath)
void extractAll(string destDir)
void close()
bool isClosed() @property const
private void parseCentralDirectory()
private void parseZip64ExtraField(ref CentralDirEntry entry, const(ubyte) * extra, ushort extraLen)Parse the ZIP64 Extra Field from a central directory entry.
private Zip64Eocd parseZip64Eocd(long eocdOffset) constParse the ZIP64 End of Central Directory record.
private long findEndOfCentralDirectory() const
Constructors
this(const(ubyte)[] data, ReadOptions opts)
Nested Templates
Zip64Eocd

True streaming ZIP reader that reads entries incrementally from a non-seekable source.

Unlike ZipReader which loads the entire archive and parses the central directory, ZipStreamReader reads local file headers sequentially, allowing processing of archives from pipes, sockets, or other non-seekable sources without buffering the entire archive in memory.

Limitations compared to ZipReader:

  • No random access (getEntry() is not supported)
  • entryCount() returns 0 (unknown until fully read)
  • contains() requires sequential scan
  • Cannot seek backwards to re-read entries

The reader handles both regular ZIP entries and entries with data descriptors (general purpose bit flag 3), as well as ZIP64 extended information.

Fields
private ByteSource _source
private ReadOptions _opts
private bool _closed
private bool _eof
private ArchiveProgressCallback _progressCallback
private size_t _entriesProcessed
private ubyte[] _buffer
private size_t _bufferPos
private size_t _bufferLen
private 262144 BUFFER_SIZE
private bool _hasCurrentEntry
private StreamEntryState _currentEntry
Methods
ArchiveFormat format() @property constReturns the archive format.
ArchiveCapabilities capabilities() @property constReturns the provider capabilities for streaming mode.
void setProgressCallback(ArchiveProgressCallback callback)Set progress callback for operation monitoring.
size_t entryCount() @property constGet total number of entries.
string comment() @property constGet archive-level comment.
bool nextEntry(out EntryInfo info)Advance to the next entry in the archive.
bool contains(string path)Check if archive contains an entry at path.
EntryInfo getEntry(string path)Get entry info by path.
void readContent(ref const EntryInfo entry, ContentSink sink)Read entry content, calling sink with chunks of decompressed data.
void extractTo(ref const EntryInfo entry, string destPath)Extract entry to filesystem path.
void extractAll(string destDir)Extract all entries to a directory.
void close()Close the reader and release resources.
bool isClosed() @property constReturns true if reader has been closed.
private bool ensureBytes(size_t n)Ensure at least `n` bytes are available in buffer.
private ubyte[] readBytes(size_t n)Read exactly n bytes from buffer, advancing position.
private void skipBytes(size_t n)Skip n bytes in the stream.
private const(ubyte)[] peekBytes(size_t n)Peek at upcoming bytes without consuming them.
private bool readLocalFileHeader()Read a local file header from the stream.
private void parseLocalZip64Extra(const(ubyte)[] extra)Parse ZIP64 extended information from local file header extra field.
private void skipCurrentEntryContent()Skip unread content of current entry.
private void skipToDataDescriptor()Skip compressed data and find data descriptor.
private void scanForDataDescriptor()Scan stream for data descriptor by decompressing DEFLATE data.
private void readDataDescriptor()Read and parse data descriptor following compressed data.
private void readAndDecompressContent(ContentSink sink)Read and decompress content of current entry, sending to sink.
private void readContentKnownSize(ContentSink sink)Read content when compressed size is known.
private void readContentWithDataDescriptor(ContentSink sink)Read content when size is in data descriptor (streaming with unknown size).
Constructors
this(ByteSource source, ReadOptions opts)Construct a streaming ZIP reader.
Nested Templates
StreamEntryState
private structLocalDirEntry
Fields
string path
ulong localHeaderOffset
ulong compressedSize
ulong uncompressedSize
ushort compressionMethod
uint crcVal
FilePermissions permissions
string comment
ushort lastModTime
ushort lastModDate
Fields
private ContentSink _sink
private WriteOptions _opts
private bool _finished
private bool _closed
private ulong _bytesWritten
private size_t _entriesWritten
private ArchiveProgressCallback _progressCallback
private LocalDirEntry[] _localEntries
Methods
ArchiveFormat format() @property const
void addDirectory(string path, FilePermissions perms = FilePermissions.fromOctal(octal!"755"))
void addFile(string path, const(ubyte)[] content, EntryWriteOptions opts = EntryWriteOptions.init)
void addFile(string path, scope const(ubyte)[] delegate() source, ulong size = 0, EntryWriteOptions opts = EntryWriteOptions.init)
void addFileFrom(string archivePath, string filesystemPath, EntryWriteOptions opts = EntryWriteOptions.init)
void addSymlink(string path, string target)
void addHardlink(string path, string target)
void addEntry(ref const EntryInfo info, scope const(ubyte)[] delegate() source)
void setComment(string comment)
void removeEntry(string path)
void updateEntry(string path, const(ubyte)[] content, EntryWriteOptions opts = EntryWriteOptions.init)
void finish()
void close()
bool isFinished() @property const
bool isClosed() @property const
ulong bytesWritten() @property const
size_t entriesWritten() @property const
private ushort getCompressionMethod()
private bool needsZip64(ulong uncompressedSize, ulong compressedSize) constCheck if a local file entry needs ZIP64 extended fields.
private void writeLocalFile(string path, const(ubyte)[] content, FilePermissions perms, bool isDirectory, ushort modTime = 0, ushort modDate = 0x0021)
private void writeCentralDirectoryEntry(ref const LocalDirEntry entry)
private void writeZip64EndOfCentralDirectory(ulong cdOffset, ulong cdSize)Write the ZIP64 End of Central Directory record and its locator.
private void writeEndOfCentralDirectory(ulong cdOffset, ulong cdSize, bool zip64)Write the regular End of Central Directory record.
Constructors

Functions 16

private fnushort readU16(const(ubyte) * p) @trusted pure nothrow
private fnuint readU32(const(ubyte) * p) @trusted pure nothrow
private fnvoid writeU16(ubyte * p, ushort v) @trusted pure nothrow
private fnvoid writeU32(ubyte * p, uint v) @trusted pure nothrow
private fnulong readU64(const(ubyte) * p) @trusted pure nothrowRead a little-endian 64-bit unsigned integer.
private fnvoid writeU64(ubyte * p, ulong v) @trusted pure nothrowWrite a little-endian 64-bit unsigned integer.
private fnuint computeCrc32(const(ubyte)[] data) nothrowCompute CRC-32 checksum using ddn.compressor.zlib.
private fnubyte[] deflateRaw(const(ubyte)[] data)Compress data using raw DEFLATE (RFC 1951) via ddn-compressor-base zlib.
private fnubyte[] inflateRaw(const(ubyte)[] data)Decompress raw DEFLATE (RFC 1951) data via ddn-compressor-base zlib.
private fnEntryInfo makeEntryInfo(string path, EntryType etype, ulong usize, ulong csize, uint crcv, FilePermissions perms, ushort method, ushort modTime = 0, ushort modDate = 0)
private fnvoid unixTimeToDosDateTime(long unixSeconds, out ushort dosTime, out ushort dosDate)Convert a Unix timestamp to DOS date and time values for ZIP headers.
private fnvoid patchCdEntryToZip64(ref ubyte[] data)Patch a normal ZIP archive to simulate ZIP64 structures for testing.
fnArchiveReader makeZipReader(const(ubyte)[] data, ReadOptions opts)Create a ZipReader for reading from an in-memory buffer.
fnArchiveReader makeZipStreamReader(ByteSource source, ReadOptions opts)Create a ZipStreamReader for reading from a streaming byte source.
fnArchiveWriter makeZipWriter(ContentSink sink, WriteOptions opts)Create a ZipWriter for writing to an output sink.
fnArchiveFormat detectZipFormat(const(ubyte)[] header)

Variables 16

private enumvarLOCAL_FILE_HEADER_SIG = 0x04034B50
private enumvarCENTRAL_DIR_HEADER_SIG = 0x02014B50
private enumvarEND_CENTRAL_DIR_SIG = 0x06054B50
private enumvarZIP64_END_CENTRAL_DIR_SIG = 0x06064B50
private enumvarZIP64_END_CENTRAL_DIR_LOCATOR_SIG = 0x07064B50
private enumvarDATA_DESCRIPTOR_SIG = 0x08074B50
private enumvarZIP64_EXTRA_FIELD_ID = 0x0001
private enumvarCOMPRESS_STORED = 0
private enumvarCOMPRESS_DEFLATED = 8
private enumvarVERSION_NEEDED = 20
private enumvarVERSION_NEEDED_ZIP64 = 45
private enumvarVERSION_MADE_BY = 20
private enumvarVERSION_MADE_BY_ZIP64 = 45
private enumvarGP_FLAG_UTF8 = 1 << 11
private enumvarGP_FLAG_DATA_DESCRIPTOR = 1 << 3
private enumvarZIP32_MAX = 0xFFFFFFFF