zip.h
Reading a .zip.
#include <sonore/zip.h>- 2types
On this page
Design notes
What it is for
A preset pack. A sample pack. An expansion somebody downloaded. Every plugin that ships more than its own binary ships it as a zip, and without this the only options are to unpack it with a shell command -- which is a process launch from a plugin, on a thread the host owns -- or to ask the user to do it themselves and then explain where.
Almost all of it already existed
gfx/inflate.h is a complete DEFLATE decoder, written by hand for PNG because every length and distance in the stream is attacker-controlled and the bounds checks were the point. A zip entry is a DEFLATE stream with a header on it, so what is here is the container format and nothing else.
Reading only, and reading is the dangerous direction
Writing a zip needs a DEFLATE COMPRESSOR, which is a different piece of work from a decompressor and one nothing here needs: a plugin reads packs, it does not make them. Stored (uncompressed) entries could be written trivially and deliberately are not -- a half-implemented writer producing zips that only this reader accepts is worse than no writer.
Every size, offset and name length in a zip comes from the file, which came from the internet. So: nothing is trusted, every read is bounds-checked against the buffer, the uncompressed size is capped, and the CRC is VERIFIED rather than reported. A decoder that skipped the CRC would hand a plugin a subtly corrupt sample and no way to know.
Zip slip
An entry may be named "../../../autostart/evil.sh". Extraction here is to MEMORY, so nothing is written anywhere by this file -- but any caller that then writes the result to disk has to check the name first, and isSafeEntryName is that check, named so it is hard to not notice.
Types 2
One thing inside the archive.
A .zip read from memory: its directory, and any entry decompressed into a buffer with its CRC checked. The reading half of the reference's class of the same name; the file comment says why there is no writer and what is checked.
It does NOT copy the archive. openFromMemory keeps a pointer to the caller's bytes, which must stay alive and unchanged for as long as entries are extracted -- until the ZipFile is destroyed or opened on something else. Stored and deflated entries only, and no Zip64. Nothing here writes to disk; a caller that does checks isSafeEntryName() first.