@@ -171,7 +171,7 @@ static zend_object *arch_ce_create_object(zend_class_entry *ce)
171171 arch_object * zobj =
172172 emalloc (sizeof (* zobj ) + zend_object_properties_size (ce ));
173173
174- zobj -> file_location = NULL ;
174+ zobj -> source_kind = ARCH_SOURCE_NONE ;
175175 zobj -> archive = NULL ;
176176 zobj -> arch_disk = NULL ;
177177 zobj -> write_disk_options = 0 ;
@@ -184,10 +184,17 @@ static zend_object *arch_ce_create_object(zend_class_entry *ce)
184184static void arch_oh_free_obj (zend_object * zobj )
185185{
186186 arch_object * obj = arch_object_fetch (zobj );
187- if (obj -> file_location ) {
188- zend_string_release (obj -> file_location );
189- obj -> file_location = NULL ;
190- }
187+ switch (obj -> source_kind ) {
188+ case ARCH_SOURCE_FILE :
189+ zend_string_release (obj -> source .file_location );
190+ break ;
191+ case ARCH_SOURCE_STREAM :
192+ zval_ptr_dtor (& obj -> source .stream_zv );
193+ break ;
194+ case ARCH_SOURCE_NONE :
195+ break ;
196+ }
197+ obj -> source_kind = ARCH_SOURCE_NONE ;
191198 if (obj -> archive ) {
192199 archive_read_close (obj -> archive );
193200 obj -> archive = NULL ;
@@ -210,47 +217,101 @@ PHP_METHOD(libarchive_Archive, __construct)
210217 }
211218
212219 arch_object * arch_obj = arch_object_from_zv (getThis ());
213- arch_obj -> file_location = zend_string_copy (file );
220+ arch_obj -> source_kind = ARCH_SOURCE_FILE ;
221+ arch_obj -> source .file_location = zend_string_copy (file );
214222 arch_obj -> write_disk_options = (int )flags ;
215223}
216224
225+ static bool arch_obj_open_read_stream (arch_object * arch_obj );
226+
217227static bool arch_obj_open_read (arch_object * arch_obj )
218228{
219229 php_stream * stream = php_stream_open_wrapper (
220- arch_obj -> file_location -> val , "rb" ,
230+ arch_obj -> source . file_location -> val , "rb" ,
221231 REPORT_ERRORS | STREAM_WILL_CAST | PHP_STREAM_PREFER_STDIO |
222232 STREAM_MUST_SEEK ,
223233 NULL );
224234
225235 if (!stream ) {
226236 zend_throw_exception_ex (except_ce , -1 , "Could not open %s" ,
227- arch_obj -> file_location -> val );
237+ arch_obj -> source . file_location -> val );
228238 return false;
229239 }
230240
231241 int fd ;
232- int res = php_stream_cast (stream , PHP_STREAM_AS_FD , (void * * )& fd , 0 );
242+ if (php_stream_can_cast (stream , PHP_STREAM_AS_FD ) == SUCCESS &&
243+ php_stream_cast (stream , PHP_STREAM_AS_FD , (void * * )& fd , 0 ) == SUCCESS ) {
244+ arch_obj -> archive = archive_read_new ();
245+ archive_read_support_filter_all (arch_obj -> archive );
246+ archive_read_support_format_all (arch_obj -> archive );
247+ int res = archive_read_open_fd (arch_obj -> archive , fd , 10240 );
248+ if (res != ARCHIVE_OK ) {
249+ zend_throw_exception_ex (
250+ except_ce , archive_errno (arch_obj -> archive ),
251+ "Could not open archive from file descriptor: %s" ,
252+ archive_error_string (arch_obj -> archive ));
253+ return false;
254+ }
255+ } else {
256+ /* FD cast not supported by this stream wrapper; fall back to FILE*.
257+ * Switch the source so arch_obj_open_read_stream can take over and
258+ * the stream resource is kept alive for the lifetime of the archive. */
259+ zend_string_release (arch_obj -> source .file_location );
260+ arch_obj -> source_kind = ARCH_SOURCE_STREAM ;
261+ php_stream_to_zval (stream , & arch_obj -> source .stream_zv );
262+ return arch_obj_open_read_stream (arch_obj );
263+ }
264+
265+ return true;
266+ }
267+
268+ static bool arch_obj_open_read_stream (arch_object * arch_obj )
269+ {
270+ php_stream * stream ;
271+ php_stream_from_zval_no_verify (stream , & arch_obj -> source .stream_zv );
272+ if (!stream ) {
273+ zend_throw_exception (except_ce , "Invalid stream resource" , -1 );
274+ return false;
275+ }
276+
277+ FILE * fp ;
278+ int res = php_stream_cast (stream , PHP_STREAM_AS_STDIO , (void * * )& fp , REPORT_ERRORS );
233279 if (res != SUCCESS ) {
234- zend_throw_exception_ex (except_ce , -1 , "Could not cast stream for %s" ,
235- arch_obj -> file_location -> val );
280+ zend_throw_exception (except_ce , "Could not cast stream to FILE*" , -1 );
236281 return false;
237282 }
238283
239284 arch_obj -> archive = archive_read_new ();
240285 archive_read_support_filter_all (arch_obj -> archive );
241286 archive_read_support_format_all (arch_obj -> archive );
242- res = archive_read_open_fd (arch_obj -> archive , fd , 10240 );
287+ res = archive_read_open_FILE (arch_obj -> archive , fp );
243288 if (res != ARCHIVE_OK ) {
244289 zend_throw_exception_ex (
245290 except_ce , archive_errno (arch_obj -> archive ),
246- "Could not open archive from file descriptor : %s" ,
291+ "Could not open archive from stream : %s" ,
247292 archive_error_string (arch_obj -> archive ));
248293 return false;
249294 }
250295
251296 return true;
252297}
253298
299+ PHP_METHOD (libarchive_Archive , fromStream )
300+ {
301+ zval * stream_zv ;
302+ zend_long flags = 0 ;
303+ if (zend_parse_parameters (ZEND_NUM_ARGS (), "r|l" , & stream_zv , & flags ) ==
304+ FAILURE ) {
305+ return ;
306+ }
307+
308+ object_init_ex (return_value , arch_ce );
309+ arch_object * arch_obj = arch_object_from_zv (return_value );
310+ arch_obj -> source_kind = ARCH_SOURCE_STREAM ;
311+ ZVAL_COPY (& arch_obj -> source .stream_zv , stream_zv );
312+ arch_obj -> write_disk_options = (int )flags ;
313+ }
314+
254315PHP_METHOD (libarchive_Archive , currentEntryStream )
255316{
256317 ZEND_PARSE_PARAMETERS_NONE ();
@@ -396,7 +457,7 @@ static zend_object_iterator *arch_ce_get_iterator(zend_class_entry *ce,
396457 }
397458
398459 arch_object * arch_obj = arch_object_from_zv (object );
399- if (arch_obj -> file_location == NULL ) {
460+ if (arch_obj -> source_kind == ARCH_SOURCE_NONE ) {
400461 php_error_docref (
401462 NULL , E_ERROR ,
402463 "The Archive object has not been properly constructed" );
@@ -407,8 +468,14 @@ static zend_object_iterator *arch_ce_get_iterator(zend_class_entry *ce,
407468 -1 );
408469 return NULL ;
409470 }
410- if (!arch_obj_open_read (arch_obj )) {
411- return NULL ;
471+ if (arch_obj -> source_kind == ARCH_SOURCE_FILE ) {
472+ if (!arch_obj_open_read (arch_obj )) {
473+ return NULL ;
474+ }
475+ } else {
476+ if (!arch_obj_open_read_stream (arch_obj )) {
477+ return NULL ;
478+ }
412479 }
413480
414481 arch_iterator * it = emalloc (sizeof * it );
0 commit comments