Search guides and the APICtrl K
  1. API reference
  2. Files and codecs

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.

↑↓ to move↵ to openEvery public name in the headers, and every guide