Archives are where extractors meet their edge cases, so this category is built to exercise them. The ZIP set runs flat, nested, and deep-tree layouts, a unicode-filename archive, a zero-entry empty archive, and a hundred-tiny-files archive for stress-testing throughput. Tarballs ship uncompressed and as gzip, bzip2, and xz variants (.tar, .tgz, .tbz2, .txz), with single-file gzip, bzip2, and xz alongside so you can isolate the codec from the container. There's a resource JAR, a real ISO 9660 disk image, and a 7z archive plus a password-protected 7z with the password printed right on the page. Every archive is deterministic, documented down to its member list, and deliberately safe — no zip bombs, no executables, no hidden payloads.
A dataset bundle ZIP — a CSV with its JSON Schema, a README, and a LICENSE — the way datasets are commonly distributed. For testing unpack-and-validate pipelines and dataset importers.
A real ISO 9660 disk image with Joliet and Rock Ridge extensions for long filenames, holding a few documented text files. For testing ISO mounting, extraction, and conversion.
The smallest valid archive in this catalog: the 8-byte ar magic and nothing after it. ar has no trailer record, so end-of-file is the only end marker, and this is what an empty static library or an empty .deb control archive looks like on disk.
An empty cpio archive is a single TRAILER!!! header record - a full 110-byte newc header with every numeric field zero - plus its alignment padding. Readers that look for member data before checking the name find none and must still report a valid, empty archive.
An empty tar is not a zero-byte file - it is exactly two 512-byte blocks of zeros, the end-of-archive marker with nothing in front of it. Writers that emit nothing at all produce a file most readers reject, which is the bug this 1024-byte file exists to distinguish.
The empty tar under bzip2. Its payload is 1024 identical bytes, which is the run-length case bzip2's block sorter treats specially, so this doubles as the smallest sane bzip2 stream to test a decoder against.
The empty tar wrapped in gzip, which is what `tar czf` produces from an empty directory. The gzip header and trailer are still there and still have to parse, so this separates 'cannot read the codec' from 'read the codec and found nothing inside'.
A valid ZIP with zero members whose end record still carries an archive comment - the combination that catches readers which treat 'no entries' as 'not an archive' and readers which look for the end record only in the last 22 bytes. Its group siblings are the same empty case in five other container formats.
The nested-JAR layout an executable fat jar uses: a manifest with a Class-Path entry and a second JAR stored uncompressed under BOOT-INF/lib so it can be read in place without being extracted first. It contains resources only - properties, JSON and text, no compiled bytecode - and the manifest uses the CRLF line endings the JAR specification requires.
A tar carrying three ZIPs: two byte-identical and a third holding the same content stored rather than deflated. A deduplicating packer should notice the first two are the same object; a content-addressed one should notice all three extract to the same files.
A gzipped tar whose second member is another gzipped tar. Tools that apply decompression greedily - gunzip until the bytes stop being gzip - skip straight past the outer tar and report the inner archive's two members as if they were the whole thing.
One ZIP holding the same two-member tar in four containers - plain, gzip, xz and bzip2 - so a recursive lister can be checked on four codecs in one pass. The already-compressed members are stored rather than deflated, which is what a competent writer does and what a naive one does not.
JSON ground-truth manifest for the canonical compressed-TAR twins, publishing each safe path, byte count, and full SHA-256 digest. Stable P8 artifact p8-convert-archive-member-manifest.
GNU-style SHA-256 list for the two canonical TAR members, preserving relative paths and full lowercase digests. Stable P8 artifact p8-convert-archive-sha256.
Existing-format ZIP/TXT media control combining a plain README and a WebVTT sidecar for nested media extraction checks Stable P8 artifact p8-convert-legacy-archive-media-control.
Existing-format ZIP extraction control for comparing member-path and hash behavior with the compressed-TAR cohort Stable P8 artifact p8-convert-zip-extraction-control.
Tiny intentionally corrupt TAR.ZST with preserved Zstandard magic and a deliberately damaged frame-header byte so strict decompressors reject it before extraction Stable P8 artifact p8-convert-tar-zst-intentionally-corrupt.
A realistic static-website project bundled as a ZIP — index.html with linked CSS, JS, and an SVG logo, plus a README. For testing project extraction, unpack-then-serve pipelines, and nested-folder handling.
A password-protected 7z archive (AES-256, encrypted header). The password is “novus-example” — printed here on purpose so you can test encrypted-archive extraction. Contains only harmless sample text.
GNU tar's extension of the same header, identified by its own magic: long names get their own 'L' record, oversized numeric fields switch to base-256, and sparse files get an in-header map. All three archives in this group hold byte-identical members with identical ownership and modification times, so any other difference a reader reports between them comes from the header encoding alone.
A 125-character path whose long component contains no slash at all, so the USTAR prefix field cannot store it. This archive uses a preceding 'L' (GNUTYPE_LONGNAME) record whose payload is the full path. Its group siblings encode the same class of path with the other two mechanisms.
The 2001 POSIX format: anything the classic header cannot express moves into an 'x' extended header of UTF-8 key=value records placed immediately before the member it describes. Here each member carries atime and ctime records, which is why this archive is structurally different from its USTAR twin rather than byte-identical to it. All three archives in this group hold byte-identical members with identical ownership and modification times, so any other difference a reader reports between them comes from the header encoding alone.
A PAX 'g' global extended header leads the stream, carrying archive-wide key=value records including a vendor-prefixed pair. Readers must apply it to every following member and must not list it as a file - a mistake that shows up as a phantom entry named 'pax_global_header'.
A 125-character path whose long component contains no slash at all, so the USTAR prefix field cannot store it. This archive uses a preceding 'x' extended header carrying a path= record in UTF-8. Its group siblings encode the same class of path with the other two mechanisms.
PAX is the only tar variant that says what encoding its names are in: extended-header records are UTF-8 by definition. These three members carry accented Spanish and Japanese path components, so a reader that applies a locale-dependent guess instead of trusting the format produces mojibake on exactly this file.
The 1988 POSIX format: 512-byte headers, octal numeric fields, names split across a 155-byte prefix and a 100-byte name, and no mechanism at all for anything that does not fit - including the access and change times its siblings carry. All three archives in this group hold byte-identical members with identical ownership and modification times, so any other difference a reader reports between them comes from the header encoding alone.
A 141-character path stored the only way plain USTAR can store one: split at a slash across the header's 155-byte prefix field and its 100-byte name field. Readers that ignore the prefix field report the truncated tail and write the file to the wrong place.
Three directory records with distinct modes, one of which - tree/empty/ - has no members underneath it and therefore exists only because the record does. A reader that synthesises directories from member paths alone silently loses it, and loses the 0750 and 0700 modes on the other two.
A FIFO, a character device and a block device, each a header with no data blocks and with the device numbers in the devmajor/devminor fields. Unprivileged extraction cannot create the two device nodes, so the correct behaviour is to skip them with a warning rather than to abort the whole archive or to create empty regular files in their place.
share/backup/records.csv is a hard link to a member that appears earlier in the stream, so its content is stored exactly once. Order matters: a reader that extracts members out of sequence, or that copies content instead of linking, changes both the on-disk byte count and the inode relationship the archive is describing.
The uid and gid fields hold 7 octal digits, so they top out at 2097151. This member is owned by uid 3000000, which needs GNU base-256 encoding: the field's high bit is set and the remaining bytes are a big-endian integer. Its group sibling encodes the same ownership the other way, so a reader can be checked against both without a second variable.
The uid and gid fields hold 7 octal digits, so they top out at 2097151. This member is owned by uid 3000000, which needs PAX uid=/gid= records in an 'x' extended header, with the classic field left at its maximum. Its group sibling encodes the same ownership the other way, so a reader can be checked against both without a second variable.
The uname and gname fields in a tar header are 32 bytes. This archive's second member is owned by a 44-character service-account name, which only fits because PAX moves it into an extended header. A USTAR writer would have truncated it to 31 characters and lost the distinction between two similarly-named accounts.
share/current.csv is a symbolic link: typeflag '2', size 0, and the target carried in the header's 100-byte linkname field rather than in any data blocks. The target is relative and stays inside the archive, so extraction is safe with or without symlink support.
A 1 MiB file with a 1047552-byte hole in the middle, stored the old GNU way: typeflag 'S' and a four-slot sparse map written into the header block itself. Only 1024 bytes are actually in the stream, so a reader that ignores the map reconstructs a 1024-byte file instead of a 1 MiB one.
The same 1 MiB sparse file in the modern encoding: an 'x' extended header declares GNU.sparse 1.0 and the real name and size, and the segment map is decimal text at the beginning of the member's own data rather than in the header. A reader that honours the records must also strip the GNUSparseFile.0/ prefix from the name it reports.
A tar that ends immediately after its last member, with none of the two 512-byte zero blocks the format calls for. Plenty of writers do this and GNU tar reads it with a warning; readers that treat a missing end marker as a truncated archive reject three perfectly good members.
The same three members followed by the end-of-archive blocks and then zero padding out to a whole 10240-byte record - tar's historical blocking factor of 20, still the default. The archive is 10240 bytes for 616 bytes of content, which is what makes tiny tarballs look so wasteful before compression.
A complete tar with 218 bytes of plain text appended after the end-of-archive blocks. A reader must stop at those blocks; one that keeps scanning finds a block whose checksum does not verify and may report the whole archive as corrupt instead of ignoring bytes that were never part of it.
A cpio archive in the newc (SVR4) format with four members — the Unix archive format used by initramfs and RPM. Hand-written to spec and documented down to its member list; for testing cpio extractors and converters.
A Unix ar archive with three members — the simple format that backs static libraries (.a) and Debian packages (.deb). Hand-written to spec; for testing ar extractors and archive tooling.
A minimal WARC 1.0 web archive with a warcinfo record and an HTTP response record capturing a small HTML page — for testing WARC parsers and web-archive tooling.
A Java Archive (JAR) — a ZIP with a META-INF/MANIFEST.MF and resource files only (no .class bytecode). For testing JAR/ZIP readers and manifest parsing.
The legacy twin: names encoded in IBM CP437 with the language-encoding flag clear, which is what the ZIP spec says an un-flagged name means. Decoding these bytes as UTF-8 produces mojibake or an outright decode error, which is exactly the bug this file is for.
The third way a ZIP carries a non-ASCII name: an ASCII-safe name in the header plus an Info-ZIP Unicode Path extra field (0x7075) holding the real UTF-8 name and a CRC32 of the header name. A reader must prefer the extra field, but only while that CRC still matches the header name it was computed from.
Member names stored as UTF-8 with general-purpose bit 11 (the language-encoding flag) set, which is the modern, unambiguous way to carry a non-ASCII filename in a ZIP. Its CP437 twin encodes the same archive the legacy way, so a reader's encoding heuristic can be compared against a case where the answer is declared.
The DOS timestamp in a ZIP header has 2-second resolution and no timezone, so Info-ZIP adds a 0x5455 extended timestamp and a 0x7875 uid/gid field. Here the uid/gid field appears in the local header only, matching what Info-ZIP actually writes, so a reader that reads extras from the central directory alone sees the timestamp but loses the ownership.
A 512-byte archive comment pushes the end-of-central-directory record well away from the end of the file. Readers that seek to the last 22 bytes and expect the end signature there fail immediately; correct readers scan backwards for it, which is what the format requires.
Two of three members carry a central-directory file comment and the third carries none. Comments exist only in the central directory, so a reader that walks local headers to build its listing loses them entirely; a rewriter that drops them loses them permanently.
share/current.csv is a symbolic link, stored the Info-ZIP way: the external attributes carry S_IFLNK and the member payload is the 16-byte target path rather than file content. The target is relative and resolves inside the archive, so extracting without symlink support produces a harmless text file instead of a dangling or escaping link.
Unix permissions ride in the top 16 bits of the ZIP external attributes field, and are only meaningful when the version-made-by byte says Unix. This archive carries 0444, 0600, 0664 and a 0750 directory, plus the MS-DOS read-only bit on the 0444 member so the two conventions can be seen disagreeing. Nothing here is marked executable.
An extra field with header ID 0x9901, which is assigned to nothing, sits alongside a recognised extended-timestamp field in a different order in each header. The extra-field area is a length-prefixed chain, so the only correct behaviour is to skip unknown IDs by their declared length and keep walking.
Two members use a backslash as the path separator, which APPNOTE 4.4.17.1 forbids and which Windows-written archives contain anyway. Readers that split on '/' only will create files literally named 'data\config.json' in the extraction root instead of data/config.json.
Three members under docs/ whose names differ only in letter case. On ext4 they are three files; on NTFS or a default APFS volume they are one file written three times, and the last one silently wins. Each payload names its own casing so you can tell which survived.
Member names carrying './' prefixes, an inner './' and one inner '../' that cancels the segment before it. Every path resolves inside the archive root, so this exercises a normaliser without being a traversal payload: docs/sub/../notes.md must land at docs/notes.md, not at docs/sub/notes.md and not outside the extraction directory.
A deliberately bounded compression-ratio fixture: 4474 bytes on disk expanding to exactly 4 MiB of zeros, roughly 937:1. It is not a decompression bomb - there is no nesting and no recursion, and the expanded size is a fixed 4 MiB - so it exercises a ratio guard or a streaming extractor's memory ceiling without being dangerous to open.
397 bytes of readable text precede the first local file header, giving the layout of a self-extracting archive without shipping an executable stub. Readers that start at byte zero see garbage; readers that find the end-of-central-directory record and work backwards read all three members. Open the file in a text editor to read the prefix.
Three empty files stored three ways - stored, deflated, and deflated behind a data descriptor - beside one real member. An empty deflate stream is still two bytes on disk with CRC 0, so readers that treat compressed size 0 as 'no data' and readers that treat CRC 0 as 'not computed' both go wrong here.
The last segment of a two-part spanned set: its end record says this is disk 1, that the central directory lives on disk 1, and that 2 of the archive's 4 entries are here. The bytes are well-formed - this is not a corrupt file - but a reader given it alone must say so rather than silently reporting a 2-entry archive. The .z01 first segment is deliberately absent, because .z01 is not a format this catalog registers.
A complete, extractable ZIP that begins with the four-byte PK00 marker a splitting writer emits when the archive fitted into a single segment after all. The marker shifts every local header four bytes forward, so a reader that assumes the first local header sits at offset 0 misparses a file it is perfectly capable of reading.
A complete ZIP prefixed with the 0x08074B50 spanning signature. That value is also the data descriptor signature, so a reader scanning the byte stream for descriptors finds one before the first local header — a genuine ambiguity in the format, reproduced here in a file that is otherwise entirely ordinary.
A ZIP whose every member uses compression method 8 (deflate). Its twin holds byte-identical content under the other method, so an extractor, a size estimator, or a repacking pipeline can be compared on the same payload with only the storage method changed.
A ZIP whose every member uses compression method 0 (stored). Its twin holds byte-identical content under the other method, so an extractor, a size estimator, or a repacking pipeline can be compared on the same payload with only the storage method changed.
The same streaming layout with the data descriptor's PK\x07\x08 signature omitted, which the spec permits and which breaks readers that scan for the signature instead of trusting the central directory. The central directory here carries the authoritative sizes and CRCs.
A ZIP written the way a streaming writer must write one: general-purpose bit 3 is set, the local header carries CRC 0 and sizes 0, and the real values follow the compressed data in a data descriptor introduced by the optional PK\x07\x08 signature.
A streaming ZIP in ZIP64 form: the data descriptor's compressed and uncompressed sizes are 8 bytes each rather than 4. Readers that assume a fixed 16-byte descriptor desynchronise on the very next local header.
The same three-directory tree with no directory records at all — the parents exist only as path components inside member names. Extractors that create directories only when they see a directory record fail on this shape, which is what most command-line ZIP writers produce.
Directory records whose names do NOT end in a slash — the directory-ness is carried only by the MS-DOS attribute bit in the external attributes field. A reader that decides by name alone creates three empty files called project, project/src and project/data, and then cannot create the directories that have to replace them.
A ZIP that stores each directory as its own zero-length record with a trailing slash and the MS-DOS directory attribute set. Its group siblings hold the same tree with the directory records implied and with the trailing slash missing, which is the trio an extractor's mkdir logic has to survive.
Ordinary 32-bit member records terminated by a ZIP64 end-of-central-directory record, its locator, and then a normal 32-bit end record — the belt-and-braces trailer some writers always emit. A reader must find the classic end record first, notice the locator in front of it, and reconcile two directories that agree.
Both the local file headers and the central directory carry a ZIP64 extended information extra field (0x0001), with the 32-bit size fields set to 0xFFFFFFFF as the spec requires. The payload is a few hundred bytes: ZIP64 is present because the writer could not seek, not because the data is large, which is precisely the case size-based heuristics miss.
The local headers are plain 32-bit while the central directory carries the ZIP64 extra field. This is legal and common: a writer that streams cannot know at local-header time whether it will need ZIP64, so it commits to the wide fields only when it writes the directory.
A central directory whose ZIP64 extra field carries the relative local-header offset as well as the sizes. The ZIP64 extra is variable length and its members appear in a fixed order, so a reader that assumes a 16-byte or 24-byte block reads the offset out of the wrong slot.
Never. There are no zip bombs, executables, or hidden payloads. Every archive is deterministic and documented down to its member list — the 'stress' samples are just many tiny harmless files.
What's the password for the encrypted 7z sample?+
It's printed directly on that file's page, so you can test password-protected extraction end to end.
How do I isolate a compression codec from its container?+
Each tar variant (.tar, .tgz, .tbz2, .txz) ships alongside single-file gzip, bzip2, and xz samples, so you can test the codec on its own or inside the tar container.
Do you cover unicode filenames and empty archives?+
Yes — there's a unicode-filename ZIP, a zero-entry empty archive, and a hundred-tiny-files archive for throughput testing, plus a resource JAR and a real ISO 9660 disk image.
We use Google Analytics and show ads via Adsterra. Non-essential cookies and ad scripts run only after you allow the matching categories. See our cookie policy.