Skip to content

Commit 6093995

Browse files
committed
Allow format/filter selection
1 parent 5aac941 commit 6093995

6 files changed

Lines changed: 303 additions & 5 deletions

File tree

libarchive.c

Lines changed: 81 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,11 @@ static zend_object *arch_ce_create_object(zend_class_entry *ce)
172172
emalloc(sizeof(*zobj) + zend_object_properties_size(ce));
173173

174174
zobj->source_kind = ARCH_SOURCE_NONE;
175+
zobj->write_disk_options = 0;
176+
zobj->formats = NULL;
177+
zobj->formats_count = 0;
178+
zobj->filters = NULL;
179+
zobj->filters_count = 0;
175180
zobj->archive = NULL;
176181
zobj->arch_disk = NULL;
177182
zobj->write_disk_options = 0;
@@ -195,6 +200,16 @@ static void arch_oh_free_obj(zend_object *zobj)
195200
break;
196201
}
197202
obj->source_kind = ARCH_SOURCE_NONE;
203+
if (obj->formats) {
204+
efree(obj->formats);
205+
obj->formats = NULL;
206+
obj->formats_count = 0;
207+
}
208+
if (obj->filters) {
209+
efree(obj->filters);
210+
obj->filters = NULL;
211+
obj->filters_count = 0;
212+
}
198213
if (obj->archive) {
199214
archive_read_close(obj->archive);
200215
obj->archive = NULL;
@@ -224,6 +239,24 @@ PHP_METHOD(libarchive_Archive, __construct)
224239

225240
static bool arch_obj_open_read_stream(arch_object *arch_obj);
226241

242+
static void arch_obj_setup_support(arch_object *arch_obj)
243+
{
244+
if (arch_obj->filters == NULL) {
245+
archive_read_support_filter_all(arch_obj->archive);
246+
} else {
247+
for (uint32_t i = 0; i < arch_obj->filters_count; i++) {
248+
archive_read_support_filter_by_code(arch_obj->archive, arch_obj->filters[i]);
249+
}
250+
}
251+
if (arch_obj->formats == NULL) {
252+
archive_read_support_format_all(arch_obj->archive);
253+
} else {
254+
for (uint32_t i = 0; i < arch_obj->formats_count; i++) {
255+
archive_read_support_format_by_code(arch_obj->archive, arch_obj->formats[i]);
256+
}
257+
}
258+
}
259+
227260
static bool arch_obj_open_read(arch_object *arch_obj)
228261
{
229262
php_stream *stream = php_stream_open_wrapper(
@@ -242,8 +275,7 @@ static bool arch_obj_open_read(arch_object *arch_obj)
242275
if (php_stream_can_cast(stream, PHP_STREAM_AS_FD) == SUCCESS &&
243276
php_stream_cast(stream, PHP_STREAM_AS_FD, (void **)&fd, 0) == SUCCESS) {
244277
arch_obj->archive = archive_read_new();
245-
archive_read_support_filter_all(arch_obj->archive);
246-
archive_read_support_format_all(arch_obj->archive);
278+
arch_obj_setup_support(arch_obj);
247279
int res = archive_read_open_fd(arch_obj->archive, fd, 10240);
248280
if (res != ARCHIVE_OK) {
249281
zend_throw_exception_ex(
@@ -282,8 +314,7 @@ static bool arch_obj_open_read_stream(arch_object *arch_obj)
282314
}
283315

284316
arch_obj->archive = archive_read_new();
285-
archive_read_support_filter_all(arch_obj->archive);
286-
archive_read_support_format_all(arch_obj->archive);
317+
arch_obj_setup_support(arch_obj);
287318
res = archive_read_open_FILE(arch_obj->archive, fp);
288319
if (res != ARCHIVE_OK) {
289320
zend_throw_exception_ex(
@@ -312,6 +343,52 @@ PHP_METHOD(libarchive_Archive, fromStream)
312343
arch_obj->write_disk_options = (int)flags;
313344
}
314345

346+
PHP_METHOD(libarchive_Archive, supportFormats)
347+
{
348+
zval *args;
349+
uint32_t num_args;
350+
ZEND_PARSE_PARAMETERS_START(1, -1)
351+
Z_PARAM_VARIADIC('+', args, num_args)
352+
ZEND_PARSE_PARAMETERS_END();
353+
354+
arch_object *arch_obj = arch_object_from_zv(getThis());
355+
if (arch_obj->archive != NULL) {
356+
zend_throw_exception(except_ce,
357+
"Cannot change format after archive has been opened", -1);
358+
return;
359+
}
360+
efree(arch_obj->formats);
361+
arch_obj->formats = safe_emalloc(num_args, sizeof(int), 0);
362+
arch_obj->formats_count = num_args;
363+
for (uint32_t i = 0; i < num_args; i++) {
364+
arch_obj->formats[i] = (int)Z_LVAL(args[i]);
365+
}
366+
RETURN_THIS();
367+
}
368+
369+
PHP_METHOD(libarchive_Archive, supportFilters)
370+
{
371+
zval *args;
372+
uint32_t num_args;
373+
ZEND_PARSE_PARAMETERS_START(1, -1)
374+
Z_PARAM_VARIADIC('+', args, num_args)
375+
ZEND_PARSE_PARAMETERS_END();
376+
377+
arch_object *arch_obj = arch_object_from_zv(getThis());
378+
if (arch_obj->archive != NULL) {
379+
zend_throw_exception(except_ce,
380+
"Cannot change filter after archive has been opened", -1);
381+
return;
382+
}
383+
efree(arch_obj->filters);
384+
arch_obj->filters = safe_emalloc(num_args, sizeof(int), 0);
385+
arch_obj->filters_count = num_args;
386+
for (uint32_t i = 0; i < num_args; i++) {
387+
arch_obj->filters[i] = (int)Z_LVAL(args[i]);
388+
}
389+
RETURN_THIS();
390+
}
391+
315392
PHP_METHOD(libarchive_Archive, currentEntryStream)
316393
{
317394
ZEND_PARSE_PARAMETERS_NONE();

libarchive.stub.php

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,68 @@
44

55
namespace libarchive {
66

7+
/** @var int
8+
* @cvalue ARCHIVE_FILTER_NONE */ const FILTER_NONE = UNKNOWN;
9+
/** @var int
10+
* @cvalue ARCHIVE_FILTER_GZIP */ const FILTER_GZIP = UNKNOWN;
11+
/** @var int
12+
* @cvalue ARCHIVE_FILTER_BZIP2 */ const FILTER_BZIP2 = UNKNOWN;
13+
/** @var int
14+
* @cvalue ARCHIVE_FILTER_COMPRESS */ const FILTER_COMPRESS = UNKNOWN;
15+
/** @var int
16+
* @cvalue ARCHIVE_FILTER_LZMA */ const FILTER_LZMA = UNKNOWN;
17+
/** @var int
18+
* @cvalue ARCHIVE_FILTER_XZ */ const FILTER_XZ = UNKNOWN;
19+
/** @var int
20+
* @cvalue ARCHIVE_FILTER_UU */ const FILTER_UU = UNKNOWN;
21+
/** @var int
22+
* @cvalue ARCHIVE_FILTER_RPM */ const FILTER_RPM = UNKNOWN;
23+
/** @var int
24+
* @cvalue ARCHIVE_FILTER_LZIP */ const FILTER_LZIP = UNKNOWN;
25+
/** @var int
26+
* @cvalue ARCHIVE_FILTER_LRZIP */ const FILTER_LRZIP = UNKNOWN;
27+
/** @var int
28+
* @cvalue ARCHIVE_FILTER_LZOP */ const FILTER_LZOP = UNKNOWN;
29+
/** @var int
30+
* @cvalue ARCHIVE_FILTER_GRZIP */ const FILTER_GRZIP = UNKNOWN;
31+
/** @var int
32+
* @cvalue ARCHIVE_FILTER_LZ4 */ const FILTER_LZ4 = UNKNOWN;
33+
/** @var int
34+
* @cvalue ARCHIVE_FILTER_ZSTD */ const FILTER_ZSTD = UNKNOWN;
35+
36+
/** @var int
37+
* @cvalue ARCHIVE_FORMAT_CPIO */ const FORMAT_CPIO = UNKNOWN;
38+
/** @var int
39+
* @cvalue ARCHIVE_FORMAT_SHAR */ const FORMAT_SHAR = UNKNOWN;
40+
/** @var int
41+
* @cvalue ARCHIVE_FORMAT_TAR */ const FORMAT_TAR = UNKNOWN;
42+
/** @var int
43+
* @cvalue ARCHIVE_FORMAT_ISO9660 */ const FORMAT_ISO9660 = UNKNOWN;
44+
/** @var int
45+
* @cvalue ARCHIVE_FORMAT_ZIP */ const FORMAT_ZIP = UNKNOWN;
46+
/** @var int
47+
* @cvalue ARCHIVE_FORMAT_EMPTY */ const FORMAT_EMPTY = UNKNOWN;
48+
/** @var int
49+
* @cvalue ARCHIVE_FORMAT_AR */ const FORMAT_AR = UNKNOWN;
50+
/** @var int
51+
* @cvalue ARCHIVE_FORMAT_MTREE */ const FORMAT_MTREE = UNKNOWN;
52+
/** @var int
53+
* @cvalue ARCHIVE_FORMAT_RAW */ const FORMAT_RAW = UNKNOWN;
54+
/** @var int
55+
* @cvalue ARCHIVE_FORMAT_XAR */ const FORMAT_XAR = UNKNOWN;
56+
/** @var int
57+
* @cvalue ARCHIVE_FORMAT_LHA */ const FORMAT_LHA = UNKNOWN;
58+
/** @var int
59+
* @cvalue ARCHIVE_FORMAT_CAB */ const FORMAT_CAB = UNKNOWN;
60+
/** @var int
61+
* @cvalue ARCHIVE_FORMAT_RAR */ const FORMAT_RAR = UNKNOWN;
62+
/** @var int
63+
* @cvalue ARCHIVE_FORMAT_7ZIP */ const FORMAT_7ZIP = UNKNOWN;
64+
/** @var int
65+
* @cvalue ARCHIVE_FORMAT_WARC */ const FORMAT_WARC = UNKNOWN;
66+
/** @var int
67+
* @cvalue ARCHIVE_FORMAT_RAR_V5 */ const FORMAT_RAR_V5 = UNKNOWN;
68+
769
/**
870
* Restore the user and group ownership of extracted entries.
971
* Equivalent to the libarchive flag ARCHIVE_EXTRACT_OWNER.
@@ -301,6 +363,34 @@ public function __construct(string $file, int $flags = 0) {}
301363
*/
302364
public static function fromStream(mixed $stream, int $flags = 0): static {}
303365

366+
/**
367+
* Restrict reading to specific archive formats.
368+
*
369+
* By default all formats are tried (auto-detect). Calling this method
370+
* limits detection to the given format codes, replacing any previous
371+
* call. Requires at least one argument.
372+
*
373+
* Must be called before iteration begins.
374+
*
375+
* @param int ...$formats One or more FORMAT_* constants.
376+
* @throws Exception If the archive has already been opened.
377+
*/
378+
public function supportFormats(int ...$formats): static {}
379+
380+
/**
381+
* Restrict reading to a specific decompression filter.
382+
*
383+
* By default all filters are tried (auto-detect). Calling this method
384+
* limits detection to the given filter codes, replacing any previous
385+
* call. Requires at least one argument.
386+
*
387+
* Must be called before iteration begins.
388+
*
389+
* @param int ...$filters One or more FILTER_* constants.
390+
* @throws Exception If the archive has already been opened.
391+
*/
392+
public function supportFilters(int ...$filters): static {}
393+
304394
/**
305395
* Extract the current archive entry to disk.
306396
*

libarchive_arginfo.h

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* This is a generated file, edit the .stub.php file instead.
2-
* Stub hash: e2b78feab80afeed324b595b8e65cfecc5be6d95 */
2+
* Stub hash: 81dea0d19df4df4a10af9d7c03bd825e47795f43 */
33

44
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_libarchive_Entry___construct, 0, 0, 0)
55
ZEND_END_ARG_INFO()
@@ -14,6 +14,14 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_libarchive_Archive_fromStr
1414
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, flags, IS_LONG, 0, "0")
1515
ZEND_END_ARG_INFO()
1616

17+
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_libarchive_Archive_supportFormats, 0, 1, IS_STATIC, 0)
18+
ZEND_ARG_VARIADIC_TYPE_INFO(0, formats, IS_LONG, 0)
19+
ZEND_END_ARG_INFO()
20+
21+
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_libarchive_Archive_supportFilters, 0, 1, IS_STATIC, 0)
22+
ZEND_ARG_VARIADIC_TYPE_INFO(0, filters, IS_LONG, 0)
23+
ZEND_END_ARG_INFO()
24+
1725
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_libarchive_Archive_extractCurrent, 0, 1, IS_VOID, 0)
1826
ZEND_ARG_OBJ_INFO(0, entry, libarchive\\Entry, 0)
1927
ZEND_END_ARG_INFO()
@@ -28,6 +36,8 @@ ZEND_END_ARG_INFO()
2836
ZEND_METHOD(libarchive_Entry, __construct);
2937
ZEND_METHOD(libarchive_Archive, __construct);
3038
ZEND_METHOD(libarchive_Archive, fromStream);
39+
ZEND_METHOD(libarchive_Archive, supportFormats);
40+
ZEND_METHOD(libarchive_Archive, supportFilters);
3141
ZEND_METHOD(libarchive_Archive, extractCurrent);
3242
ZEND_METHOD(libarchive_Archive, currentEntryStream);
3343
ZEND_METHOD(libarchive_Archive, getIterator);
@@ -47,6 +57,8 @@ static const zend_function_entry class_libarchive_Entry_methods[] = {
4757
static const zend_function_entry class_libarchive_Archive_methods[] = {
4858
ZEND_ME(libarchive_Archive, __construct, arginfo_class_libarchive_Archive___construct, ZEND_ACC_PUBLIC)
4959
ZEND_ME(libarchive_Archive, fromStream, arginfo_class_libarchive_Archive_fromStream, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
60+
ZEND_ME(libarchive_Archive, supportFormats, arginfo_class_libarchive_Archive_supportFormats, ZEND_ACC_PUBLIC)
61+
ZEND_ME(libarchive_Archive, supportFilters, arginfo_class_libarchive_Archive_supportFilters, ZEND_ACC_PUBLIC)
5062
ZEND_ME(libarchive_Archive, extractCurrent, arginfo_class_libarchive_Archive_extractCurrent, ZEND_ACC_PUBLIC)
5163
ZEND_ME(libarchive_Archive, currentEntryStream, arginfo_class_libarchive_Archive_currentEntryStream, ZEND_ACC_PUBLIC)
5264
ZEND_ME(libarchive_Archive, getIterator, arginfo_class_libarchive_Archive_getIterator, ZEND_ACC_PUBLIC)
@@ -55,6 +67,36 @@ static const zend_function_entry class_libarchive_Archive_methods[] = {
5567

5668
static void register_libarchive_symbols(int module_number)
5769
{
70+
REGISTER_LONG_CONSTANT("libarchive\\FILTER_NONE", ARCHIVE_FILTER_NONE, CONST_PERSISTENT);
71+
REGISTER_LONG_CONSTANT("libarchive\\FILTER_GZIP", ARCHIVE_FILTER_GZIP, CONST_PERSISTENT);
72+
REGISTER_LONG_CONSTANT("libarchive\\FILTER_BZIP2", ARCHIVE_FILTER_BZIP2, CONST_PERSISTENT);
73+
REGISTER_LONG_CONSTANT("libarchive\\FILTER_COMPRESS", ARCHIVE_FILTER_COMPRESS, CONST_PERSISTENT);
74+
REGISTER_LONG_CONSTANT("libarchive\\FILTER_LZMA", ARCHIVE_FILTER_LZMA, CONST_PERSISTENT);
75+
REGISTER_LONG_CONSTANT("libarchive\\FILTER_XZ", ARCHIVE_FILTER_XZ, CONST_PERSISTENT);
76+
REGISTER_LONG_CONSTANT("libarchive\\FILTER_UU", ARCHIVE_FILTER_UU, CONST_PERSISTENT);
77+
REGISTER_LONG_CONSTANT("libarchive\\FILTER_RPM", ARCHIVE_FILTER_RPM, CONST_PERSISTENT);
78+
REGISTER_LONG_CONSTANT("libarchive\\FILTER_LZIP", ARCHIVE_FILTER_LZIP, CONST_PERSISTENT);
79+
REGISTER_LONG_CONSTANT("libarchive\\FILTER_LRZIP", ARCHIVE_FILTER_LRZIP, CONST_PERSISTENT);
80+
REGISTER_LONG_CONSTANT("libarchive\\FILTER_LZOP", ARCHIVE_FILTER_LZOP, CONST_PERSISTENT);
81+
REGISTER_LONG_CONSTANT("libarchive\\FILTER_GRZIP", ARCHIVE_FILTER_GRZIP, CONST_PERSISTENT);
82+
REGISTER_LONG_CONSTANT("libarchive\\FILTER_LZ4", ARCHIVE_FILTER_LZ4, CONST_PERSISTENT);
83+
REGISTER_LONG_CONSTANT("libarchive\\FILTER_ZSTD", ARCHIVE_FILTER_ZSTD, CONST_PERSISTENT);
84+
REGISTER_LONG_CONSTANT("libarchive\\FORMAT_CPIO", ARCHIVE_FORMAT_CPIO, CONST_PERSISTENT);
85+
REGISTER_LONG_CONSTANT("libarchive\\FORMAT_SHAR", ARCHIVE_FORMAT_SHAR, CONST_PERSISTENT);
86+
REGISTER_LONG_CONSTANT("libarchive\\FORMAT_TAR", ARCHIVE_FORMAT_TAR, CONST_PERSISTENT);
87+
REGISTER_LONG_CONSTANT("libarchive\\FORMAT_ISO9660", ARCHIVE_FORMAT_ISO9660, CONST_PERSISTENT);
88+
REGISTER_LONG_CONSTANT("libarchive\\FORMAT_ZIP", ARCHIVE_FORMAT_ZIP, CONST_PERSISTENT);
89+
REGISTER_LONG_CONSTANT("libarchive\\FORMAT_EMPTY", ARCHIVE_FORMAT_EMPTY, CONST_PERSISTENT);
90+
REGISTER_LONG_CONSTANT("libarchive\\FORMAT_AR", ARCHIVE_FORMAT_AR, CONST_PERSISTENT);
91+
REGISTER_LONG_CONSTANT("libarchive\\FORMAT_MTREE", ARCHIVE_FORMAT_MTREE, CONST_PERSISTENT);
92+
REGISTER_LONG_CONSTANT("libarchive\\FORMAT_RAW", ARCHIVE_FORMAT_RAW, CONST_PERSISTENT);
93+
REGISTER_LONG_CONSTANT("libarchive\\FORMAT_XAR", ARCHIVE_FORMAT_XAR, CONST_PERSISTENT);
94+
REGISTER_LONG_CONSTANT("libarchive\\FORMAT_LHA", ARCHIVE_FORMAT_LHA, CONST_PERSISTENT);
95+
REGISTER_LONG_CONSTANT("libarchive\\FORMAT_CAB", ARCHIVE_FORMAT_CAB, CONST_PERSISTENT);
96+
REGISTER_LONG_CONSTANT("libarchive\\FORMAT_RAR", ARCHIVE_FORMAT_RAR, CONST_PERSISTENT);
97+
REGISTER_LONG_CONSTANT("libarchive\\FORMAT_7ZIP", ARCHIVE_FORMAT_7ZIP, CONST_PERSISTENT);
98+
REGISTER_LONG_CONSTANT("libarchive\\FORMAT_WARC", ARCHIVE_FORMAT_WARC, CONST_PERSISTENT);
99+
REGISTER_LONG_CONSTANT("libarchive\\FORMAT_RAR_V5", ARCHIVE_FORMAT_RAR_V5, CONST_PERSISTENT);
58100
REGISTER_LONG_CONSTANT("libarchive\\EXTRACT_OWNER", ARCHIVE_EXTRACT_OWNER, CONST_PERSISTENT);
59101
REGISTER_LONG_CONSTANT("libarchive\\EXTRACT_PERM", ARCHIVE_EXTRACT_PERM, CONST_PERSISTENT);
60102
REGISTER_LONG_CONSTANT("libarchive\\EXTRACT_TIME", ARCHIVE_EXTRACT_TIME, CONST_PERSISTENT);

php_compat.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
#pragma once
22

3+
#if PHP_VERSION_ID < 80200
4+
#define RETURN_THIS() ZVAL_COPY(return_value, getThis()); return
5+
#endif
6+
37
#if PHP_VERSION_ID < 80400
48
static inline zend_class_entry *php_libarchive_register_class_with_flags(
59
zend_class_entry *ce, zend_class_entry *parent_ce, uint32_t flags)

php_libarchive.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ typedef struct _arch_object {
4646
struct archive *nullable archive;
4747
struct archive *nullable arch_disk;
4848
int write_disk_options;
49+
int *nullable formats; /* NULL = auto-detect all; emalloc'd array of ARCHIVE_FORMAT_* codes */
50+
uint32_t formats_count;
51+
int *nullable filters; /* NULL = auto-detect all; emalloc'd array of ARCHIVE_FILTER_* codes */
52+
uint32_t filters_count;
4953
uint32_t entry_generation; /* incremented before each archive_read_next_header2 call */
5054
zend_object parent;
5155
} arch_object;

0 commit comments

Comments
 (0)