Files
LisherSong--ps5-web-file-ma…/src/zipx_volume.h
T
Songlx516 9b2f5a07c3 feat(7z): read multi-volume 7z sets as one stream
A split 7z (`name.7z.001`, `.002`, ...) only contains the first slice of the
archive, so SzArEx_Open() followed the header offsets off the end of the file
and gave up with SZ_ERROR_INPUT_EOF -- the set was unusable even though the
file listing of each part looked fine.

src/sevenz_volstream.c backs ISeekInStream with the ordered part list, so the
SDK sees one continuous archive and never learns it was split. Nothing is
merged on disk: a 160 GiB set would otherwise need a second 160 GiB scratch
copy. A 7z split is a plain byte split, so offsets stored inside the archive
are already absolute and the Stream/Seek callbacks stay trivial.

The ordered list comes from zipx_volume, which already understands
`name.7z.001` naming, so an incomplete set fails before any decoding starts
and names the missing part. Two further checks report a set that could not
have worked anyway: a lone first volume, and a part whose size differs from
the earlier ones (7-Zip cuts equal sized parts and lets only the last one be
short).

To reuse the split-layout constants without dragging the ZIP stream header
into the 7z build, ZIPX_VOL_MODE_* moved to zipx_volume.h: they describe the
set, and every consumer of zipx_volume_t needs them.

The e2e driver now opens its input through the volume stream, so the packed
data reads go through it too.

Matrix: all 10 single-volume fixtures plus vol.7z.001 are byte-identical
(13 passed, 0 failed). Remaining known gaps: 7zAES (aes, aeshe).
Regression: ZIP 108 / RAR 27 checks, 0 failures.
2026-09-12 17:53:17 +08:00

59 lines
2.1 KiB
C

/* zipx_volume -- group a multi-file archive volume set into an ordered list.
part of ps5-web-file-manager
Supports the naming conventions seen in the wild:
name.zip.001, name.zip.002, ... byte split (7-Zip "split to volumes")
name.part1.zip, name.part2.zip byte split (WinRAR zip volumes)
name.z01, name.z02, ..., name.zip zip split disks (Info-ZIP / PKZIP)
A caller can hand in any member of the set (the user usually clicks one file
in the browser) and gets back the full ordered list plus the split layout so
the engine can pick the matching stream behaviour. */
#ifndef ZIPX_VOLUME_H
#define ZIPX_VOLUME_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#define ZIPX_VOL_MAX_PARTS 512
/* How the set is split. A byte split (`name.zip.001`, `name.7z.001`,
`name.part1.zip`) is the concatenation of its parts with absolute offsets;
zip split disks (`name.z01` + `name.zip`) store per-disk offsets instead.
The constants live here because they describe the *set*, and every consumer
of zipx_volume_t needs them. */
#define ZIPX_VOL_MODE_CONCAT 0
#define ZIPX_VOL_MODE_DISK 1
typedef struct {
char **paths; /* ordered part paths, owned by this struct */
int count;
int index; /* position of the path that was handed in (-1 unknown) */
int mode; /* ZIPX_VOL_MODE_CONCAT or ZIPX_VOL_MODE_DISK */
int is_set; /* 1 when the path is part of a multi-file set */
} zipx_volume_t;
/* Inspects `path`: 1 when it belongs to a multi-file set (out is filled),
0 when it is an ordinary single file (out is cleared), -1 on a hard error
(*err, when non-NULL, receives a malloc'd message the caller must free;
it is also set for the 0 case when a sibling set looks broken, so callers
can surface "volumes are incomplete" instead of a generic open failure). */
int zipx_volume_detect(const char *path, zipx_volume_t *out, char **err);
void zipx_volume_free(zipx_volume_t *vol);
/* True when `path` looks like the first volume of a set ("x.zip.001",
"x.z01", "x.part1.zip"), used by the UI to label the entry. */
int zipx_volume_is_first(const char *path);
#ifdef __cplusplus
}
#endif
#endif