mirror of
https://github.com/php-win-ext/php-rar.git
synced 2026-03-24 04:52:07 +01:00
Compare commits
226 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6bb74bf820 | ||
|
|
1a2f9f5104 | ||
|
|
0fd6896a25 | ||
|
|
d2a8a89e64 | ||
|
|
d95d7a794f | ||
|
|
9129dab024 | ||
|
|
897139b2ce | ||
|
|
2a29f7e763 | ||
|
|
3a830bc07c | ||
|
|
119722d581 | ||
|
|
a20ca1559c | ||
|
|
2ab141deed | ||
|
|
498cad468e | ||
|
|
65d5132550 | ||
|
|
2ea5d74e6d | ||
|
|
5840034b59 | ||
|
|
d72ef1dbce | ||
|
|
e2db202b89 | ||
|
|
1cf4e2c02c | ||
|
|
ee28abf175 | ||
|
|
ece47716ab | ||
|
|
388707153c | ||
|
|
60cf649b85 | ||
|
|
113935cbc5 | ||
|
|
881989bbac | ||
|
|
b1c3582301 | ||
|
|
1cfe9592c0 | ||
|
|
c92f03f1e2 | ||
|
|
430a8ba763 | ||
|
|
63d3b18405 | ||
|
|
6963ed8f43 | ||
|
|
0a57b9b313 | ||
|
|
3b9dd4dd6e | ||
|
|
28e2572026 | ||
|
|
21cba90843 | ||
|
|
0473c464e1 | ||
|
|
9cd367de03 | ||
|
|
0ef63a5fbb | ||
|
|
75486ffa92 | ||
|
|
e06c6250d0 | ||
|
|
eca703e481 | ||
|
|
47ff0254ea | ||
|
|
1f4496b5b0 | ||
|
|
3c74636516 | ||
|
|
02c0f562a8 | ||
|
|
36c26dacda | ||
|
|
c9373a4869 | ||
|
|
d35e6962c4 | ||
|
|
9cdbc652ed | ||
|
|
14afaf33a9 | ||
|
|
25087577be | ||
|
|
bf0df5d1ed | ||
|
|
010ca980e0 | ||
|
|
b92bcc5d5f | ||
|
|
da39115344 | ||
|
|
5947ee8db4 | ||
|
|
3fbc9ce3e9 | ||
|
|
45dbaf4a4f | ||
|
|
681739fbb5 | ||
|
|
d7d2318aad | ||
|
|
9cd2943b79 | ||
|
|
d9ccfe265f | ||
|
|
8aba0685be | ||
|
|
a6b4c57b1c | ||
|
|
535f0ea828 | ||
|
|
5d1aafd746 | ||
|
|
9d49ce4842 | ||
|
|
438d8a4b0b | ||
|
|
1e97aa1ef1 | ||
|
|
929b252665 | ||
|
|
7bfe225895 | ||
|
|
dff57d32cb | ||
|
|
71fb41635c | ||
|
|
9a7227a9e0 | ||
|
|
79b78f81b9 | ||
|
|
b1a21bb20c | ||
|
|
a72bceba89 | ||
|
|
d2e33c32c0 | ||
|
|
b081085cc9 | ||
|
|
ffde50b702 | ||
|
|
8bab79ae80 | ||
|
|
dadab995f5 | ||
|
|
0f950603be | ||
|
|
a88a995ca0 | ||
|
|
f92f731da3 | ||
|
|
99996abdb9 | ||
|
|
eb12649fb2 | ||
|
|
506493c52d | ||
|
|
3c8d037135 | ||
|
|
2fb18b2fe4 | ||
|
|
8f206263cb | ||
|
|
0f76b938a4 | ||
|
|
670290aad1 | ||
|
|
82d3711a99 | ||
|
|
af49aafb1d | ||
|
|
7288320a37 | ||
|
|
fc23699737 | ||
|
|
fffcb9d508 | ||
|
|
79afa19815 | ||
|
|
02855820f7 | ||
|
|
5f7b823e40 | ||
|
|
59437d527f | ||
|
|
9be4e1e0e3 | ||
|
|
7089587b9e | ||
|
|
43dc0541aa | ||
|
|
36b2b5d2fc | ||
|
|
4e2dc20b2d | ||
|
|
61183fa339 | ||
|
|
7da530c6e3 | ||
|
|
b7794e851d | ||
|
|
444ee4b790 | ||
|
|
51b5b9b267 | ||
|
|
65758585af | ||
|
|
5966259561 | ||
|
|
67d29529f1 | ||
|
|
e09548cd2f | ||
|
|
6faef72502 | ||
|
|
c39465fa08 | ||
|
|
633a15f4b4 | ||
|
|
c4432e6c4b | ||
|
|
81934056d0 | ||
|
|
896a5d3a91 | ||
|
|
a153f2ba84 | ||
|
|
6c8276f3c8 | ||
|
|
380eb4fd06 | ||
|
|
c502332f09 | ||
|
|
e64419b1c3 | ||
|
|
a9d71e2adb | ||
|
|
c56f0c4ad9 | ||
|
|
6de793130a | ||
|
|
ba66f77e5f | ||
|
|
f93c189947 | ||
|
|
5ba817d02c | ||
|
|
3655bf9e21 | ||
|
|
3254b497a2 | ||
|
|
da1c055202 | ||
|
|
d3ffa6d3ba | ||
|
|
8d24ef1195 | ||
|
|
84d8d1c93f | ||
|
|
22be3d8ee9 | ||
|
|
397d6de791 | ||
|
|
6d00347ddd | ||
|
|
1401a0604c | ||
|
|
d033b8f836 | ||
|
|
b15940e101 | ||
|
|
829e402dbb | ||
|
|
48c55f71ea | ||
|
|
9876090ea6 | ||
|
|
3a71ec0c0f | ||
|
|
c52d6a92a6 | ||
|
|
8f65391767 | ||
|
|
3f841aca84 | ||
|
|
d39e216566 | ||
|
|
ed74b331d8 | ||
|
|
36e67a3493 | ||
|
|
d6673b97fd | ||
|
|
04ac7f6eba | ||
|
|
a4b1479338 | ||
|
|
d528906ec7 | ||
|
|
3c08bc522f | ||
|
|
dc4037e8ed | ||
|
|
b79060c741 | ||
|
|
2ea98f9c07 | ||
|
|
40b585bc2f | ||
|
|
62ebac8d88 | ||
|
|
cf7947cbbd | ||
|
|
f6900cb024 | ||
|
|
fa8c1c8aa8 | ||
|
|
4d7c5fc2c4 | ||
|
|
10d2444b31 | ||
|
|
63e0df6078 | ||
|
|
54ac112b0d | ||
|
|
9ec063426c | ||
|
|
1d4ad5767b | ||
|
|
0866f20178 | ||
|
|
5db1495374 | ||
|
|
75f63eae35 | ||
|
|
5f0d4b1516 | ||
|
|
7430bfae21 | ||
|
|
3010bc351e | ||
|
|
bfaaaa95fe | ||
|
|
379f5d1d43 | ||
|
|
f45fb54b0a | ||
|
|
e4d1885168 | ||
|
|
b5cecfd421 | ||
|
|
57f518d804 | ||
|
|
0ed5106066 | ||
|
|
473e865b38 | ||
|
|
b08d2ebc66 | ||
|
|
198fda108f | ||
|
|
a745071a2a | ||
|
|
6e5f90d038 | ||
|
|
45ac56f43b | ||
|
|
c3913f5ee9 | ||
|
|
289e63250b | ||
|
|
9b7245f2ba | ||
|
|
a4f66e2dca | ||
|
|
5ec39978bc | ||
|
|
34652b09b2 | ||
|
|
905a30a02d | ||
|
|
355edc6bf5 | ||
|
|
1ba294df92 | ||
|
|
c85047e54c | ||
|
|
5cbc4174f7 | ||
|
|
c3d082f6b3 | ||
|
|
884f7db326 | ||
|
|
d5b4779393 | ||
|
|
a0021aa3c2 | ||
|
|
80af4abe5a | ||
|
|
890f103f50 | ||
|
|
101fddb80a | ||
|
|
8a59dd703c | ||
|
|
7a18c6a556 | ||
|
|
c1a3d3d0a7 | ||
|
|
95146b812d | ||
|
|
9447de1436 | ||
|
|
c594c7a9e1 | ||
|
|
b474abaecf | ||
|
|
652574e80f | ||
|
|
42b0d2c57d | ||
|
|
7d6d5a605b | ||
|
|
78f6dc0bda | ||
|
|
950825aa18 | ||
|
|
cd443a6e7d | ||
|
|
604059cedf | ||
|
|
1f63a42ba8 |
42
.gitignore
vendored
Normal file
42
.gitignore
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
*.o
|
||||
*.lo
|
||||
/tests/*.sh
|
||||
/tests/*.exp
|
||||
/tests/*.diff
|
||||
/tests/*.log
|
||||
/tests/*.php
|
||||
/tests/*.out
|
||||
/tests/*.mem
|
||||
/run-tests.php
|
||||
/modules
|
||||
/missing
|
||||
/.deps
|
||||
/.libs
|
||||
/Makefile
|
||||
/Makefile.fragments
|
||||
/Makefile.global
|
||||
/Makefile.objects
|
||||
/acinclude.m4
|
||||
/aclocal.m4
|
||||
/autom4te.cache
|
||||
/build
|
||||
/config.guess
|
||||
/config.h
|
||||
/config.h.in
|
||||
/config.log
|
||||
/config.nice
|
||||
/config.status
|
||||
/config.sub
|
||||
/configure
|
||||
/configure.in
|
||||
/install-sh
|
||||
/intl.la
|
||||
/libtool
|
||||
/mkinstalldirs
|
||||
/ltmain.sh
|
||||
/.cproject
|
||||
/.project
|
||||
/.settings
|
||||
/pecl-rar.*
|
||||
/rar.la
|
||||
*.autosave
|
||||
23
.travis.yml
Normal file
23
.travis.yml
Normal file
@@ -0,0 +1,23 @@
|
||||
language: c
|
||||
dist: trusty
|
||||
|
||||
env:
|
||||
#- PHP_VERSION=5.2.17 ZTS=yes MIRROR=http://museum.php.net/php5/
|
||||
- PHP_VERSION=5.3.29 ZTS=yes
|
||||
- PHP_VERSION=5.4.45 ZTS=yes
|
||||
- PHP_VERSION=5.5.37 ZTS=yes
|
||||
- PHP_VERSION=5.6.30 ZTS=yes
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/php_builds
|
||||
|
||||
before_install:
|
||||
- source travis.sh
|
||||
- maybe_install_php $PHP_VERSION $ZTS
|
||||
|
||||
install:
|
||||
- build $PHP_VERSION $ZTS
|
||||
|
||||
script:
|
||||
- run_tests $PHP_VERSION $ZTS
|
||||
68
LICENSE
Normal file
68
LICENSE
Normal file
@@ -0,0 +1,68 @@
|
||||
--------------------------------------------------------------------
|
||||
The PHP License, version 3.01
|
||||
Copyright (c) 1999 - 2010 The PHP Group. All rights reserved.
|
||||
--------------------------------------------------------------------
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, is permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
3. The name "PHP" must not be used to endorse or promote products
|
||||
derived from this software without prior written permission. For
|
||||
written permission, please contact group@php.net.
|
||||
|
||||
4. Products derived from this software may not be called "PHP", nor
|
||||
may "PHP" appear in their name, without prior written permission
|
||||
from group@php.net. You may indicate that your software works in
|
||||
conjunction with PHP by saying "Foo for PHP" instead of calling
|
||||
it "PHP Foo" or "phpfoo"
|
||||
|
||||
5. The PHP Group may publish revised and/or new versions of the
|
||||
license from time to time. Each version will be given a
|
||||
distinguishing version number.
|
||||
Once covered code has been published under a particular version
|
||||
of the license, you may always continue to use it under the terms
|
||||
of that version. You may also choose to use such covered code
|
||||
under the terms of any subsequent version of the license
|
||||
published by the PHP Group. No one other than the PHP Group has
|
||||
the right to modify the terms applicable to covered code created
|
||||
under this License.
|
||||
|
||||
6. Redistributions of any form whatsoever must retain the following
|
||||
acknowledgment:
|
||||
"This product includes PHP software, freely available from
|
||||
<http://www.php.net/software/>".
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE PHP DEVELOPMENT TEAM ``AS IS'' AND
|
||||
ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PHP
|
||||
DEVELOPMENT TEAM OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
--------------------------------------------------------------------
|
||||
|
||||
This software consists of voluntary contributions made by many
|
||||
individuals on behalf of the PHP Group.
|
||||
|
||||
The PHP Group can be contacted via Email at group@php.net.
|
||||
|
||||
For more information on the PHP Group and the PHP project,
|
||||
please see <http://www.php.net>.
|
||||
|
||||
PHP includes the Zend Engine, freely available at
|
||||
<http://www.zend.com>.
|
||||
12
README
Normal file
12
README
Normal file
@@ -0,0 +1,12 @@
|
||||
PHP extension for reading RAR archives using the bundled UnRAR library.
|
||||
|
||||
This extension uses a modified version of the UnRAR library. The UnRAR library
|
||||
is an official open-source library by RARLabs, an auto generated subset of the
|
||||
RAR codebase. It is available from http://www.rarlab.com/rar_add.htm
|
||||
Please note that it has a more restrictive license than the PHP bindings,
|
||||
barring using it to re-create the RAR compression algorithm. See
|
||||
unrar/LICENSE.txt for details.
|
||||
|
||||
Some modifications have been applied to the UnRAR library, mainly to allow
|
||||
streaming extraction of files without using threads.
|
||||
|
||||
42
config.m4
Normal file
42
config.m4
Normal file
@@ -0,0 +1,42 @@
|
||||
dnl $Id$
|
||||
dnl config.m4 for extension rar
|
||||
|
||||
PHP_ARG_ENABLE(rar, whether to enable rar support,
|
||||
[ --enable-rar Enable rar support])
|
||||
|
||||
unrar_sources="unrar/sha256.cpp unrar/qopen.cpp \
|
||||
unrar/blake2s.cpp unrar/recvol.cpp \
|
||||
unrar/headers.cpp unrar/match.cpp \
|
||||
unrar/find.cpp \
|
||||
unrar/resource.cpp \
|
||||
unrar/pathfn.cpp \
|
||||
unrar/dll.cpp unrar/threadpool.cpp unrar/volume.cpp \
|
||||
unrar/unpack.cpp \
|
||||
unrar/extract.cpp unrar/errhnd.cpp \
|
||||
unrar/crc.cpp unrar/rijndael.cpp unrar/crypt.cpp \
|
||||
unrar/rawread.cpp \
|
||||
unrar/rs.cpp unrar/smallfn.cpp \
|
||||
unrar/isnt.cpp unrar/rar.cpp unrar/consio.cpp \
|
||||
unrar/scantree.cpp unrar/archive.cpp unrar/strfn.cpp \
|
||||
unrar/strlist.cpp \
|
||||
unrar/getbits.cpp unrar/hash.cpp \
|
||||
unrar/filestr.cpp \
|
||||
unrar/extinfo.cpp unrar/ui.cpp unrar/rarvm.cpp \
|
||||
unrar/timefn.cpp unrar/sha1.cpp \
|
||||
unrar/rdwrfn.cpp unrar/rs16.cpp unrar/cmddata.cpp \
|
||||
unrar/extractchunk.cpp unrar/system.cpp \
|
||||
unrar/unicode.cpp unrar/filcreat.cpp \
|
||||
unrar/arcread.cpp unrar/filefn.cpp \
|
||||
unrar/global.cpp unrar/list.cpp \
|
||||
unrar/encname.cpp unrar/file.cpp \
|
||||
unrar/secpassword.cpp unrar/options.cpp"
|
||||
|
||||
if test "$PHP_RAR" != "no"; then
|
||||
AC_DEFINE(HAVE_RAR, 1, [Whether you have rar support])
|
||||
PHP_SUBST(RAR_SHARED_LIBADD)
|
||||
PHP_REQUIRE_CXX()
|
||||
PHP_ADD_LIBRARY_WITH_PATH(stdc++, "", RAR_SHARED_LIBADD)
|
||||
|
||||
PHP_NEW_EXTENSION(rar, rar.c rar_error.c rararch.c rarentry.c rar_stream.c rar_navigation.c $unrar_sources, $ext_shared,,-DRARDLL -DSILENT -Wno-write-strings -Wall -I@ext_srcdir@/unrar)
|
||||
PHP_ADD_BUILD_DIR($ext_builddir/unrar)
|
||||
fi
|
||||
29
config.w32
Normal file
29
config.w32
Normal file
@@ -0,0 +1,29 @@
|
||||
// $Id$
|
||||
// vim:ft=javascript
|
||||
|
||||
ARG_ENABLE("rar", "Rar support", "no");
|
||||
|
||||
if (PHP_RAR != "no") {
|
||||
EXTENSION("rar", "rar.c rar_error.c rararch.c rarentry.c rar_stream.c rar_navigation.c", PHP_RAR_SHARED, "/DRARDLL /DGUI /DSILENT /EHsc /D_WSTDIO_DEFINED");
|
||||
ADD_SOURCES(configure_module_dirname + "/unrar",
|
||||
"rar.cpp strlist.cpp strfn.cpp \
|
||||
pathfn.cpp smallfn.cpp savepos.cpp \
|
||||
global.cpp file.cpp filefn.cpp \
|
||||
filcreat.cpp archive.cpp arcread.cpp \
|
||||
unicode.cpp system.cpp isnt.cpp \
|
||||
crypt.cpp crc.cpp rawread.cpp \
|
||||
encname.cpp resource.cpp match.cpp \
|
||||
timefn.cpp rdwrfn.cpp consio.cpp \
|
||||
options.cpp ulinks.cpp errhnd.cpp \
|
||||
rarvm.cpp rijndael.cpp getbits.cpp \
|
||||
sha1.cpp extinfo.cpp extract.cpp \
|
||||
volume.cpp find.cpp \
|
||||
unpack.cpp cmddata.cpp dll.cpp \
|
||||
filestr.cpp recvol.cpp rs.cpp \
|
||||
scantree.cpp extractchunk.cpp log.cpp \
|
||||
secpassword.cpp ", "rar");
|
||||
|
||||
AC_DEFINE("HAVE_RAR", 1, "Rar support");
|
||||
}
|
||||
|
||||
|
||||
22
example.php
Normal file
22
example.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<?
|
||||
|
||||
$archive_name = '/full/path/to/file.rar'
|
||||
$entry_name = 'path/to/archive/entry.txt'; //notice: no slash at the beginning
|
||||
$dir_to_extract_to = '/path/to/extract/dir';
|
||||
$new_entry_name = 'some.txt';
|
||||
|
||||
|
||||
$rar = rar_open($archive_name) OR die('failed to open ' . $archive_name);
|
||||
$entry = rar_entry_get($rar, $entry_name) OR die('failed to find ' . $entry_name . ' in ' . $archive_name);
|
||||
|
||||
// this will create all necessary subdirs under $dir_to_extract_to
|
||||
$entry->extract($dir_to_extract_to);
|
||||
/* OR */
|
||||
|
||||
// this will create only one new file $new_entry_name in $dir_to_extract_to
|
||||
$entry->extract('', $dir_to_extract_to.'/'.$new_entry_name);
|
||||
|
||||
// this line is really not necessary
|
||||
rar_close($rar);
|
||||
|
||||
?>
|
||||
62
extflow.txt
Normal file
62
extflow.txt
Normal file
@@ -0,0 +1,62 @@
|
||||
(some information is outdated)
|
||||
|
||||
rar_open/RarArchive::open()
|
||||
gives
|
||||
RarArchive object
|
||||
-
|
||||
. stores 2 open data structs (are used to tell the lib e.g. which file to open and the lib in return stores some data in them)
|
||||
- list_open_data has open mode RAR_OM_LIST_INCSPLIT and is used to list the contents of the archive
|
||||
- extract_open_data has open mode RAR_OM_EXTRACT and is used by RarEntry::extract
|
||||
. stores one opened archive handle, opened with the list_open_data struct. This handle remains
|
||||
open until the archive is closed or the object is destroyed
|
||||
. a RarArchive object is considered closed when the opened archive handle created here is set to NULL
|
||||
|
||||
|
||||
rar_list()/RarArchive::getEntries()
|
||||
gives
|
||||
RarEntry objects
|
||||
-
|
||||
. CALL _rar_list_files, which fills the lazy cache rar->entries by using the opened archive handle to retrieve ALL the RarHeaderDataEx headers
|
||||
. CALL _rar_raw_entries_to_files to turn the rar->entries RarHeaderDataEx headers into zvals
|
||||
- in turn, _rar_raw_entries_to_files creates the zval and sets the property that holds the zval reference to the RarArchive object (see below)
|
||||
- calculates the packed size by summing over all the headers that concern each file (a file may have more than one header in case there are volumes)
|
||||
- then CALLs _rar_entry_to_zval with the last header for each file and the packed size so that it can fill the remaining properties
|
||||
. each of the RarEntry objects store a zval referencing the RarArchive object. The RarArchive object is not destroyed until all its spawned RarEntry objects are destroyed (it can however be closed)
|
||||
|
||||
|
||||
rar_entry_get()/RarArchive::getEntry()
|
||||
gives
|
||||
RarEntry object
|
||||
-
|
||||
. CALL _rar_list_files, if it's necessary to fill the lazy cache rar->entries
|
||||
. CALL _rar_raw_entries_to_files, which traverses rar->entries until it finds the request filename, the header(s) are then converted into one zval
|
||||
. again, the RarEntry object stores a reference to the RarArchive object
|
||||
|
||||
|
||||
RarArchive traversal with an iterator
|
||||
gives
|
||||
RarEntry objects (one at a time)
|
||||
-
|
||||
. iterator creation CALLs_rar_list_files, if it's necessary to fill the lazy cache rar->entries
|
||||
. iterator stores the index (with respect to the rar->entries array) of the last header in rar->entries that is to be read (starts with 0)
|
||||
. iterator CALLs _rar_raw_entries_to_files, which here stops after reading each file and advances the index
|
||||
|
||||
|
||||
RarEntry::extract()
|
||||
extracts the file
|
||||
-
|
||||
. uses the extract_open_data that's stored in the parent RarArchive object
|
||||
. makes a shallow copy of parent RarArchive's rar->cb_userdata, eventually modified with the given file password.
|
||||
. passes them to _rar_find_file to open the file with RAR_OM_EXTRACT and skip to the desired entry
|
||||
. extracts the file
|
||||
. closes the rar handle
|
||||
|
||||
|
||||
RarEntry::getStream()
|
||||
obtains stream
|
||||
-
|
||||
. CALL php_stream_rar_open with the archive name (obtained from parent RarArchive object's extract_open_data->ArcName), the filename of the entry and a shallow copy of parent RarArchive's rar->cb_userdata, eventually modified with the given file password.
|
||||
. in turn, php_stream_rar_open CALLs _rar_find_file with a brand new rar open data struct with RAR_OM_EXTRACT. _rar_find_file opens the RAR archive and skips to the desired entry
|
||||
. the resulting stream has no connection to the original RarArchive object or to the RarEntry object
|
||||
. the rar archive is not closed until the stream is destroyed or closed
|
||||
|
||||
496
package.xml
Normal file
496
package.xml
Normal file
@@ -0,0 +1,496 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<package packagerversion="1.5.4" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0
|
||||
http://pear.php.net/dtd/tasks-1.0.xsd
|
||||
http://pear.php.net/dtd/package-2.0
|
||||
http://pear.php.net/dtd/package-2.0.xsd">
|
||||
<name>rar</name>
|
||||
<channel>pecl.php.net</channel>
|
||||
<summary>rar extension</summary>
|
||||
<description>PHP extension for reading RAR archives using bundled unRAR library.
|
||||
</description>
|
||||
|
||||
<lead>
|
||||
<name>Gustavo Lopes</name>
|
||||
<user>cataphract</user>
|
||||
<email>cataphract@php.net</email>
|
||||
<active>yes</active>
|
||||
</lead>
|
||||
|
||||
<developer>
|
||||
<name>Antony Dovgal</name>
|
||||
<user>tony2001</user>
|
||||
<email>tony@daylessday.org</email>
|
||||
<active>no</active>
|
||||
</developer>
|
||||
|
||||
<date>2013-10-11</date>
|
||||
<time>13:00:00</time>
|
||||
<version>
|
||||
<release>3.0.2</release>
|
||||
<api>3.0.0</api>
|
||||
</version>
|
||||
|
||||
<stability>
|
||||
<release>stable</release>
|
||||
<api>stable</api>
|
||||
</stability>
|
||||
|
||||
<license uri="http://www.php.net/license">PHP License</license>
|
||||
<notes>- Fixed build with PHP 5.5.
|
||||
- Upgraded bundled unrar to version 4.2.4.
|
||||
</notes>
|
||||
<contents>
|
||||
<dir name="/">
|
||||
<dir name="tests">
|
||||
<file role="test" name="001.phpt"/>
|
||||
<file role="test" name="002.phpt"/>
|
||||
<file role="test" name="003.phpt"/>
|
||||
<file role="test" name="004.phpt"/>
|
||||
<file role="test" name="4mb.rar"/>
|
||||
<file role="test" name="005.phpt"/>
|
||||
<file role="test" name="006.phpt"/>
|
||||
<file role="test" name="007.phpt"/>
|
||||
<file role="test" name="008.phpt"/>
|
||||
<file role="test" name="009.phpt"/>
|
||||
<file role="test" name="010.phpt"/>
|
||||
<file role="test" name="011.phpt"/>
|
||||
<file role="test" name="012.phpt"/>
|
||||
<file role="test" name="013.phpt"/>
|
||||
<file role="test" name="014.phpt"/>
|
||||
<file role="test" name="015.phpt"/>
|
||||
<file role="test" name="016.phpt"/>
|
||||
<file role="test" name="017.phpt"/>
|
||||
<file role="test" name="018.phpt"/>
|
||||
<file role="test" name="019.phpt"/>
|
||||
<file role="test" name="020.phpt"/>
|
||||
<file role="test" name="021.phpt"/>
|
||||
<file role="test" name="022.phpt"/>
|
||||
<file role="test" name="023.phpt"/>
|
||||
<file role="test" name="024.phpt"/>
|
||||
<file role="test" name="025.phpt"/>
|
||||
<file role="test" name="026.phpt"/>
|
||||
<file role="test" name="027.phpt"/>
|
||||
<file role="test" name="028.phpt"/>
|
||||
<file role="test" name="029.phpt"/>
|
||||
<file role="test" name="030.phpt"/>
|
||||
<file role="test" name="031.phpt"/>
|
||||
<file role="test" name="032.phpt"/>
|
||||
<file role="test" name="033.phpt"/>
|
||||
<file role="test" name="034.phpt"/>
|
||||
<file role="test" name="035.phpt"/>
|
||||
<file role="test" name="036.phpt"/>
|
||||
<file role="test" name="037.phpt"/>
|
||||
<file role="test" name="038.phpt"/>
|
||||
<file role="test" name="039.phpt"/>
|
||||
<file role="test" name="040.phpt"/>
|
||||
<file role="test" name="041.phpt"/>
|
||||
<file role="test" name="042.phpt"/>
|
||||
<file role="test" name="043.phpt"/>
|
||||
<file role="test" name="044.phpt"/>
|
||||
<file role="test" name="045.phpt"/>
|
||||
<file role="test" name="046.phpt"/>
|
||||
<file role="test" name="047.phpt"/>
|
||||
<file role="test" name="048.phpt"/>
|
||||
<file role="test" name="049.phpt"/>
|
||||
<file role="test" name="050.phpt"/>
|
||||
<file role="test" name="051.phpt"/>
|
||||
<file role="test" name="052.phpt"/>
|
||||
<file role="test" name="053.phpt"/>
|
||||
<file role="test" name="054.phpt"/>
|
||||
<file role="test" name="055.phpt"/>
|
||||
<file role="test" name="056.phpt"/>
|
||||
<file role="test" name="057.phpt"/>
|
||||
<file role="test" name="058.phpt"/>
|
||||
<file role="test" name="059.phpt"/>
|
||||
<file role="test" name="060.phpt"/>
|
||||
<file role="test" name="061.phpt"/>
|
||||
<file role="test" name="062.phpt"/>
|
||||
<file role="test" name="063.phpt"/>
|
||||
<file role="test" name="064.phpt"/>
|
||||
<file role="test" name="065.phpt"/>
|
||||
<file role="test" name="066.phpt"/>
|
||||
<file role="test" name="067.phpt"/>
|
||||
<file role="test" name="068.phpt"/>
|
||||
<file role="test" name="069.phpt"/>
|
||||
<file role="test" name="070.phpt"/>
|
||||
<file role="test" name="071.phpt"/>
|
||||
<file role="test" name="072.phpt"/>
|
||||
<file role="test" name="073.phpt"/>
|
||||
<file role="test" name="074.phpt"/>
|
||||
<file role="test" name="075.phpt"/>
|
||||
<file role="test" name="076.phpt"/>
|
||||
<file role="test" name="077.phpt"/>
|
||||
<file role="test" name="078.phpt"/>
|
||||
<file role="test" name="079.phpt"/>
|
||||
<file role="test" name="080.phpt"/>
|
||||
<file role="test" name="081.phpt"/>
|
||||
<file role="test" name="082.phpt"/>
|
||||
<file role="test" name="083.phpt"/>
|
||||
<file role="test" name="084.phpt"/>
|
||||
<file role="test" name="085.phpt"/>
|
||||
<file role="test" name="086.phpt"/>
|
||||
<file role="test" name="087.phpt"/>
|
||||
<file role="test" name="088.phpt"/>
|
||||
<file role="test" name="089.phpt"/>
|
||||
<file role="test" name="090.phpt"/>
|
||||
<file role="test" name="091.phpt"/>
|
||||
<file role="test" name="092.phpt"/>
|
||||
<file role="test" name="093.phpt"/>
|
||||
<file role="test" name="094.phpt"/>
|
||||
<file role="test" name="095.phpt"/>
|
||||
<file role="test" name="096.phpt"/>
|
||||
<file role="test" name="097.phpt"/>
|
||||
<file role="test" name="098.phpt"/>
|
||||
<file role="test" name="099.phpt"/>
|
||||
<file role="test" name="commented.rar"/>
|
||||
<file role="test" name="corrupted.rar"/>
|
||||
<file role="test" name="directories.rar"/>
|
||||
<file role="test" name="dirlink_unix.rar"/>
|
||||
<file role="test" name="dirs_and_extra_headers.rar"/>
|
||||
<file role="test" name="empty_file.rar"/>
|
||||
<file role="test" name="encrypted_headers.rar"/>
|
||||
<file role="test" name="encrypted_only_files.rar"/>
|
||||
<file role="test" name="garbage.part03.rar"/>
|
||||
<file role="test" name="latest_winrar.rar"/>
|
||||
<file role="test" name="linux_rar.rar"/>
|
||||
<file role="test" name="multi.part1.rar"/>
|
||||
<file role="test" name="multi.part2.rar"/>
|
||||
<file role="test" name="multi.part3.rar"/>
|
||||
<file role="test" name="multi_broken.part1.rar"/>
|
||||
<file role="test" name="rar_notrar.rar"/>
|
||||
<file role="test" name="rar_unicode.rar"/>
|
||||
<file role="test" name="repeated_name.rar"/>
|
||||
<file role="test" name="secret-crypted-none.rar"/>
|
||||
<file role="test" name="secret-none.rar"/>
|
||||
<file role="test" name="solid.rar"/>
|
||||
<file role="test" name="sparsefiles_rar.rar"/>
|
||||
<file role="test" name="store_method.rar"/>
|
||||
</dir> <!-- /tests -->
|
||||
<dir name="unrar">
|
||||
<file name="acknow.txt" role="doc" />
|
||||
<file name="arccmt.cpp" role="src" />
|
||||
<file name="archive.cpp" role="src" />
|
||||
<file name="archive.hpp" role="src" />
|
||||
<file name="arcread.cpp" role="src" />
|
||||
<file name="array.hpp" role="src" />
|
||||
<file name="beosea.cpp" role="src" />
|
||||
<file name="cmddata.cpp" role="src" />
|
||||
<file name="cmddata.hpp" role="src" />
|
||||
<file name="coder.cpp" role="src" />
|
||||
<file name="coder.hpp" role="src" />
|
||||
<file name="compress.hpp" role="src" />
|
||||
<file name="consio.cpp" role="src" />
|
||||
<file name="consio.hpp" role="src" />
|
||||
<file name="crc.cpp" role="src" />
|
||||
<file name="crc.hpp" role="src" />
|
||||
<file name="crypt.cpp" role="src" />
|
||||
<file name="crypt.hpp" role="src" />
|
||||
<file name="dll.cpp" role="src" />
|
||||
<file name="dll.hpp" role="src" />
|
||||
<file name="encname.cpp" role="src" />
|
||||
<file name="encname.hpp" role="src" />
|
||||
<file name="errhnd.cpp" role="src" />
|
||||
<file name="errhnd.hpp" role="src" />
|
||||
<file name="extinfo.cpp" role="src" />
|
||||
<file name="extinfo.hpp" role="src" />
|
||||
<file name="extract.cpp" role="src" />
|
||||
<file name="extract.hpp" role="src" />
|
||||
<file name="extractchunk.cpp" role="src" />
|
||||
<file name="filcreat.cpp" role="src" />
|
||||
<file name="filcreat.hpp" role="src" />
|
||||
<file name="file.cpp" role="src" />
|
||||
<file name="file.hpp" role="src" />
|
||||
<file name="filefn.cpp" role="src" />
|
||||
<file name="filefn.hpp" role="src" />
|
||||
<file name="filestr.cpp" role="src" />
|
||||
<file name="filestr.hpp" role="src" />
|
||||
<file name="find.cpp" role="src" />
|
||||
<file name="find.hpp" role="src" />
|
||||
<file name="getbits.cpp" role="src" />
|
||||
<file name="getbits.hpp" role="src" />
|
||||
<file name="global.cpp" role="src" />
|
||||
<file name="global.hpp" role="src" />
|
||||
<file name="headers.hpp" role="src" />
|
||||
<file name="isnt.cpp" role="src" />
|
||||
<file name="isnt.hpp" role="src" />
|
||||
<file name="LICENSE.txt" role="doc" />
|
||||
<file name="list.cpp" role="src" />
|
||||
<file name="list.hpp" role="src" />
|
||||
<file name="loclang.hpp" role="src" />
|
||||
<file name="log.cpp" role="src" />
|
||||
<file name="log.hpp" role="src" />
|
||||
<file name="match.cpp" role="src" />
|
||||
<file name="match.hpp" role="src" />
|
||||
<file name="model.cpp" role="src" />
|
||||
<file name="model.hpp" role="src" />
|
||||
<file name="options.cpp" role="src" />
|
||||
<file name="options.hpp" role="src" />
|
||||
<file name="os.hpp" role="src" />
|
||||
<file name="os2ea.cpp" role="src" />
|
||||
<file name="pathfn.cpp" role="src" />
|
||||
<file name="pathfn.hpp" role="src" />
|
||||
<file name="rar.cpp" role="src" />
|
||||
<file name="rar.hpp" role="src" />
|
||||
<file name="rardefs.hpp" role="src" />
|
||||
<file name="rarlang.hpp" role="src" />
|
||||
<file name="raros.hpp" role="src" />
|
||||
<file name="rartypes.hpp" role="src" />
|
||||
<file name="rarvm.cpp" role="src" />
|
||||
<file name="rarvm.hpp" role="src" />
|
||||
<file name="rarvmtbl.cpp" role="src" />
|
||||
<file name="rawread.cpp" role="src" />
|
||||
<file name="rawread.hpp" role="src" />
|
||||
<file name="rdwrfn.cpp" role="src" />
|
||||
<file name="rdwrfn.hpp" role="src" />
|
||||
<file name="README.txt" role="doc" />
|
||||
<file name="recvol.cpp" role="src" />
|
||||
<file name="recvol.hpp" role="src" />
|
||||
<file name="resource.cpp" role="src" />
|
||||
<file name="resource.hpp" role="src" />
|
||||
<file name="rijndael.cpp" role="src" />
|
||||
<file name="rijndael.hpp" role="src" />
|
||||
<file name="rs.cpp" role="src" />
|
||||
<file name="rs.hpp" role="src" />
|
||||
<file name="savepos.cpp" role="src" />
|
||||
<file name="savepos.hpp" role="src" />
|
||||
<file name="scantree.cpp" role="src" />
|
||||
<file name="scantree.hpp" role="src" />
|
||||
<file name="secpassword.cpp" role="src" />
|
||||
<file name="secpassword.hpp" role="src" />
|
||||
<file name="sha1.cpp" role="src" />
|
||||
<file name="sha1.hpp" role="src" />
|
||||
<file name="smallfn.cpp" role="src" />
|
||||
<file name="smallfn.hpp" role="src" />
|
||||
<file name="strfn.cpp" role="src" />
|
||||
<file name="strfn.hpp" role="src" />
|
||||
<file name="strlist.cpp" role="src" />
|
||||
<file name="strlist.hpp" role="src" />
|
||||
<file name="suballoc.cpp" role="src" />
|
||||
<file name="suballoc.hpp" role="src" />
|
||||
<file name="system.cpp" role="src" />
|
||||
<file name="system.hpp" role="src" />
|
||||
<file name="timefn.cpp" role="src" />
|
||||
<file name="timefn.hpp" role="src" />
|
||||
<file name="ulinks.cpp" role="src" />
|
||||
<file name="ulinks.hpp" role="src" />
|
||||
<file name="unicode.cpp" role="src" />
|
||||
<file name="unicode.hpp" role="src" />
|
||||
<file name="unios2.cpp" role="src" />
|
||||
<file name="unpack.cpp" role="src" />
|
||||
<file name="unpack.hpp" role="src" />
|
||||
<file name="unpack15.cpp" role="src" />
|
||||
<file name="unpack20.cpp" role="src" />
|
||||
<file name="uowners.cpp" role="src" />
|
||||
<file name="version.hpp" role="src" />
|
||||
<file name="volume.cpp" role="src" />
|
||||
<file name="volume.hpp" role="src" />
|
||||
<file name="win32acl.cpp" role="src" />
|
||||
<file name="win32stm.cpp" role="src" />
|
||||
</dir> <!-- /unrar -->
|
||||
<file name="config.m4" role="src" />
|
||||
<file name="config.w32" role="src" />
|
||||
<file name="CREDITS" role="doc" />
|
||||
<file name="LICENSE" role="doc" />
|
||||
<file name="README" role="doc" />
|
||||
<file name="example.php" role="doc" />
|
||||
<file name="php_rar.h" role="src" />
|
||||
<file name="rar.c" role="src" />
|
||||
<file name="rar_stream.c" role="src" />
|
||||
<file name="rararch.c" role="src" />
|
||||
<file name="rarentry.c" role="src" />
|
||||
<file name="rar_error.c" role="src" />
|
||||
<file role="src" name="rar_navigation.c"/>
|
||||
</dir> <!-- / -->
|
||||
</contents>
|
||||
|
||||
<dependencies>
|
||||
<required>
|
||||
<php>
|
||||
<min>5.2.0</min>
|
||||
</php>
|
||||
<pearinstaller>
|
||||
<min>1.4.0</min>
|
||||
</pearinstaller>
|
||||
</required>
|
||||
</dependencies>
|
||||
|
||||
<providesextension>rar</providesextension>
|
||||
|
||||
<extsrcrelease />
|
||||
|
||||
<changelog>
|
||||
<release>
|
||||
<version>
|
||||
<release>3.0.1</release>
|
||||
<api>3.0.0</api>
|
||||
</version>
|
||||
<stability>
|
||||
<release>stable</release>
|
||||
<api>stable</api>
|
||||
</stability>
|
||||
<date>2012-07-29</date>
|
||||
<notes>Changes in this version:
|
||||
- Merge changes made to unrar up to version 4.2.2.
|
||||
- Fix leak in PHP >= 5.3.11, = 5.4.0 and compile error in master.
|
||||
- Fix some tests failing if TZ != Europe/Lisbon.
|
||||
- Fix bad pointer in an error message.
|
||||
- Added test for bug #59939 (can't reproduce).
|
||||
</notes>
|
||||
</release>
|
||||
<release>
|
||||
<version>
|
||||
<release>2.0.0</release>
|
||||
<api>2.0.0</api>
|
||||
</version>
|
||||
<stability>
|
||||
<release>stable</release>
|
||||
<api>stable</api>
|
||||
</stability>
|
||||
<date>2010-04-20</date>
|
||||
<notes>Changes with respect to release 2.0.0RC1:
|
||||
- Fixed infinite loop when opening RAR archive missing a volume (later report in bug #17177).
|
||||
- Fixed bug #17025 (changed the name of method RarArchive::list into RarArchive::getEntries). If backwards compatibility with the release candidate is required, RarArchive::list can be reintroduced by defining RAR_ARCHIVE_LIST_ALIAS.
|
||||
Incompatible changes with respect to release 1.0.0:
|
||||
PHP Support:
|
||||
- Support for PHP 4.3 dropped. PHP 5.2.x or 5.3.x is required.
|
||||
API backwards incompatible changes:
|
||||
- Handles unicode filenames (uses UTF-8 external encoding). The file names inside the RAR archives are always returned in UTF-8. This will probably break your scripts.
|
||||
- Calling rar_close/RarArchive::close() invalidates RarEntry objects (actually, only extraction is forbidden, but don't rely on it).
|
||||
For the other changes, see the changelog for version 2.0.0RC1.
|
||||
</notes>
|
||||
</release>
|
||||
<release>
|
||||
<version>
|
||||
<release>2.0.0RC1</release>
|
||||
<api>2.0.0RC1</api>
|
||||
</version>
|
||||
<stability>
|
||||
<release>beta</release>
|
||||
<api>beta</api>
|
||||
</stability>
|
||||
<date>2010-01-17</date>
|
||||
<license>PHP License and UnRar license</license>
|
||||
<notes>Changes in respect to release 1.0.0:
|
||||
PHP SUPPORT:
|
||||
- Support for PHP 4.3 dropped. PHP 5.2.x or 5.3.x is required.
|
||||
API BACKWARDS INCOMPATIBLE CHANGES:
|
||||
- Handles unicode filenames (uses UTF-8 external encoding). The file names inside the RAR archives are always returned in UTF-8. This will probably break your scripts.
|
||||
- Calling rar_close/RarArchive::close() invalidates RarEntry objects (actually, only extraction is forbidden, but don't rely on it).
|
||||
API backwards compatible changes:
|
||||
- Supports streaming from RAR archives. See RarEntry::getStream() method.
|
||||
- Added a bunch of constants to RarEntry.
|
||||
- Added RarEntry::__toString() method.
|
||||
- Added RarEntry::isDirectory() method.
|
||||
- Added RarEntry::isEncrypted() method.
|
||||
- Added OOP interface for rar_* functions with the RarArchive class.
|
||||
- Added rar_comment_get/RarArchive::getComment().
|
||||
- Added RarArchive::isSolid()/rar_solid_is().
|
||||
- Added RarArchive::__toString() method.
|
||||
- Added RarException class.
|
||||
- Exception throwing for expectable errors can be turned on by calling RarException::setUsingExceptions(). To check whether exception throwing is turned on, RarException::isUsingExceptions() can be used.
|
||||
Bug fixes:
|
||||
- Fixed by PECL bug #8821 (relative paths not working).
|
||||
- Fixed PECL bug #9470 (wrong CRC on multi-volume archives).
|
||||
- Fixed PECL bug #9649 (rar_close() not closing file descriptors if there were undestroyed RarEntry objects)
|
||||
- Fixed volumes opened with middle volumes showing files continued from previous volume with incorrect packed and unpacked sizes.
|
||||
- Fixed bug in UnRAR library that could cause a read out of buffer bounds on some corrupted RAR files.
|
||||
- Fixed RarEntry::getPackedSize() and RarEntry::getUnpackedSize() giving incorrect results for files > 2 GiB. Still, on platforms with 32-bit integers, MAX_INT will be returned for such files, othwerwise the correct value is given.
|
||||
Other changes:
|
||||
- Updated bundled UnRAR library to version 3.9.7 (RAR 3.9.1).
|
||||
- Changed bundled UnRAR library to allow partial file extraction.
|
||||
- All RarEntry properties are now private. This doesn't break the API because those properties were never part of the contract.
|
||||
- rar_open gives more detailed error messages on failure.
|
||||
- Extension now uses extended UnRAR library structures.
|
||||
- Added arginfo.
|
||||
- Added a bunch of tests.
|
||||
- A lot of refactoring and compilation as C, not C++.
|
||||
</notes>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<version>
|
||||
<release>1.0.0</release>
|
||||
<api>1.0.0</api>
|
||||
</version>
|
||||
<stability>
|
||||
<release>stable</release>
|
||||
<api>stable</api>
|
||||
</stability>
|
||||
<date>2008-02-26</date>
|
||||
<license uri="http://www.php.net/license">PHP License</license>
|
||||
<notes>- Upgraded bundled UnRar to version 3.7.8.
|
||||
- Updated source code to use new parameter parsing API.
|
||||
- Fixed PECL bug #9002 (rar_list invalidates rar resource)
|
||||
- Fixed PECL bug #11430 (rar_extract() doesn't close handles gracefully)
|
||||
- rar_open() now throws an error when failed to open the specified file.
|
||||
</notes>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<version>
|
||||
<release>0.3.1</release>
|
||||
<api>0.3.1</api>
|
||||
</version>
|
||||
<stability>
|
||||
<release>beta</release>
|
||||
<api>beta</api>
|
||||
</stability>
|
||||
<date>2006-08-28</date>
|
||||
<license uri="http://www.php.net/license">PHP License</license>
|
||||
<notes>- Updated bundled unrar to version 3.6.8.
|
||||
- Fixed PHP4 compatibility.
|
||||
</notes>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<version>
|
||||
<release>0.3.0</release>
|
||||
<api>0.3.0</api>
|
||||
</version>
|
||||
<stability>
|
||||
<release>beta</release>
|
||||
<api>beta</api>
|
||||
</stability>
|
||||
<date>2006-06-06</date>
|
||||
<license uri="http://www.php.net/license">PHP License</license>
|
||||
<notes>- Updated bundled unrar to version 3.6.2 (fixes compile errors with GCC4).
|
||||
- Several minor fixes.
|
||||
</notes>
|
||||
</release>
|
||||
<release>
|
||||
<version>
|
||||
<release>0.2</release>
|
||||
<api>0.2</api>
|
||||
</version>
|
||||
<stability>
|
||||
<release>beta</release>
|
||||
<api>beta</api>
|
||||
</stability>
|
||||
<date>2004-12-02</date>
|
||||
<license uri="http://www.php.net/license">PHP License</license>
|
||||
<notes>1) Added open_basedir and safe_mode checks.
|
||||
2) Fixed Win32 build issues (thanks to Edin).
|
||||
Currently only 5.x builds are available.
|
||||
3) Added OS constants.
|
||||
4) Fixed 0 bugs. There are no bugs, wee =)
|
||||
</notes>
|
||||
</release>
|
||||
<release>
|
||||
<version>
|
||||
<release>0.1</release>
|
||||
<api>0.1</api>
|
||||
</version>
|
||||
<stability>
|
||||
<release>alpha</release>
|
||||
<api>alpha</api>
|
||||
</stability>
|
||||
<date>2004-06-11</date>
|
||||
<license uri="http://www.php.net/license">PHP License</license>
|
||||
<notes>1) Initial release
|
||||
</notes>
|
||||
</release>
|
||||
</changelog>
|
||||
</package>
|
||||
<!--
|
||||
vim:et:ts=1:sw=1
|
||||
-->
|
||||
303
php_rar.h
Normal file
303
php_rar.h
Normal file
@@ -0,0 +1,303 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2004 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.0 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.php.net/license/3_0.txt. |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
| |
|
||||
| **** WARNING **** |
|
||||
| |
|
||||
| This module makes use of unRAR - free utility for RAR archives. |
|
||||
| Its license states, that you MUST NOT use its code to develop |
|
||||
| a RAR (WinRAR) compatible archiver. |
|
||||
| Please, read unRAR license for full information. |
|
||||
| unRAR & RAR copyrights are owned by Eugene Roshal |
|
||||
+----------------------------------------------------------------------+
|
||||
| Author: Antony Dovgal <tony@daylessday.org> |
|
||||
| Author: Gustavo Lopes <cataphract@php.net> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
/* TODO: metadata block reading */
|
||||
/* TODO: correct support for symlinks inside RAR files. This includes:
|
||||
* - Respecting PHP_STREAM_URL_STAT_LINK in the url_stater
|
||||
* - Following the symlinks when asked to open one inside the RAR
|
||||
* Sym link support on windows will be more complicated */
|
||||
/* TODO: add support for opening RAR files in a persisten fashion */
|
||||
/* TODO: consider making struct rar opaque, outside rararch.c only
|
||||
* RarEntry::extract/getStream access the fields */
|
||||
/* TODO: consider using a php memory/tmpfile stream to serve as buffer for
|
||||
* rar file streams */
|
||||
/* TODO: improve RAR archive cache key for url_stater/dir_opener, so that it
|
||||
* can detect file modification */
|
||||
/* TODO: make configurable the capacity of the url_stater/dir_opener cache */
|
||||
/* TODO: optimize _rar_nav_directory_match with the depth */
|
||||
/* TODO: tests with truncated RAR archive (for which _rar_list_files fails) */
|
||||
|
||||
#ifndef PHP_RAR_H
|
||||
#define PHP_RAR_H
|
||||
|
||||
extern zend_module_entry rar_module_entry;
|
||||
#define phpext_rar_ptr &rar_module_entry
|
||||
|
||||
#define PHP_RAR_VERSION "4.0.0"
|
||||
|
||||
#ifdef PHP_WIN32
|
||||
#define PHP_RAR_API __declspec(dllexport)
|
||||
#else
|
||||
#define PHP_RAR_API
|
||||
#endif
|
||||
|
||||
#ifdef ZTS
|
||||
#include "TSRM.h"
|
||||
#endif
|
||||
|
||||
/* causes linking errors (multiple definitions) in functions
|
||||
that were requested inlining but were not inlined by the compiler */
|
||||
/* #include "unrar/rar.hpp */
|
||||
/* only these includes are necessary anyway: */
|
||||
#include "unrar/raros.hpp"
|
||||
#include "unrar/rartypes.hpp"
|
||||
/* no need to reinclude windows.h or new.h */
|
||||
#define LEAN_RAR_INCLUDES
|
||||
#include "unrar/os.hpp"
|
||||
#include "unrar/dll.hpp"
|
||||
#include "unrar/version.hpp"
|
||||
/* These are in unrar/headers.hpp, but that header depends on several other */
|
||||
enum HOST_SYSTEM {
|
||||
HOST_MSDOS=0,HOST_OS2=1,HOST_WIN32=2,HOST_UNIX=3,HOST_MACOS=4,
|
||||
HOST_BEOS=5,HOST_MAX
|
||||
};
|
||||
|
||||
/* maximum comment size if 64KB */
|
||||
#define RAR_MAX_COMMENT_SIZE 65536
|
||||
|
||||
typedef struct _rar_cb_user_data {
|
||||
char *password; /* can be NULL */
|
||||
zval *callable; /* can be NULL */
|
||||
} rar_cb_user_data;
|
||||
|
||||
typedef struct rar {
|
||||
zend_object_handle id;
|
||||
struct _rar_entries *entries;
|
||||
struct RAROpenArchiveDataEx *list_open_data;
|
||||
struct RAROpenArchiveDataEx *extract_open_data;
|
||||
/* archive handle opened with RAR_OM_LIST_INCSPLIT open mode */
|
||||
void *arch_handle;
|
||||
/* user data to pass the RAR callback */
|
||||
rar_cb_user_data cb_userdata;
|
||||
int allow_broken;
|
||||
} rar_file_t;
|
||||
|
||||
/* Misc */
|
||||
#ifdef ZTS
|
||||
# define RAR_TSRMLS_TC , void ***
|
||||
#else
|
||||
# define RAR_TSRMLS_TC
|
||||
#endif
|
||||
|
||||
#define RAR_RETNULL_ON_ARGS() \
|
||||
if (zend_parse_parameters_none() == FAILURE) { \
|
||||
RETURN_NULL(); \
|
||||
}
|
||||
|
||||
/* Per-request cache or make last the duration of the PHP lifespan?
|
||||
* - per-request advantages: we can re-use rar_open and store close RarArchive
|
||||
* objects. We store either pointers to the objects directly and manipulate
|
||||
* the refcount in the store or we store zvals. Either way, we must decrement
|
||||
* the refcounts on request shutdown. Also, the memory usage is best kept
|
||||
* in check because the memory is freed after each request.
|
||||
* - per PHP lifespan advantages: more cache hits. We can also re-use rar_open,
|
||||
* but then we have to copy rar->entries and rar->entries_idx into
|
||||
* persistently allocated buffers since the RarArchive objects cannot be made
|
||||
* persistent themselves.
|
||||
*
|
||||
* I'll go with per-request and store zval pointers with a cache key that
|
||||
* considers filename, modificaion time and stream context (currently only
|
||||
* filename).
|
||||
* I'll also go with a FIFO eviction policy because it's simpler to implement
|
||||
* (just delete the first element of the HashTable).
|
||||
*/
|
||||
typedef struct _rar_contents_cache {
|
||||
int max_size;
|
||||
HashTable *data; /* persistent HashTable, will hold rar_cache_entry */
|
||||
int hits;
|
||||
int misses;
|
||||
/* args: cache key, cache key size, cached object) */
|
||||
void (*put)(const char *, uint, zval * RAR_TSRMLS_TC);
|
||||
zval *(*get)(const char *, uint RAR_TSRMLS_TC);
|
||||
} rar_contents_cache;
|
||||
|
||||
/* Module globals, currently used for dir wrappers cache */
|
||||
ZEND_BEGIN_MODULE_GLOBALS(rar)
|
||||
rar_contents_cache contents_cache;
|
||||
ZEND_END_MODULE_GLOBALS(rar)
|
||||
|
||||
ZEND_EXTERN_MODULE_GLOBALS(rar);
|
||||
|
||||
#ifdef ZTS
|
||||
# define RAR_G(v) TSRMG(rar_globals_id, zend_rar_globals *, v)
|
||||
#else
|
||||
# define RAR_G(v) (rar_globals.v)
|
||||
#endif
|
||||
|
||||
/* PHP 5.2 compatibility */
|
||||
#if PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION < 3
|
||||
#define zend_parse_parameters_none() \
|
||||
zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "")
|
||||
#define Z_DELREF_P ZVAL_DELREF
|
||||
# define STREAM_ASSUME_REALPATH 0
|
||||
# define ALLOC_PERMANENT_ZVAL(z) \
|
||||
(z) = (zval*) malloc(sizeof(zval));
|
||||
# define OPENBASEDIR_CHECKPATH(filename) \
|
||||
(PG(safe_mode) && \
|
||||
(!php_checkuid(filename, NULL, CHECKUID_CHECK_FILE_AND_DIR))) \
|
||||
|| php_check_open_basedir(filename TSRMLS_CC)
|
||||
# undef ZEND_BEGIN_ARG_INFO_EX
|
||||
# define ZEND_BEGIN_ARG_INFO_EX(name, pass_rest_by_reference, return_reference, required_num_args) \
|
||||
static const zend_arg_info name[] = { \
|
||||
{ NULL, 0, NULL, 0, 0, 0, pass_rest_by_reference, return_reference, required_num_args },
|
||||
#endif
|
||||
|
||||
/* Other compatibility quirks */
|
||||
#if !defined(HAVE_STRNLEN) || !HAVE_STRNLEN
|
||||
size_t _rar_strnlen(const char *s, size_t maxlen);
|
||||
# define strnlen _rar_strnlen
|
||||
#else
|
||||
# define _rar_strnlen strnlen
|
||||
#endif
|
||||
|
||||
/* rar.c */
|
||||
PHP_MINIT_FUNCTION(rar);
|
||||
PHP_MSHUTDOWN_FUNCTION(rar);
|
||||
PHP_RINIT_FUNCTION(rar);
|
||||
PHP_RSHUTDOWN_FUNCTION(rar);
|
||||
PHP_MINFO_FUNCTION(rar);
|
||||
|
||||
PHP_FUNCTION(rar_bogus_ctor);
|
||||
|
||||
void _rar_wide_to_utf(const wchar_t *src, char *dest, size_t dest_size);
|
||||
void _rar_utf_to_wide(const char *src, wchar_t *dest, size_t dest_size);
|
||||
void _rar_destroy_userdata(rar_cb_user_data *udata);
|
||||
int _rar_find_file(struct RAROpenArchiveDataEx *open_data, /* IN */
|
||||
const char *const utf_file_name, /* IN */
|
||||
rar_cb_user_data *cb_udata, /* IN, must be managed outside */
|
||||
void **arc_handle, /* OUT: where to store rar archive handle */
|
||||
int *found, /* OUT */
|
||||
struct RARHeaderDataEx *header_data /* OUT, can be null */
|
||||
);
|
||||
int _rar_find_file_w(struct RAROpenArchiveDataEx *open_data, /* IN */
|
||||
const wchar_t *const file_name, /* IN */
|
||||
rar_cb_user_data *cb_udata, /* IN, must be managed outside */
|
||||
void **arc_handle, /* OUT: where to store rar archive handle */
|
||||
int *found, /* OUT */
|
||||
struct RARHeaderDataEx *header_data /* OUT, can be null */
|
||||
);
|
||||
int _rar_find_file_p(struct RAROpenArchiveDataEx *open_data, /* IN */
|
||||
size_t position, /* IN */
|
||||
rar_cb_user_data *cb_udata, /* IN, must be managed outside */
|
||||
void **arc_handle, /* OUT: where to store rar archive handle */
|
||||
int *found, /* OUT */
|
||||
struct RARHeaderDataEx *header_data /* OUT, can be null */
|
||||
);
|
||||
int CALLBACK _rar_unrar_callback(UINT msg, LPARAM UserData, LPARAM P1, LPARAM P2);
|
||||
|
||||
/* rar_error.c */
|
||||
extern zend_class_entry *rarexception_ce_ptr;
|
||||
int _rar_handle_error(int errcode TSRMLS_DC);
|
||||
int _rar_handle_error_ex(const char *preamble, int errcode TSRMLS_DC);
|
||||
void _rar_handle_ext_error(const char *format TSRMLS_DC, ...);
|
||||
int _rar_using_exceptions(TSRMLS_D);
|
||||
const char * _rar_error_to_string(int errcode);
|
||||
void minit_rarerror(TSRMLS_D);
|
||||
|
||||
/* rar_navigation.c */
|
||||
|
||||
int _rar_list_files(rar_file_t *rar TSRMLS_DC);
|
||||
void _rar_delete_entries(rar_file_t *rar TSRMLS_DC);
|
||||
size_t _rar_entry_count(rar_file_t *rar);
|
||||
|
||||
/* entry search API {{{ */
|
||||
typedef struct _rar_find_output {
|
||||
int found;
|
||||
size_t position;
|
||||
struct RARHeaderDataEx * header;
|
||||
unsigned long packed_size;
|
||||
int eof;
|
||||
} rar_find_output;
|
||||
#define RAR_SEARCH_INDEX 0x01U
|
||||
#define RAR_SEARCH_TRAVERSE 0x01U
|
||||
#define RAR_SEARCH_DIRECTORY 0x02U
|
||||
#define RAR_SEARCH_NAME 0x02U
|
||||
void _rar_entry_search_start(rar_file_t *rar,
|
||||
unsigned mode,
|
||||
rar_find_output **state TSRMLS_DC);
|
||||
void _rar_entry_search_end(rar_find_output *state);
|
||||
void _rar_entry_search_seek(rar_find_output *state, size_t pos);
|
||||
void _rar_entry_search_rewind(rar_find_output *state);
|
||||
void _rar_entry_search_advance(rar_find_output *state,
|
||||
const wchar_t * const file, /* NULL = give next */
|
||||
size_t file_size, /* length + 1 */
|
||||
int directory_match);
|
||||
/* end entry search API }}} */
|
||||
|
||||
/* rararch.c */
|
||||
int _rar_create_rararch_obj(const char* resolved_path,
|
||||
const char* open_password,
|
||||
zval *volume_callback, /* must be callable or NULL */
|
||||
zval *object,
|
||||
int *err_code TSRMLS_DC);
|
||||
void _rar_close_file_resource(rar_file_t *rar);
|
||||
|
||||
/* Fetches the rar_file_t part of the RarArchive object in order to use the
|
||||
* operations above and (discouraged) to have direct access to the fields
|
||||
* RarEntry::extract/getStream access extract_open_dat and cb_userdata */
|
||||
int _rar_get_file_resource(zval *zval_file, rar_file_t **rar_file TSRMLS_DC);
|
||||
int _rar_get_file_resource_ex(zval *zval_file, rar_file_t **rar_file, int silent TSRMLS_DC);
|
||||
void minit_rararch(TSRMLS_D);
|
||||
|
||||
PHP_FUNCTION(rar_open);
|
||||
PHP_FUNCTION(rar_list);
|
||||
PHP_FUNCTION(rar_entry_get);
|
||||
PHP_FUNCTION(rar_solid_is);
|
||||
PHP_FUNCTION(rar_comment_get);
|
||||
PHP_FUNCTION(rar_broken_is);
|
||||
PHP_FUNCTION(rar_allow_broken_set);
|
||||
PHP_FUNCTION(rar_close);
|
||||
|
||||
/* rarentry.c */
|
||||
extern zend_class_entry *rar_class_entry_ptr;
|
||||
void minit_rarentry(TSRMLS_D);
|
||||
void _rar_entry_to_zval(zval *parent,
|
||||
struct RARHeaderDataEx *entry,
|
||||
unsigned long packed_size,
|
||||
size_t index,
|
||||
zval *entry_object TSRMLS_DC);
|
||||
|
||||
/* rar_stream.c */
|
||||
php_stream *php_stream_rar_open(char *arc_name,
|
||||
size_t position,
|
||||
rar_cb_user_data *cb_udata_ptr /* will be copied */
|
||||
STREAMS_DC TSRMLS_DC);
|
||||
extern php_stream_wrapper php_stream_rar_wrapper;
|
||||
|
||||
#endif /* PHP_RAR_H */
|
||||
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* tab-width: 4
|
||||
* c-basic-offset: 4
|
||||
* End:
|
||||
* vim600: noet sw=4 ts=4 fdm=marker
|
||||
* vim<600: noet sw=4 ts=4
|
||||
*/
|
||||
790
rar.c
Normal file
790
rar.c
Normal file
@@ -0,0 +1,790 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2009 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.0 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.php.net/license/3_0.txt. |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
| |
|
||||
| **** WARNING **** |
|
||||
| |
|
||||
| This module makes use of unRAR - free utility for RAR archives. |
|
||||
| Its license states that you MUST NOT use its code to develop |
|
||||
| a RAR (WinRAR) compatible archiver. |
|
||||
| Please, read unRAR license for full information. |
|
||||
| unRAR & RAR copyrights are owned by Eugene Roshal |
|
||||
+----------------------------------------------------------------------+
|
||||
| Author: Antony Dovgal <tony@daylessday.org> |
|
||||
| Author: Gustavo Lopes <cataphract@php.net> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <string.h>
|
||||
|
||||
#ifdef PHP_WIN32
|
||||
# include <math.h>
|
||||
#endif
|
||||
|
||||
#include <wchar.h>
|
||||
|
||||
#include <php.h>
|
||||
#include <php_ini.h>
|
||||
#include <zend_exceptions.h>
|
||||
#include <ext/standard/info.h>
|
||||
#include <ext/spl/spl_exceptions.h>
|
||||
|
||||
#if HAVE_RAR
|
||||
|
||||
#include "php_rar.h"
|
||||
|
||||
/* {{{ Function prototypes for functions with internal linkage */
|
||||
static void _rar_fix_wide(wchar_t *str, size_t max_size);
|
||||
static int _rar_unrar_volume_user_callback(char* dst_buffer,
|
||||
zend_fcall_info *fci,
|
||||
zend_fcall_info_cache *cache
|
||||
TSRMLS_DC);
|
||||
static int _rar_make_userdata_fcall(zval *callable,
|
||||
zend_fcall_info *fci,
|
||||
zend_fcall_info_cache *cache TSRMLS_DC);
|
||||
/* }}} */
|
||||
|
||||
/* {{{ Functions with external linkage */
|
||||
#if !defined(HAVE_STRNLEN) || !HAVE_STRNLEN
|
||||
size_t _rar_strnlen(const char *s, size_t maxlen) /* {{{ */
|
||||
{
|
||||
char *r = memchr(s, '\0', maxlen);
|
||||
return r ? r-s : maxlen;
|
||||
}
|
||||
/* }}} */
|
||||
#endif
|
||||
|
||||
/* From unicode.cpp
|
||||
* I can't use that one directy because it takes a const wchar, not wchar_t.
|
||||
* And I shouldn't because it's not a public API.
|
||||
*/
|
||||
void _rar_wide_to_utf(const wchar_t *src, char *dest, size_t dest_size) /* {{{ */
|
||||
{
|
||||
long dsize= (long) dest_size;
|
||||
dsize--;
|
||||
while (*src != 0 && --dsize >= 0) {
|
||||
uint c =*(src++);
|
||||
if (c < 0x80)
|
||||
*(dest++) = (char) c;
|
||||
else if (c < 0x800 && --dsize >= 0) {
|
||||
*(dest++) = (char) (0xc0 | (c >> 6));
|
||||
*(dest++) = (0x80 | (c & 0x3f));
|
||||
}
|
||||
else if (c < 0x10000 && (dsize -= 2) >= 0) {
|
||||
*(dest++) = (char) (0xe0 | (c >> 12));
|
||||
*(dest++) = (0x80 | ((c >> 6) & 0x3f));
|
||||
*(dest++) = (0x80 | (c & 0x3f));
|
||||
}
|
||||
else if (c < 0x200000 && (dsize -= 3) >= 0) {
|
||||
*(dest++) = (char) (0xf0 | (c >> 18));
|
||||
*(dest++) = (0x80 | ((c >> 12) & 0x3f));
|
||||
*(dest++) = (0x80 | ((c >> 6) & 0x3f));
|
||||
*(dest++) = (0x80 | (c & 0x3f));
|
||||
}
|
||||
}
|
||||
*dest = 0;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* idem */
|
||||
void _rar_utf_to_wide(const char *src, wchar_t *dest, size_t dest_size) /* {{{ */
|
||||
{
|
||||
long dsize = (long) dest_size;
|
||||
dsize--;
|
||||
while (*src != 0) {
|
||||
uint c = (unsigned char) *(src++),
|
||||
d;
|
||||
if (c < 0x80)
|
||||
d = c;
|
||||
else if ((c >> 5) == 6) {
|
||||
if ((*src & 0xc0) != 0x80)
|
||||
break;
|
||||
d=((c & 0x1f) << 6)|(*src & 0x3f);
|
||||
src++;
|
||||
}
|
||||
else if ((c>>4)==14) {
|
||||
if ((src[0] & 0xc0) != 0x80 || (src[1] & 0xc0) != 0x80)
|
||||
break;
|
||||
d = ((c & 0xf) << 12) | ((src[0] & 0x3f) << 6) | (src[1] & 0x3f);
|
||||
src += 2;
|
||||
}
|
||||
else if ((c>>3)==30) {
|
||||
if ((src[0] & 0xc0) != 0x80 || (src[1] & 0xc0) != 0x80 || (src[2] & 0xc0) != 0x80)
|
||||
break;
|
||||
d = ((c & 7) << 18) | ((src[0] & 0x3f) << 12) | ((src[1] & 0x3f) << 6) | (src[2] & 0x3f);
|
||||
src += 3;
|
||||
}
|
||||
else
|
||||
break;
|
||||
if (--dsize < 0)
|
||||
break;
|
||||
if (d > 0xffff) {
|
||||
if (--dsize < 0 || d > 0x10ffff)
|
||||
break;
|
||||
*(dest++) = (wchar_t) (((d - 0x10000) >> 10) + 0xd800);
|
||||
*(dest++) = (d & 0x3ff) + 0xdc00;
|
||||
}
|
||||
else
|
||||
*(dest++) = (wchar_t) d;
|
||||
}
|
||||
*dest = 0;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
void _rar_destroy_userdata(rar_cb_user_data *udata) /* {{{ */
|
||||
{
|
||||
assert(udata != NULL);
|
||||
|
||||
if (udata->password != NULL) {
|
||||
efree(udata->password);
|
||||
}
|
||||
|
||||
if (udata->callable != NULL)
|
||||
zval_ptr_dtor(&udata->callable);
|
||||
|
||||
udata->password = NULL;
|
||||
udata->callable = NULL;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
int _rar_find_file(struct RAROpenArchiveDataEx *open_data, /* IN */
|
||||
const char *const utf_file_name, /* IN */
|
||||
rar_cb_user_data *cb_udata, /* IN, must be managed outside */
|
||||
void **arc_handle, /* OUT: where to store rar archive handle */
|
||||
int *found, /* OUT */
|
||||
struct RARHeaderDataEx *header_data /* OUT, can be null */
|
||||
) /* {{{ */
|
||||
{
|
||||
wchar_t *file_name = NULL;
|
||||
size_t utf_file_name_len = strlen(utf_file_name);
|
||||
int ret;
|
||||
|
||||
file_name = ecalloc(utf_file_name_len + 1, sizeof *file_name);
|
||||
_rar_utf_to_wide(utf_file_name, file_name, utf_file_name_len + 1);
|
||||
ret = _rar_find_file_w(open_data, file_name, cb_udata, arc_handle, found,
|
||||
header_data);
|
||||
efree(file_name);
|
||||
return ret;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* WARNING: It's the caller who must close the archive and manage the lifecycle
|
||||
of cb_udata (must be valid while the archive is opened). */
|
||||
/*
|
||||
* This function opens a RAR file and looks for the file with the
|
||||
* name utf_file_name.
|
||||
* If the operation is sucessful, arc_handle is populated with the RAR file
|
||||
* handle, found is set to TRUE if the file is found and FALSE if it is not
|
||||
* found; additionaly, the optional header_data is populated with the first
|
||||
* header that corresponds to the request file. If the file is not found and
|
||||
* header_data is specified, its values are undefined.
|
||||
* Note that even when the file is not found, the caller must still close
|
||||
* the archive.
|
||||
*/
|
||||
int _rar_find_file_w(struct RAROpenArchiveDataEx *open_data, /* IN */
|
||||
const wchar_t *const file_name, /* IN */
|
||||
rar_cb_user_data *cb_udata, /* IN, must be managed outside */
|
||||
void **arc_handle, /* OUT: where to store rar archive handle */
|
||||
int *found, /* OUT */
|
||||
struct RARHeaderDataEx *header_data /* OUT, can be null */
|
||||
) /* {{{ */
|
||||
{
|
||||
int result,
|
||||
process_result;
|
||||
struct RARHeaderDataEx *used_header_data;
|
||||
int retval = 0; /* success in rar parlance */
|
||||
|
||||
assert(open_data != NULL);
|
||||
assert(file_name != NULL);
|
||||
assert(arc_handle != NULL);
|
||||
assert(found != NULL);
|
||||
*found = FALSE;
|
||||
*arc_handle = NULL;
|
||||
used_header_data = header_data != NULL ?
|
||||
header_data :
|
||||
ecalloc(1, sizeof *used_header_data);
|
||||
|
||||
*arc_handle = RAROpenArchiveEx(open_data);
|
||||
if (*arc_handle == NULL) {
|
||||
retval = open_data->OpenResult;
|
||||
goto cleanup;
|
||||
}
|
||||
RARSetCallback(*arc_handle, _rar_unrar_callback, (LPARAM) cb_udata);
|
||||
|
||||
while ((result = RARReadHeaderEx(*arc_handle, used_header_data)) == 0) {
|
||||
#if WCHAR_MAX > 0xffff
|
||||
_rar_fix_wide(used_header_data->FileNameW, NM);
|
||||
#endif
|
||||
|
||||
if (wcsncmp(used_header_data->FileNameW, file_name, NM) == 0) {
|
||||
*found = TRUE;
|
||||
goto cleanup;
|
||||
} else {
|
||||
process_result = RARProcessFile(*arc_handle, RAR_SKIP, NULL, NULL);
|
||||
}
|
||||
if (process_result != 0) {
|
||||
retval = process_result;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
if (result != 0 && result != 1) {
|
||||
/* 0 indicates success, 1 indicates normal end of file */
|
||||
retval = result;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
if (header_data == NULL)
|
||||
efree(used_header_data);
|
||||
|
||||
return retval;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
int _rar_find_file_p(struct RAROpenArchiveDataEx *open_data, /* IN */
|
||||
size_t position, /* IN */
|
||||
rar_cb_user_data *cb_udata, /* IN, must be managed outside */
|
||||
void **arc_handle, /* OUT: where to store rar archive handle */
|
||||
int *found, /* OUT */
|
||||
struct RARHeaderDataEx *header_data /* OUT, can be null */
|
||||
) /* {{{ */
|
||||
{
|
||||
int result,
|
||||
process_result;
|
||||
struct RARHeaderDataEx *used_header_data;
|
||||
int retval = 0; /* success in rar parlance */
|
||||
size_t curpos = 0;
|
||||
|
||||
assert(open_data != NULL);
|
||||
assert(arc_handle != NULL);
|
||||
assert(found != NULL);
|
||||
*found = FALSE;
|
||||
*arc_handle = NULL;
|
||||
used_header_data = header_data != NULL ?
|
||||
header_data :
|
||||
ecalloc(1, sizeof *used_header_data);
|
||||
|
||||
*arc_handle = RAROpenArchiveEx(open_data);
|
||||
if (*arc_handle == NULL) {
|
||||
retval = open_data->OpenResult;
|
||||
goto cleanup;
|
||||
}
|
||||
RARSetCallback(*arc_handle, _rar_unrar_callback, (LPARAM) cb_udata);
|
||||
|
||||
while ((result = RARReadHeaderEx(*arc_handle, used_header_data)) == 0) {
|
||||
/* skip entries that were split before with incrementing current pos */
|
||||
if ((used_header_data->Flags & RHDF_SPLITBEFORE) ||
|
||||
(curpos++ != position)) {
|
||||
process_result = RARProcessFile(*arc_handle, RAR_SKIP, NULL, NULL);
|
||||
} else {
|
||||
*found = TRUE;
|
||||
goto cleanup;
|
||||
}
|
||||
if (process_result != 0) {
|
||||
retval = process_result;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
if (result != 0 && result != 1) {
|
||||
/* 0 indicates success, 1 indicates normal end of file */
|
||||
retval = result;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
if (header_data == NULL)
|
||||
efree(used_header_data);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* An unRAR callback.
|
||||
* Processes requests for passwords and missing volumes
|
||||
* If there is (userland) volume find callback specified, try to use that
|
||||
* callback to retrieve the name of the missing volume. Otherwise, or if
|
||||
* the volume find callback returns null, cancel the operation. */
|
||||
int CALLBACK _rar_unrar_callback(UINT msg, LPARAM UserData, LPARAM P1, LPARAM P2) /* {{{ */
|
||||
{
|
||||
rar_cb_user_data *userdata = (rar_cb_user_data*) UserData;
|
||||
TSRMLS_FETCH();
|
||||
|
||||
if (msg == UCM_NEEDPASSWORD) {
|
||||
/* user data is the password or null if none */
|
||||
char *password = userdata->password;
|
||||
|
||||
if (password == NULL || password[0] == '\0') {
|
||||
/*php_error_docref(NULL TSRMLS_CC, E_WARNING,
|
||||
"Password needed, but it has not been specified");*/
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
strncpy((char *) P1, password, (size_t) P2);
|
||||
assert((size_t) P2 > 0);
|
||||
((char *) P1)[(size_t) P2 - 1] = '\0';
|
||||
}
|
||||
}
|
||||
else if (msg == UCM_CHANGEVOLUME) {
|
||||
if (((int) P2) == RAR_VOL_ASK) {
|
||||
int ret, called_cb = 0;
|
||||
if (userdata->callable == NULL) {
|
||||
/* if there's no callback, abort */
|
||||
ret = -1;
|
||||
}
|
||||
else {
|
||||
zend_fcall_info fci;
|
||||
zend_fcall_info_cache cache;
|
||||
/* make_userdata_fcall and volume_user_callback are chatty */
|
||||
if (_rar_make_userdata_fcall(userdata->callable, &fci, &cache
|
||||
TSRMLS_CC) == SUCCESS) {
|
||||
ret = _rar_unrar_volume_user_callback(
|
||||
(char*) P1, &fci, &cache TSRMLS_CC);
|
||||
called_cb = 1;
|
||||
}
|
||||
else {
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* always a warning, never an exception here */
|
||||
if (ret == -1 && !called_cb)
|
||||
php_error_docref(NULL TSRMLS_CC, E_WARNING,
|
||||
"Volume %s was not found", (char*) P1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
PHP_FUNCTION(rar_bogus_ctor) /* {{{ */
|
||||
{
|
||||
/* This exception should not be thrown. The point is to add this as
|
||||
* a class constructor and make it private. This code would be able to
|
||||
* run only if the constructor were made public */
|
||||
zend_throw_exception(NULL,
|
||||
"An object of this type cannot be created with the new operator.",
|
||||
0 TSRMLS_CC);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
PHP_FUNCTION(rar_wrapper_cache_stats) /* {{{ */
|
||||
{
|
||||
char *result = NULL;
|
||||
int len;
|
||||
|
||||
if (zend_parse_parameters_none() == FAILURE)
|
||||
return;
|
||||
|
||||
len = spprintf(&result, 0, "%u/%u (hits/misses)",
|
||||
RAR_G(contents_cache).hits, RAR_G(contents_cache).misses);
|
||||
|
||||
RETURN_STRINGL(result, len, 0);
|
||||
}
|
||||
/* }}} */
|
||||
/* }}} */
|
||||
|
||||
/* {{{ Functions with internal linkage */
|
||||
/*
|
||||
* Only relevant when sizeof(wchar_t) > 2 (so not windows).
|
||||
* Removes the characters use value if > 0x10ffff; these are not
|
||||
* valid UTF characters.
|
||||
*/
|
||||
|
||||
static void _rar_fix_wide(wchar_t *str, size_t max_size) /* {{{ */
|
||||
{
|
||||
wchar_t *write,
|
||||
*read,
|
||||
*max_fin;
|
||||
max_fin = str + max_size;
|
||||
for (write = str, read = str; *read != L'\0' && read != max_fin; read++) {
|
||||
if ((unsigned) *read <= 0x10ffff)
|
||||
*(write++) = *read;
|
||||
}
|
||||
*write = L'\0';
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* called from the RAR callback; calls a user callback in case a volume was
|
||||
* not found
|
||||
* This function sends messages instead of calling _rar_handle_ext_error
|
||||
* because, in case we're using exceptions, we want to let an exception with
|
||||
* error code ERAR_EOPEN to be thrown.
|
||||
*/
|
||||
static int _rar_unrar_volume_user_callback(char* dst_buffer,
|
||||
zend_fcall_info *fci,
|
||||
zend_fcall_info_cache *cache
|
||||
TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
zval *failed_vol,
|
||||
*retval_ptr = NULL,
|
||||
**params;
|
||||
int ret = -1;
|
||||
|
||||
MAKE_STD_ZVAL(failed_vol);
|
||||
ZVAL_STRING(failed_vol, dst_buffer, 1);
|
||||
params = &failed_vol;
|
||||
fci->retval_ptr_ptr = &retval_ptr;
|
||||
fci->params = ¶ms;
|
||||
fci->param_count = 1;
|
||||
|
||||
if (zend_call_function(fci, cache TSRMLS_CC) != SUCCESS ||
|
||||
fci->retval_ptr_ptr == NULL ||
|
||||
*fci->retval_ptr_ptr == NULL) {
|
||||
php_error_docref(NULL TSRMLS_CC, E_WARNING,
|
||||
"Failure to call volume find callback");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
assert(*fci->retval_ptr_ptr == retval_ptr);
|
||||
if (Z_TYPE_P(retval_ptr) == IS_NULL) {
|
||||
/* let return -1 */
|
||||
}
|
||||
else if (Z_TYPE_P(retval_ptr) == IS_STRING) {
|
||||
char *filename = Z_STRVAL_P(retval_ptr);
|
||||
char resolved_path[MAXPATHLEN];
|
||||
size_t resolved_len;
|
||||
|
||||
if (OPENBASEDIR_CHECKPATH(filename)) {
|
||||
goto cleanup;
|
||||
}
|
||||
if (!expand_filepath(filename, resolved_path TSRMLS_CC)) {
|
||||
php_error_docref(NULL TSRMLS_CC, E_WARNING,
|
||||
"Cound not expand filename %s", filename);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
resolved_len = _rar_strnlen(resolved_path, MAXPATHLEN);
|
||||
/* dst_buffer size is NM; first condition won't happen short of a bug
|
||||
* in expand_filepath */
|
||||
if (resolved_len == MAXPATHLEN || resolved_len > NM - 1) {
|
||||
php_error_docref(NULL TSRMLS_CC, E_WARNING,
|
||||
"Resolved path is too big for the unRAR library");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
strncpy(dst_buffer, resolved_path, NM);
|
||||
dst_buffer[NM - 1] = '\0';
|
||||
ret = 1; /* try this new filename */
|
||||
}
|
||||
else {
|
||||
php_error_docref(NULL TSRMLS_CC, E_WARNING,
|
||||
"Wrong type returned by volume find callback, "
|
||||
"expected string or NULL");
|
||||
/* let return -1 */
|
||||
}
|
||||
|
||||
cleanup:
|
||||
zval_ptr_dtor(&failed_vol);
|
||||
if (retval_ptr != NULL)
|
||||
zval_ptr_dtor(&retval_ptr);
|
||||
return ret;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static int _rar_make_userdata_fcall(zval *callable,
|
||||
zend_fcall_info *fci,
|
||||
zend_fcall_info_cache *cache TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
char *error = NULL;
|
||||
assert(callable != NULL);
|
||||
assert(fci != NULL);
|
||||
assert(cache != NULL);
|
||||
|
||||
*cache = empty_fcall_info_cache;
|
||||
|
||||
#if PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION == 2
|
||||
if (zend_fcall_info_init(callable, fci, cache TSRMLS_CC) != SUCCESS) {
|
||||
php_error_docref(NULL TSRMLS_CC, E_WARNING,
|
||||
"The RAR file was not opened in rar_open/RarArchive::open with a "
|
||||
"valid callback.", error);
|
||||
return FAILURE;
|
||||
}
|
||||
else {
|
||||
return SUCCESS;
|
||||
}
|
||||
#else
|
||||
if (zend_fcall_info_init(callable, IS_CALLABLE_STRICT, fci, cache, NULL,
|
||||
&error TSRMLS_CC) == SUCCESS) {
|
||||
if (error) {
|
||||
php_error_docref(NULL TSRMLS_CC, E_STRICT,
|
||||
"The RAR file was not opened with a strictly valid callback (%s)",
|
||||
error);
|
||||
efree(error);
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
else {
|
||||
if (error) {
|
||||
php_error_docref(NULL TSRMLS_CC, E_STRICT,
|
||||
"The RAR file was not opened with a valid callback (%s)",
|
||||
error);
|
||||
efree(error);
|
||||
}
|
||||
return FAILURE;
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* }}} */
|
||||
|
||||
#ifdef COMPILE_DL_RAR
|
||||
ZEND_GET_MODULE(rar)
|
||||
#endif
|
||||
|
||||
/* {{{ arginfo */
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_rar_open, 0, 0, 1)
|
||||
ZEND_ARG_INFO(0, filename)
|
||||
ZEND_ARG_INFO(0, password)
|
||||
ZEND_ARG_INFO(0, volume_callback)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_rar_void_archmeth, 0, 0, 1)
|
||||
#if 0 /* don't turn on type hinting yet */
|
||||
ZEND_ARG_OBJ_INFO(0, rarfile, RarArchive, 0)
|
||||
#else
|
||||
ZEND_ARG_INFO(0, rarfile)
|
||||
#endif
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_rar_entry_get, 0, 0, 2)
|
||||
#if 0 /* don't turn on type hinting yet */
|
||||
ZEND_ARG_OBJ_INFO(0, rarfile, RarArchive, 0)
|
||||
#else
|
||||
ZEND_ARG_INFO(0, rarfile)
|
||||
#endif
|
||||
ZEND_ARG_INFO(0, filename)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_rar_allow_broken_set, 0, 0, 2)
|
||||
#if 0 /* don't turn on type hinting yet */
|
||||
ZEND_ARG_OBJ_INFO(0, rarfile, RarArchive, 0)
|
||||
#else
|
||||
ZEND_ARG_INFO(0, rarfile)
|
||||
#endif
|
||||
ZEND_ARG_INFO(0, allow_broken)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_INFO(arginfo_rar_wrapper_cache_stats, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
/* }}} */
|
||||
|
||||
/* {{{ rar_functions[]
|
||||
*
|
||||
*/
|
||||
static zend_function_entry rar_functions[] = {
|
||||
PHP_FE(rar_open, arginfo_rar_open)
|
||||
PHP_FE(rar_list, arginfo_rar_void_archmeth)
|
||||
PHP_FE(rar_entry_get, arginfo_rar_entry_get)
|
||||
PHP_FE(rar_solid_is, arginfo_rar_void_archmeth)
|
||||
PHP_FE(rar_comment_get, arginfo_rar_void_archmeth)
|
||||
PHP_FE(rar_broken_is, arginfo_rar_void_archmeth)
|
||||
PHP_FE(rar_allow_broken_set, arginfo_rar_allow_broken_set)
|
||||
PHP_FE(rar_close, arginfo_rar_void_archmeth)
|
||||
PHP_FE(rar_wrapper_cache_stats, arginfo_rar_wrapper_cache_stats)
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
/* }}} */
|
||||
|
||||
/* {{{ Globals' related activities */
|
||||
ZEND_DECLARE_MODULE_GLOBALS(rar);
|
||||
|
||||
static int _rar_array_apply_remove_first(void *pDest TSRMLS_DC)
|
||||
{
|
||||
return (ZEND_HASH_APPLY_STOP | ZEND_HASH_APPLY_REMOVE);
|
||||
}
|
||||
|
||||
/* caller should increment zval refcount before calling this */
|
||||
static void _rar_contents_cache_put(const char *key,
|
||||
uint key_len,
|
||||
zval *zv TSRMLS_DC)
|
||||
{
|
||||
rar_contents_cache *cc = &RAR_G(contents_cache);
|
||||
int cur_size;
|
||||
|
||||
cur_size = zend_hash_num_elements(cc->data);
|
||||
if (cur_size == cc->max_size) {
|
||||
zend_hash_apply(cc->data, _rar_array_apply_remove_first TSRMLS_CC);
|
||||
assert(zend_hash_num_elements(cc->data) == cur_size - 1);
|
||||
}
|
||||
zval_add_ref(&zv);
|
||||
zend_hash_update(cc->data, key, key_len, &zv, sizeof(zv), NULL);
|
||||
}
|
||||
|
||||
static zval *_rar_contents_cache_get(const char *key,
|
||||
uint key_len TSRMLS_DC)
|
||||
{
|
||||
rar_contents_cache *cc = &RAR_G(contents_cache);
|
||||
zval **element = NULL;
|
||||
zend_hash_find(cc->data, key, key_len, (void **) &element);
|
||||
|
||||
if (element != NULL) {
|
||||
cc->hits++;
|
||||
zval_add_ref(element);
|
||||
return *element;
|
||||
}
|
||||
else {
|
||||
cc->misses++;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* ZEND_MODULE_GLOBALS_CTOR_D declares it receiving zend_rar_globals*,
|
||||
* which is incompatible; once cast into ts_allocate_ctor by the macro,
|
||||
* ZEND_INIT_MODULE_GLOBALS, it cannot (per the spec) be used. */
|
||||
static void ZEND_MODULE_GLOBALS_CTOR_N(rar)(void *arg TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
zend_rar_globals *rar_globals = arg;
|
||||
rar_globals->contents_cache.max_size = 5; /* TODO make configurable */
|
||||
rar_globals->contents_cache.hits = 0;
|
||||
rar_globals->contents_cache.misses = 0;
|
||||
rar_globals->contents_cache.put = _rar_contents_cache_put;
|
||||
rar_globals->contents_cache.get = _rar_contents_cache_get;
|
||||
rar_globals->contents_cache.data =
|
||||
pemalloc(sizeof *rar_globals->contents_cache.data, 1);
|
||||
zend_hash_init(rar_globals->contents_cache.data,
|
||||
rar_globals->contents_cache.max_size, NULL,
|
||||
ZVAL_PTR_DTOR, 1);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static void ZEND_MODULE_GLOBALS_DTOR_N(rar)(void *arg TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
zend_rar_globals *rar_globals = arg;
|
||||
zend_hash_destroy(rar_globals->contents_cache.data);
|
||||
pefree(rar_globals->contents_cache.data, 1);
|
||||
}
|
||||
/* }}} */
|
||||
/* }}} */
|
||||
|
||||
/* {{{ ZEND_MODULE_STARTUP */
|
||||
ZEND_MODULE_STARTUP_D(rar)
|
||||
{
|
||||
minit_rararch(TSRMLS_C);
|
||||
minit_rarentry(TSRMLS_C);
|
||||
minit_rarerror(TSRMLS_C);
|
||||
|
||||
/* This doesn't work, it tries to call the destructor after the
|
||||
* module has been unloaded. This information is in the zend_module_entry
|
||||
* instead; that information is correctly used before the module is
|
||||
* unloaded */
|
||||
/* ZEND_INIT_MODULE_GLOBALS(rar, ZEND_MODULE_GLOBALS_CTOR_N(rar),
|
||||
ZEND_MODULE_GLOBALS_DTOR_N(rar)); */
|
||||
|
||||
php_register_url_stream_wrapper("rar", &php_stream_rar_wrapper TSRMLS_CC);
|
||||
|
||||
REGISTER_LONG_CONSTANT("RAR_HOST_MSDOS", HOST_MSDOS, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("RAR_HOST_OS2", HOST_OS2, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("RAR_HOST_WIN32", HOST_WIN32, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("RAR_HOST_UNIX", HOST_UNIX, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("RAR_HOST_MACOS", HOST_MACOS, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("RAR_HOST_BEOS", HOST_BEOS, CONST_CS | CONST_PERSISTENT);
|
||||
/* PHP < 5.3 doesn't have the PHP_MAXPATHLEN constant */
|
||||
#if PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION < 3
|
||||
REGISTER_LONG_CONSTANT("RAR_MAXPATHLEN", MAXPATHLEN, CONST_CS | CONST_PERSISTENT);
|
||||
#endif
|
||||
return SUCCESS;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ ZEND_MODULE_DEACTIVATE */
|
||||
ZEND_MODULE_DEACTIVATE_D(rar)
|
||||
{
|
||||
/* clean cache on request shutdown */
|
||||
zend_hash_clean(RAR_G(contents_cache).data);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ ZEND_MODULE_INFO */
|
||||
ZEND_MODULE_INFO_D(rar)
|
||||
{
|
||||
char version[256];
|
||||
char api_version[256];
|
||||
|
||||
php_info_print_table_start();
|
||||
php_info_print_table_header(2, "RAR support", "enabled");
|
||||
php_info_print_table_row(2, "RAR EXT version", PHP_RAR_VERSION);
|
||||
|
||||
#if RARVER_BETA != 0
|
||||
sprintf(version,"%d.%02d beta%d patch%d %d-%02d-%02d", RARVER_MAJOR,
|
||||
RARVER_MINOR, RARVER_BETA, RARVER_PATCH, RARVER_YEAR, RARVER_MONTH,
|
||||
RARVER_DAY);
|
||||
#else
|
||||
sprintf(version,"%d.%02d patch%d %d-%02d-%02d", RARVER_MAJOR, RARVER_MINOR,
|
||||
RARVER_PATCH, RARVER_YEAR, RARVER_MONTH, RARVER_DAY);
|
||||
#endif
|
||||
|
||||
sprintf(api_version,"%d extension %d", RAR_DLL_VERSION,
|
||||
RAR_DLL_EXT_VERSION);
|
||||
|
||||
php_info_print_table_row(2, "UnRAR version", version);
|
||||
php_info_print_table_row(2, "UnRAR API version", api_version);
|
||||
php_info_print_table_end();
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ rar_module_entry
|
||||
*/
|
||||
zend_module_entry rar_module_entry = {
|
||||
STANDARD_MODULE_HEADER,
|
||||
"rar",
|
||||
rar_functions,
|
||||
ZEND_MODULE_STARTUP_N(rar),
|
||||
/* ZEND_MODULE_SHUTDOWN_N(rar), */
|
||||
NULL,
|
||||
/* ZEND_MODULE_ACTIVATE_N(rar), */
|
||||
NULL,
|
||||
ZEND_MODULE_DEACTIVATE_N(rar),
|
||||
ZEND_MODULE_INFO_N(rar),
|
||||
PHP_RAR_VERSION,
|
||||
ZEND_MODULE_GLOBALS(rar),
|
||||
ZEND_MODULE_GLOBALS_CTOR_N(rar),
|
||||
ZEND_MODULE_GLOBALS_DTOR_N(rar),
|
||||
NULL, /* post_deactivate_func */
|
||||
STANDARD_MODULE_PROPERTIES_EX,
|
||||
};
|
||||
/* }}} */
|
||||
|
||||
#endif /* HAVE_RAR */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* tab-width: 4
|
||||
* c-basic-offset: 4
|
||||
* End:
|
||||
* vim600: noet sw=4 ts=4 fdm=marker
|
||||
* vim<600: noet sw=4 ts=4
|
||||
*/
|
||||
238
rar_error.c
Normal file
238
rar_error.c
Normal file
@@ -0,0 +1,238 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2009 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.0 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.php.net/license/3_0.txt. |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
| |
|
||||
| **** WARNING **** |
|
||||
| |
|
||||
| This module makes use of unRAR - free utility for RAR archives. |
|
||||
| Its license states that you MUST NOT use its code to develop |
|
||||
| a RAR (WinRAR) compatible archiver. |
|
||||
| Please, read unRAR license for full information. |
|
||||
| unRAR & RAR copyrights are owned by Eugene Roshal |
|
||||
+----------------------------------------------------------------------+
|
||||
| Author: Antony Dovgal <tony@daylessday.org> |
|
||||
| Author: Gustavo Lopes <cataphract@php.net> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <php.h>
|
||||
#include <zend_exceptions.h>
|
||||
#include "php_rar.h"
|
||||
|
||||
/* {{{ Globals with external linkage */
|
||||
zend_class_entry *rarexception_ce_ptr;
|
||||
/* }}} */
|
||||
|
||||
/* Functions with external linkage {{{ */
|
||||
/* Functions with external linkage {{{ */
|
||||
int _rar_handle_error(int errcode TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
return _rar_handle_error_ex("", errcode TSRMLS_CC);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
int _rar_handle_error_ex(const char *preamble, int errcode TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
const char *err = _rar_error_to_string(errcode);
|
||||
|
||||
if (err == NULL) {
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
if (_rar_using_exceptions(TSRMLS_C)) {
|
||||
zend_throw_exception_ex(rarexception_ce_ptr, errcode TSRMLS_CC,
|
||||
"unRAR internal error: %s%s", preamble, err);
|
||||
}
|
||||
else {
|
||||
php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s%s", preamble, err);
|
||||
}
|
||||
return FAILURE;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* Errors not related to the unRAR library */
|
||||
void _rar_handle_ext_error(const char *format TSRMLS_DC, ...) /* {{{ */
|
||||
{
|
||||
va_list arg;
|
||||
char *message;
|
||||
|
||||
#ifdef ZTS
|
||||
va_start(arg, TSRMLS_C);
|
||||
#else
|
||||
va_start(arg, format);
|
||||
#endif
|
||||
vspprintf(&message, 0, format, arg);
|
||||
va_end(arg);
|
||||
|
||||
if (_rar_using_exceptions(TSRMLS_C))
|
||||
zend_throw_exception(rarexception_ce_ptr, message, -1L TSRMLS_CC);
|
||||
else
|
||||
php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", message);
|
||||
efree(message);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
int _rar_using_exceptions(TSRMLS_D)
|
||||
{
|
||||
zval *pval;
|
||||
pval = zend_read_static_property(rarexception_ce_ptr, "usingExceptions",
|
||||
sizeof("usingExceptions") -1, (zend_bool) 1 TSRMLS_CC);
|
||||
assert(Z_TYPE_P(pval) == IS_BOOL);
|
||||
|
||||
return Z_BVAL_P(pval);
|
||||
}
|
||||
|
||||
/* returns a string or NULL if not an error */
|
||||
const char * _rar_error_to_string(int errcode) /* {{{ */
|
||||
{
|
||||
const char *ret;
|
||||
switch (errcode) {
|
||||
case 0:
|
||||
/* no error */
|
||||
case 1:
|
||||
/* no error (comment completely read) */
|
||||
case ERAR_END_ARCHIVE:
|
||||
/* no error */
|
||||
ret = NULL;
|
||||
break;
|
||||
case ERAR_NO_MEMORY:
|
||||
ret = "ERAR_NO_MEMORY (not enough memory)";
|
||||
break;
|
||||
case ERAR_BAD_DATA:
|
||||
ret = "ERAR_BAD_DATA";
|
||||
break;
|
||||
case ERAR_BAD_ARCHIVE:
|
||||
ret = "ERAR_BAD_ARCHIVE";
|
||||
break;
|
||||
case ERAR_UNKNOWN_FORMAT:
|
||||
ret = "ERAR_UNKNOWN_FORMAT";
|
||||
break;
|
||||
case ERAR_EOPEN:
|
||||
ret = "ERAR_EOPEN (file open error)";
|
||||
break;
|
||||
case ERAR_ECREATE:
|
||||
ret = "ERAR_ECREATE";
|
||||
break;
|
||||
case ERAR_ECLOSE:
|
||||
ret = "ERAR_ECLOSE (error closing file)";
|
||||
break;
|
||||
case ERAR_EREAD:
|
||||
ret = "ERAR_EREAD";
|
||||
break;
|
||||
case ERAR_EWRITE:
|
||||
ret = "ERAR_EWRITE";
|
||||
break;
|
||||
case ERAR_SMALL_BUF:
|
||||
ret = "ERAR_SMALL_BUF";
|
||||
break;
|
||||
case ERAR_UNKNOWN:
|
||||
ret = "ERAR_UNKNOWN (unknown RAR error)";
|
||||
break;
|
||||
case ERAR_MISSING_PASSWORD:
|
||||
ret = "ERAR_MISSING_PASSWORD (password needed but not specified)";
|
||||
break;
|
||||
default:
|
||||
ret = "unknown RAR error (should not happen)";
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
/* }}} */
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto bool RarException::setUsingExceptions(using_exceptions)
|
||||
Set whether exceptions are to be used */
|
||||
PHP_METHOD(rarexception, setUsingExceptions)
|
||||
{
|
||||
zend_bool argval;
|
||||
int result;
|
||||
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "b", &argval) == FAILURE ) {
|
||||
return;
|
||||
}
|
||||
|
||||
result = zend_update_static_property_bool(rarexception_ce_ptr,
|
||||
"usingExceptions", sizeof("usingExceptions") -1,
|
||||
(long) argval TSRMLS_CC);
|
||||
|
||||
if (result == FAILURE) {
|
||||
php_error_docref(NULL TSRMLS_CC, E_WARNING,
|
||||
"Could not set error handling mode. "
|
||||
"This is a bug, please report it.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto bool RarException::isUsingExceptions()
|
||||
Return whether exceptions are being used */
|
||||
PHP_METHOD(rarexception, isUsingExceptions)
|
||||
{
|
||||
zval **pval;
|
||||
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE ) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* or zend_read_static_property, which calls zend_std_get... after chg scope */
|
||||
#if PHP_VERSION_ID < 50399
|
||||
pval = zend_std_get_static_property(rarexception_ce_ptr, "usingExceptions",
|
||||
sizeof("usingExceptions") -1, (zend_bool) 0 TSRMLS_CC);
|
||||
#else
|
||||
pval = zend_std_get_static_property(rarexception_ce_ptr, "usingExceptions",
|
||||
sizeof("usingExceptions") -1, (zend_bool) 0, NULL TSRMLS_CC);
|
||||
#endif
|
||||
/* property always exists */
|
||||
assert(pval != NULL);
|
||||
assert(Z_TYPE_PP(pval) == IS_BOOL);
|
||||
|
||||
RETURN_ZVAL(*pval, 0, 0);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ arginfo */
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_rarexception_sue, 0, 0, 1)
|
||||
ZEND_ARG_INFO(0, using_exceptions)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_INFO(arginfo_rarexception_void, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
/* }}} */
|
||||
|
||||
static zend_function_entry php_rarexception_class_functions[] = {
|
||||
PHP_ME(rarexception, setUsingExceptions, arginfo_rarexception_sue, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
|
||||
PHP_ME(rarexception, isUsingExceptions, arginfo_rarexception_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
void minit_rarerror(TSRMLS_D) /* {{{ */
|
||||
{
|
||||
zend_class_entry ce;
|
||||
|
||||
INIT_CLASS_ENTRY(ce, "RarException", php_rarexception_class_functions);
|
||||
rarexception_ce_ptr = zend_register_internal_class_ex(&ce,
|
||||
zend_exception_get_default(TSRMLS_C), NULL TSRMLS_CC);
|
||||
rarexception_ce_ptr->ce_flags |= ZEND_ACC_FINAL;
|
||||
zend_declare_property_bool(rarexception_ce_ptr, "usingExceptions",
|
||||
sizeof("usingExceptions") -1, 0L /* FALSE */,
|
||||
ZEND_ACC_PRIVATE | ZEND_ACC_STATIC TSRMLS_CC);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
597
rar_navigation.c
Normal file
597
rar_navigation.c
Normal file
@@ -0,0 +1,597 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2009 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.0 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.php.net/license/3_0.txt. |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
| |
|
||||
| **** WARNING **** |
|
||||
| |
|
||||
| This module makes use of unRAR - free utility for RAR archives. |
|
||||
| Its license states that you MUST NOT use its code to develop |
|
||||
| a RAR (WinRAR) compatible archiver. |
|
||||
| Please, read unRAR license for full information. |
|
||||
| unRAR & RAR copyrights are owned by Eugene Roshal |
|
||||
+----------------------------------------------------------------------+
|
||||
| Author: Gustavo Lopes <cataphract@php.net> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <php.h>
|
||||
#include <wchar.h>
|
||||
#include "php_rar.h"
|
||||
|
||||
#if HAVE_RAR
|
||||
|
||||
/* {{{ Structure definitions */
|
||||
|
||||
typedef struct _rar_find_state {
|
||||
rar_find_output out;
|
||||
rar_file_t *rar;
|
||||
size_t index; /* next unread in entries_array or entries_array_s */
|
||||
} rar_find_state;
|
||||
|
||||
struct _rar_unique_entry {
|
||||
size_t id; /* position in the entries_array */
|
||||
struct RARHeaderDataEx entry; /* last entry */
|
||||
unsigned long packed_size;
|
||||
int depth; /* number of directory separators */
|
||||
size_t name_wlen; /* excluding L'\0' terminator */
|
||||
};
|
||||
|
||||
/* last_accessed has the index of the last accessed entry. Its purpose is to make
|
||||
* more efficient the situation wherein the user traverses a directory and
|
||||
* stats each the gotten entry in each iteration. This gives 100% cache hits in
|
||||
* directory traversal tests 064 and 065 for exact name searches */
|
||||
struct _rar_entries {
|
||||
size_t num_entries;
|
||||
struct _rar_unique_entry **entries_array; /* shoud not be NULL */
|
||||
struct _rar_unique_entry **entries_array_s; /* sorted version for bsearch */
|
||||
struct _rar_unique_entry *last_accessed;
|
||||
int list_result; /* tell whether the archive's broken */
|
||||
};
|
||||
/* }}} */
|
||||
|
||||
|
||||
/* {{{ Function prototypes for functions with internal linkage */
|
||||
static void _rar_nav_get_depth_and_length(wchar_t *filenamew, const size_t file_size,
|
||||
int *depth_out, size_t *wlen_out TSRMLS_DC);
|
||||
static int _rar_nav_get_depth(const wchar_t *filenamew, const size_t file_size);
|
||||
static int _rar_nav_compare_entries(const void *op1, const void *op2 TSRMLS_DC);
|
||||
static int _rar_nav_compare_entries_std(const void *op1, const void *op2);
|
||||
static inline int _rar_nav_compare_values(const wchar_t *str1, const int depth1,
|
||||
const wchar_t *str2, const int depth2,
|
||||
const size_t max_size);
|
||||
static int _rar_nav_directory_match(const wchar_t *dir, const size_t dir_len,
|
||||
const wchar_t *entry, const size_t entry_len);
|
||||
static size_t _rar_nav_position_on_dir_start(const wchar_t *dir_name,
|
||||
int dir_depth,
|
||||
size_t dir_size,
|
||||
struct _rar_unique_entry **entries,
|
||||
size_t low, size_t high);
|
||||
/* }}} */
|
||||
|
||||
|
||||
/* {{{ Functions with external linkage */
|
||||
|
||||
/* {{{ _rar_entry_count */
|
||||
size_t _rar_entry_count(rar_file_t *rar) {
|
||||
return rar->entries->num_entries;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ _rar_entry_search_start */
|
||||
void _rar_entry_search_start(rar_file_t *rar,
|
||||
unsigned mode,
|
||||
rar_find_output **state TSRMLS_DC)
|
||||
{
|
||||
rar_find_state **out = (rar_find_state **) state;
|
||||
assert(out != NULL);
|
||||
*out = ecalloc(1, sizeof **out);
|
||||
(*out)->rar = rar;
|
||||
(*out)->out.position = -1;
|
||||
assert(rar->entries != NULL);
|
||||
assert(rar->entries->num_entries == 0 || rar->entries->entries_array != NULL);
|
||||
if ((mode & 0x02U) && (rar->entries->num_entries > 0) &&
|
||||
(rar->entries->entries_array_s == NULL)) {
|
||||
rar->entries->entries_array_s = emalloc(rar->entries->num_entries *
|
||||
sizeof rar->entries->entries_array_s[0]);
|
||||
memcpy(rar->entries->entries_array_s, rar->entries->entries_array,
|
||||
rar->entries->num_entries * sizeof rar->entries->entries_array[0]);
|
||||
zend_qsort(rar->entries->entries_array_s, rar->entries->num_entries,
|
||||
sizeof *rar->entries->entries_array_s, _rar_nav_compare_entries
|
||||
TSRMLS_CC);
|
||||
}
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ _rar_entry_search_seek */
|
||||
void _rar_entry_search_seek(rar_find_output *state, size_t pos)
|
||||
{
|
||||
rar_find_state *rstate = (rar_find_state *) state;
|
||||
assert(pos >= 0);
|
||||
rstate->out.eof = 0;
|
||||
rstate->out.found = 0;
|
||||
rstate->out.position = -1;
|
||||
rstate->out.header = NULL;
|
||||
rstate->out.packed_size = 0;
|
||||
rstate->index = pos;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ _rar_entry_search_end */
|
||||
void _rar_entry_search_end(rar_find_output *state)
|
||||
{
|
||||
efree(state);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ _rar_entry_search_rewind */
|
||||
void _rar_entry_search_rewind(rar_find_output *state)
|
||||
{
|
||||
rar_find_state *rstate = (rar_find_state *) state;
|
||||
rstate->out.eof = 0;
|
||||
rstate->out.found = 0;
|
||||
rstate->out.position = -1;
|
||||
rstate->out.header = NULL;
|
||||
rstate->out.packed_size = 0;
|
||||
rstate->index = 0;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ _rar_entry_search_advance */
|
||||
void _rar_entry_search_advance(rar_find_output *state,
|
||||
const wchar_t * const file, /* NULL = give next */
|
||||
size_t file_size, /* length + 1; 0 if unknown */
|
||||
int directory_match)
|
||||
{
|
||||
rar_find_state *rstate = (rar_find_state *) state;
|
||||
struct _rar_entries *entries;
|
||||
int found = FALSE;
|
||||
int in_sorted;
|
||||
size_t filenamewsize;
|
||||
|
||||
assert(state != NULL);
|
||||
assert(file == NULL || file_size == 0 || file[file_size - 1] == L'\0');
|
||||
|
||||
entries = rstate->rar->entries;
|
||||
assert(entries != NULL);
|
||||
|
||||
if ((file != NULL) && (file_size == 0))
|
||||
file_size = wcslen(file) + 1;
|
||||
|
||||
/* reset output */
|
||||
memset(&rstate->out, 0, sizeof rstate->out);
|
||||
|
||||
filenamewsize = sizeof(entries->entries_array[0]->entry.FileNameW) /
|
||||
sizeof(entries->entries_array[0]->entry.FileNameW[0]); /* = 1024 */
|
||||
if (rstate->out.eof || (rstate->index >= entries->num_entries) ||
|
||||
(file_size > filenamewsize)) {
|
||||
rstate->out.found = 0;
|
||||
rstate->out.eof = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
/* three different cases:
|
||||
* (1) ask next
|
||||
* (2) ask by name
|
||||
* (3) ask next directory child */
|
||||
|
||||
if (!directory_match && (file == NULL)) {
|
||||
/* ask next */
|
||||
in_sorted = FALSE;
|
||||
found = TRUE;
|
||||
/* populate cache for exact name access */
|
||||
entries->last_accessed = entries->entries_array[rstate->index];
|
||||
}
|
||||
else if (!directory_match) {
|
||||
/* ask by exact name */
|
||||
struct _rar_unique_entry temp_entry,
|
||||
*temp_entry_ptr = &temp_entry,
|
||||
**found_entry;
|
||||
/* try to hit cache */
|
||||
if (entries->last_accessed != NULL) {
|
||||
if ((entries->last_accessed->name_wlen == file_size - 1) &&
|
||||
wmemcmp(entries->last_accessed->entry.FileNameW, file,
|
||||
file_size) == 0) {
|
||||
/* cache hit */
|
||||
in_sorted = FALSE;
|
||||
found = TRUE;
|
||||
rstate->index = entries->last_accessed->id;
|
||||
/*php_printf("cache hit\n", entries);*/
|
||||
}
|
||||
else {
|
||||
entries->last_accessed = NULL;
|
||||
/*php_printf("cache miss\n", entries);*/
|
||||
}
|
||||
}
|
||||
/*else
|
||||
php_printf("cache miss (empty)\n", entries);*/
|
||||
|
||||
if (!found) { /* the cache didn't do; use binary search */
|
||||
wmemcpy(temp_entry.entry.FileNameW, file, file_size);
|
||||
temp_entry.depth = _rar_nav_get_depth(file, file_size);
|
||||
found_entry = bsearch(&temp_entry_ptr,
|
||||
&entries->entries_array_s[rstate->index],
|
||||
entries->num_entries - rstate->index,
|
||||
sizeof entries->entries_array_s[0],
|
||||
_rar_nav_compare_entries_std);
|
||||
if (found_entry != NULL) {
|
||||
in_sorted = TRUE;
|
||||
found = TRUE;
|
||||
rstate->index = found_entry - entries->entries_array_s;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* ask by next directory child */
|
||||
struct _rar_unique_entry *cur = entries->entries_array_s[rstate->index];
|
||||
in_sorted = TRUE;
|
||||
assert(file != NULL);
|
||||
if (_rar_nav_directory_match(file, file_size - 1,
|
||||
cur->entry.FileNameW, cur->name_wlen)) {
|
||||
found = TRUE;
|
||||
/* populate cache for exact name access */
|
||||
entries->last_accessed = cur;
|
||||
}
|
||||
else {
|
||||
/* no directory match for current */
|
||||
int comp, dir_depth;
|
||||
dir_depth = _rar_nav_get_depth(file, file_size);
|
||||
comp = _rar_nav_compare_values(cur->entry.FileNameW, cur->depth,
|
||||
file, dir_depth + 1, file_size); /* guaranteed file_size <= 1024 */
|
||||
assert(comp != 0); /* because + 1 was summed to the depth */
|
||||
if (comp > 0) {
|
||||
/* past the entries of the directory */
|
||||
/* do nothing */
|
||||
}
|
||||
else {
|
||||
int pos = _rar_nav_position_on_dir_start(file, dir_depth,
|
||||
file_size, entries->entries_array_s, rstate->index,
|
||||
entries->num_entries);
|
||||
if (pos != -1) {
|
||||
found = TRUE;
|
||||
rstate->index = pos;
|
||||
/* populate cache for exact name access */
|
||||
entries->last_accessed = entries->entries_array_s[pos];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (found == FALSE) {
|
||||
rstate->out.found = 0;
|
||||
rstate->out.eof = 1;
|
||||
}
|
||||
else {
|
||||
struct _rar_unique_entry *cur;
|
||||
if (in_sorted)
|
||||
cur = entries->entries_array_s[rstate->index];
|
||||
else
|
||||
cur = entries->entries_array[rstate->index];
|
||||
rstate->out.found = 1;
|
||||
rstate->out.position = cur->id;
|
||||
rstate->out.header = &cur->entry;
|
||||
rstate->out.packed_size = cur->packed_size;
|
||||
rstate->index++;
|
||||
}
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ _rar_delete_entries - accepts an allocated entries list */
|
||||
void _rar_delete_entries(rar_file_t *rar TSRMLS_DC)
|
||||
{
|
||||
if (rar->entries != NULL) {
|
||||
if (rar->entries->entries_array != NULL) {
|
||||
size_t i;
|
||||
for (i = 0; i < rar->entries->num_entries; i++) {
|
||||
efree(rar->entries->entries_array[i]);
|
||||
}
|
||||
efree(rar->entries->entries_array);
|
||||
|
||||
if (rar->entries->entries_array_s != NULL)
|
||||
efree(rar->entries->entries_array_s);
|
||||
}
|
||||
efree(rar->entries);
|
||||
}
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* guarantees correct initialization of rar->entries on failure
|
||||
* If the passed rar_file_t structure has the allow_broken option, it
|
||||
* always returns success (ERAR_END_ARCHIVE) */
|
||||
int _rar_list_files(rar_file_t *rar TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
int result = 0;
|
||||
size_t capacity = 0;
|
||||
int first_file_check = TRUE;
|
||||
unsigned long packed_size = 0UL;
|
||||
struct _rar_entries *ents;
|
||||
|
||||
if (rar->entries != NULL) {
|
||||
/* we've already listed this file's entries */
|
||||
if (rar->allow_broken)
|
||||
return ERAR_END_ARCHIVE;
|
||||
else
|
||||
return rar->entries->list_result;
|
||||
}
|
||||
|
||||
assert(rar->entries == NULL);
|
||||
rar->entries = emalloc(sizeof *rar->entries);
|
||||
ents = rar->entries;
|
||||
ents->num_entries = 0;
|
||||
ents->entries_array = NULL;
|
||||
ents->entries_array_s = NULL;
|
||||
ents->last_accessed = NULL;
|
||||
|
||||
while (result == 0) {
|
||||
struct RARHeaderDataEx entry = {0};
|
||||
result = RARReadHeaderEx(rar->arch_handle, &entry);
|
||||
/* value of 2nd argument is irrelevant in RAR_OM_LIST_[SPLIT] mode */
|
||||
if (result == 0) {
|
||||
result = RARProcessFile(rar->arch_handle, RAR_SKIP, NULL, NULL);
|
||||
}
|
||||
if (result != 0)
|
||||
break;
|
||||
|
||||
if (first_file_check) {
|
||||
if (entry.Flags & RHDF_SPLITBEFORE)
|
||||
continue;
|
||||
else
|
||||
first_file_check = FALSE;
|
||||
}
|
||||
|
||||
/* reset packed size if not split before */
|
||||
if ((entry.Flags & RHDF_SPLITBEFORE) == 0)
|
||||
packed_size = 0UL;
|
||||
|
||||
/* we would exceed size of ulong. cap at ulong_max
|
||||
* equivalent to packed_size + entry.PackSize > ULONG_MAX,
|
||||
* but without overflowing */
|
||||
if (ULONG_MAX - packed_size < entry.PackSize)
|
||||
packed_size = ULONG_MAX;
|
||||
else {
|
||||
packed_size += entry.PackSize;
|
||||
if (entry.PackSizeHigh != 0) {
|
||||
#if ULONG_MAX > 0xffffffffUL
|
||||
packed_size += ((unsigned long) entry.PackSizeHigh) << 32;
|
||||
#else
|
||||
packed_size = ULONG_MAX; /* cap */
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (entry.Flags & RHDF_SPLITAFTER) /* do not commit */
|
||||
continue;
|
||||
|
||||
/* commit the entry */
|
||||
assert(capacity >= ents->num_entries);
|
||||
if (capacity == ents->num_entries) { /* 0, 2, 6, 14, 30... */
|
||||
capacity = (capacity + 1) * 2;
|
||||
ents->entries_array = safe_erealloc(ents->entries_array, capacity,
|
||||
sizeof(*ents->entries_array), 0);
|
||||
}
|
||||
assert(capacity > ents->num_entries);
|
||||
|
||||
ents->entries_array[ents->num_entries] =
|
||||
emalloc(sizeof *ents->entries_array[0]);
|
||||
memcpy(&ents->entries_array[ents->num_entries]->entry, &entry,
|
||||
sizeof ents->entries_array[0]->entry);
|
||||
ents->entries_array[ents->num_entries]->id = ents->num_entries;
|
||||
ents->entries_array[ents->num_entries]->packed_size = packed_size;
|
||||
_rar_nav_get_depth_and_length(entry.FileNameW,
|
||||
sizeof(entry.FileNameW) / sizeof(entry.FileNameW[0]), /* = 1024 */
|
||||
&ents->entries_array[ents->num_entries]->depth,
|
||||
&ents->entries_array[ents->num_entries]->name_wlen TSRMLS_CC);
|
||||
ents->num_entries++;
|
||||
}
|
||||
|
||||
rar->entries->list_result = result;
|
||||
|
||||
return rar->allow_broken ? ERAR_END_ARCHIVE : result;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* end functions with external linkage }}} */
|
||||
|
||||
|
||||
/* {{{ Functions with internal linkage */
|
||||
|
||||
static void _rar_nav_get_depth_and_length(wchar_t *filenamew, const size_t file_size,
|
||||
int *depth_out, size_t *wlen_out TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
size_t i;
|
||||
int depth = 0;
|
||||
|
||||
assert(file_size >= 1);
|
||||
|
||||
for (i = 0; i < file_size; i++) {
|
||||
if (filenamew[i] == L'\0')
|
||||
break;
|
||||
if (filenamew[i] == SPATHDIVIDER[0])
|
||||
depth++;
|
||||
}
|
||||
|
||||
if (i == file_size) { /* should not happen */
|
||||
php_error_docref(NULL TSRMLS_CC, E_WARNING,
|
||||
"The library gave an unterminated file name. "
|
||||
"This is a bug, please report it.");
|
||||
i--;
|
||||
filenamew[i] = L'\0';
|
||||
}
|
||||
|
||||
if ((i >= 1) && (filenamew[i-1] == SPATHDIVIDER[0])) {
|
||||
/* entry name ended in path divider. shouldn't happen */
|
||||
i--;
|
||||
filenamew[i] = L'\0';
|
||||
depth--;
|
||||
}
|
||||
|
||||
*depth_out = depth;
|
||||
if (wlen_out != NULL)
|
||||
*wlen_out = (size_t) i;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static int _rar_nav_get_depth(const wchar_t *filenamew, const size_t file_size) /* {{{ */
|
||||
{
|
||||
size_t i;
|
||||
int depth = 0;
|
||||
|
||||
for (i = 0; i < file_size; i++) {
|
||||
if (filenamew[i] == L'\0')
|
||||
break;
|
||||
if (filenamew[i] == SPATHDIVIDER[0])
|
||||
depth++;
|
||||
}
|
||||
assert(i < file_size);
|
||||
|
||||
return depth;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static int _rar_nav_compare_entries(const void *op1, const void *op2 TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
const struct _rar_unique_entry *a = *((struct _rar_unique_entry **) op1),
|
||||
*b = *((struct _rar_unique_entry **) op2);
|
||||
|
||||
return _rar_nav_compare_values(a->entry.FileNameW, a->depth,
|
||||
b->entry.FileNameW, b->depth,
|
||||
sizeof(a->entry.FileNameW) / sizeof(a->entry.FileNameW[0]) /*1024*/);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static int _rar_nav_compare_entries_std(const void *op1, const void *op2) /* {{{ */
|
||||
{
|
||||
const struct _rar_unique_entry *a = *((struct _rar_unique_entry **) op1),
|
||||
*b = *((struct _rar_unique_entry **) op2);
|
||||
|
||||
return _rar_nav_compare_values(a->entry.FileNameW, a->depth,
|
||||
b->entry.FileNameW, b->depth,
|
||||
sizeof(a->entry.FileNameW) / sizeof(a->entry.FileNameW[0]) /*1024*/);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static inline int _rar_nav_compare_values(const wchar_t *str1, const int depth1,
|
||||
const wchar_t *str2, const int depth2,
|
||||
const size_t max_size) /* {{{ */
|
||||
{
|
||||
if (depth1 == depth2) {
|
||||
return wcsncmp(str1, str2, max_size);
|
||||
}
|
||||
else {
|
||||
return depth1 > depth2 ? 1 : -1;
|
||||
}
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* does not assume null termination */
|
||||
static int _rar_nav_directory_match(const wchar_t *dir, const size_t dir_len,
|
||||
const wchar_t *entry, const size_t entry_len) /* {{{ */
|
||||
{
|
||||
const wchar_t *chr,
|
||||
*entry_rem;
|
||||
size_t entry_rem_len;
|
||||
|
||||
/* dir does not end with the path separator */
|
||||
|
||||
if (dir_len > 0) {
|
||||
if (entry_len <= dir_len) /* don't match the dir itself */
|
||||
return FALSE;
|
||||
/* assert(entry_len > dir_len > 0) */
|
||||
if (wmemcmp(dir, entry, dir_len) != 0)
|
||||
return FALSE;
|
||||
/* directory name does not follow path sep or path sep ends the name */
|
||||
if (entry[dir_len] != SPATHDIVIDER[0] || entry_len == dir_len + 1)
|
||||
return FALSE;
|
||||
/* assert(entry_len > dir_len + 1) */
|
||||
entry_rem = &entry[dir_len + 1];
|
||||
entry_rem_len = entry_len - (dir_len + 1);
|
||||
}
|
||||
else {
|
||||
entry_rem = entry;
|
||||
entry_rem_len = entry_len;
|
||||
}
|
||||
|
||||
chr = wmemchr(entry_rem, SPATHDIVIDER[0], entry_rem_len);
|
||||
/* must have no / after the directory */
|
||||
return (chr == NULL);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static size_t _rar_nav_position_on_dir_start(const wchar_t *dir_name,
|
||||
int dir_depth,
|
||||
size_t dir_size,
|
||||
struct _rar_unique_entry **entries,
|
||||
size_t low, size_t high) /* {{{ */
|
||||
{
|
||||
size_t mid;
|
||||
int comp;
|
||||
size_t orig_high = high;
|
||||
|
||||
if (dir_size == 1) { /* root */
|
||||
if (low >= high)
|
||||
return -1;
|
||||
|
||||
if (entries[low]->depth == 0)
|
||||
return low;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (low < high) {
|
||||
mid = low + (high - low) / 2;
|
||||
comp = _rar_nav_compare_values(dir_name, dir_depth + 1,
|
||||
entries[mid]->entry.FileNameW, entries[mid]->depth,
|
||||
dir_size);
|
||||
if (comp > 0)
|
||||
low = mid + 1;
|
||||
else
|
||||
high = mid;
|
||||
}
|
||||
|
||||
if (low >= orig_high)
|
||||
return -1;
|
||||
|
||||
if (_rar_nav_directory_match(dir_name, dir_size - 1,
|
||||
entries[low]->entry.FileNameW, entries[low]->name_wlen))
|
||||
return low;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
|
||||
/* end functions with internal linkage */
|
||||
|
||||
#endif /* HAVE_RAR */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* tab-width: 4
|
||||
* c-basic-offset: 4
|
||||
* End:
|
||||
* vim600: noet sw=4 ts=4 fdm=marker
|
||||
* vim<600: noet sw=4 ts=4
|
||||
*/
|
||||
|
||||
|
||||
1324
rar_stream.c
Normal file
1324
rar_stream.c
Normal file
File diff suppressed because it is too large
Load Diff
993
rararch.c
Normal file
993
rararch.c
Normal file
@@ -0,0 +1,993 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2009 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.0 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.php.net/license/3_0.txt. |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
| |
|
||||
| **** WARNING **** |
|
||||
| |
|
||||
| This module makes use of unRAR - free utility for RAR archives. |
|
||||
| Its license states that you MUST NOT use its code to develop |
|
||||
| a RAR (WinRAR) compatible archiver. |
|
||||
| Please, read unRAR license for full information. |
|
||||
| unRAR & RAR copyrights are owned by Eugene Roshal |
|
||||
+----------------------------------------------------------------------+
|
||||
| Author: Antony Dovgal <tony@daylessday.org> |
|
||||
| Author: Gustavo Lopes <cataphract@php.net> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <string.h>
|
||||
|
||||
#include <wchar.h>
|
||||
#include <php.h>
|
||||
#include <zend_interfaces.h>
|
||||
#include "php_rar.h"
|
||||
|
||||
/* {{{ Type definitions reserved for this translation unit */
|
||||
typedef struct _ze_rararch_object {
|
||||
zend_object parent;
|
||||
rar_file_t *rar_file;
|
||||
} ze_rararch_object;
|
||||
|
||||
typedef struct _rararch_iterator {
|
||||
zend_object_iterator parent;
|
||||
rar_find_output *state;
|
||||
zval *value;
|
||||
int empty_iterator; /* iterator should give nothing */
|
||||
} rararch_iterator;
|
||||
/* }}} */
|
||||
|
||||
/* {{{ Globals with internal linkage */
|
||||
static zend_class_entry *rararch_ce_ptr;
|
||||
static zend_object_handlers rararch_object_handlers;
|
||||
/* }}} */
|
||||
|
||||
/* {{{ Helper macros */
|
||||
#define RAR_THIS_OR_NO_ARGS(file) \
|
||||
if (file == NULL) { \
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", \
|
||||
&file, rararch_ce_ptr) == FAILURE) { \
|
||||
RETURN_NULL(); \
|
||||
} \
|
||||
} \
|
||||
else { \
|
||||
RAR_RETNULL_ON_ARGS(); \
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ Function prototypes for functions with internal linkage */
|
||||
static zend_object_value rararch_ce_create_object(zend_class_entry *class_type TSRMLS_DC);
|
||||
static void rararch_ce_free_object_storage(ze_rararch_object *object TSRMLS_DC);
|
||||
/* }}} */
|
||||
|
||||
/* {{{ RarArchive handlers */
|
||||
static int rararch_handlers_preamble(zval *object, rar_file_t **rar TSRMLS_DC);
|
||||
static int rararch_dimensions_preamble(rar_file_t *rar, zval *offset, long *index, int quiet TSRMLS_DC);
|
||||
static int rararch_count_elements(zval *object, long *count TSRMLS_DC);
|
||||
static zval *rararch_read_dimension(zval *object, zval *offset, int type TSRMLS_DC);
|
||||
static void rararch_write_dimension(zval *object, zval *offset, zval *value TSRMLS_DC);
|
||||
static int rararch_has_dimension(zval *object, zval *offset, int check_empty TSRMLS_DC);
|
||||
/* }}} */
|
||||
|
||||
/* {{{ Function definitions with external linkage */
|
||||
int _rar_get_file_resource(zval *zval_file, rar_file_t **rar_file TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
return _rar_get_file_resource_ex(zval_file, rar_file, FALSE TSRMLS_CC);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* Creates a RarArchive object, all three in args will be dupped */
|
||||
int _rar_create_rararch_obj(const char* resolved_path,
|
||||
const char* open_password,
|
||||
zval *volume_callback, /* must be callable or NULL */
|
||||
zval *object,
|
||||
int *err_code TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
rar_file_t *rar = NULL;
|
||||
|
||||
rar = emalloc(sizeof *rar);
|
||||
rar->list_open_data = ecalloc(1, sizeof *rar->list_open_data);
|
||||
rar->list_open_data->ArcName = estrdup(resolved_path);
|
||||
rar->list_open_data->OpenMode = RAR_OM_LIST_INCSPLIT;
|
||||
rar->list_open_data->CmtBuf = ecalloc(RAR_MAX_COMMENT_SIZE, 1);
|
||||
rar->list_open_data->CmtBufSize = RAR_MAX_COMMENT_SIZE;
|
||||
rar->extract_open_data = ecalloc(1, sizeof *rar->extract_open_data);
|
||||
rar->extract_open_data->ArcName = estrdup(resolved_path);
|
||||
rar->extract_open_data->OpenMode = RAR_OM_EXTRACT;
|
||||
rar->extract_open_data->CmtBuf = NULL; /* not interested in it again */
|
||||
rar->cb_userdata.password = NULL;
|
||||
rar->cb_userdata.callable = NULL;
|
||||
rar->entries = NULL;
|
||||
rar->allow_broken = 0;
|
||||
|
||||
rar->arch_handle = RAROpenArchiveEx(rar->list_open_data);
|
||||
if (rar->arch_handle != NULL && rar->list_open_data->OpenResult == 0) {
|
||||
ze_rararch_object *zobj;
|
||||
|
||||
if (open_password != NULL) {
|
||||
rar->cb_userdata.password = estrdup(open_password);
|
||||
}
|
||||
if (volume_callback != NULL) {
|
||||
rar->cb_userdata.callable = volume_callback;
|
||||
zval_add_ref(&rar->cb_userdata.callable);
|
||||
SEPARATE_ZVAL(&rar->cb_userdata.callable);
|
||||
}
|
||||
|
||||
object_init_ex(object, rararch_ce_ptr);
|
||||
zobj = zend_object_store_get_object(object TSRMLS_CC);
|
||||
zobj->rar_file = rar;
|
||||
rar->id = Z_OBJ_HANDLE_P(object);
|
||||
|
||||
RARSetCallback(rar->arch_handle, _rar_unrar_callback,
|
||||
(LPARAM) &rar->cb_userdata);
|
||||
|
||||
return SUCCESS;
|
||||
} else {
|
||||
*err_code = rar->list_open_data->OpenResult;
|
||||
|
||||
efree(rar->list_open_data->ArcName);
|
||||
efree(rar->list_open_data->CmtBuf);
|
||||
efree(rar->list_open_data);
|
||||
efree(rar->extract_open_data->ArcName);
|
||||
efree(rar->extract_open_data);
|
||||
efree(rar);
|
||||
return FAILURE;
|
||||
}
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
void _rar_close_file_resource(rar_file_t *rar) /* {{{ */
|
||||
{
|
||||
assert(rar->arch_handle != NULL);
|
||||
|
||||
/* When changed from resource to custom object, instead of fiddling
|
||||
* with the refcount to force object destruction, an indication that
|
||||
* the file is already closed is given by setting rar->arch_handle
|
||||
* to NULL. This is checked by _rar_get_file_resource. */
|
||||
RARCloseArchive(rar->arch_handle);
|
||||
rar->arch_handle = NULL;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* Receives archive zval, returns object struct.
|
||||
* If silent is FALSE, it checks whether the archive is alredy closed, and if it
|
||||
* is, an exception/error is raised and FAILURE is returned
|
||||
*/
|
||||
int _rar_get_file_resource_ex(zval *zval_file, rar_file_t **rar_file, int silent TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
ze_rararch_object *zobj;
|
||||
zobj = zend_object_store_get_object(zval_file TSRMLS_CC);
|
||||
if (zobj == NULL) {
|
||||
php_error_docref(NULL TSRMLS_CC, E_WARNING,
|
||||
"Could not find object in the store. This is a bug, please report it.");
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
*rar_file = zobj->rar_file;
|
||||
if ((*rar_file)->arch_handle == NULL && !silent) { /* rar_close was called */
|
||||
_rar_handle_ext_error("The archive is already closed" TSRMLS_CC);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
/* }}} */
|
||||
/* end functions with external linkage }}} */
|
||||
|
||||
/* {{{ Helper functions and preprocessor definitions */
|
||||
|
||||
/* target should be initialized */
|
||||
static void _rar_raw_entries_to_array(rar_file_t *rar, zval *target TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
rar_find_output *state;
|
||||
zval *rararch_obj;
|
||||
|
||||
/* create zval to point to the RarArchive object) */
|
||||
MAKE_STD_ZVAL(rararch_obj);
|
||||
Z_TYPE_P(rararch_obj) = IS_OBJECT;
|
||||
Z_OBJ_HANDLE_P(rararch_obj) = rar->id;
|
||||
Z_OBJ_HT_P(rararch_obj) = &rararch_object_handlers;
|
||||
/* object has a new reference; if not incremented, the object would be
|
||||
* be destroyed when this new zval we created was destroyed */
|
||||
zend_objects_store_add_ref_by_handle(rar->id TSRMLS_CC);
|
||||
|
||||
_rar_entry_search_start(rar, RAR_SEARCH_TRAVERSE, &state TSRMLS_CC);
|
||||
do {
|
||||
_rar_entry_search_advance(state, NULL, 0, 0);
|
||||
if (state->found) {
|
||||
zval *entry_obj;
|
||||
|
||||
MAKE_STD_ZVAL(entry_obj);
|
||||
_rar_entry_to_zval(rararch_obj, state->header, state->packed_size,
|
||||
state->position, entry_obj TSRMLS_CC);
|
||||
|
||||
add_next_index_zval(target, entry_obj);
|
||||
}
|
||||
} while (state->eof == 0);
|
||||
_rar_entry_search_end(state);
|
||||
|
||||
/* it was created with refcount=1 and incremented for each RarEntry object
|
||||
* created, so we must decrease by one (this will also destroy it if
|
||||
* there were no entries */
|
||||
zval_ptr_dtor(&rararch_obj);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static zend_object_value rararch_ce_create_object(zend_class_entry *class_type TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
zend_object_value zov;
|
||||
ze_rararch_object *zobj;
|
||||
|
||||
zobj = emalloc(sizeof *zobj);
|
||||
/* rararch_ce_free_object_storage will attempt to access it otherwise */
|
||||
zobj->rar_file = NULL;
|
||||
zend_object_std_init((zend_object*) zobj, class_type TSRMLS_CC);
|
||||
|
||||
#if PHP_VERSION_ID < 50399
|
||||
zend_hash_copy(((zend_object*)zobj)->properties,
|
||||
&(class_type->default_properties),
|
||||
(copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval*));
|
||||
#else
|
||||
object_properties_init((zend_object*)zobj, class_type);
|
||||
#endif
|
||||
zov.handle = zend_objects_store_put(zobj,
|
||||
(zend_objects_store_dtor_t) zend_objects_destroy_object,
|
||||
(zend_objects_free_object_storage_t) rararch_ce_free_object_storage,
|
||||
NULL TSRMLS_CC);
|
||||
zov.handlers = &rararch_object_handlers;
|
||||
return zov;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static void rararch_ce_free_object_storage(ze_rararch_object *object TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
rar_file_t *rar = object->rar_file;
|
||||
|
||||
/* may be NULL if the user did new RarArchive() */
|
||||
if (rar != NULL) {
|
||||
if (rar->arch_handle != NULL) {
|
||||
RARCloseArchive(rar->arch_handle);
|
||||
}
|
||||
|
||||
_rar_destroy_userdata(&rar->cb_userdata);
|
||||
|
||||
_rar_delete_entries(rar TSRMLS_CC);
|
||||
|
||||
efree(rar->list_open_data->ArcName);
|
||||
efree(rar->list_open_data->CmtBuf);
|
||||
efree(rar->list_open_data);
|
||||
efree(rar->extract_open_data->ArcName);
|
||||
efree(rar->extract_open_data);
|
||||
efree(rar);
|
||||
}
|
||||
|
||||
/* could call zend_objects_free_object_storage here (not before!), but
|
||||
* instead I'll mimic its behaviour */
|
||||
zend_object_std_dtor((zend_object*) object TSRMLS_CC);
|
||||
efree(object);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* }}} */
|
||||
|
||||
/* {{{ RarArchive handlers */
|
||||
static int rararch_handlers_preamble(zval *object, rar_file_t **rar TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
/* don't call zend_objects_get_address or zend_object_store_get directly;
|
||||
* _rar_get_file_resource checks if the archive was closed */
|
||||
if (_rar_get_file_resource(object, rar TSRMLS_CC) == FAILURE) {
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
return _rar_handle_error(_rar_list_files(*rar TSRMLS_CC) TSRMLS_CC);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
#define RAR_DOCREF_IF_UNQUIET(...) \
|
||||
if (!quiet) { php_error_docref(__VA_ARGS__); }
|
||||
|
||||
/* {{{ rararch_dimensions_preamble - semi-strict parsing of int argument */
|
||||
static int rararch_dimensions_preamble(rar_file_t *rar,
|
||||
zval *offset,
|
||||
long *index,
|
||||
int quiet TSRMLS_DC)
|
||||
{
|
||||
if (offset == NULL) {
|
||||
RAR_DOCREF_IF_UNQUIET(NULL TSRMLS_CC, E_ERROR,
|
||||
"Empty dimension syntax is not supported for RarArchive objects");
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
if (Z_TYPE_P(offset) == IS_LONG) {
|
||||
*index = Z_LVAL_P(offset);
|
||||
}
|
||||
else if (Z_TYPE_P(offset) == IS_STRING) {
|
||||
int type;
|
||||
double d;
|
||||
|
||||
if ((type = is_numeric_string(Z_STRVAL_P(offset), Z_STRLEN_P(offset),
|
||||
index, &d, -1)) == 0) {
|
||||
RAR_DOCREF_IF_UNQUIET(NULL TSRMLS_CC, E_WARNING,
|
||||
"Attempt to use a non-numeric dimension to access a "
|
||||
"RarArchive object (invalid string)");
|
||||
return FAILURE;
|
||||
}
|
||||
else if (type == IS_DOUBLE) {
|
||||
if (d > LONG_MAX || d < LONG_MIN) {
|
||||
RAR_DOCREF_IF_UNQUIET(NULL TSRMLS_CC, E_WARNING,
|
||||
"Dimension index is out of integer bounds");
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
*index = (long) d;
|
||||
}
|
||||
}
|
||||
else if (Z_TYPE_P(offset) == IS_DOUBLE) {
|
||||
if (Z_DVAL_P(offset) > LONG_MAX || Z_DVAL_P(offset) < LONG_MIN) {
|
||||
RAR_DOCREF_IF_UNQUIET(NULL TSRMLS_CC, E_WARNING,
|
||||
"Dimension index is out of integer bounds");
|
||||
return FAILURE;
|
||||
}
|
||||
*index = (long) Z_DVAL_P(offset);
|
||||
}
|
||||
else if (Z_TYPE_P(offset) == IS_OBJECT) {
|
||||
if (Z_OBJ_HT_P(offset)->get) {
|
||||
/* get handler cannot return NULL */
|
||||
zval *newoffset = Z_OBJ_HT_P(offset)->get(offset TSRMLS_CC);
|
||||
int ret;
|
||||
|
||||
if (Z_TYPE_P(newoffset) == IS_OBJECT) {
|
||||
RAR_DOCREF_IF_UNQUIET(NULL TSRMLS_CC, E_WARNING,
|
||||
"Could not convert object given as dimension index into "
|
||||
"an integer (get handler returned another object)");
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
ret = rararch_dimensions_preamble(rar, newoffset, index, quiet
|
||||
TSRMLS_CC);
|
||||
FREE_ZVAL(newoffset);
|
||||
return ret;
|
||||
}
|
||||
else {
|
||||
RAR_DOCREF_IF_UNQUIET(NULL TSRMLS_CC, E_WARNING,
|
||||
"Attempt to use an object with no get handler as a dimension "
|
||||
"to access a RarArchive object");
|
||||
return FAILURE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
RAR_DOCREF_IF_UNQUIET(NULL TSRMLS_CC, E_WARNING,
|
||||
"Attempt to use a non-numeric dimension to access a "
|
||||
"RarArchive object (invalid type)");
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
if (*index < 0L) {
|
||||
RAR_DOCREF_IF_UNQUIET(NULL TSRMLS_CC, E_WARNING,
|
||||
"Dimension index must be non-negative, given %ld", *index);
|
||||
return FAILURE;
|
||||
}
|
||||
if ((size_t) *index >= _rar_entry_count(rar)) {
|
||||
RAR_DOCREF_IF_UNQUIET(NULL TSRMLS_CC, E_WARNING,
|
||||
"Dimension index exceeds or equals number of entries in RAR "
|
||||
"archive");
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ RarArchive count_elements handler */
|
||||
static int rararch_count_elements(zval *object, long *count TSRMLS_DC)
|
||||
{
|
||||
rar_file_t *rar = NULL;
|
||||
size_t entry_count;
|
||||
|
||||
if (rararch_handlers_preamble(object, &rar TSRMLS_CC) == FAILURE) {
|
||||
*count = 0L;
|
||||
return SUCCESS; /* intentional */
|
||||
}
|
||||
|
||||
entry_count = _rar_entry_count(rar);
|
||||
if (entry_count > LONG_MAX)
|
||||
entry_count = (size_t) LONG_MAX;
|
||||
|
||||
*count = (long) entry_count;
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ RarArchive read_dimension handler */
|
||||
static zval *rararch_read_dimension(zval *object, zval *offset, int type TSRMLS_DC)
|
||||
{
|
||||
long index;
|
||||
rar_file_t *rar = NULL;
|
||||
struct _rar_find_output *out;
|
||||
zval *ret = NULL;
|
||||
|
||||
if (rararch_handlers_preamble(object, &rar TSRMLS_CC) == FAILURE) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (rararch_dimensions_preamble(rar, offset, &index, (type == BP_VAR_IS)
|
||||
TSRMLS_CC) == FAILURE)
|
||||
return NULL;
|
||||
|
||||
if (type == BP_VAR_RW || type == BP_VAR_W || type == BP_VAR_UNSET)
|
||||
php_error_docref(NULL TSRMLS_CC, E_ERROR,
|
||||
"A RarArchive object is not modifiable");
|
||||
|
||||
_rar_entry_search_start(rar, RAR_SEARCH_INDEX, &out TSRMLS_CC);
|
||||
_rar_entry_search_seek(out, (size_t) index);
|
||||
_rar_entry_search_advance(out, NULL, 0, 0);
|
||||
assert(out->found);
|
||||
ALLOC_INIT_ZVAL(ret);
|
||||
_rar_entry_to_zval(object, out->header, out->packed_size, out->position,
|
||||
ret TSRMLS_CC);
|
||||
_rar_entry_search_end(out);
|
||||
Z_DELREF_P(ret); /* set refcount to 0 */
|
||||
return ret;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ RarArchive write_dimension handler */
|
||||
static void rararch_write_dimension(zval *object, zval *offset, zval *value TSRMLS_DC)
|
||||
{
|
||||
php_error_docref(NULL TSRMLS_CC, E_ERROR,
|
||||
"A RarArchive object is not writable");
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ RarArchive has_dimension handler */
|
||||
static int rararch_has_dimension(zval *object, zval *offset, int check_empty TSRMLS_DC)
|
||||
{
|
||||
long index;
|
||||
rar_file_t *rar = NULL;
|
||||
|
||||
(void) check_empty; /* don't care */
|
||||
|
||||
if (rararch_handlers_preamble(object, &rar TSRMLS_CC) == FAILURE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (rararch_dimensions_preamble(rar, offset, &index, 1 TSRMLS_CC) ==
|
||||
SUCCESS);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ RarArchive unset_dimension handler */
|
||||
static void rararch_unset_dimension(zval *object, zval *offset TSRMLS_DC)
|
||||
{
|
||||
php_error_docref(NULL TSRMLS_CC, E_ERROR,
|
||||
"A RarArchive object is not writable");
|
||||
}
|
||||
/* }}} */
|
||||
/* }}} */
|
||||
|
||||
/* module functions */
|
||||
|
||||
/* {{{ proto RarArchive rar_open(string filename [, string password = NULL
|
||||
[, callback volume_cb = NULL ]])
|
||||
Open RAR archive and return RarArchive object */
|
||||
PHP_FUNCTION(rar_open)
|
||||
{
|
||||
char *filename;
|
||||
char *password = NULL;
|
||||
char resolved_path[MAXPATHLEN];
|
||||
int filename_len;
|
||||
int password_len = 0;
|
||||
zval *callable = NULL;
|
||||
int err_code;
|
||||
|
||||
/* Files are only opened here and in _rar_find_file */
|
||||
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s!z!", &filename,
|
||||
&filename_len, &password, &password_len, &callable) == FAILURE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (OPENBASEDIR_CHECKPATH(filename)) {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
if (!expand_filepath(filename, resolved_path TSRMLS_CC)) {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
assert(strnlen(resolved_path, MAXPATHLEN) < MAXPATHLEN);
|
||||
|
||||
if (callable != NULL) { /* given volume resolver callback */
|
||||
#if PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION == 2
|
||||
if (!zend_is_callable(callable, IS_CALLABLE_STRICT, NULL)) {
|
||||
#else
|
||||
if (!zend_is_callable(callable, IS_CALLABLE_STRICT, NULL TSRMLS_CC)) {
|
||||
#endif
|
||||
_rar_handle_ext_error("%s" TSRMLS_CC, "Expected the third "
|
||||
"argument, if provided, to be a valid callback");
|
||||
RETURN_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (_rar_create_rararch_obj(resolved_path, password, callable,
|
||||
return_value, &err_code TSRMLS_CC) == FAILURE) {
|
||||
const char *err_str = _rar_error_to_string(err_code);
|
||||
if (err_str == NULL)
|
||||
_rar_handle_ext_error("%s" TSRMLS_CC, "Archive opened failed "
|
||||
"(returned NULL handle), but did not return an error. "
|
||||
"Should not happen.");
|
||||
else {
|
||||
char *preamble;
|
||||
spprintf(&preamble, 0, "Failed to open %s: ", resolved_path);
|
||||
_rar_handle_error_ex(preamble, err_code TSRMLS_CC);
|
||||
efree(preamble);
|
||||
}
|
||||
|
||||
RETURN_FALSE;
|
||||
}
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto array rar_list(RarArchive rarfile)
|
||||
Return entries from the rar archive */
|
||||
PHP_FUNCTION(rar_list)
|
||||
{
|
||||
zval *file = getThis();
|
||||
rar_file_t *rar = NULL;
|
||||
|
||||
RAR_THIS_OR_NO_ARGS(file);
|
||||
|
||||
if (_rar_get_file_resource(file, &rar TSRMLS_CC) == FAILURE) {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
if (_rar_handle_error(_rar_list_files(rar TSRMLS_CC) TSRMLS_CC) == FAILURE)
|
||||
RETURN_FALSE;
|
||||
|
||||
array_init(return_value);
|
||||
|
||||
_rar_raw_entries_to_array(rar, return_value TSRMLS_CC);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto object rar_entry_get(RarArchive rarfile, string filename)
|
||||
Return entry from the rar archive */
|
||||
PHP_FUNCTION(rar_entry_get)
|
||||
{
|
||||
zval *file = getThis();
|
||||
char *filename;
|
||||
rar_file_t *rar = NULL;
|
||||
int filename_len;
|
||||
wchar_t *filename_c = NULL;
|
||||
rar_find_output *sstate;
|
||||
|
||||
if (file == NULL) {
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Os",
|
||||
&file, rararch_ce_ptr, &filename, &filename_len) == FAILURE) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s",
|
||||
&filename, &filename_len) == FAILURE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_rar_get_file_resource(file, &rar TSRMLS_CC) == FAILURE) {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
if (_rar_handle_error(_rar_list_files(rar TSRMLS_CC) TSRMLS_CC) == FAILURE)
|
||||
RETURN_FALSE;
|
||||
|
||||
filename_c = ecalloc(filename_len + 1, sizeof *filename_c);
|
||||
_rar_utf_to_wide(filename, filename_c, filename_len + 1);
|
||||
|
||||
_rar_entry_search_start(rar, RAR_SEARCH_NAME, &sstate TSRMLS_CC);
|
||||
_rar_entry_search_advance(sstate, filename_c, 0, 0);
|
||||
if (sstate->found) {
|
||||
_rar_entry_to_zval(file, sstate->header, sstate->packed_size,
|
||||
sstate->position, return_value TSRMLS_CC);
|
||||
}
|
||||
else {
|
||||
_rar_handle_ext_error(
|
||||
"cannot find file \"%s\" in Rar archive \"%s\""
|
||||
TSRMLS_CC, filename, rar->list_open_data->ArcName);
|
||||
RETVAL_FALSE;
|
||||
}
|
||||
_rar_entry_search_end(sstate);
|
||||
|
||||
efree(filename_c);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto string rar_solid_is(RarArchive rarfile)
|
||||
Return whether RAR archive is solid */
|
||||
PHP_FUNCTION(rar_solid_is)
|
||||
{
|
||||
zval *file = getThis();
|
||||
rar_file_t *rar = NULL;
|
||||
|
||||
RAR_THIS_OR_NO_ARGS(file);
|
||||
|
||||
if (_rar_get_file_resource(file, &rar TSRMLS_CC) == FAILURE) {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
RETURN_BOOL((rar->list_open_data->Flags & 0x0008) != 0);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto string rar_comment_get(RarArchive rarfile)
|
||||
Return comment of the rar archive */
|
||||
PHP_FUNCTION(rar_comment_get)
|
||||
{
|
||||
zval *file = getThis();
|
||||
rar_file_t *rar = NULL;
|
||||
unsigned cmt_state;
|
||||
|
||||
RAR_THIS_OR_NO_ARGS(file);
|
||||
|
||||
if (_rar_get_file_resource(file, &rar TSRMLS_CC) == FAILURE) {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
cmt_state = rar->list_open_data->CmtState;
|
||||
|
||||
if (_rar_handle_error(cmt_state TSRMLS_CC) == FAILURE)
|
||||
RETURN_FALSE;
|
||||
|
||||
if (cmt_state == 0) /* comment not present */
|
||||
RETURN_NULL();
|
||||
|
||||
if (cmt_state == 1) { /* comment read completely */
|
||||
/* CmtSize - 1 because we don't need the null terminator */
|
||||
RETURN_STRINGL(rar->list_open_data->CmtBuf,
|
||||
rar->list_open_data->CmtSize - 1, 1);
|
||||
}
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto bool rar_is_broken(RarArchive rarfile)
|
||||
Check whether a RAR archive is broken */
|
||||
PHP_FUNCTION(rar_broken_is)
|
||||
{
|
||||
zval *file = getThis();
|
||||
rar_file_t *rar = NULL;
|
||||
int result,
|
||||
orig_allow_broken;
|
||||
|
||||
RAR_THIS_OR_NO_ARGS(file);
|
||||
|
||||
if (_rar_get_file_resource(file, &rar TSRMLS_CC) == FAILURE) {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
orig_allow_broken = rar->allow_broken;
|
||||
rar->allow_broken = 0; /* with 1 we'd always get success from list_files */
|
||||
result = _rar_list_files(rar TSRMLS_CC);
|
||||
rar->allow_broken = orig_allow_broken;
|
||||
|
||||
RETURN_BOOL(_rar_error_to_string(result) != NULL);
|
||||
}
|
||||
|
||||
/* {{{ proto bool rar_allow_broken_set(RarArchive rarfile, bool allow_broken)
|
||||
Whether to allow entry retrieval of broken RAR archives */
|
||||
PHP_FUNCTION(rar_allow_broken_set)
|
||||
{
|
||||
zval *file = getThis();
|
||||
rar_file_t *rar = NULL;
|
||||
zend_bool allow_broken;
|
||||
|
||||
if (file == NULL) {
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Ob",
|
||||
&file, rararch_ce_ptr, &allow_broken) == FAILURE) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "b",
|
||||
&allow_broken) == FAILURE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_rar_get_file_resource(file, &rar TSRMLS_CC) == FAILURE) {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
rar->allow_broken = (int) allow_broken;
|
||||
|
||||
RETURN_TRUE;
|
||||
}
|
||||
|
||||
/* {{{ proto bool rar_close(RarArchive rarfile)
|
||||
Close Rar archive and free all resources */
|
||||
PHP_FUNCTION(rar_close)
|
||||
{
|
||||
zval *file = getThis();
|
||||
rar_file_t *rar = NULL;
|
||||
|
||||
RAR_THIS_OR_NO_ARGS(file);
|
||||
|
||||
if (_rar_get_file_resource(file, &rar TSRMLS_CC) == FAILURE) {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
_rar_close_file_resource(rar);
|
||||
|
||||
RETURN_TRUE;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto string RarEntry::__toString()
|
||||
Return string representation for entry */
|
||||
PHP_METHOD(rararch, __toString)
|
||||
{
|
||||
zval *arch_obj = getThis();
|
||||
rar_file_t *rar = NULL;
|
||||
const char format[] = "RAR Archive \"%s\"%s",
|
||||
closed[] = " (closed)";
|
||||
char *restring;
|
||||
size_t restring_size;
|
||||
int is_closed;
|
||||
|
||||
RAR_RETNULL_ON_ARGS();
|
||||
|
||||
if (_rar_get_file_resource_ex(arch_obj, &rar, TRUE TSRMLS_CC) == FAILURE) {
|
||||
RETURN_FALSE; /* should never happen */
|
||||
}
|
||||
|
||||
is_closed = (rar->arch_handle == NULL);
|
||||
|
||||
/* 2 is size of %s, 1 is terminating 0 */
|
||||
restring_size = (sizeof(format) - 1) - 2 * 2 + 1;
|
||||
restring_size += strlen(rar->list_open_data->ArcName);
|
||||
if (is_closed)
|
||||
restring_size += sizeof(closed) - 1;
|
||||
|
||||
restring = emalloc(restring_size);
|
||||
snprintf(restring, restring_size, format, rar->list_open_data->ArcName,
|
||||
is_closed?closed:"");
|
||||
restring[restring_size - 1] = '\0'; /* just to be safe */
|
||||
|
||||
RETURN_STRINGL(restring, (int) restring_size - 1, 0);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ arginfo */
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_rararchive_open, 0, 0, 1)
|
||||
ZEND_ARG_INFO(0, filename)
|
||||
ZEND_ARG_INFO(0, password)
|
||||
ZEND_ARG_INFO(0, volume_callback)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_rararchive_getentry, 0, 0, 1)
|
||||
ZEND_ARG_INFO(0, filename)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_rararchive_setallowbroken, 0, 0, 1)
|
||||
ZEND_ARG_INFO(0, allow_broken)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_INFO(arginfo_rararchive_void, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
/* }}} */
|
||||
|
||||
static zend_function_entry php_rararch_class_functions[] = {
|
||||
PHP_ME_MAPPING(open, rar_open, arginfo_rararchive_open, ZEND_ACC_STATIC | ZEND_ACC_PUBLIC)
|
||||
PHP_ME_MAPPING(getEntries, rar_list, arginfo_rararchive_void, ZEND_ACC_PUBLIC)
|
||||
PHP_ME_MAPPING(getEntry, rar_entry_get, arginfo_rararchive_getentry, ZEND_ACC_PUBLIC)
|
||||
#ifdef RAR_ARCHIVE_LIST_ALIAS
|
||||
PHP_ME_MAPPING(list, rar_list, arginfo_rararchive_void, ZEND_ACC_PUBLIC | ZEND_ACC_DEPRECATED)
|
||||
#endif
|
||||
PHP_ME_MAPPING(isSolid, rar_solid_is, arginfo_rararchive_void, ZEND_ACC_PUBLIC)
|
||||
PHP_ME_MAPPING(getComment, rar_comment_get, arginfo_rararchive_void, ZEND_ACC_PUBLIC)
|
||||
PHP_ME_MAPPING(isBroken, rar_broken_is, arginfo_rararchive_void, ZEND_ACC_PUBLIC)
|
||||
PHP_ME_MAPPING(setAllowBroken, rar_allow_broken_set, arginfo_rararchive_setallowbroken, ZEND_ACC_PUBLIC)
|
||||
PHP_ME_MAPPING(close, rar_close, arginfo_rararchive_void, ZEND_ACC_PUBLIC)
|
||||
PHP_ME(rararch, __toString, arginfo_rararchive_void, ZEND_ACC_PUBLIC)
|
||||
PHP_ME_MAPPING(__construct, rar_bogus_ctor, arginfo_rararchive_void, ZEND_ACC_PRIVATE | ZEND_ACC_CTOR)
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
/* {{{ Iteration. Very boring stuff indeed. */
|
||||
|
||||
/* {{{ Iteration Prototypes */
|
||||
static zend_object_iterator *rararch_it_get_iterator(zend_class_entry *ce,
|
||||
zval *object,
|
||||
int by_ref TSRMLS_DC);
|
||||
/* static void rararch_it_delete_cache(zend_object_iterator *iter TSRMLS_DC); */
|
||||
static void rararch_it_dtor(zend_object_iterator *iter TSRMLS_DC);
|
||||
static void rararch_it_fetch(rararch_iterator *it TSRMLS_DC);
|
||||
static int rararch_it_valid(zend_object_iterator *iter TSRMLS_DC);
|
||||
static void rararch_it_current_data(zend_object_iterator *iter,
|
||||
zval ***data TSRMLS_DC);
|
||||
static void rararch_it_move_forward(zend_object_iterator *iter TSRMLS_DC);
|
||||
static void rararch_it_rewind(zend_object_iterator *iter TSRMLS_DC);
|
||||
/* }}} */
|
||||
|
||||
/* {{{ rararch_it_get_iterator */
|
||||
static zend_object_iterator *rararch_it_get_iterator(zend_class_entry *ce,
|
||||
zval *object,
|
||||
int by_ref TSRMLS_DC)
|
||||
{
|
||||
rararch_iterator *it;
|
||||
rar_file_t *rar;
|
||||
int res;
|
||||
|
||||
if (by_ref) {
|
||||
php_error_docref(NULL TSRMLS_CC, E_ERROR,
|
||||
"An iterator cannot be used with foreach by reference");
|
||||
}
|
||||
|
||||
it = emalloc(sizeof *it);
|
||||
|
||||
res = _rar_get_file_resource_ex(object, &rar, 1 TSRMLS_CC);
|
||||
if (res == FAILURE)
|
||||
php_error_docref(NULL TSRMLS_CC, E_ERROR,
|
||||
"Cannot fetch RarArchive object");
|
||||
if (rar->arch_handle == NULL)
|
||||
php_error_docref(NULL TSRMLS_CC, E_ERROR,
|
||||
"The archive is already closed, cannot give an iterator");
|
||||
res = _rar_list_files(rar TSRMLS_CC);
|
||||
if (_rar_handle_error(res TSRMLS_CC) == FAILURE) {
|
||||
/* if it failed, do not expose the possibly incomplete entry list */
|
||||
it->empty_iterator = 1;
|
||||
}
|
||||
else
|
||||
it->empty_iterator = 0;
|
||||
|
||||
zval_add_ref(&object);
|
||||
it->parent.data = object;
|
||||
it->parent.funcs = ce->iterator_funcs.funcs;
|
||||
_rar_entry_search_start(rar, RAR_SEARCH_TRAVERSE, &it->state TSRMLS_CC);
|
||||
it->value = NULL;
|
||||
return (zend_object_iterator*) it;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ rararch_it_invalidate_current */
|
||||
static void rararch_it_invalidate_current(zend_object_iterator *iter TSRMLS_DC)
|
||||
{
|
||||
rararch_iterator *it = (rararch_iterator *) iter;
|
||||
if (it->value != NULL) {
|
||||
zval_ptr_dtor(&it->value);
|
||||
it->value = NULL;
|
||||
}
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ rararch_it_dtor */
|
||||
static void rararch_it_dtor(zend_object_iterator *iter TSRMLS_DC)
|
||||
{
|
||||
rararch_iterator *it = (rararch_iterator *) iter;
|
||||
|
||||
rararch_it_invalidate_current((zend_object_iterator *) it TSRMLS_CC);
|
||||
|
||||
zval_ptr_dtor((zval**) &it->parent.data); /* decrease refcount on zval object */
|
||||
|
||||
_rar_entry_search_end(it->state);
|
||||
efree(it);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ rararch_it_fetch - populates it->current */
|
||||
static void rararch_it_fetch(rararch_iterator *it TSRMLS_DC)
|
||||
{
|
||||
rar_file_t *rar_file;
|
||||
int res;
|
||||
|
||||
assert(it->value == NULL);
|
||||
|
||||
if (it->empty_iterator) {
|
||||
MAKE_STD_ZVAL(it->value);
|
||||
ZVAL_FALSE(it->value);
|
||||
return;
|
||||
}
|
||||
|
||||
res = _rar_get_file_resource_ex(it->parent.data, &rar_file, 1 TSRMLS_CC);
|
||||
if (res == FAILURE)
|
||||
php_error_docref(NULL TSRMLS_CC, E_ERROR,
|
||||
"Cannot fetch RarArchive object");
|
||||
|
||||
_rar_entry_search_advance(it->state, NULL, 0, 0);
|
||||
MAKE_STD_ZVAL(it->value);
|
||||
if (it->state->found)
|
||||
_rar_entry_to_zval(it->parent.data, it->state->header,
|
||||
it->state->packed_size, it->state->position, it->value TSRMLS_CC);
|
||||
else
|
||||
ZVAL_FALSE(it->value);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ rararch_it_valid */
|
||||
static int rararch_it_valid(zend_object_iterator *iter TSRMLS_DC)
|
||||
{
|
||||
zval *value = ((rararch_iterator *) iter)->value;
|
||||
assert(value != NULL);
|
||||
return (Z_TYPE_P(value) != IS_BOOL)?SUCCESS:FAILURE;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ rararch_it_current_data */
|
||||
static void rararch_it_current_data(zend_object_iterator *iter,
|
||||
zval ***data TSRMLS_DC)
|
||||
{
|
||||
zval **value = &(((rararch_iterator *) iter)->value);
|
||||
assert(*value != NULL);
|
||||
*data = value;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ rararch_it_move_forward */
|
||||
static void rararch_it_move_forward(zend_object_iterator *iter TSRMLS_DC)
|
||||
{
|
||||
rararch_iterator *it = (rararch_iterator *) iter;
|
||||
rararch_it_invalidate_current((zend_object_iterator *) it TSRMLS_CC);
|
||||
it->value = NULL;
|
||||
rararch_it_fetch(it TSRMLS_CC);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ rararch_it_rewind */
|
||||
static void rararch_it_rewind(zend_object_iterator *iter TSRMLS_DC)
|
||||
{
|
||||
rararch_iterator *it = (rararch_iterator *) iter;
|
||||
rararch_it_invalidate_current((zend_object_iterator *) it TSRMLS_CC);
|
||||
_rar_entry_search_rewind(it->state);
|
||||
it->value = NULL;
|
||||
rararch_it_fetch(it TSRMLS_CC);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* iterator handler table */
|
||||
static zend_object_iterator_funcs rararch_it_funcs = {
|
||||
rararch_it_dtor,
|
||||
rararch_it_valid,
|
||||
rararch_it_current_data,
|
||||
NULL,
|
||||
rararch_it_move_forward,
|
||||
rararch_it_rewind,
|
||||
rararch_it_invalidate_current
|
||||
};
|
||||
/* }}} */
|
||||
|
||||
void minit_rararch(TSRMLS_D)
|
||||
{
|
||||
zend_class_entry ce;
|
||||
|
||||
memcpy(&rararch_object_handlers, zend_get_std_object_handlers(),
|
||||
sizeof rararch_object_handlers);
|
||||
rararch_object_handlers.count_elements = rararch_count_elements;
|
||||
rararch_object_handlers.read_dimension = rararch_read_dimension;
|
||||
rararch_object_handlers.write_dimension = rararch_write_dimension;
|
||||
rararch_object_handlers.has_dimension = rararch_has_dimension;
|
||||
rararch_object_handlers.unset_dimension = rararch_unset_dimension;
|
||||
|
||||
INIT_CLASS_ENTRY(ce, "RarArchive", php_rararch_class_functions);
|
||||
rararch_ce_ptr = zend_register_internal_class(&ce TSRMLS_CC);
|
||||
rararch_ce_ptr->ce_flags |= ZEND_ACC_FINAL_CLASS;
|
||||
rararch_ce_ptr->clone = NULL;
|
||||
rararch_ce_ptr->create_object = &rararch_ce_create_object;
|
||||
rararch_ce_ptr->get_iterator = rararch_it_get_iterator;
|
||||
rararch_ce_ptr->iterator_funcs.funcs = &rararch_it_funcs;
|
||||
zend_class_implements(rararch_ce_ptr TSRMLS_CC, 1, zend_ce_traversable);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
722
rarentry.c
Normal file
722
rarentry.c
Normal file
@@ -0,0 +1,722 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2009 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.0 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.php.net/license/3_0.txt. |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
| |
|
||||
| **** WARNING **** |
|
||||
| |
|
||||
| This module makes use of unRAR - free utility for RAR archives. |
|
||||
| Its license states that you MUST NOT use its code to develop |
|
||||
| a RAR (WinRAR) compatible archiver. |
|
||||
| Please, read unRAR license for full information. |
|
||||
| unRAR & RAR copyrights are owned by Eugene Roshal |
|
||||
+----------------------------------------------------------------------+
|
||||
| Author: Antony Dovgal <tony@daylessday.org> |
|
||||
| Author: Gustavo Lopes <cataphract@php.net> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <string.h>
|
||||
|
||||
#include <php.h>
|
||||
#include "php_rar.h"
|
||||
|
||||
/* {{{ Globals with external linkage */
|
||||
zend_class_entry *rar_class_entry_ptr;
|
||||
/* }}} */
|
||||
|
||||
/* {{{ Globals with internal linkage */
|
||||
static zend_object_handlers rarentry_object_handlers;
|
||||
/* }}} */
|
||||
|
||||
/* {{{ Function prototypes for functions with internal linkage */
|
||||
static int _rar_decl_priv_prop_null(zend_class_entry *ce, const char *name,
|
||||
int name_length, char *doc_comment,
|
||||
int doc_comment_len TSRMLS_DC);
|
||||
static zval *_rar_entry_get_property(zval *entry_obj, char *name, int namelen TSRMLS_DC);
|
||||
static void _rar_dos_date_to_text(int dos_time, char *date_string);
|
||||
static zend_object_value rarentry_ce_create_object(zend_class_entry *class_type TSRMLS_DC);
|
||||
/* }}} */
|
||||
|
||||
/* {{{ Functions with external linkage */
|
||||
/* should be passed the last entry that corresponds to a given file
|
||||
* only that one has the correct CRC. Still, it may have a wrong packedSize */
|
||||
void _rar_entry_to_zval(zval *parent, /* zval to RarArchive object, will have its refcount increased */
|
||||
struct RARHeaderDataEx *entry,
|
||||
unsigned long packed_size,
|
||||
size_t position,
|
||||
zval *object TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
char tmp_s [MAX_LENGTH_OF_LONG + 1];
|
||||
char time[50];
|
||||
char *filename;
|
||||
int filename_size, filename_len;
|
||||
long unp_size; /* zval stores PHP ints as long, so use that here */
|
||||
|
||||
object_init_ex(object, rar_class_entry_ptr);
|
||||
zend_update_property(rar_class_entry_ptr, object, "rarfile",
|
||||
sizeof("rararch") - 1, parent TSRMLS_CC);
|
||||
|
||||
#if ULONG_MAX > 0xffffffffUL
|
||||
unp_size = ((long) entry->UnpSize) + (((long) entry->UnpSizeHigh) << 32);
|
||||
#else
|
||||
/* for 32-bit long, at least don't give negative values */
|
||||
if ((unsigned long) entry->UnpSize > (unsigned long) LONG_MAX
|
||||
|| entry->UnpSizeHigh != 0)
|
||||
unp_size = LONG_MAX;
|
||||
else
|
||||
unp_size = (long) entry->UnpSize;
|
||||
#endif
|
||||
|
||||
filename_size = sizeof(entry->FileNameW) * sizeof(wchar_t);
|
||||
filename = (char*) emalloc(filename_size);
|
||||
|
||||
if (packed_size > (unsigned long) LONG_MAX)
|
||||
packed_size = LONG_MAX;
|
||||
_rar_wide_to_utf(entry->FileNameW, filename, filename_size);
|
||||
/* OK; safe usage below: */
|
||||
filename_len = _rar_strnlen(filename, filename_size);
|
||||
/* we're not in class scope, so we cannot change the class private
|
||||
* properties from here with add_property_x, or
|
||||
* direct call to rarentry_object_handlers.write_property
|
||||
* zend_update_property_x updates the scope accordingly */
|
||||
zend_update_property_long(rar_class_entry_ptr, object, "position",
|
||||
sizeof("position") - 1, (long) position TSRMLS_CC);
|
||||
zend_update_property_stringl(rar_class_entry_ptr, object, "name",
|
||||
sizeof("name") - 1, filename, filename_len TSRMLS_CC);
|
||||
zend_update_property_long(rar_class_entry_ptr, object, "unpacked_size",
|
||||
sizeof("unpacked_size") - 1, unp_size TSRMLS_CC);
|
||||
zend_update_property_long(rar_class_entry_ptr, object, "packed_size",
|
||||
sizeof("packed_size") - 1, packed_size TSRMLS_CC);
|
||||
zend_update_property_long(rar_class_entry_ptr, object, "host_os",
|
||||
sizeof("host_os") - 1, entry->HostOS TSRMLS_CC);
|
||||
|
||||
_rar_dos_date_to_text(entry->FileTime, time);
|
||||
zend_update_property_string(rar_class_entry_ptr, object, "file_time",
|
||||
sizeof("file_time") - 1, time TSRMLS_CC);
|
||||
|
||||
sprintf(tmp_s, "%x", entry->FileCRC);
|
||||
zend_update_property_string(rar_class_entry_ptr, object, "crc",
|
||||
sizeof("crc") - 1, tmp_s TSRMLS_CC);
|
||||
|
||||
zend_update_property_long(rar_class_entry_ptr, object, "attr",
|
||||
sizeof("attr") - 1, entry->FileAttr TSRMLS_CC);
|
||||
zend_update_property_long(rar_class_entry_ptr, object, "version",
|
||||
sizeof("version") - 1, entry->UnpVer TSRMLS_CC);
|
||||
zend_update_property_long(rar_class_entry_ptr, object, "method",
|
||||
sizeof("method") - 1, entry->Method TSRMLS_CC);
|
||||
zend_update_property_long(rar_class_entry_ptr, object, "flags",
|
||||
sizeof("flags") - 1, entry->Flags TSRMLS_CC);
|
||||
|
||||
efree(filename);
|
||||
}
|
||||
/* }}} */
|
||||
/* }}} */
|
||||
|
||||
/* {{{ Helper functions and preprocessor definitions */
|
||||
#define RAR_GET_PROPERTY(var, prop_name) \
|
||||
if (!entry_obj) { \
|
||||
php_error_docref(NULL TSRMLS_CC, E_WARNING, "this method cannot be called statically"); \
|
||||
RETURN_FALSE; \
|
||||
} \
|
||||
if ((var = _rar_entry_get_property(entry_obj, prop_name, \
|
||||
sizeof(prop_name) - 1 TSRMLS_CC)) == NULL) { \
|
||||
RETURN_FALSE; \
|
||||
}
|
||||
|
||||
#define REG_RAR_CLASS_CONST_LONG(const_name, value) \
|
||||
zend_declare_class_constant_long(rar_class_entry_ptr, const_name, \
|
||||
sizeof(const_name) - 1, (long) value TSRMLS_CC)
|
||||
|
||||
#define REG_RAR_PROPERTY(name, comment) \
|
||||
_rar_decl_priv_prop_null(rar_class_entry_ptr, name, sizeof(name) -1, \
|
||||
comment, sizeof(comment) - 1 TSRMLS_CC)
|
||||
|
||||
static int _rar_decl_priv_prop_null(zend_class_entry *ce, const char *name,
|
||||
int name_length, char *doc_comment,
|
||||
int doc_comment_len TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
zval *property;
|
||||
ALLOC_PERMANENT_ZVAL(property);
|
||||
INIT_ZVAL(*property);
|
||||
return zend_declare_property_ex(ce, name, name_length, property,
|
||||
ZEND_ACC_PRIVATE, doc_comment, doc_comment_len TSRMLS_CC);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static zval *_rar_entry_get_property(zval *entry_obj, char *name, int namelen TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
zval *tmp;
|
||||
zend_class_entry *orig_scope = EG(scope);
|
||||
|
||||
EG(scope) = rar_class_entry_ptr;
|
||||
|
||||
tmp = zend_read_property(Z_OBJCE_P(entry_obj), entry_obj, name, namelen, 1 TSRMLS_CC);
|
||||
if (tmp == NULL) {
|
||||
php_error_docref(NULL TSRMLS_CC, E_WARNING,
|
||||
"Bug: unable to find property '%s'. Please report.", name);
|
||||
}
|
||||
|
||||
EG(scope) = orig_scope;
|
||||
|
||||
return tmp;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static void _rar_dos_date_to_text(int dos_time, char *date_string) /* {{{ */
|
||||
{
|
||||
int second, minute, hour, day, month, year;
|
||||
/* following lines were taken from timefn.cpp */
|
||||
second = (dos_time & 0x1f)*2;
|
||||
minute = (dos_time>>5) & 0x3f;
|
||||
hour = (dos_time>>11) & 0x1f;
|
||||
day = (dos_time>>16) & 0x1f;
|
||||
month = (dos_time>>21) & 0x0f;
|
||||
year = (dos_time>>25)+1980;
|
||||
sprintf(date_string, "%u-%02u-%02u %02u:%02u:%02u", year, month, day, hour, minute, second);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static zend_object_value rarentry_ce_create_object(zend_class_entry *class_type TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
zend_object_value zov;
|
||||
zend_object *zobj;
|
||||
|
||||
zobj = emalloc(sizeof *zobj);
|
||||
zend_object_std_init(zobj, class_type TSRMLS_CC);
|
||||
|
||||
#if PHP_VERSION_ID < 50399
|
||||
zend_hash_copy(zobj->properties, &(class_type->default_properties),
|
||||
(copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval*));
|
||||
#else
|
||||
object_properties_init(zobj, class_type);
|
||||
#endif
|
||||
zov.handle = zend_objects_store_put(zobj,
|
||||
(zend_objects_store_dtor_t) zend_objects_destroy_object,
|
||||
(zend_objects_free_object_storage_t) zend_objects_free_object_storage,
|
||||
NULL TSRMLS_CC);
|
||||
zov.handlers = &rarentry_object_handlers;
|
||||
return zov;
|
||||
}
|
||||
/* }}} */
|
||||
/* }}} */
|
||||
|
||||
/* {{{ Methods */
|
||||
/* {{{ proto bool RarEntry::extract(string dir [, string filepath = ''
|
||||
[, string password = NULL [, bool extended_data = FALSE]])
|
||||
Extract file from the archive */
|
||||
PHP_METHOD(rarentry, extract)
|
||||
{ /* lots of variables, but no need to be intimidated */
|
||||
char *dir,
|
||||
*filepath = NULL,
|
||||
*password = NULL;
|
||||
int dir_len,
|
||||
filepath_len = 0,
|
||||
password_len = 0;
|
||||
char *considered_path;
|
||||
char considered_path_res[MAXPATHLEN];
|
||||
int with_second_arg;
|
||||
zend_bool process_ed = 0;
|
||||
|
||||
zval *tmp,
|
||||
*tmp_position;
|
||||
rar_file_t *rar = NULL;
|
||||
zval *entry_obj = getThis();
|
||||
struct RARHeaderDataEx entry;
|
||||
HANDLE extract_handle = NULL;
|
||||
int result;
|
||||
int found;
|
||||
/* gotta have a new copy (shallow is enough) because we may want to use a
|
||||
* password that's different from the one stored in the rar_file_t object*/
|
||||
rar_cb_user_data cb_udata = {NULL};
|
||||
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ss!b", &dir,
|
||||
&dir_len, &filepath, &filepath_len, &password, &password_len,
|
||||
&process_ed) == FAILURE ) {
|
||||
return;
|
||||
}
|
||||
|
||||
RAR_GET_PROPERTY(tmp, "rarfile");
|
||||
if (_rar_get_file_resource(tmp, &rar TSRMLS_CC) == FAILURE) {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
/* Decide where to extract */
|
||||
with_second_arg = (filepath_len != 0);
|
||||
|
||||
/* the arguments are mutually exclusive.
|
||||
* If the second is specified, we ignore the first */
|
||||
if (!with_second_arg) {
|
||||
if (dir_len == 0) /* both params empty */
|
||||
dir = ".";
|
||||
considered_path = dir;
|
||||
}
|
||||
else {
|
||||
considered_path = filepath;
|
||||
}
|
||||
|
||||
if (OPENBASEDIR_CHECKPATH(considered_path)) {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
if (!expand_filepath(considered_path, considered_path_res TSRMLS_CC)) {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
/* Find file inside archive */
|
||||
RAR_GET_PROPERTY(tmp_position, "position");
|
||||
|
||||
/* don't set the new password now because maybe the headers are
|
||||
* encrypted with a password different from this file's (though WinRAR
|
||||
* does not support that: if you encrypt the headers, you must encrypt
|
||||
* the files with the same password). By not replacing the password
|
||||
* now, we're using the password given to rar_open, if any (which must
|
||||
* have enabled decrypting the headers or else we wouldn't be here) */
|
||||
memcpy(&cb_udata, &rar->cb_userdata, sizeof cb_udata);
|
||||
|
||||
result = _rar_find_file_p(rar->extract_open_data,
|
||||
(size_t) Z_LVAL_P(tmp_position), &cb_udata, &extract_handle, &found,
|
||||
&entry);
|
||||
|
||||
if (_rar_handle_error(result TSRMLS_CC) == FAILURE) {
|
||||
RETVAL_FALSE;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
_rar_handle_ext_error("Can't find file with index %d in archive %s"
|
||||
TSRMLS_CC, Z_LVAL_P(tmp_position),
|
||||
rar->extract_open_data->ArcName);
|
||||
RETVAL_FALSE;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
RARSetProcessExtendedData(extract_handle, (int) process_ed);
|
||||
|
||||
/* now use the password given to this method. If none was given, we're
|
||||
* still stuck with the password given to rar_open, if any */
|
||||
if (password != NULL)
|
||||
cb_udata.password = password;
|
||||
|
||||
/* Do extraction */
|
||||
if (!with_second_arg)
|
||||
result = RARProcessFile(extract_handle, RAR_EXTRACT,
|
||||
considered_path_res, NULL);
|
||||
else
|
||||
result = RARProcessFile(extract_handle, RAR_EXTRACT,
|
||||
NULL, considered_path_res);
|
||||
|
||||
if (_rar_handle_error(result TSRMLS_CC) == FAILURE) {
|
||||
RETVAL_FALSE;
|
||||
}
|
||||
else {
|
||||
RETVAL_TRUE;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
if (extract_handle != NULL)
|
||||
RARCloseArchive(extract_handle);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto int RarEntry::getPosiiton()
|
||||
Return position for the entry */
|
||||
PHP_METHOD(rarentry, getPosition)
|
||||
{
|
||||
zval *tmp;
|
||||
zval *entry_obj = getThis();
|
||||
|
||||
RAR_RETNULL_ON_ARGS();
|
||||
|
||||
RAR_GET_PROPERTY(tmp, "position");
|
||||
|
||||
RETURN_LONG(Z_LVAL_P(tmp));
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto string RarEntry::getName()
|
||||
Return entry name */
|
||||
PHP_METHOD(rarentry, getName)
|
||||
{
|
||||
zval *tmp;
|
||||
zval *entry_obj = getThis();
|
||||
|
||||
RAR_RETNULL_ON_ARGS();
|
||||
|
||||
RAR_GET_PROPERTY(tmp, "name");
|
||||
|
||||
RETURN_STRINGL(Z_STRVAL_P(tmp), Z_STRLEN_P(tmp), 1);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto int RarEntry::getUnpackedSize()
|
||||
Return unpacked size of the entry */
|
||||
PHP_METHOD(rarentry, getUnpackedSize)
|
||||
{
|
||||
zval *tmp;
|
||||
zval *entry_obj = getThis();
|
||||
|
||||
RAR_RETNULL_ON_ARGS();
|
||||
|
||||
RAR_GET_PROPERTY(tmp, "unpacked_size");
|
||||
|
||||
RETURN_LONG(Z_LVAL_P(tmp));
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto int RarEntry::getPackedSize()
|
||||
Return packed size of the entry */
|
||||
PHP_METHOD(rarentry, getPackedSize)
|
||||
{
|
||||
zval *tmp;
|
||||
zval *entry_obj = getThis();
|
||||
|
||||
RAR_RETNULL_ON_ARGS();
|
||||
|
||||
RAR_GET_PROPERTY(tmp, "packed_size");
|
||||
|
||||
RETURN_LONG(Z_LVAL_P(tmp));
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto int RarEntry::getHostOs()
|
||||
Return host OS of the entry */
|
||||
PHP_METHOD(rarentry, getHostOs)
|
||||
{
|
||||
zval *tmp;
|
||||
zval *entry_obj = getThis();
|
||||
|
||||
RAR_RETNULL_ON_ARGS();
|
||||
|
||||
RAR_GET_PROPERTY(tmp, "host_os");
|
||||
|
||||
RETURN_LONG(Z_LVAL_P(tmp));
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto string RarEntry::getFileTime()
|
||||
Return modification time of the entry.
|
||||
Due to the way the unrar library returns this time, this is in the
|
||||
system's timezone. */
|
||||
PHP_METHOD(rarentry, getFileTime)
|
||||
{
|
||||
zval *tmp;
|
||||
zval *entry_obj = getThis();
|
||||
|
||||
RAR_RETNULL_ON_ARGS();
|
||||
|
||||
RAR_GET_PROPERTY(tmp, "file_time");
|
||||
|
||||
RETURN_STRINGL(Z_STRVAL_P(tmp), Z_STRLEN_P(tmp), 1);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto string RarEntry::getCrc()
|
||||
Return CRC of the entry */
|
||||
PHP_METHOD(rarentry, getCrc)
|
||||
{
|
||||
zval *tmp;
|
||||
zval *entry_obj = getThis();
|
||||
|
||||
RAR_RETNULL_ON_ARGS();
|
||||
|
||||
RAR_GET_PROPERTY(tmp, "crc");
|
||||
|
||||
RETURN_STRINGL(Z_STRVAL_P(tmp), Z_STRLEN_P(tmp), 1);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto int RarEntry::getAttr()
|
||||
Return attributes of the entry */
|
||||
PHP_METHOD(rarentry, getAttr)
|
||||
{
|
||||
zval *tmp;
|
||||
zval *entry_obj = getThis();
|
||||
|
||||
RAR_RETNULL_ON_ARGS();
|
||||
|
||||
RAR_GET_PROPERTY(tmp, "attr");
|
||||
|
||||
RETURN_LONG(Z_LVAL_P(tmp));
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto int RarEntry::getVersion()
|
||||
Return version of the archiver, used to create this entry */
|
||||
PHP_METHOD(rarentry, getVersion)
|
||||
{
|
||||
zval *tmp;
|
||||
zval *entry_obj = getThis();
|
||||
|
||||
RAR_RETNULL_ON_ARGS();
|
||||
|
||||
RAR_GET_PROPERTY(tmp, "version");
|
||||
|
||||
RETURN_LONG(Z_LVAL_P(tmp));
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto int RarEntry::getMethod()
|
||||
Return packing method */
|
||||
PHP_METHOD(rarentry, getMethod)
|
||||
{
|
||||
zval *tmp;
|
||||
zval *entry_obj = getThis();
|
||||
|
||||
RAR_RETNULL_ON_ARGS();
|
||||
|
||||
RAR_GET_PROPERTY(tmp, "method");
|
||||
|
||||
RETURN_LONG(Z_LVAL_P(tmp));
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto resource RarEntry::getStream([string password = NULL])
|
||||
Return stream for current entry */
|
||||
PHP_METHOD(rarentry, getStream)
|
||||
{
|
||||
zval *tmp,
|
||||
*position;
|
||||
rar_file_t *rar = NULL;
|
||||
zval *entry_obj = getThis();
|
||||
php_stream *stream = NULL;
|
||||
char *password = NULL;
|
||||
int password_len; /* ignored */
|
||||
rar_cb_user_data cb_udata = {NULL};
|
||||
|
||||
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!",
|
||||
&password, &password_len) == FAILURE ) {
|
||||
return;
|
||||
}
|
||||
|
||||
RAR_GET_PROPERTY(position, "position");
|
||||
RAR_GET_PROPERTY(tmp, "rarfile");
|
||||
if (_rar_get_file_resource(tmp, &rar TSRMLS_CC) == FAILURE) {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
/* use rar_open password (stored in rar->cb_userdata) by default */
|
||||
memcpy(&cb_udata, &rar->cb_userdata, sizeof cb_udata);
|
||||
if (password != NULL)
|
||||
cb_udata.password = password;
|
||||
|
||||
/* doesn't matter that cb_udata is stack allocated, it will be copied */
|
||||
stream = php_stream_rar_open(rar->extract_open_data->ArcName,
|
||||
Z_LVAL_P(position), &cb_udata STREAMS_CC TSRMLS_CC);
|
||||
|
||||
if (stream != NULL) {
|
||||
php_stream_to_zval(stream, return_value);
|
||||
}
|
||||
else
|
||||
RETVAL_FALSE;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto int RarEntry::isDirectory()
|
||||
Return whether the entry represents a directory */
|
||||
PHP_METHOD(rarentry, isDirectory)
|
||||
{
|
||||
zval *tmp;
|
||||
zval *entry_obj = getThis();
|
||||
long flags;
|
||||
int is_dir;
|
||||
|
||||
RAR_RETNULL_ON_ARGS();
|
||||
|
||||
RAR_GET_PROPERTY(tmp, "flags");
|
||||
flags = Z_LVAL_P(tmp);
|
||||
is_dir = (flags & RHDF_DIRECTORY) != 0;
|
||||
|
||||
RETURN_BOOL(is_dir);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto int RarEntry::isEncrypted()
|
||||
Return whether the entry is encrypted and needs a password */
|
||||
PHP_METHOD(rarentry, isEncrypted)
|
||||
{
|
||||
zval *tmp;
|
||||
zval *entry_obj = getThis();
|
||||
long flags;
|
||||
int is_encrypted;
|
||||
|
||||
RAR_RETNULL_ON_ARGS();
|
||||
|
||||
RAR_GET_PROPERTY(tmp, "flags");
|
||||
flags = Z_LVAL_P(tmp);
|
||||
is_encrypted = (flags & RHDF_ENCRYPTED) != 0;
|
||||
|
||||
RETURN_BOOL(is_encrypted);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto string RarEntry::__toString()
|
||||
Return string representation for entry */
|
||||
PHP_METHOD(rarentry, __toString)
|
||||
{
|
||||
zval *flags_zval,
|
||||
*name_zval,
|
||||
*crc_zval;
|
||||
zval *entry_obj = getThis();
|
||||
long flags;
|
||||
int is_dir;
|
||||
char *name,
|
||||
*crc;
|
||||
char *restring;
|
||||
int restring_len;
|
||||
const char format[] = "RarEntry for %s \"%s\" (%s)";
|
||||
|
||||
RAR_RETNULL_ON_ARGS();
|
||||
|
||||
RAR_GET_PROPERTY(flags_zval, "flags");
|
||||
flags = Z_LVAL_P(flags_zval);
|
||||
is_dir = flags & RHDF_DIRECTORY;
|
||||
|
||||
RAR_GET_PROPERTY(name_zval, "name");
|
||||
name = Z_STRVAL_P(name_zval);
|
||||
|
||||
RAR_GET_PROPERTY(crc_zval, "crc");
|
||||
crc = Z_STRVAL_P(crc_zval);
|
||||
|
||||
/* 2 is size of %s, 8 is size of crc */
|
||||
restring_len = (sizeof(format)-1) - 2 * 3 + (sizeof("directory")-1) +
|
||||
strlen(name) + 8 + 1;
|
||||
restring = emalloc(restring_len);
|
||||
snprintf(restring, restring_len, format, is_dir?"directory":"file",
|
||||
name, crc);
|
||||
restring[restring_len - 1] = '\0'; /* just to be safe */
|
||||
|
||||
RETURN_STRING(restring, 0);
|
||||
}
|
||||
/* }}} */
|
||||
/* }}} */
|
||||
|
||||
/* {{{ arginfo */
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_rarentry_extract, 0, 0, 1)
|
||||
ZEND_ARG_INFO(0, path)
|
||||
ZEND_ARG_INFO(0, filename)
|
||||
ZEND_ARG_INFO(0, password)
|
||||
ZEND_ARG_INFO(0, extended_data)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_rarentry_getstream, 0, 0, 0)
|
||||
ZEND_ARG_INFO(0, password)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_INFO(arginfo_rar_void, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
/* }}} */
|
||||
|
||||
static zend_function_entry php_rar_class_functions[] = {
|
||||
PHP_ME(rarentry, extract, arginfo_rarentry_extract, ZEND_ACC_PUBLIC)
|
||||
PHP_ME(rarentry, getPosition, arginfo_rar_void, ZEND_ACC_PUBLIC)
|
||||
PHP_ME(rarentry, getName, arginfo_rar_void, ZEND_ACC_PUBLIC)
|
||||
PHP_ME(rarentry, getUnpackedSize, arginfo_rar_void, ZEND_ACC_PUBLIC)
|
||||
PHP_ME(rarentry, getPackedSize, arginfo_rar_void, ZEND_ACC_PUBLIC)
|
||||
PHP_ME(rarentry, getHostOs, arginfo_rar_void, ZEND_ACC_PUBLIC)
|
||||
PHP_ME(rarentry, getFileTime, arginfo_rar_void, ZEND_ACC_PUBLIC)
|
||||
PHP_ME(rarentry, getCrc, arginfo_rar_void, ZEND_ACC_PUBLIC)
|
||||
PHP_ME(rarentry, getAttr, arginfo_rar_void, ZEND_ACC_PUBLIC)
|
||||
PHP_ME(rarentry, getVersion, arginfo_rar_void, ZEND_ACC_PUBLIC)
|
||||
PHP_ME(rarentry, getMethod, arginfo_rar_void, ZEND_ACC_PUBLIC)
|
||||
PHP_ME(rarentry, getStream, arginfo_rarentry_getstream, ZEND_ACC_PUBLIC)
|
||||
PHP_ME(rarentry, isDirectory, arginfo_rar_void, ZEND_ACC_PUBLIC)
|
||||
PHP_ME(rarentry, isEncrypted, arginfo_rar_void, ZEND_ACC_PUBLIC)
|
||||
PHP_ME(rarentry, __toString, arginfo_rar_void, ZEND_ACC_PUBLIC)
|
||||
PHP_ME_MAPPING(__construct, rar_bogus_ctor, arginfo_rar_void, ZEND_ACC_PRIVATE | ZEND_ACC_CTOR)
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
void minit_rarentry(TSRMLS_D)
|
||||
{
|
||||
zend_class_entry ce;
|
||||
|
||||
memcpy(&rarentry_object_handlers, zend_get_std_object_handlers(),
|
||||
sizeof rarentry_object_handlers);
|
||||
|
||||
INIT_CLASS_ENTRY(ce, "RarEntry", php_rar_class_functions);
|
||||
rar_class_entry_ptr = zend_register_internal_class(&ce TSRMLS_CC);
|
||||
rar_class_entry_ptr->ce_flags |= ZEND_ACC_FINAL_CLASS;
|
||||
rar_class_entry_ptr->clone = NULL;
|
||||
/* Custom creation currently not really needed, but you never know... */
|
||||
rar_class_entry_ptr->create_object = &rarentry_ce_create_object;
|
||||
|
||||
REG_RAR_PROPERTY("rarfile", "Associated RAR archive");
|
||||
REG_RAR_PROPERTY("position", "Position inside the RAR archive");
|
||||
REG_RAR_PROPERTY("name", "File or directory name with path");
|
||||
REG_RAR_PROPERTY("unpacked_size", "Size of file when unpacked");
|
||||
REG_RAR_PROPERTY("packed_size", "Size of the packed file inside the archive");
|
||||
REG_RAR_PROPERTY("host_os", "OS used to pack the file");
|
||||
REG_RAR_PROPERTY("file_time", "Entry's time of last modification");
|
||||
REG_RAR_PROPERTY("crc", "CRC checksum for the unpacked file");
|
||||
REG_RAR_PROPERTY("attr", "OS-dependent file attributes");
|
||||
REG_RAR_PROPERTY("version", "RAR version needed to extract entry");
|
||||
REG_RAR_PROPERTY("method", "Identifier for packing method");
|
||||
REG_RAR_PROPERTY("flags", "Entry header flags");
|
||||
|
||||
REG_RAR_CLASS_CONST_LONG("HOST_MSDOS", HOST_MSDOS);
|
||||
REG_RAR_CLASS_CONST_LONG("HOST_OS2", HOST_OS2);
|
||||
REG_RAR_CLASS_CONST_LONG("HOST_WIN32", HOST_WIN32);
|
||||
REG_RAR_CLASS_CONST_LONG("HOST_UNIX", HOST_UNIX);
|
||||
REG_RAR_CLASS_CONST_LONG("HOST_MACOS", HOST_MACOS);
|
||||
REG_RAR_CLASS_CONST_LONG("HOST_BEOS", HOST_BEOS);
|
||||
|
||||
/* see WinNT.h */
|
||||
REG_RAR_CLASS_CONST_LONG("ATTRIBUTE_WIN_READONLY", 0x00001L);
|
||||
REG_RAR_CLASS_CONST_LONG("ATTRIBUTE_WIN_HIDDEN", 0x00002L);
|
||||
REG_RAR_CLASS_CONST_LONG("ATTRIBUTE_WIN_SYSTEM", 0x00004L);
|
||||
REG_RAR_CLASS_CONST_LONG("ATTRIBUTE_WIN_DIRECTORY", 0x00010L);
|
||||
REG_RAR_CLASS_CONST_LONG("ATTRIBUTE_WIN_ARCHIVE", 0x00020L);
|
||||
REG_RAR_CLASS_CONST_LONG("ATTRIBUTE_WIN_DEVICE", 0x00040L);
|
||||
REG_RAR_CLASS_CONST_LONG("ATTRIBUTE_WIN_NORMAL", 0x00080L);
|
||||
REG_RAR_CLASS_CONST_LONG("ATTRIBUTE_WIN_TEMPORARY", 0x00100L);
|
||||
REG_RAR_CLASS_CONST_LONG("ATTRIBUTE_WIN_SPARSE_FILE", 0x00200L);
|
||||
REG_RAR_CLASS_CONST_LONG("ATTRIBUTE_WIN_REPARSE_POINT", 0x00400L);
|
||||
REG_RAR_CLASS_CONST_LONG("ATTRIBUTE_WIN_COMPRESSED", 0x00800L);
|
||||
REG_RAR_CLASS_CONST_LONG("ATTRIBUTE_WIN_OFFLINE", 0x01000L);
|
||||
REG_RAR_CLASS_CONST_LONG("ATTRIBUTE_WIN_NOT_CONTENT_INDEXED", 0x02000L);
|
||||
REG_RAR_CLASS_CONST_LONG("ATTRIBUTE_WIN_ENCRYPTED", 0x04000L);
|
||||
REG_RAR_CLASS_CONST_LONG("ATTRIBUTE_WIN_VIRTUAL", 0x10000L);
|
||||
|
||||
REG_RAR_CLASS_CONST_LONG("ATTRIBUTE_UNIX_WORLD_EXECUTE", 0x00001L);
|
||||
REG_RAR_CLASS_CONST_LONG("ATTRIBUTE_UNIX_WORLD_WRITE", 0x00002L);
|
||||
REG_RAR_CLASS_CONST_LONG("ATTRIBUTE_UNIX_WORLD_READ", 0x00004L);
|
||||
REG_RAR_CLASS_CONST_LONG("ATTRIBUTE_UNIX_GROUP_EXECUTE", 0x00008L);
|
||||
REG_RAR_CLASS_CONST_LONG("ATTRIBUTE_UNIX_GROUP_WRITE", 0x00010L);
|
||||
REG_RAR_CLASS_CONST_LONG("ATTRIBUTE_UNIX_GROUP_READ", 0x00020L);
|
||||
REG_RAR_CLASS_CONST_LONG("ATTRIBUTE_UNIX_OWNER_EXECUTE", 0x00040L);
|
||||
REG_RAR_CLASS_CONST_LONG("ATTRIBUTE_UNIX_OWNER_WRITE", 0x00080L);
|
||||
REG_RAR_CLASS_CONST_LONG("ATTRIBUTE_UNIX_OWNER_READ", 0x00100L);
|
||||
REG_RAR_CLASS_CONST_LONG("ATTRIBUTE_UNIX_STICKY", 0x00200L);
|
||||
REG_RAR_CLASS_CONST_LONG("ATTRIBUTE_UNIX_SETGID", 0x00400L);
|
||||
REG_RAR_CLASS_CONST_LONG("ATTRIBUTE_UNIX_SETUID", 0x00800L);
|
||||
|
||||
REG_RAR_CLASS_CONST_LONG("ATTRIBUTE_UNIX_FINAL_QUARTET", 0x0F000L);
|
||||
REG_RAR_CLASS_CONST_LONG("ATTRIBUTE_UNIX_FIFO", 0x01000L);
|
||||
REG_RAR_CLASS_CONST_LONG("ATTRIBUTE_UNIX_CHAR_DEV", 0x02000L);
|
||||
REG_RAR_CLASS_CONST_LONG("ATTRIBUTE_UNIX_DIRECTORY", 0x04000L);
|
||||
REG_RAR_CLASS_CONST_LONG("ATTRIBUTE_UNIX_BLOCK_DEV", 0x06000L);
|
||||
REG_RAR_CLASS_CONST_LONG("ATTRIBUTE_UNIX_REGULAR_FILE", 0x08000L);
|
||||
REG_RAR_CLASS_CONST_LONG("ATTRIBUTE_UNIX_SYM_LINK", 0x0A000L);
|
||||
REG_RAR_CLASS_CONST_LONG("ATTRIBUTE_UNIX_SOCKET", 0x0C000L);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
275
technote.txt
Normal file
275
technote.txt
Normal file
@@ -0,0 +1,275 @@
|
||||
|
||||
RAR version 3.93 - Technical information
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
THE ARCHIVE FORMAT DESCRIBED BELOW IS ONLY VALID FOR VERSIONS SINCE 1.50
|
||||
|
||||
==========================================================================
|
||||
RAR archive file format
|
||||
==========================================================================
|
||||
|
||||
Archive file consists of variable length blocks. The order of these
|
||||
blocks may vary, but the first block must be a marker block followed by
|
||||
an archive header block.
|
||||
|
||||
Each block begins with the following fields:
|
||||
|
||||
HEAD_CRC 2 bytes CRC of total block or block part
|
||||
HEAD_TYPE 1 byte Block type
|
||||
HEAD_FLAGS 2 bytes Block flags
|
||||
HEAD_SIZE 2 bytes Block size
|
||||
ADD_SIZE 4 bytes Optional field - added block size
|
||||
|
||||
Field ADD_SIZE present only if (HEAD_FLAGS & 0x8000) != 0
|
||||
|
||||
Total block size is HEAD_SIZE if (HEAD_FLAGS & 0x8000) == 0
|
||||
and HEAD_SIZE+ADD_SIZE if the field ADD_SIZE is present - when
|
||||
(HEAD_FLAGS & 0x8000) != 0.
|
||||
|
||||
In each block the followings bits in HEAD_FLAGS have the same meaning:
|
||||
|
||||
0x4000 - if set, older RAR versions will ignore the block
|
||||
and remove it when the archive is updated.
|
||||
if clear, the block is copied to the new archive
|
||||
file when the archive is updated;
|
||||
|
||||
0x8000 - if set, ADD_SIZE field is present and the full block
|
||||
size is HEAD_SIZE+ADD_SIZE.
|
||||
|
||||
Declared block types:
|
||||
|
||||
HEAD_TYPE=0x72 marker block
|
||||
HEAD_TYPE=0x73 archive header
|
||||
HEAD_TYPE=0x74 file header
|
||||
HEAD_TYPE=0x75 old style comment header
|
||||
HEAD_TYPE=0x76 old style authenticity information
|
||||
HEAD_TYPE=0x77 old style subblock
|
||||
HEAD_TYPE=0x78 old style recovery record
|
||||
HEAD_TYPE=0x79 old style authenticity information
|
||||
HEAD_TYPE=0x7a subblock
|
||||
|
||||
Comment block is actually used only within other blocks and doesn't
|
||||
exist separately.
|
||||
|
||||
Archive processing is made in the following manner:
|
||||
|
||||
1. Read and check marker block
|
||||
2. Read archive header
|
||||
3. Read or skip HEAD_SIZE-sizeof(MAIN_HEAD) bytes
|
||||
4. If end of archive encountered then terminate archive processing,
|
||||
else read 7 bytes into fields HEAD_CRC, HEAD_TYPE, HEAD_FLAGS,
|
||||
HEAD_SIZE.
|
||||
5. Check HEAD_TYPE.
|
||||
if HEAD_TYPE==0x74
|
||||
read file header ( first 7 bytes already read )
|
||||
read or skip HEAD_SIZE-sizeof(FILE_HEAD) bytes
|
||||
if (HEAD_FLAGS & 0x100)
|
||||
read or skip HIGH_PACK_SIZE*0x100000000+PACK_SIZE bytes
|
||||
else
|
||||
read or skip PACK_SIZE bytes
|
||||
else
|
||||
read corresponding HEAD_TYPE block:
|
||||
read HEAD_SIZE-7 bytes
|
||||
if (HEAD_FLAGS & 0x8000)
|
||||
read ADD_SIZE bytes
|
||||
6. go to 4.
|
||||
|
||||
|
||||
==========================================================================
|
||||
Block Formats
|
||||
==========================================================================
|
||||
|
||||
|
||||
Marker block ( MARK_HEAD )
|
||||
|
||||
|
||||
HEAD_CRC Always 0x6152
|
||||
2 bytes
|
||||
|
||||
HEAD_TYPE Header type: 0x72
|
||||
1 byte
|
||||
|
||||
HEAD_FLAGS Always 0x1a21
|
||||
2 bytes
|
||||
|
||||
HEAD_SIZE Block size = 0x0007
|
||||
2 bytes
|
||||
|
||||
The marker block is actually considered as a fixed byte
|
||||
sequence: 0x52 0x61 0x72 0x21 0x1a 0x07 0x00
|
||||
|
||||
|
||||
|
||||
Archive header ( MAIN_HEAD )
|
||||
|
||||
|
||||
HEAD_CRC CRC of fields HEAD_TYPE to RESERVED2
|
||||
2 bytes
|
||||
|
||||
HEAD_TYPE Header type: 0x73
|
||||
1 byte
|
||||
|
||||
HEAD_FLAGS Bit flags:
|
||||
2 bytes
|
||||
0x0001 - Volume attribute (archive volume)
|
||||
0x0002 - Archive comment present
|
||||
RAR 3.x uses the separate comment block
|
||||
and does not set this flag.
|
||||
|
||||
0x0004 - Archive lock attribute
|
||||
0x0008 - Solid attribute (solid archive)
|
||||
0x0010 - New volume naming scheme ('volname.partN.rar')
|
||||
0x0020 - Authenticity information present
|
||||
RAR 3.x does not set this flag.
|
||||
|
||||
0x0040 - Recovery record present
|
||||
0x0080 - Block headers are encrypted
|
||||
0x0100 - First volume (set only by RAR 3.0 and later)
|
||||
|
||||
other bits in HEAD_FLAGS are reserved for
|
||||
internal use
|
||||
|
||||
HEAD_SIZE Archive header total size including archive comments
|
||||
2 bytes
|
||||
|
||||
RESERVED1 Reserved
|
||||
2 bytes
|
||||
|
||||
RESERVED2 Reserved
|
||||
4 bytes
|
||||
|
||||
|
||||
|
||||
File header (File in archive)
|
||||
|
||||
|
||||
HEAD_CRC CRC of fields from HEAD_TYPE to FILEATTR
|
||||
2 bytes and file name
|
||||
|
||||
HEAD_TYPE Header type: 0x74
|
||||
1 byte
|
||||
|
||||
HEAD_FLAGS Bit flags:
|
||||
2 bytes
|
||||
0x01 - file continued from previous volume
|
||||
0x02 - file continued in next volume
|
||||
0x04 - file encrypted with password
|
||||
|
||||
0x08 - file comment present
|
||||
RAR 3.x uses the separate comment block
|
||||
and does not set this flag.
|
||||
|
||||
0x10 - information from previous files is used (solid flag)
|
||||
(for RAR 2.0 and later)
|
||||
|
||||
bits 7 6 5 (for RAR 2.0 and later)
|
||||
|
||||
0 0 0 - dictionary size 64 KB
|
||||
0 0 1 - dictionary size 128 KB
|
||||
0 1 0 - dictionary size 256 KB
|
||||
0 1 1 - dictionary size 512 KB
|
||||
1 0 0 - dictionary size 1024 KB
|
||||
1 0 1 - dictionary size 2048 KB
|
||||
1 1 0 - dictionary size 4096 KB
|
||||
1 1 1 - file is directory
|
||||
|
||||
0x100 - HIGH_PACK_SIZE and HIGH_UNP_SIZE fields
|
||||
are present. These fields are used to archive
|
||||
only very large files (larger than 2Gb),
|
||||
for smaller files these fields are absent.
|
||||
|
||||
0x200 - FILE_NAME contains both usual and encoded
|
||||
Unicode name separated by zero. In this case
|
||||
NAME_SIZE field is equal to the length
|
||||
of usual name plus encoded Unicode name plus 1.
|
||||
|
||||
If this flag is present, but FILE_NAME does not
|
||||
contain zero bytes, it means that file name
|
||||
is encoded using UTF-8.
|
||||
|
||||
0x400 - the header contains additional 8 bytes
|
||||
after the file name, which are required to
|
||||
increase encryption security (so called 'salt').
|
||||
|
||||
0x800 - Version flag. It is an old file version,
|
||||
a version number is appended to file name as ';n'.
|
||||
|
||||
0x1000 - Extended time field present.
|
||||
|
||||
0x8000 - this bit always is set, so the complete
|
||||
block size is HEAD_SIZE + PACK_SIZE
|
||||
(and plus HIGH_PACK_SIZE, if bit 0x100 is set)
|
||||
|
||||
HEAD_SIZE File header full size including file name and comments
|
||||
2 bytes
|
||||
|
||||
PACK_SIZE Compressed file size
|
||||
4 bytes
|
||||
|
||||
UNP_SIZE Uncompressed file size
|
||||
4 bytes
|
||||
|
||||
HOST_OS Operating system used for archiving
|
||||
1 byte 0 - MS DOS
|
||||
1 - OS/2
|
||||
2 - Win32
|
||||
3 - Unix
|
||||
4 - Mac OS
|
||||
5 - BeOS
|
||||
|
||||
FILE_CRC File CRC
|
||||
4 bytes
|
||||
|
||||
FTIME Date and time in standard MS DOS format
|
||||
4 bytes
|
||||
|
||||
UNP_VER RAR version needed to extract file
|
||||
1 byte
|
||||
Version number is encoded as
|
||||
10 * Major version + minor version.
|
||||
|
||||
METHOD Packing method
|
||||
1 byte
|
||||
0x30 - storing
|
||||
0x31 - fastest compression
|
||||
0x32 - fast compression
|
||||
0x33 - normal compression
|
||||
0x34 - good compression
|
||||
0x35 - best compression
|
||||
|
||||
NAME_SIZE File name size
|
||||
2 bytes
|
||||
|
||||
ATTR File attributes
|
||||
4 bytes
|
||||
|
||||
HIGH_PACK_SIZE High 4 bytes of 64 bit value of compressed file size.
|
||||
4 bytes Optional value, presents only if bit 0x100 in HEAD_FLAGS
|
||||
is set.
|
||||
|
||||
HIGH_UNP_SIZE High 4 bytes of 64 bit value of uncompressed file size.
|
||||
4 bytes Optional value, presents only if bit 0x100 in HEAD_FLAGS
|
||||
is set.
|
||||
|
||||
FILE_NAME File name - string of NAME_SIZE bytes size
|
||||
|
||||
SALT present if (HEAD_FLAGS & 0x400) != 0
|
||||
8 bytes
|
||||
|
||||
EXT_TIME present if (HEAD_FLAGS & 0x1000) != 0
|
||||
variable size
|
||||
|
||||
other new fields may appear here.
|
||||
|
||||
|
||||
==========================================================================
|
||||
Application notes
|
||||
==========================================================================
|
||||
|
||||
1. To process an SFX archive you need to skip the SFX module searching
|
||||
for the marker block in the archive. There is no marker block sequence (0x52
|
||||
0x61 0x72 0x21 0x1a 0x07 0x00) in the SFX module itself.
|
||||
|
||||
2. The CRC is calculated using the standard polynomial 0xEDB88320. In
|
||||
case the size of the CRC is less than 4 bytes, only the low order bytes
|
||||
are used.
|
||||
27
tests/001.phpt
Normal file
27
tests/001.phpt
Normal file
@@ -0,0 +1,27 @@
|
||||
--TEST--
|
||||
rar_open() function
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip"; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$rar_file1 = rar_open(dirname(__FILE__).'/linux_rar.rar');
|
||||
var_dump($rar_file1);
|
||||
|
||||
$rar_file2 = rar_open(dirname(__FILE__).'/latest_winrar.rar');
|
||||
var_dump($rar_file2);
|
||||
|
||||
$rar_file3 = rar_open(dirname(__FILE__).'/no_such_file.rar');
|
||||
var_dump($rar_file3);
|
||||
|
||||
echo "Done\n";
|
||||
?>
|
||||
--EXPECTF--
|
||||
object(RarArchive)#%d (%d) {
|
||||
}
|
||||
object(RarArchive)#%d (%d) {
|
||||
}
|
||||
|
||||
Warning: rar_open(): Failed to open %sno_such_file.rar: ERAR_EOPEN (file open error) in %s on line %d
|
||||
bool(false)
|
||||
Done
|
||||
144
tests/002.phpt
Normal file
144
tests/002.phpt
Normal file
@@ -0,0 +1,144 @@
|
||||
--TEST--
|
||||
rar_list() function
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip"; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$rar_file1 = rar_open(dirname(__FILE__).'/linux_rar.rar');
|
||||
$list1 = rar_list($rar_file1);
|
||||
var_dump($list1);
|
||||
|
||||
$rar_file2 = rar_open(dirname(__FILE__).'/latest_winrar.rar');
|
||||
$list2 = rar_list($rar_file2);
|
||||
var_dump($list2);
|
||||
|
||||
$rar_file3 = rar_open(dirname(__FILE__).'/no_such_file.rar');
|
||||
$list3 = rar_list($rar_file3);
|
||||
var_dump($list3);
|
||||
|
||||
echo "Done\n";
|
||||
?>
|
||||
--EXPECTF--
|
||||
array(2) {
|
||||
[0]=>
|
||||
object(RarEntry)#%d (%d) {
|
||||
["rarfile%sprivate%s=>
|
||||
object(RarArchive)#%d (%d) {
|
||||
}
|
||||
["position%sprivate%s=>
|
||||
int(0)
|
||||
["name%sprivate%s=>
|
||||
string(9) "plain.txt"
|
||||
["unpacked_size%sprivate%s=>
|
||||
int(15)
|
||||
["packed_size%sprivate%s=>
|
||||
int(25)
|
||||
["host_os%sprivate%s=>
|
||||
int(3)
|
||||
["file_time%sprivate%s=>
|
||||
string(19) "2004-06-11 11:01:24"
|
||||
["crc%sprivate%s=>
|
||||
string(8) "7728b6fe"
|
||||
["attr%sprivate%s=>
|
||||
int(33188)
|
||||
["version%sprivate%s=>
|
||||
int(29)
|
||||
["method%sprivate%s=>
|
||||
int(51)
|
||||
["flags%sprivate%s=>
|
||||
int(0)
|
||||
}
|
||||
[1]=>
|
||||
object(RarEntry)#%d (%d) {
|
||||
["rarfile%sprivate%s=>
|
||||
object(RarArchive)#%d (%d) {
|
||||
}
|
||||
["position%sprivate%s=>
|
||||
int(1)
|
||||
["name%sprivate%s=>
|
||||
string(30) "test file with whitespaces.txt"
|
||||
["unpacked_size%sprivate%s=>
|
||||
int(14)
|
||||
["packed_size%sprivate%s=>
|
||||
int(20)
|
||||
["host_os%sprivate%s=>
|
||||
int(3)
|
||||
["file_time%sprivate%s=>
|
||||
string(19) "2004-06-11 11:01:32"
|
||||
["crc%sprivate%s=>
|
||||
string(8) "21890dd9"
|
||||
["attr%sprivate%s=>
|
||||
int(33188)
|
||||
["version%sprivate%s=>
|
||||
int(29)
|
||||
["method%sprivate%s=>
|
||||
int(51)
|
||||
["flags%sprivate%s=>
|
||||
int(0)
|
||||
}
|
||||
}
|
||||
array(2) {
|
||||
[0]=>
|
||||
object(RarEntry)#%d (%d) {
|
||||
["rarfile%sprivate%s=>
|
||||
object(RarArchive)#%d (%d) {
|
||||
}
|
||||
["position%sprivate%s=>
|
||||
int(0)
|
||||
["name%sprivate%s=>
|
||||
string(5) "1.txt"
|
||||
["unpacked_size%sprivate%s=>
|
||||
int(5)
|
||||
["packed_size%sprivate%s=>
|
||||
int(17)
|
||||
["host_os%sprivate%s=>
|
||||
int(2)
|
||||
["file_time%sprivate%s=>
|
||||
string(19) "2004-06-11 10:07:18"
|
||||
["crc%sprivate%s=>
|
||||
string(8) "a0de71c0"
|
||||
["attr%sprivate%s=>
|
||||
int(32)
|
||||
["version%sprivate%s=>
|
||||
int(29)
|
||||
["method%sprivate%s=>
|
||||
int(53)
|
||||
["flags%sprivate%s=>
|
||||
int(0)
|
||||
}
|
||||
[1]=>
|
||||
object(RarEntry)#%d (%d) {
|
||||
["rarfile%sprivate%s=>
|
||||
object(RarArchive)#%d (%d) {
|
||||
}
|
||||
["position%sprivate%s=>
|
||||
int(1)
|
||||
["name%sprivate%s=>
|
||||
string(5) "2.txt"
|
||||
["unpacked_size%sprivate%s=>
|
||||
int(5)
|
||||
["packed_size%sprivate%s=>
|
||||
int(16)
|
||||
["host_os%sprivate%s=>
|
||||
int(2)
|
||||
["file_time%sprivate%s=>
|
||||
string(19) "2004-06-11 10:07:26"
|
||||
["crc%sprivate%s=>
|
||||
string(8) "45a918de"
|
||||
["attr%sprivate%s=>
|
||||
int(32)
|
||||
["version%sprivate%s=>
|
||||
int(29)
|
||||
["method%sprivate%s=>
|
||||
int(53)
|
||||
["flags%sprivate%s=>
|
||||
int(16)
|
||||
}
|
||||
}
|
||||
|
||||
Warning: rar_open(): Failed to open %s: ERAR_EOPEN (file open error) in %s on line %d
|
||||
|
||||
Warning: rar_list() expects parameter 1 to be RarArchive, boolean given in %s on line %d
|
||||
NULL
|
||||
Done
|
||||
82
tests/003.phpt
Normal file
82
tests/003.phpt
Normal file
@@ -0,0 +1,82 @@
|
||||
--TEST--
|
||||
rar_entry_get() function
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip"; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$rar_file1 = rar_open(dirname(__FILE__).'/linux_rar.rar');
|
||||
$entry1 = rar_entry_get($rar_file1, 'test file with whitespaces.txt');
|
||||
var_dump($entry1);
|
||||
|
||||
$rar_file2 = rar_open(dirname(__FILE__).'/latest_winrar.rar');
|
||||
$entry2 = rar_entry_get($rar_file2, '2.txt');
|
||||
var_dump($entry2);
|
||||
|
||||
$rar_file3 = rar_open(dirname(__FILE__).'/no_such_file.rar');
|
||||
$entry3 = rar_entry_get($rar_file3, '2.txt');
|
||||
var_dump($entry3);
|
||||
|
||||
echo "Done\n";
|
||||
?>
|
||||
--EXPECTF--
|
||||
object(RarEntry)#%d (%d) {
|
||||
["rarfile%sprivate%s=>
|
||||
object(RarArchive)#%d (%d) {
|
||||
}
|
||||
["position%sprivate%s=>
|
||||
int(1)
|
||||
["name%sprivate%s=>
|
||||
string(30) "test file with whitespaces.txt"
|
||||
["unpacked_size%sprivate%s=>
|
||||
int(14)
|
||||
["packed_size%sprivate%s=>
|
||||
int(20)
|
||||
["host_os%sprivate%s=>
|
||||
int(3)
|
||||
["file_time%sprivate%s=>
|
||||
string(19) "2004-06-11 11:01:32"
|
||||
["crc%sprivate%s=>
|
||||
string(8) "21890dd9"
|
||||
["attr%sprivate%s=>
|
||||
int(33188)
|
||||
["version%sprivate%s=>
|
||||
int(29)
|
||||
["method%sprivate%s=>
|
||||
int(51)
|
||||
["flags%sprivate%s=>
|
||||
int(0)
|
||||
}
|
||||
object(RarEntry)#%d (%d) {
|
||||
["rarfile%sprivate%s=>
|
||||
object(RarArchive)#%d (%d) {
|
||||
}
|
||||
["position%sprivate%s=>
|
||||
int(1)
|
||||
["name%sprivate%s=>
|
||||
string(5) "2.txt"
|
||||
["unpacked_size%sprivate%s=>
|
||||
int(5)
|
||||
["packed_size%sprivate%s=>
|
||||
int(16)
|
||||
["host_os%sprivate%s=>
|
||||
int(2)
|
||||
["file_time%sprivate%s=>
|
||||
string(19) "2004-06-11 10:07:26"
|
||||
["crc%sprivate%s=>
|
||||
string(8) "45a918de"
|
||||
["attr%sprivate%s=>
|
||||
int(32)
|
||||
["version%sprivate%s=>
|
||||
int(29)
|
||||
["method%sprivate%s=>
|
||||
int(53)
|
||||
["flags%sprivate%s=>
|
||||
int(16)
|
||||
}
|
||||
|
||||
Warning: rar_open(): Failed to open %s: ERAR_EOPEN (file open error) in %s on line %d
|
||||
|
||||
Warning: rar_entry_get() expects parameter 1 to be RarArchive, boolean given in %s on line %d
|
||||
NULL
|
||||
Done
|
||||
84
tests/004.phpt
Normal file
84
tests/004.phpt
Normal file
@@ -0,0 +1,84 @@
|
||||
--TEST--
|
||||
RarEntry::extract() method
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip"; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$rar_file1 = rar_open(dirname(__FILE__).'/linux_rar.rar');
|
||||
$entry1 = rar_entry_get($rar_file1, 'test file with whitespaces.txt');
|
||||
|
||||
$entry1->extract(dirname(__FILE__));
|
||||
$contents11 = file_get_contents(dirname(__FILE__).'/test file with whitespaces.txt');
|
||||
echo $contents11."\n";
|
||||
@unlink(dirname(__FILE__).'/test file with whitespaces.txt');
|
||||
|
||||
$entry1->extract(false,dirname(__FILE__).'/1.txt');
|
||||
$contents12 = file_get_contents(dirname(__FILE__).'/1.txt');
|
||||
echo $contents12."\n";
|
||||
@unlink(dirname(__FILE__).'/1.txt');
|
||||
|
||||
$rar_file2 = rar_open(dirname(__FILE__).'/latest_winrar.rar');
|
||||
$entry2 = rar_entry_get($rar_file2, '2.txt');
|
||||
|
||||
$entry2->extract(dirname(__FILE__));
|
||||
$contents21 = file_get_contents(dirname(__FILE__).'/2.txt');
|
||||
echo $contents21."\n";
|
||||
@unlink(dirname(__FILE__).'/2.txt');
|
||||
|
||||
$entry2->extract(false,dirname(__FILE__).'/some.txt');
|
||||
$contents22 = file_get_contents(dirname(__FILE__).'/some.txt');
|
||||
echo $contents22."\n";
|
||||
@unlink(dirname(__FILE__).'/some.txt');
|
||||
|
||||
$entry2->extract(dirname(__FILE__));
|
||||
var_dump(file_get_contents(dirname(__FILE__).'/2.txt'));
|
||||
@unlink(dirname(__FILE__).'/2.txt');
|
||||
|
||||
$oldcwd = getcwd();
|
||||
chdir(dirname(__FILE__));
|
||||
|
||||
var_dump($entry2);
|
||||
var_dump($entry2->extract("",""));
|
||||
|
||||
@unlink('2.txt');
|
||||
|
||||
chdir($oldcwd);
|
||||
|
||||
echo "Done\n";
|
||||
?>
|
||||
--EXPECTF--
|
||||
blah-blah-blah
|
||||
blah-blah-blah
|
||||
22222
|
||||
22222
|
||||
string(5) "22222"
|
||||
object(RarEntry)#%d (%d) {
|
||||
["rarfile%sprivate%s=>
|
||||
object(RarArchive)#%d (%d) {
|
||||
}
|
||||
["position%sprivate%s=>
|
||||
int(1)
|
||||
["name%sprivate%s=>
|
||||
string(5) "2.txt"
|
||||
["unpacked_size%sprivate%s=>
|
||||
int(5)
|
||||
["packed_size%sprivate%s=>
|
||||
int(16)
|
||||
["host_os%sprivate%s=>
|
||||
int(2)
|
||||
["file_time%sprivate%s=>
|
||||
string(19) "2004-06-11 10:07:26"
|
||||
["crc%sprivate%s=>
|
||||
string(8) "45a918de"
|
||||
["attr%sprivate%s=>
|
||||
int(32)
|
||||
["version%sprivate%s=>
|
||||
int(29)
|
||||
["method%sprivate%s=>
|
||||
int(53)
|
||||
["flags%sprivate%s=>
|
||||
int(16)
|
||||
}
|
||||
bool(true)
|
||||
Done
|
||||
36
tests/005.phpt
Normal file
36
tests/005.phpt
Normal file
@@ -0,0 +1,36 @@
|
||||
--TEST--
|
||||
rar_comment_get() function
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip"; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$rar_file1 = rar_open(dirname(__FILE__).'/commented.rar');
|
||||
var_export(rar_comment_get($rar_file1));
|
||||
echo "\n";
|
||||
var_export(rar_comment_get($rar_file1));
|
||||
echo "\n";
|
||||
var_export($rar_file1->getComment());
|
||||
echo "\n";
|
||||
|
||||
$rar_file2 = rar_open(dirname(__FILE__).'/linux_rar.rar');
|
||||
var_export(rar_comment_get($rar_file2));
|
||||
echo "\n";
|
||||
rar_close($rar_file2);
|
||||
var_export(rar_comment_get($rar_file2));
|
||||
echo "\n";
|
||||
|
||||
|
||||
|
||||
|
||||
echo "Done\n";
|
||||
?>
|
||||
--EXPECTF--
|
||||
'This is the comment of the file commented.rar.'
|
||||
'This is the comment of the file commented.rar.'
|
||||
'This is the comment of the file commented.rar.'
|
||||
NULL
|
||||
|
||||
Warning: rar_comment_get(): The archive is already closed in %s on line %d
|
||||
false
|
||||
Done
|
||||
22
tests/006.phpt
Normal file
22
tests/006.phpt
Normal file
@@ -0,0 +1,22 @@
|
||||
--TEST--
|
||||
RarEntry::getCrc() method in multi-volume archives (PECL bug #9470)
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip"; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$rar_file1 = rar_open(dirname(__FILE__).'/multi.part1.rar');
|
||||
$list = rar_list($rar_file1);
|
||||
echo $list[0]->getCrc()."\n";
|
||||
echo $list[1]->getCrc()."\n";
|
||||
echo $list[2]->getCrc()."\n";
|
||||
echo "\n";
|
||||
|
||||
echo "Done\n";
|
||||
?>
|
||||
--EXPECTF--
|
||||
52b28202
|
||||
f2c79881
|
||||
bcbce32e
|
||||
|
||||
Done
|
||||
18
tests/007.phpt
Normal file
18
tests/007.phpt
Normal file
@@ -0,0 +1,18 @@
|
||||
--TEST--
|
||||
rar_open() function with a non-RAR
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip"; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$rar_file1 = rar_open(dirname(__FILE__).'/rar_notrar.rar');
|
||||
var_dump($rar_file1);
|
||||
echo "\n";
|
||||
|
||||
echo "Done\n";
|
||||
?>
|
||||
--EXPECTF--
|
||||
Warning: rar_open(): Failed to open %s: ERAR_BAD_ARCHIVE in %s on line %d
|
||||
bool(false)
|
||||
|
||||
Done
|
||||
34
tests/008.phpt
Normal file
34
tests/008.phpt
Normal file
@@ -0,0 +1,34 @@
|
||||
--TEST--
|
||||
rar_entry_get() function
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip"; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$rar_file1 = rar_open(dirname(__FILE__).'/multi.part1.rar');
|
||||
$entry = rar_entry_get($rar_file1, "file1.txt");
|
||||
echo "$entry\n";
|
||||
$entry = rar_entry_get($rar_file1, "nonexistent_file.txt");
|
||||
var_dump($entry);
|
||||
echo "\n";
|
||||
|
||||
$rar_file2 = rar_open(dirname(__FILE__).'/nonexistent.rar');
|
||||
$entry = rar_entry_get($rar_file2, "file1.txt");
|
||||
var_dump($entry);
|
||||
echo "\n";
|
||||
|
||||
echo "Done\n";
|
||||
?>
|
||||
--EXPECTF--
|
||||
RarEntry for file "file1.txt" (52b28202)
|
||||
|
||||
Warning: rar_entry_get(): cannot find file "nonexistent_file.txt" in Rar archive "%s" in %s on line %d
|
||||
bool(false)
|
||||
|
||||
|
||||
Warning: rar_open(): Failed to open %s: ERAR_EOPEN (file open error) in %s on line %d
|
||||
|
||||
Warning: rar_entry_get() expects parameter 1 to be RarArchive, boolean given in %s on line %d
|
||||
NULL
|
||||
|
||||
Done
|
||||
19
tests/009.phpt
Normal file
19
tests/009.phpt
Normal file
@@ -0,0 +1,19 @@
|
||||
--TEST--
|
||||
RarEntry::getName() function with unicode filenames
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip"; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$rar_file1 = rar_open(dirname(__FILE__).'/rar_unicode.rar');
|
||||
$entries = rar_list($rar_file1);
|
||||
$name = reset($entries)->getName();
|
||||
var_dump($name);
|
||||
echo "\n";
|
||||
|
||||
echo "Done\n";
|
||||
?>
|
||||
--EXPECTF--
|
||||
string(13) "file1À۞.txt"
|
||||
|
||||
Done
|
||||
32
tests/010.phpt
Normal file
32
tests/010.phpt
Normal file
@@ -0,0 +1,32 @@
|
||||
--TEST--
|
||||
RarEntry::getStream() function (good RAR file, one volume)
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip"; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$rar_file1 = rar_open(dirname(__FILE__).'/latest_winrar.rar');
|
||||
$entries = rar_list($rar_file1);
|
||||
echo count($entries)." files:\n\n";
|
||||
//var_dump($entries);
|
||||
foreach ($entries as $e) {
|
||||
$stream = $e->getStream();
|
||||
echo $e->getName().":\n";
|
||||
while (!feof($stream)) {
|
||||
echo fread($stream, 8192);
|
||||
}
|
||||
echo "\n\n";
|
||||
}
|
||||
|
||||
echo "Done\n";
|
||||
?>
|
||||
--EXPECTF--
|
||||
2 files:
|
||||
|
||||
1.txt:
|
||||
11111
|
||||
|
||||
2.txt:
|
||||
22222
|
||||
|
||||
Done
|
||||
42
tests/011.phpt
Normal file
42
tests/011.phpt
Normal file
@@ -0,0 +1,42 @@
|
||||
--TEST--
|
||||
RarEntry::getStream() function (good RAR file, several volumes)
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip"; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$rar_file1 = rar_open(dirname(__FILE__).'/multi.part1.rar');
|
||||
$entries = rar_list($rar_file1);
|
||||
echo count($entries)." files:\n\n";
|
||||
//var_dump($entries);
|
||||
function int32_to_hex($value) {
|
||||
$value &= 0xffffffff;
|
||||
return str_pad(strtoupper(dechex($value)), 8, "0", STR_PAD_LEFT);
|
||||
}
|
||||
foreach ($entries as $e) {
|
||||
$stream = $e->getStream();
|
||||
if ($stream === false) {
|
||||
die("Failed to get stream.\n");
|
||||
break;
|
||||
}
|
||||
echo $e->getName().": ";
|
||||
$a = "";
|
||||
while (!feof($stream)) {
|
||||
$a .= fread($stream, 8192);
|
||||
}
|
||||
echo strlen($a)." bytes, CRC ";
|
||||
echo int32_to_hex(crc32($a))."\n\n"; //you can confirm they're equal to those given by $e->getCrc()
|
||||
}
|
||||
|
||||
echo "Done\n";
|
||||
?>
|
||||
--EXPECTF--
|
||||
3 files:
|
||||
|
||||
file1.txt: 18 bytes, CRC 52B28202
|
||||
|
||||
file2.txt: 17704 bytes, CRC F2C79881
|
||||
|
||||
file3.txt: 18 bytes, CRC BCBCE32E
|
||||
|
||||
Done
|
||||
41
tests/012.phpt
Normal file
41
tests/012.phpt
Normal file
@@ -0,0 +1,41 @@
|
||||
--TEST--
|
||||
RarEntry::getStream() function (bad RAR file)
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip"; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
$rar_file1 = rar_open(dirname(__FILE__).'/corrupted.rar');
|
||||
$entries = rar_list($rar_file1);
|
||||
echo count($entries)." files (will test only the first 4):\n\n";
|
||||
//var_dump($entries);
|
||||
$i = 0;
|
||||
foreach ($entries as $e) {
|
||||
if ($i++ >= 2)
|
||||
break;
|
||||
//$e->extract(false, dirname(__FILE__).'/temp.txt');
|
||||
//echo "now stream\n";
|
||||
$stream = $e->getStream();
|
||||
echo $e->getName().": ";
|
||||
if ($stream === false) {
|
||||
echo "Could not get stream.\n\n";
|
||||
continue;
|
||||
}
|
||||
while (!feof($stream) && $i != 2) {
|
||||
echo fread($stream, 8192);
|
||||
}
|
||||
fclose($stream);
|
||||
echo "\n";
|
||||
|
||||
}
|
||||
|
||||
echo "Done\n";
|
||||
?>
|
||||
--EXPECTF--
|
||||
51 files (will test only the first 4):
|
||||
|
||||
test/C:5B': The great battle of Gunprex versus Optiter!!!!!1
|
||||
Gunprex, Fire!
|
||||
So long, Optiter!
|
||||
|
||||
test/Sbv=Ð:
|
||||
Done
|
||||
20
tests/013.phpt
Normal file
20
tests/013.phpt
Normal file
@@ -0,0 +1,20 @@
|
||||
--TEST--
|
||||
rar_entry_get() and RarEntry::getName() coherence
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip"; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$rar_file1 = rar_open(dirname(__FILE__).'/rar_unicode.rar');
|
||||
$entries = rar_list($rar_file1);
|
||||
$name = reset($entries)->getName();
|
||||
$entryback = rar_entry_get($rar_file1, $name);
|
||||
echo "$entryback\n";
|
||||
echo "\n";
|
||||
|
||||
echo "Done\n";
|
||||
?>
|
||||
--EXPECTF--
|
||||
RarEntry for file "file1À۞.txt" (52b28202)
|
||||
|
||||
Done
|
||||
26
tests/014.phpt
Normal file
26
tests/014.phpt
Normal file
@@ -0,0 +1,26 @@
|
||||
--TEST--
|
||||
RarEntry::getStream() on unicode entry
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip"; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$rar_file1 = rar_open(dirname(__FILE__).'/rar_unicode.rar');
|
||||
$entry = rar_entry_get($rar_file1, "file1À۞.txt");
|
||||
echo $entry."\n";
|
||||
echo "\n";
|
||||
$stream = $entry->getStream();
|
||||
if ($stream !== false)
|
||||
while (!feof($stream)) {
|
||||
echo fread($stream, 8192);
|
||||
}
|
||||
|
||||
echo "\n";
|
||||
|
||||
echo "Done\n";
|
||||
?>
|
||||
--EXPECTF--
|
||||
RarEntry for file "file1À۞.txt" (52b28202)
|
||||
|
||||
contents of file 1
|
||||
Done
|
||||
30
tests/015.phpt
Normal file
30
tests/015.phpt
Normal file
@@ -0,0 +1,30 @@
|
||||
--TEST--
|
||||
rar_close() liberates resource (PECL bug #9649)
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip"; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
copy(dirname(__FILE__).'/latest_winrar.rar', dirname(__FILE__).'/temp.rar');
|
||||
$rar_file1 = rar_open(dirname(__FILE__).'/temp.rar');
|
||||
echo $rar_file1."\n";
|
||||
$entries = rar_list($rar_file1);
|
||||
$entry1 = reset($entries);
|
||||
unset($entries);
|
||||
echo $entry1."\n";
|
||||
echo "\n";
|
||||
|
||||
rar_close($rar_file1);
|
||||
echo $rar_file1."\n";
|
||||
$entry1->extract(".");
|
||||
unlink(dirname(__FILE__).'/temp.rar');
|
||||
|
||||
echo "Done\n";
|
||||
?>
|
||||
--EXPECTF--
|
||||
RAR Archive "%s"
|
||||
RarEntry for file "1.txt" (a0de71c0)
|
||||
|
||||
RAR Archive "%s" (closed)
|
||||
|
||||
Warning: RarEntry::extract(): The archive is already closed in %s on line %d
|
||||
Done
|
||||
50
tests/016.phpt
Normal file
50
tests/016.phpt
Normal file
@@ -0,0 +1,50 @@
|
||||
--TEST--
|
||||
RarEntry::extract() method (corrupt RAR file)
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip"; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
$rar_file1 = rar_open(dirname(__FILE__).'/corrupted.rar');
|
||||
$entries = rar_list($rar_file1);
|
||||
echo count($entries)." files (will test only the first 4):\n\n";
|
||||
//var_dump($entries);
|
||||
$i = 0;
|
||||
foreach ($entries as $e) {
|
||||
if ($i++ >= 4)
|
||||
break;
|
||||
echo "Extraction of file #$i:\n";
|
||||
$ret = $e->extract(false, dirname(__FILE__).'/temp.txt');
|
||||
if ($ret)
|
||||
echo "\tSUCCESS\n";
|
||||
else
|
||||
echo "\tFAILED\n";
|
||||
|
||||
echo "\n";
|
||||
}
|
||||
|
||||
@unlink(dirname(__FILE__).'/temp.txt');
|
||||
|
||||
echo "Done\n";
|
||||
?>
|
||||
--EXPECTF--
|
||||
51 files (will test only the first 4):
|
||||
|
||||
Extraction of file #1:
|
||||
SUCCESS
|
||||
|
||||
Extraction of file #2:
|
||||
|
||||
Warning: RarEntry::extract(): ERAR_BAD_DATA in %s on line %d
|
||||
FAILED
|
||||
|
||||
Extraction of file #3:
|
||||
|
||||
Warning: RarEntry::extract(): ERAR_BAD_DATA in %s on line %d
|
||||
FAILED
|
||||
|
||||
Extraction of file #4:
|
||||
|
||||
Warning: RarEntry::extract(): ERAR_BAD_DATA in %s on line %d
|
||||
FAILED
|
||||
|
||||
Done
|
||||
22
tests/017.phpt
Normal file
22
tests/017.phpt
Normal file
@@ -0,0 +1,22 @@
|
||||
--TEST--
|
||||
RarEntry::extract() with unicode files
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip"; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
$rar_file1 = rar_open(dirname(__FILE__).'/rar_unicode.rar');
|
||||
$entries = rar_list($rar_file1);
|
||||
$e = reset($entries);
|
||||
|
||||
$e->extract(false, dirname(__FILE__).'/temp.txt');
|
||||
|
||||
echo file_get_contents(dirname(__FILE__).'/temp.txt');
|
||||
echo "\n";
|
||||
|
||||
@unlink(dirname(__FILE__).'/temp.txt');
|
||||
|
||||
echo "Done\n";
|
||||
?>
|
||||
--EXPECTF--
|
||||
contents of file 1
|
||||
Done
|
||||
24
tests/018.phpt
Normal file
24
tests/018.phpt
Normal file
@@ -0,0 +1,24 @@
|
||||
--TEST--
|
||||
rar_list()/rar_entry_get() with not first volume
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip"; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
$rar_file1 = rar_open(dirname(__FILE__).'/multi.part2.rar');
|
||||
$entries = rar_list($rar_file1);
|
||||
echo "Number of entries: " . count($entries) . "\n";
|
||||
echo reset($entries)."\n";
|
||||
$e = rar_entry_get($rar_file1, "file2.txt");
|
||||
var_dump($e);
|
||||
$e = rar_entry_get($rar_file1, "file3.txt");
|
||||
echo $e."\n";
|
||||
|
||||
echo "Done\n";
|
||||
--EXPECTF--
|
||||
Number of entries: 1
|
||||
RarEntry for file "file3.txt" (bcbce32e)
|
||||
|
||||
Warning: rar_entry_get(): cannot find file "file2.txt" in Rar archive "%s in %s on line %d
|
||||
bool(false)
|
||||
RarEntry for file "file3.txt" (bcbce32e)
|
||||
Done
|
||||
34
tests/019.phpt
Normal file
34
tests/019.phpt
Normal file
@@ -0,0 +1,34 @@
|
||||
--TEST--
|
||||
RarEntry::getStream() function (store method)
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip"; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$rar_file1 = rar_open(dirname(__FILE__).'/store_method.rar');
|
||||
$entries = rar_list($rar_file1);
|
||||
echo count($entries)." files:\n\n";
|
||||
//var_dump($entries);
|
||||
function int32_to_hex($value) {
|
||||
$value &= 0xffffffff;
|
||||
return str_pad(strtoupper(dechex($value)), 8, "0", STR_PAD_LEFT);
|
||||
}
|
||||
foreach ($entries as $e) {
|
||||
$stream = $e->getStream();
|
||||
echo $e->getName().": ";
|
||||
$a = "";
|
||||
while (!feof($stream)) {
|
||||
$a .= fread($stream, 512);
|
||||
}
|
||||
echo strlen($a)." bytes, CRC ";
|
||||
echo int32_to_hex(crc32($a))."\n\n"; //you can confirm they're equal to those given by $e->getCrc()
|
||||
}
|
||||
|
||||
echo "Done\n";
|
||||
?>
|
||||
--EXPECTF--
|
||||
1 files:
|
||||
|
||||
tese.txt: 787 bytes, CRC 23B93A7A
|
||||
|
||||
Done
|
||||
36
tests/020.phpt
Normal file
36
tests/020.phpt
Normal file
@@ -0,0 +1,36 @@
|
||||
--TEST--
|
||||
RarEntry::getStream() function (solid archive)
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip"; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$rar_file1 = rar_open(dirname(__FILE__).'/solid.rar');
|
||||
$entries = rar_list($rar_file1);
|
||||
echo count($entries)." files:\n\n";
|
||||
//var_dump($entries);
|
||||
function int32_to_hex($value) {
|
||||
$value &= 0xffffffff;
|
||||
return str_pad(strtoupper(dechex($value)), 8, "0", STR_PAD_LEFT);
|
||||
}
|
||||
foreach ($entries as $e) {
|
||||
$stream = $e->getStream();
|
||||
echo $e->getName().": ";
|
||||
$a = "";
|
||||
while (!feof($stream)) {
|
||||
$a .= fread($stream, 8192);
|
||||
}
|
||||
echo strlen($a)." bytes, CRC ";
|
||||
echo int32_to_hex(crc32($a))."\n\n"; //you can confirm they're equal to those given by $e->getCrc()
|
||||
}
|
||||
|
||||
echo "Done\n";
|
||||
?>
|
||||
--EXPECTF--
|
||||
2 files:
|
||||
|
||||
tese.txt: 787 bytes, CRC 23B93A7A
|
||||
|
||||
unrardll.txt: 19192 bytes, CRC 2ED64B6E
|
||||
|
||||
Done
|
||||
19
tests/021.phpt
Normal file
19
tests/021.phpt
Normal file
@@ -0,0 +1,19 @@
|
||||
--TEST--
|
||||
RarEntry::isDirectory() basic test
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip"; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
$rar_file1 = rar_open(dirname(__FILE__).'/directories.rar');
|
||||
$entries = rar_list($rar_file1);
|
||||
|
||||
foreach ($entries as $e) {
|
||||
echo "{$e->getName()} is ". ($e->isDirectory()?"":"not ") . "a directory.\n";
|
||||
}
|
||||
|
||||
echo "Done\n";
|
||||
--EXPECTF--
|
||||
dirwithsth%cfileindir.txt is not a directory.
|
||||
dirwithsth is a directory.
|
||||
emptydir is a directory.
|
||||
Done
|
||||
40
tests/022.phpt
Normal file
40
tests/022.phpt
Normal file
@@ -0,0 +1,40 @@
|
||||
--TEST--
|
||||
RarEntry::extract() with directory
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip"; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
$rar_file1 = rar_open(dirname(__FILE__).'/directories.rar');
|
||||
$e = rar_entry_get($rar_file1, "emptydir");
|
||||
|
||||
$dir = dirname(__FILE__) . DIRECTORY_SEPARATOR . "emptydir";
|
||||
$exists = is_dir($dir);
|
||||
var_dump($exists);
|
||||
$extrres = $e->extract(dirname(__FILE__));
|
||||
var_dump($extrres);
|
||||
$exists = is_dir($dir);
|
||||
var_dump($exists);
|
||||
@rmdir($dir);
|
||||
|
||||
echo "\n\n";
|
||||
|
||||
$dir = dirname(__FILE__) . DIRECTORY_SEPARATOR . "emptydircust";
|
||||
$exists = is_dir($dir);
|
||||
var_dump($exists);
|
||||
$extrres = $e->extract(false, $dir);
|
||||
var_dump($extrres);
|
||||
$exists = is_dir($dir);
|
||||
var_dump($exists);
|
||||
@rmdir($dir);
|
||||
|
||||
echo "Done\n";
|
||||
--EXPECTF--
|
||||
bool(false)
|
||||
bool(true)
|
||||
bool(true)
|
||||
|
||||
|
||||
bool(false)
|
||||
bool(true)
|
||||
bool(true)
|
||||
Done
|
||||
21
tests/023.phpt
Normal file
21
tests/023.phpt
Normal file
@@ -0,0 +1,21 @@
|
||||
--TEST--
|
||||
RarEntry::getStream() with directory
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip"; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
$rar_file1 = rar_open(dirname(__FILE__).'/directories.rar');
|
||||
$e = rar_entry_get($rar_file1, "emptydir");
|
||||
$stream = $e->getStream();
|
||||
var_dump($stream);
|
||||
var_dump(feof($stream));
|
||||
var_dump(fread($stream, 200));
|
||||
var_dump(feof($stream));
|
||||
|
||||
echo "Done\n";
|
||||
--EXPECTF--
|
||||
resource(%d) of type (stream)
|
||||
bool(false)
|
||||
string(0) ""
|
||||
bool(true)
|
||||
Done
|
||||
46
tests/024.phpt
Normal file
46
tests/024.phpt
Normal file
@@ -0,0 +1,46 @@
|
||||
--TEST--
|
||||
rar_open()/RarEntry::getStream() (headers level password)
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip"; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
echo "--> should fail (no password):\n";
|
||||
$rar_file1 = rar_open(dirname(__FILE__).'/encrypted_headers.rar');
|
||||
$entries = rar_list($rar_file1);
|
||||
|
||||
echo "\n--> should fail (wrong password):\n";
|
||||
$rar_file1 = rar_open(dirname(__FILE__).'/encrypted_headers.rar', 'wrongpassword');
|
||||
$entries = rar_list($rar_file1);
|
||||
|
||||
echo "\n--> should work:\n";
|
||||
$rar_file2 = rar_open(dirname(__FILE__).'/encrypted_headers.rar', 'samplepassword');
|
||||
$entries = rar_list($rar_file2);
|
||||
|
||||
echo "Found " . count($entries) . " files.\n";
|
||||
echo "Content of first one follows:\n";
|
||||
//reset($entries)->extract(false, "./temp.txt");
|
||||
$stream = reset($entries)->getStream();
|
||||
var_dump($stream);
|
||||
if ($stream !== FALSE) {
|
||||
while (!feof($stream)) {
|
||||
echo fread($stream, 128);
|
||||
}
|
||||
}
|
||||
echo "\n";
|
||||
|
||||
echo "Done\n";
|
||||
--EXPECTF--
|
||||
--> should fail (no password):
|
||||
|
||||
Warning: rar_list(): ERAR_MISSING_PASSWORD (password needed but not specified) in %s on line %d
|
||||
|
||||
--> should fail (wrong password):
|
||||
|
||||
Warning: rar_list(): ERAR_BAD_DATA in %s on line %d
|
||||
|
||||
--> should work:
|
||||
Found 2 files.
|
||||
Content of first one follows:
|
||||
resource(%d) of type (stream)
|
||||
Encrypted file 1 contents.
|
||||
Done
|
||||
26
tests/025.phpt
Normal file
26
tests/025.phpt
Normal file
@@ -0,0 +1,26 @@
|
||||
--TEST--
|
||||
rar_open()/RarEntry::extract() (headers level password)
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip"; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
$rar_file2 = rar_open(dirname(__FILE__).'/encrypted_headers.rar', 'samplepassword');
|
||||
$entries = rar_list($rar_file2);
|
||||
|
||||
echo "Found " . count($entries) . " files.\n";
|
||||
$tempfile = dirname(__FILE__).'/temp.txt';
|
||||
@unlink($tempfile);
|
||||
var_dump(reset($entries)->extract(false, $tempfile));
|
||||
echo "Content of first one follows:\n";
|
||||
echo file_get_contents($tempfile);
|
||||
$stream = reset($entries)->getStream();
|
||||
@unlink($tempfile);
|
||||
echo "\n";
|
||||
|
||||
echo "Done\n";
|
||||
--EXPECTF--
|
||||
Found 2 files.
|
||||
bool(true)
|
||||
Content of first one follows:
|
||||
Encrypted file 1 contents.
|
||||
Done
|
||||
52
tests/026.phpt
Normal file
52
tests/026.phpt
Normal file
@@ -0,0 +1,52 @@
|
||||
--TEST--
|
||||
RarEntry::getStream() (file level password)
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip"; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
echo "--> should fail (no password):\n";
|
||||
$rar_file1 = rar_open(dirname(__FILE__).'/encrypted_only_files.rar');
|
||||
$entries = rar_list($rar_file1);
|
||||
var_dump(count($entries));
|
||||
var_dump($entries[0]->getStream());
|
||||
echo "\n";
|
||||
|
||||
echo "--> success (password is the same as the one given on rar_open):\n";
|
||||
$rar_file2 = rar_open(dirname(__FILE__).'/encrypted_only_files.rar', 'samplepassword');
|
||||
$entries = rar_list($rar_file2);
|
||||
echo stream_get_contents($entries[0]->getStream());
|
||||
echo "\n\n";
|
||||
|
||||
echo "--> should give incorrect data (password of 2nd file different from the one given on rar_open):\n";
|
||||
echo rawurlencode(stream_get_contents($entries[1]->getStream()));
|
||||
echo "\n\n";
|
||||
|
||||
echo "--> should give correct data (password of 2nd file is specified):\n";
|
||||
echo stream_get_contents($entries[1]->getStream('samplepassword2'));
|
||||
echo "\n\n";
|
||||
|
||||
echo "--> success (password is the same as the one given on rar_open, which shouldn't have been forgotten):\n";
|
||||
echo stream_get_contents($entries[0]->getStream());
|
||||
echo "\n\n";
|
||||
|
||||
echo "Done\n";
|
||||
--EXPECTF--
|
||||
--> should fail (no password):
|
||||
int(2)
|
||||
|
||||
Warning: RarEntry::getStream(): ERAR_MISSING_PASSWORD (password needed but not specified) in %s on line %d
|
||||
bool(false)
|
||||
|
||||
--> success (password is the same as the one given on rar_open):
|
||||
Encrypted file 1 contents.
|
||||
|
||||
--> should give incorrect data (password of 2nd file different from the one given on rar_open):
|
||||
t%09%A6%2B%0D%1B%F6%815%5E%E7%EC%C0%0BF%5EH%3A%C0%0D%815%5E%E7%EC%C0
|
||||
|
||||
--> should give correct data (password of 2nd file is specified):
|
||||
Encrypted file 1 contents.
|
||||
|
||||
--> success (password is the same as the one given on rar_open, which shouldn't have been forgotten):
|
||||
Encrypted file 1 contents.
|
||||
|
||||
Done
|
||||
54
tests/027.phpt
Normal file
54
tests/027.phpt
Normal file
@@ -0,0 +1,54 @@
|
||||
--TEST--
|
||||
RarEntry::getStream() with Linux directories and links
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip"; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
$rar = rar_open(dirname(__FILE__) . "/dirlink_unix.rar");
|
||||
|
||||
echo "\nDirectory\n";
|
||||
|
||||
$e = rar_entry_get($rar, "nopermdir");
|
||||
echo $e."\n";
|
||||
echo "perms: " . decoct($e->getAttr() & 0x1FF) . "\n"; //no read/write/execute perms
|
||||
echo "win directory bit: " . (($e->getAttr() & RarEntry::ATTRIBUTE_WIN_DIRECTORY) != 0) ."\n";
|
||||
echo "unix directory attr: " . (($e->getAttr() & RarEntry::ATTRIBUTE_UNIX_FINAL_QUARTET)
|
||||
== RarEntry::ATTRIBUTE_UNIX_DIRECTORY) ."\n";
|
||||
echo "unix symlink attr: " . (($e->getAttr() & RarEntry::ATTRIBUTE_UNIX_FINAL_QUARTET)
|
||||
== RarEntry::ATTRIBUTE_UNIX_SYM_LINK) ."\n";
|
||||
$stream = $e->getStream();
|
||||
$cont = stream_get_contents($stream);
|
||||
echo "$cont (strlen() " . strlen($cont) . ")\n";
|
||||
|
||||
echo "\nLink\n";
|
||||
|
||||
$e = rar_entry_get($rar, "link");
|
||||
echo $e."\n";
|
||||
echo "perms: " . decoct($e->getAttr() & 0x1FF) . "\n";
|
||||
echo "win directory bit: " . (($e->getAttr() & RarEntry::ATTRIBUTE_WIN_DIRECTORY) != 0) ."\n"; //coincidence
|
||||
echo "unix directory attr: " . (($e->getAttr() & RarEntry::ATTRIBUTE_UNIX_FINAL_QUARTET)
|
||||
== RarEntry::ATTRIBUTE_UNIX_DIRECTORY) ."\n";
|
||||
echo "unix symlink attr: " . (($e->getAttr() & RarEntry::ATTRIBUTE_UNIX_FINAL_QUARTET)
|
||||
== RarEntry::ATTRIBUTE_UNIX_SYM_LINK) ."\n";
|
||||
$stream = $e->getStream();
|
||||
$cont = stream_get_contents($stream);
|
||||
echo "$cont (strlen() " . strlen($cont) . ")\n"; //varies on windows and linux
|
||||
|
||||
echo "Done\n";
|
||||
--EXPECTF--
|
||||
Directory
|
||||
RarEntry for directory "nopermdir" (0)
|
||||
perms: 0
|
||||
win directory bit:
|
||||
unix directory attr: 1
|
||||
unix symlink attr:
|
||||
(strlen() 0)
|
||||
|
||||
Link
|
||||
RarEntry for file "link" (43e55b49)
|
||||
perms: 777
|
||||
win directory bit: 1
|
||||
unix directory attr:
|
||||
unix symlink attr: 1
|
||||
%s
|
||||
Done
|
||||
14
tests/028.phpt
Normal file
14
tests/028.phpt
Normal file
@@ -0,0 +1,14 @@
|
||||
--TEST--
|
||||
RarArchive::open() basic test
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip"; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
$arch = RarArchive::open(dirname(__FILE__) . "/dirlink_unix.rar");
|
||||
var_dump(get_class($arch));
|
||||
|
||||
|
||||
echo "Done\n";
|
||||
--EXPECTF--
|
||||
string(10) "RarArchive"
|
||||
Done
|
||||
21
tests/029.phpt
Normal file
21
tests/029.phpt
Normal file
@@ -0,0 +1,21 @@
|
||||
--TEST--
|
||||
RarArchive::getEntries() basic test
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip"; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
$arch = RarArchive::open(dirname(__FILE__) . "/dirlink_unix.rar");
|
||||
foreach ($arch->getEntries() as $e) {
|
||||
echo $e . "\n";
|
||||
}
|
||||
|
||||
echo "Done\n";
|
||||
--EXPECTF--
|
||||
RarEntry for file "emptydir%clink" (36ac99f1)
|
||||
RarEntry for file "file" (b95e8411)
|
||||
RarEntry for file "link" (43e55b49)
|
||||
RarEntry for directory "emptydir" (0)
|
||||
RarEntry for directory "nopermdir" (0)
|
||||
RarEntry for directory "setuiddir" (0)
|
||||
RarEntry for directory "stickydir" (0)
|
||||
Done
|
||||
14
tests/030.phpt
Normal file
14
tests/030.phpt
Normal file
@@ -0,0 +1,14 @@
|
||||
--TEST--
|
||||
RarArchive::getEntry() basic test
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip"; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
$rar_arch = RarArchive::open(dirname(__FILE__) . '/solid.rar');
|
||||
$rar_entry = $rar_arch->getEntry('tese.txt');
|
||||
echo $rar_entry;
|
||||
echo "\n";
|
||||
echo "Done\n";
|
||||
--EXPECTF--
|
||||
RarEntry for file "tese.txt" (23b93a7a)
|
||||
Done
|
||||
13
tests/031.phpt
Normal file
13
tests/031.phpt
Normal file
@@ -0,0 +1,13 @@
|
||||
--TEST--
|
||||
RarArchive::getComment() basic test
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip"; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
$rar_arch = RarArchive::open(dirname(__FILE__) . '/commented.rar');
|
||||
echo $rar_arch->getComment();
|
||||
echo "\n";
|
||||
echo "Done\n";
|
||||
--EXPECTF--
|
||||
This is the comment of the file commented.rar.
|
||||
Done
|
||||
16
tests/032.phpt
Normal file
16
tests/032.phpt
Normal file
@@ -0,0 +1,16 @@
|
||||
--TEST--
|
||||
RarArchive traversal with multi-part archive
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip"; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
$rarF = RarArchive::open(dirname(__FILE__) . '/multi.part1.rar');
|
||||
foreach ($rarF as $k => $rarE) {
|
||||
echo "$k. $rarE\n";
|
||||
}
|
||||
echo "Done\n";
|
||||
--EXPECTF--
|
||||
0. RarEntry for file "file1.txt" (52b28202)
|
||||
1. RarEntry for file "file2.txt" (f2c79881)
|
||||
2. RarEntry for file "file3.txt" (bcbce32e)
|
||||
Done
|
||||
24
tests/033.phpt
Normal file
24
tests/033.phpt
Normal file
@@ -0,0 +1,24 @@
|
||||
--TEST--
|
||||
rar_solid_is() basic test
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip"; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
$arch1 = RarArchive::open(dirname(__FILE__) . "/store_method.rar");
|
||||
$arch2 = RarArchive::open(dirname(__FILE__) . "/solid.rar");
|
||||
echo "$arch1: " . ($arch1->isSolid()?'yes':'no') ."\n";
|
||||
echo "$arch2: " . (rar_solid_is($arch2)?'yes':'no') . "\n";
|
||||
|
||||
$arch2->close();
|
||||
var_dump(rar_solid_is($arch2));
|
||||
|
||||
echo "\n";
|
||||
echo "Done.\n";
|
||||
--EXPECTF--
|
||||
RAR Archive "%sstore_method.rar": no
|
||||
RAR Archive "%ssolid.rar": yes
|
||||
|
||||
Warning: rar_solid_is(): The archive is already closed in %s on line %d
|
||||
bool(false)
|
||||
|
||||
Done.
|
||||
16
tests/034.phpt
Normal file
16
tests/034.phpt
Normal file
@@ -0,0 +1,16 @@
|
||||
--TEST--
|
||||
RarException::(set/is)UsingExceptions() test
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip"; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
echo "Initial state: " . (RarException::isUsingExceptions()?'yes':'no').".\n";
|
||||
RarException::setUsingExceptions(true);
|
||||
echo "State change done.\n";
|
||||
echo "Final state: " . (RarException::isUsingExceptions()?'yes':'no').".\n";
|
||||
echo "Done.\n";
|
||||
--EXPECTF--
|
||||
Initial state: no.
|
||||
State change done.
|
||||
Final state: yes.
|
||||
Done.
|
||||
19
tests/035.phpt
Normal file
19
tests/035.phpt
Normal file
@@ -0,0 +1,19 @@
|
||||
--TEST--
|
||||
rar_entry_get() non-existent file with exceptions
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip"; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
RarException::setUsingExceptions(true);
|
||||
$arch = RarArchive::open(dirname(__FILE__) . "/latest_winrar.rar");
|
||||
try {
|
||||
$arch->getEntry('nonexistentfile.txt');
|
||||
} catch (RarException $re) {
|
||||
echo "Message: " . $re->getMessage()."\n";
|
||||
echo "Code: " . $re->getCode() ."\n";
|
||||
}
|
||||
echo "Done.\n";
|
||||
--EXPECTF--
|
||||
Message: cannot find file "nonexistentfile.txt" in Rar archive "%slatest_winrar.rar"
|
||||
Code: -1
|
||||
Done.
|
||||
18
tests/036.phpt
Normal file
18
tests/036.phpt
Normal file
@@ -0,0 +1,18 @@
|
||||
--TEST--
|
||||
rar_open() non-existent archive with exceptions
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip"; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
RarException::setUsingExceptions(true);
|
||||
try {
|
||||
$arch = RarArchive::open(dirname(__FILE__) . "/nonexistentarchive.rar");
|
||||
} catch (RarException $re) {
|
||||
echo "Message: " . $re->getMessage()."\n";
|
||||
echo "Code: " . $re->getCode() ."\n";
|
||||
}
|
||||
echo "Done.\n";
|
||||
--EXPECTF--
|
||||
Message: unRAR internal error: Failed to open %snonexistentarchive.rar: ERAR_EOPEN (file open error)
|
||||
Code: 15
|
||||
Done.
|
||||
24
tests/037.phpt
Normal file
24
tests/037.phpt
Normal file
@@ -0,0 +1,24 @@
|
||||
--TEST--
|
||||
RarEntry::getStream(), password not given, with exceptions
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip"; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
RarException::setUsingExceptions(true);
|
||||
echo "--> should fail (no password):\n";
|
||||
$rar_file1 = rar_open(dirname(__FILE__).'/encrypted_only_files.rar');
|
||||
$entries = rar_list($rar_file1);
|
||||
var_dump(count($entries));
|
||||
try {
|
||||
var_dump($entries[0]->getStream());
|
||||
} catch (RarException $re) {
|
||||
echo "Message: " . $re->getMessage()."\n";
|
||||
echo "Code: " . $re->getCode() ."\n";
|
||||
}
|
||||
echo "Done.\n";
|
||||
--EXPECTF--
|
||||
--> should fail (no password):
|
||||
int(2)
|
||||
Message: unRAR internal error: ERAR_MISSING_PASSWORD (password needed but not specified)
|
||||
Code: 22
|
||||
Done.
|
||||
15
tests/038.phpt
Normal file
15
tests/038.phpt
Normal file
@@ -0,0 +1,15 @@
|
||||
--TEST--
|
||||
RarArchive get iterator on closed file
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip"; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
$rarF = RarArchive::open(dirname(__FILE__) . '/latest_winrar.rar');
|
||||
$rarF->close();
|
||||
foreach ($rarF as $k => $rarE) {
|
||||
echo "$k. $rarE\n";
|
||||
unset($rarE);
|
||||
}
|
||||
echo "Done.\n";
|
||||
--EXPECTF--
|
||||
Fatal error: main(): The archive is already closed, cannot give an iterator in %s on line %d
|
||||
15
tests/039.phpt
Normal file
15
tests/039.phpt
Normal file
@@ -0,0 +1,15 @@
|
||||
--TEST--
|
||||
Access RAR archive with missing volumes
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip"; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
$rarF = RarArchive::open(dirname(__FILE__) . '/multi_broken.part1.rar');
|
||||
var_dump(rar_list($rarF));
|
||||
echo "Done.\n";
|
||||
--EXPECTF--
|
||||
Warning: rar_list(): Volume %smulti_broken.part2.rar was not found in %s on line %d
|
||||
|
||||
Warning: rar_list(): ERAR_EOPEN (file open error) in %s on line %d
|
||||
bool(false)
|
||||
Done.
|
||||
26
tests/040.phpt
Normal file
26
tests/040.phpt
Normal file
@@ -0,0 +1,26 @@
|
||||
--TEST--
|
||||
RarEntry::getUnpackedSize() on platforms with 32-bit longs
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if(!extension_loaded("rar")) die("skip");
|
||||
if (PHP_INT_SIZE != 4) die("skip this test is for 32bit platforms only");
|
||||
--FILE--
|
||||
<?php
|
||||
$fn1 = dirname(__FILE__) . '/sparsefiles_rar.rar';
|
||||
$fn2 = dirname(__FILE__) . '/sparsefiles.tmp.rar';
|
||||
$rarF = RarArchive::open($fn1);
|
||||
$t = $rarF->getEntries();
|
||||
reset($t)->extract(false, $fn2);
|
||||
$rarF2 = RarArchive::open($fn2);
|
||||
$t = $rarF2->getEntries();
|
||||
var_dump($t[0]->getUnpackedSize());
|
||||
var_dump($t[1]->getUnpackedSize());
|
||||
echo "Done.\n";
|
||||
--CLEAN--
|
||||
<?php
|
||||
$fn2 = dirname(__FILE__) . '/sparsefiles.tmp.rar';
|
||||
@unlink($fn2);
|
||||
--EXPECTF--
|
||||
int(2147483647)
|
||||
int(2147483647)
|
||||
Done.
|
||||
26
tests/041.phpt
Normal file
26
tests/041.phpt
Normal file
@@ -0,0 +1,26 @@
|
||||
--TEST--
|
||||
RarEntry::getUnpackedSize() on platforms with 64-bit longs
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if(!extension_loaded("rar")) die("skip");
|
||||
if (PHP_INT_SIZE != 8) die("skip this test is for 64bit platforms only");
|
||||
--FILE--
|
||||
<?php
|
||||
$fn1 = dirname(__FILE__) . '/sparsefiles_rar.rar';
|
||||
$fn2 = dirname(__FILE__) . '/sparsefiles.tmp.rar';
|
||||
$rarF = RarArchive::open($fn1);
|
||||
$t = $rarF->getEntries();
|
||||
reset($t)->extract(false, $fn2);
|
||||
$rarF2 = RarArchive::open($fn2);
|
||||
$t = $rarF2->getEntries();
|
||||
var_dump($t[0]->getUnpackedSize());
|
||||
var_dump($t[1]->getUnpackedSize());
|
||||
echo "Done.\n";
|
||||
--CLEAN--
|
||||
<?php
|
||||
$fn2 = dirname(__FILE__) . '/sparsefiles.tmp.rar';
|
||||
@unlink($fn2);
|
||||
--EXPECTF--
|
||||
int(2621440000)
|
||||
int(5368709120)
|
||||
Done.
|
||||
38
tests/042.phpt
Normal file
38
tests/042.phpt
Normal file
@@ -0,0 +1,38 @@
|
||||
--TEST--
|
||||
rar_open() with volume find callback basic test
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if(!extension_loaded("rar")) die("skip");
|
||||
--FILE--
|
||||
<?php
|
||||
chdir(dirname(__FILE__));
|
||||
function volume_callback($vol) {
|
||||
if (preg_match('/_fail/', $vol))
|
||||
$ret = basename(str_replace('_fail', '', $vol));
|
||||
elseif (preg_match('/_broken/', $vol))
|
||||
$ret = basename(str_replace('_broken', '_fail', $vol));
|
||||
else
|
||||
$ret = null;
|
||||
echo "Not found:\n\t$vol\nReplacing with:\n\t$ret\n";
|
||||
return $ret;
|
||||
}
|
||||
$fn = dirname(__FILE__) . '/multi_broken.part1.rar';
|
||||
$rar = RarArchive::open($fn, null, 'volume_callback');
|
||||
foreach ($rar as $e) {
|
||||
echo "Entry: $e.\n";
|
||||
}
|
||||
echo "Done.\n";
|
||||
--EXPECTF--
|
||||
Not found:
|
||||
%smulti_broken.part2.rar
|
||||
Replacing with:
|
||||
multi_fail.part2.rar
|
||||
Not found:
|
||||
%smulti_fail.part2.rar
|
||||
Replacing with:
|
||||
multi.part2.rar
|
||||
Entry: RarEntry for file "file1.txt" (52b28202).
|
||||
Entry: RarEntry for file "file2.txt" (f2c79881).
|
||||
Entry: RarEntry for file "file3.txt" (bcbce32e).
|
||||
Done.
|
||||
|
||||
47
tests/043.phpt
Normal file
47
tests/043.phpt
Normal file
@@ -0,0 +1,47 @@
|
||||
--TEST--
|
||||
rar_open() with volume find (callback variants 1)
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if(!extension_loaded("rar")) die("skip");
|
||||
--FILE--
|
||||
<?php
|
||||
class A {
|
||||
public static function resolve($vol) {
|
||||
if (preg_match('/_broken/', $vol))
|
||||
return str_replace('_broken', '', $vol);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
public static function resolveStatic($vol) {
|
||||
echo "A::resolveStatic()\n";
|
||||
return self::resolve($vol);
|
||||
}
|
||||
|
||||
public function resolveInstance($vol) {
|
||||
echo "A::resolveInstance()\n";
|
||||
return self::resolve($vol);
|
||||
}
|
||||
}
|
||||
|
||||
$fn = dirname(__FILE__) . '/multi_broken.part1.rar';
|
||||
$rar = RarArchive::open($fn, null, "A::resolveStatic");
|
||||
$rar->getEntries();
|
||||
$rar = RarArchive::open($fn, null, array("A", "resolveStatic"));
|
||||
$rar->getEntries();
|
||||
$rar = RarArchive::open($fn, null, array(new A(), "resolveInstance"));
|
||||
$rar->getEntries();
|
||||
function testA() {
|
||||
global $fn;
|
||||
$obj = new A();
|
||||
return RarArchive::open($fn, null, array($obj, "resolveInstance"));
|
||||
}
|
||||
$rar = testA();
|
||||
$rar->getEntries();
|
||||
echo "Done.\n";
|
||||
--EXPECTF--
|
||||
A::resolveStatic()
|
||||
A::resolveStatic()
|
||||
A::resolveInstance()
|
||||
A::resolveInstance()
|
||||
Done.
|
||||
|
||||
45
tests/044.phpt
Normal file
45
tests/044.phpt
Normal file
@@ -0,0 +1,45 @@
|
||||
--TEST--
|
||||
rar_open() with volume find (callback variants 2)
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if(!extension_loaded("rar")) die("skip");
|
||||
if(!defined('PHP_VERSION_ID') || PHP_VERSION_ID<50300) die("skip");
|
||||
--FILE--
|
||||
<?php
|
||||
class A {
|
||||
public static function resolve($vol) {
|
||||
if (preg_match('/_broken/', $vol))
|
||||
return str_replace('_broken', '', $vol);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
public function __invoke($vol) {
|
||||
echo "A::__invoke()\n";
|
||||
return self::resolve($vol);
|
||||
}
|
||||
}
|
||||
|
||||
$fn = dirname(__FILE__) . '/multi_broken.part1.rar';
|
||||
$f = function ($vol) {
|
||||
echo "Closure\n";
|
||||
return A::resolve($vol);
|
||||
};
|
||||
$rar = RarArchive::open($fn, null, new A());
|
||||
$rar->getEntries();
|
||||
$rar = RarArchive::open($fn, null, $f);
|
||||
$rar->getEntries();
|
||||
|
||||
$f2 = function ($vol) {
|
||||
echo "Closure (2)\n";
|
||||
return A::resolve($vol);
|
||||
};
|
||||
$rar = RarArchive::open($fn, null, $f2);
|
||||
unset($f2);
|
||||
$rar->getEntries();
|
||||
echo "Done.\n";
|
||||
--EXPECTF--
|
||||
A::__invoke()
|
||||
Closure
|
||||
Closure (2)
|
||||
Done.
|
||||
|
||||
92
tests/045.phpt
Normal file
92
tests/045.phpt
Normal file
@@ -0,0 +1,92 @@
|
||||
--TEST--
|
||||
rar_open() with invalid volume callback
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if(!extension_loaded("rar")) die("skip");
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class A {
|
||||
public static function resolve($vol) {
|
||||
if (preg_match('/_broken/', $vol))
|
||||
return str_replace('_broken', '', $vol);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
public function resolveInstance($vol) {
|
||||
echo "A::resolveInstance()\n";
|
||||
return self::resolve($vol);
|
||||
}
|
||||
}
|
||||
|
||||
$fn = dirname(__FILE__) . '/multi_broken.part1.rar';
|
||||
|
||||
echo "\nNot given a callback:\n";
|
||||
$rar = RarArchive::open($fn, null, new Exception());
|
||||
|
||||
echo "\nGiven static callback for instance method (test IS_CALLABLE_STRICT):\n";
|
||||
$rar = RarArchive::open($fn, null, "A::resolveInstance");
|
||||
var_dump($rar);
|
||||
|
||||
echo "\nGiven callback that takes more arguments:\n";
|
||||
$rar = RarArchive::open($fn, null, 'array_walk');
|
||||
$rar->getEntries();
|
||||
|
||||
echo "\nGiven callback that takes another kind of arguments:\n";
|
||||
$rar = RarArchive::open($fn, null, 'ksort');
|
||||
$rar->getEntries();
|
||||
|
||||
echo "\nGiven callback that returns another kind of arguments:\n";
|
||||
function testA($vol) { return true; }
|
||||
$rar = RarArchive::open($fn, null, 'testA');
|
||||
$rar->getEntries();
|
||||
|
||||
echo "\nGiven callback that throws Exception:\n";
|
||||
function testB($vol) { throw new Exception(); }
|
||||
$rar = RarArchive::open($fn, null, 'testB');
|
||||
try {
|
||||
$rar->getEntries();
|
||||
die("should have thrown exception.");
|
||||
} catch (Exception $e) {
|
||||
echo "OK, threw exception.\n";
|
||||
}
|
||||
|
||||
echo "Done.\n";
|
||||
--EXPECTF--
|
||||
Not given a callback:
|
||||
|
||||
Warning: RarArchive::open(): Expected the third argument, if provided, to be a valid callback in %s on line %d
|
||||
|
||||
Given static callback for instance method (test IS_CALLABLE_STRICT):
|
||||
|
||||
Warning: RarArchive::open(): Expected the third argument, if provided, to be a valid callback in %s on line %d
|
||||
bool(false)
|
||||
|
||||
Given callback that takes more arguments:
|
||||
|
||||
Warning: array_walk() expects at least %d parameters, 1 given in %s on line %d
|
||||
|
||||
Warning: RarArchive::getEntries(): ERAR_EOPEN (file open error) in %s on line %d
|
||||
|
||||
Given callback that takes another kind of arguments:
|
||||
|
||||
Warning: ksort() expects parameter 1 to be array, string given in %s on line %d
|
||||
|
||||
Warning: RarArchive::getEntries(): Wrong type returned by volume find callback, expected string or NULL in %s on line %d
|
||||
|
||||
Warning: RarArchive::getEntries(): ERAR_EOPEN (file open error) in %s on line %d
|
||||
|
||||
Given callback that returns another kind of arguments:
|
||||
|
||||
Warning: RarArchive::getEntries(): Wrong type returned by volume find callback, expected string or NULL in %s on line %d
|
||||
|
||||
Warning: RarArchive::getEntries(): ERAR_EOPEN (file open error) in %s on line %d
|
||||
|
||||
Given callback that throws Exception:
|
||||
|
||||
Warning: RarArchive::getEntries(): Failure to call volume find callback in %s on line %d
|
||||
|
||||
Warning: RarArchive::getEntries(): ERAR_EOPEN (file open error) in %s on line %d
|
||||
OK, threw exception.
|
||||
Done.
|
||||
|
||||
38
tests/046.phpt
Normal file
38
tests/046.phpt
Normal file
@@ -0,0 +1,38 @@
|
||||
--TEST--
|
||||
RarEntry::getStream() function (broken set fixed with volume callback)
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip"; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
function resolve($vol) {
|
||||
if (preg_match('/_broken/', $vol))
|
||||
return str_replace('_broken', '', $vol);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
function int32_to_hex($value) {
|
||||
$value &= 0xffffffff;
|
||||
return str_pad(strtoupper(dechex($value)), 8, "0", STR_PAD_LEFT);
|
||||
}
|
||||
$rar_file1 = rar_open(dirname(__FILE__).'/multi_broken.part1.rar', null, 'resolve');
|
||||
foreach ($rar_file1 as $e) {
|
||||
$stream = $e->getStream();
|
||||
echo $e->getName().": ";
|
||||
$a = "";
|
||||
while (is_resource($stream) && !feof($stream)) {
|
||||
$a .= fread($stream, 8192);
|
||||
}
|
||||
echo strlen($a)." bytes, CRC ";
|
||||
echo int32_to_hex(crc32($a))."\n\n"; //you can confirm they're equal to those given by $e->getCrc()
|
||||
}
|
||||
|
||||
echo "Done\n";
|
||||
?>
|
||||
--EXPECTF--
|
||||
file1.txt: 18 bytes, CRC 52B28202
|
||||
|
||||
file2.txt: 17704 bytes, CRC F2C79881
|
||||
|
||||
file3.txt: 18 bytes, CRC BCBCE32E
|
||||
|
||||
Done
|
||||
41
tests/047.phpt
Normal file
41
tests/047.phpt
Normal file
@@ -0,0 +1,41 @@
|
||||
--TEST--
|
||||
RarEntry::extract() function (broken set fixed with volume callback)
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip"; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
function resolve($vol) {
|
||||
if (preg_match('/_broken/', $vol))
|
||||
return str_replace('_broken', '', $vol);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
function int32_to_hex($value) {
|
||||
$value &= 0xffffffff;
|
||||
return str_pad(strtoupper(dechex($value)), 8, "0", STR_PAD_LEFT);
|
||||
}
|
||||
echo "Fail:\n";
|
||||
$rar_file1 = rar_open(dirname(__FILE__).'/multi_broken.part1.rar');
|
||||
$entry = $rar_file1->getEntry('file2.txt');
|
||||
|
||||
echo "\nSuccess:\n";
|
||||
$rar_file1 = rar_open(dirname(__FILE__).'/multi_broken.part1.rar', null, 'resolve');
|
||||
$entry = $rar_file1->getEntry('file2.txt');
|
||||
$entry->extract(null, dirname(__FILE__) . "/temp_file2.txt");
|
||||
echo int32_to_hex(crc32(file_get_contents(dirname(__FILE__) . "/temp_file2.txt")));
|
||||
echo "\n";
|
||||
echo "Done\n";
|
||||
?>
|
||||
--CLEAN--
|
||||
<?php
|
||||
@unlink(dirname(__FILE__) . "/temp_file2.txt");
|
||||
--EXPECTF--
|
||||
Fail:
|
||||
|
||||
Warning: RarArchive::getEntry(): Volume %smulti_broken.part2.rar was not found in %s on line %d
|
||||
|
||||
Warning: RarArchive::getEntry(): ERAR_EOPEN (file open error) in %s on line %d
|
||||
|
||||
Success:
|
||||
F2C79881
|
||||
Done
|
||||
26
tests/048.phpt
Normal file
26
tests/048.phpt
Normal file
@@ -0,0 +1,26 @@
|
||||
--TEST--
|
||||
RarArchive::open() volume callback long return (case MAXPATHLEN <= NM)
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if(!extension_loaded("rar")) die("skip");
|
||||
if (!defined("PHP_MAXPATHLEN"))
|
||||
define("PHP_MAXPATHLEN", RAR_MAXPATHLEN);
|
||||
if (!(PHP_MAXPATHLEN <= 1024))
|
||||
die("skip; this test is for systems where MAXPATHLEN <= 1024");
|
||||
--FILE--
|
||||
<?php
|
||||
if (!defined("PHP_MAXPATHLEN"))
|
||||
define("PHP_MAXPATHLEN", RAR_MAXPATHLEN);
|
||||
|
||||
$fn = dirname(__FILE__) . '/multi_broken.part1.rar';
|
||||
|
||||
function testA($vol) { if ($vol[0] != 'a') return str_repeat("a", PHP_MAXPATHLEN); }
|
||||
$rar = RarArchive::open($fn, null, 'testA');
|
||||
$rar->getEntries();
|
||||
|
||||
echo "Done.\n";
|
||||
--EXPECTF--
|
||||
Warning: RarArchive::getEntries(): Cound not expand filename aaaa%s in %s on line %d
|
||||
|
||||
Warning: RarArchive::getEntries(): ERAR_EOPEN (file open error) in %s on line %d
|
||||
Done.
|
||||
30
tests/049.phpt
Normal file
30
tests/049.phpt
Normal file
@@ -0,0 +1,30 @@
|
||||
--TEST--
|
||||
RarArchive::open() volume callback long return (case MAXPATHLEN > NM)
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if(!extension_loaded("rar")) die("skip");
|
||||
if (!defined("PHP_MAXPATHLEN"))
|
||||
define("PHP_MAXPATHLEN", RAR_MAXPATHLEN);
|
||||
if (!(PHP_MAXPATHLEN > 2048))
|
||||
die("skip test is for systems where MAXPATHLEN > 2048");
|
||||
$rp = dirname(__FILE__) . "/" . str_repeat("a", 2048);
|
||||
if (strlen(dirname(__FILE__) > PHP_MAXPATHLEN - 1))
|
||||
die("skip current directory is too deep.");
|
||||
--FILE--
|
||||
<?php
|
||||
if (!defined("PHP_MAXPATHLEN"))
|
||||
define("PHP_MAXPATHLEN", RAR_MAXPATHLEN);
|
||||
|
||||
chdir(dirname(__FILE__));
|
||||
$fn = dirname(__FILE__) . '/multi_broken.part1.rar';
|
||||
|
||||
function testA($vol) { if ($vol[0] != 'a') return str_repeat("a", 2048); }
|
||||
$rar = RarArchive::open($fn, null, 'testA');
|
||||
$rar->getEntries();
|
||||
|
||||
echo "Done.\n";
|
||||
--EXPECTF--
|
||||
Warning: RarArchive::getEntries(): Resolved path is too big for the unRAR library in %s on line %d
|
||||
|
||||
Warning: RarArchive::getEntries(): ERAR_EOPEN (file open error) in %s on line %d
|
||||
Done.
|
||||
16
tests/050.phpt
Normal file
16
tests/050.phpt
Normal file
@@ -0,0 +1,16 @@
|
||||
--TEST--
|
||||
Stream wrapper basic test
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if(!extension_loaded("rar")) die("skip");
|
||||
--FILE--
|
||||
<?php
|
||||
$stream = fopen("rar://" .
|
||||
dirname(__FILE__) . '/latest_winrar.rar' .
|
||||
"#1.txt", "r");
|
||||
var_dump(stream_get_contents($stream));
|
||||
|
||||
echo "Done.\n";
|
||||
--EXPECTF--
|
||||
string(5) "11111"
|
||||
Done.
|
||||
62
tests/051.phpt
Normal file
62
tests/051.phpt
Normal file
@@ -0,0 +1,62 @@
|
||||
--TEST--
|
||||
Stream wrapper relative path test
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if(!extension_loaded("rar")) die("skip");
|
||||
--CLEAN--
|
||||
<?php
|
||||
unlink(dirname(__FILE__) . '/temp/tmp.rar');
|
||||
rmdir(dirname(__FILE__) . "/temp");
|
||||
--FILE--
|
||||
<?php
|
||||
mkdir(dirname(__FILE__) . "/temp");
|
||||
chdir(dirname(__FILE__) . "/temp");
|
||||
|
||||
echo "Test relative to working dir:\n";
|
||||
$stream = fopen("rar://" .
|
||||
'../latest_winrar.rar' .
|
||||
"#1.txt", "r");
|
||||
var_dump(stream_get_contents($stream));
|
||||
|
||||
echo "\nTest with include path:\n";
|
||||
copy(dirname(__FILE__) . '/latest_winrar.rar',
|
||||
dirname(__FILE__) . '/temp/tmp.rar');
|
||||
chdir(dirname(__FILE__));
|
||||
|
||||
//now with include
|
||||
echo "Should fail (not in include):\n";
|
||||
$stream = fopen("rar://" .
|
||||
'tmp.rar' .
|
||||
"#1.txt", "r");
|
||||
|
||||
echo "\nShould fail (include unused):\n";
|
||||
|
||||
set_include_path(dirname(__FILE__). '/temp');
|
||||
$stream = fopen("rar://" .
|
||||
'tmp.rar' .
|
||||
"#1.txt", "r");
|
||||
|
||||
echo "\nShould succeed:\n";
|
||||
$stream = fopen("rar://" .
|
||||
'tmp.rar' .
|
||||
"#1.txt", "r", true);
|
||||
var_dump(stream_get_contents($stream));
|
||||
|
||||
echo "Done.\n";
|
||||
--EXPECTF--
|
||||
Test relative to working dir:
|
||||
string(5) "11111"
|
||||
|
||||
Test with include path:
|
||||
Should fail (not in include):
|
||||
|
||||
Warning: fopen(rar://tmp.rar#1.txt): failed to open stream: Error opening RAR archive %stmp.rar: ERAR_EOPEN (file open error) in %s on line %d
|
||||
|
||||
Should fail (include unused):
|
||||
|
||||
Warning: fopen(rar://tmp.rar#1.txt): failed to open stream: Error opening RAR archive %stmp.rar: ERAR_EOPEN (file open error) in %s on line %d
|
||||
|
||||
Should succeed:
|
||||
string(5) "11111"
|
||||
Done.
|
||||
|
||||
28
tests/052.phpt
Normal file
28
tests/052.phpt
Normal file
@@ -0,0 +1,28 @@
|
||||
--TEST--
|
||||
Stream wrapper archive/file not found
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if(!extension_loaded("rar")) die("skip");
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
echo "Archive not found :\n";
|
||||
$stream = fopen("rar://" .
|
||||
dirname(__FILE__) . "/not_found.rar" .
|
||||
"#1.txt", "r");
|
||||
|
||||
echo "\nFile not found :\n";
|
||||
$stream = fopen("rar://" .
|
||||
dirname(__FILE__) . "/latest_winrar.rar" .
|
||||
"#not_found.txt", "r");
|
||||
|
||||
echo "Done.\n";
|
||||
--EXPECTF--
|
||||
Archive not found :
|
||||
|
||||
Warning: fopen(rar://%snot_found.rar#1.txt): failed to open stream: Error opening RAR archive %snot_found.rar: ERAR_EOPEN (file open error) in %s on line %d
|
||||
|
||||
File not found :
|
||||
|
||||
Warning: fopen(rar://%slatest_winrar.rar#not_found.txt): failed to open stream: Can't file not_found.txt in RAR archive %s on line %d
|
||||
Done.
|
||||
47
tests/053.phpt
Normal file
47
tests/053.phpt
Normal file
@@ -0,0 +1,47 @@
|
||||
--TEST--
|
||||
Stream wrapper malformed url
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if(!extension_loaded("rar")) die("skip");
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
echo "Test empty:\n";
|
||||
$stream = fopen("rar://", "r");
|
||||
|
||||
echo "\nTest no fragment:\n";
|
||||
$stream = fopen("rar://file.rar", "r");
|
||||
|
||||
echo "\nTest empty fragment:\n";
|
||||
$stream = fopen("rar://file.rar#", "r");
|
||||
|
||||
echo "\nTest no path:\n";
|
||||
|
||||
$stream = fopen("rar://#frag", "r");
|
||||
|
||||
echo "\nTest no path and empty fragment:\n";
|
||||
|
||||
$stream = fopen("rar://#", "r");
|
||||
|
||||
echo "Done.\n";
|
||||
--EXPECTF--
|
||||
Test empty:
|
||||
|
||||
Warning: fopen(rar://): failed to open stream: The url must contain a path and a non-empty fragment; it must be in the form "rar://<urlencoded path to RAR archive>[*]#<urlencoded entry name>" in %s on line %d
|
||||
|
||||
Test no fragment:
|
||||
|
||||
Warning: fopen(rar://file.rar): failed to open stream: The url must contain a path and a non-empty fragment; it must be in the form "rar://<urlencoded path to RAR archive>[*]#<urlencoded entry name>" in %s on line %d
|
||||
|
||||
Test empty fragment:
|
||||
|
||||
Warning: fopen(rar://file.rar#): failed to open stream: The url must contain a path and a non-empty fragment; it must be in the form "rar://<urlencoded path to RAR archive>[*]#<urlencoded entry name>" in %s on line %d
|
||||
|
||||
Test no path:
|
||||
|
||||
Warning: fopen(rar://#frag): failed to open stream: The url must contain a path and a non-empty fragment; it must be in the form "rar://<urlencoded path to RAR archive>[*]#<urlencoded entry name>" in %s on line %d
|
||||
|
||||
Test no path and empty fragment:
|
||||
|
||||
Warning: fopen(rar://#): failed to open stream: The url must contain a path and a non-empty fragment; it must be in the form "rar://<urlencoded path to RAR archive>[*]#<urlencoded entry name>" in %s on line %d
|
||||
Done.
|
||||
79
tests/054.phpt
Normal file
79
tests/054.phpt
Normal file
@@ -0,0 +1,79 @@
|
||||
--TEST--
|
||||
Stream wrapper with header or file level passwords
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if(!extension_loaded("rar")) die("skip");
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
echo "Headers: should not work (no password):\n";
|
||||
$stream = fopen("rar://" .
|
||||
dirname(__FILE__) . '/encrypted_headers.rar' .
|
||||
"#encfile1.txt", "r");
|
||||
|
||||
|
||||
echo "\nHeaders: should not work (password given was file_password):\n";
|
||||
|
||||
$stream = fopen("rar://" .
|
||||
dirname(__FILE__) . '/encrypted_headers.rar' .
|
||||
"#encfile1.txt", "r", false,
|
||||
stream_context_create(array('rar'=>array('file_password'=>'samplepassword'))));
|
||||
|
||||
echo "\nHeaders: should work (password given was open_password):\n";
|
||||
|
||||
$stream = fopen("rar://" .
|
||||
dirname(__FILE__) . '/encrypted_headers.rar' .
|
||||
"#encfile1.txt", "r", false,
|
||||
stream_context_create(array('rar'=>array('open_password'=>'samplepassword'))));
|
||||
var_dump(stream_get_contents($stream));
|
||||
|
||||
//////////////////////
|
||||
|
||||
echo "\n\nFiles: should not work (no password):\n";
|
||||
$stream = fopen("rar://" .
|
||||
dirname(__FILE__) . '/encrypted_only_files.rar' .
|
||||
"#encfile1.txt", "r");
|
||||
|
||||
|
||||
echo "\nFiles: should not work (password given was open_password):\n";
|
||||
|
||||
$stream = fopen("rar://" .
|
||||
dirname(__FILE__) . '/encrypted_only_files.rar' .
|
||||
"#encfile1.txt", "r", false,
|
||||
stream_context_create(array('rar'=>array('open_password'=>'samplepassword'))));
|
||||
|
||||
echo "\nFiles: should work (password given was file_password):\n";
|
||||
|
||||
$stream = fopen("rar://" .
|
||||
dirname(__FILE__) . '/encrypted_only_files.rar' .
|
||||
"#encfile1.txt", "r", false,
|
||||
stream_context_create(array('rar'=>array('file_password'=>'samplepassword'))));
|
||||
var_dump(stream_get_contents($stream));
|
||||
|
||||
echo "\nDone.\n";
|
||||
|
||||
--EXPECTF--
|
||||
Headers: should not work (no password):
|
||||
|
||||
Warning: fopen(rar://%sencrypted_headers.rar#encfile1.txt): failed to open stream: Error opening RAR archive %sencrypted_headers.rar: ERAR_MISSING_PASSWORD (password needed but not specified) in %s on line %d
|
||||
|
||||
Headers: should not work (password given was file_password):
|
||||
|
||||
Warning: fopen(rar://%sencrypted_headers.rar#encfile1.txt): failed to open stream: Error opening RAR archive %sencrypted_headers.rar: ERAR_MISSING_PASSWORD (password needed but not specified) in %s on line %d
|
||||
|
||||
Headers: should work (password given was open_password):
|
||||
string(26) "Encrypted file 1 contents."
|
||||
|
||||
|
||||
Files: should not work (no password):
|
||||
|
||||
Warning: fopen(rar://%sencrypted_only_files.rar#encfile1.txt): failed to open stream: Error opening file encfile1.txt inside RAR archive %sencrypted_only_files.rar: ERAR_MISSING_PASSWORD (password needed but not specified) in %s on line %d
|
||||
|
||||
Files: should not work (password given was open_password):
|
||||
|
||||
Warning: fopen(rar://%sencrypted_only_files.rar#encfile1.txt): failed to open stream: Error opening file encfile1.txt inside RAR archive %sencrypted_only_files.rar: ERAR_MISSING_PASSWORD (password needed but not specified) in %s on line %d
|
||||
|
||||
Files: should work (password given was file_password):
|
||||
string(26) "Encrypted file 1 contents."
|
||||
|
||||
Done.
|
||||
30
tests/055.phpt
Normal file
30
tests/055.phpt
Normal file
@@ -0,0 +1,30 @@
|
||||
--TEST--
|
||||
Stream wrapper with volume find callback
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if(!extension_loaded("rar")) die("skip");
|
||||
--FILE--
|
||||
<?php
|
||||
function resolve($vol) {
|
||||
if (preg_match('/_broken/', $vol))
|
||||
return str_replace('_broken', '', $vol);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
function int32_to_hex($value) {
|
||||
$value &= 0xffffffff;
|
||||
return str_pad(strtoupper(dechex($value)), 8, "0", STR_PAD_LEFT);
|
||||
}
|
||||
$stream = fopen("rar://" .
|
||||
dirname(__FILE__) . '/multi_broken.part1.rar' .
|
||||
"#file2.txt", "r", false,
|
||||
stream_context_create(array('rar'=>array('volume_callback'=>'resolve'))));
|
||||
$a = stream_get_contents($stream);
|
||||
echo strlen($a)." bytes, CRC ";
|
||||
echo int32_to_hex(crc32($a))."\n\n"; //you can confirm they're equal to those given by $e->getCrc()
|
||||
echo "Done.\n";
|
||||
--EXPECTF--
|
||||
17704 bytes, CRC F2C79881
|
||||
|
||||
Done.
|
||||
|
||||
34
tests/056.phpt
Normal file
34
tests/056.phpt
Normal file
@@ -0,0 +1,34 @@
|
||||
--TEST--
|
||||
RAR file stream stat
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if(!extension_loaded("rar")) die("skip");
|
||||
--ENV--
|
||||
TZ=Europe/Lisbon
|
||||
--FILE--
|
||||
<?php
|
||||
umask(0);
|
||||
$stream = fopen("rar://" .
|
||||
dirname(__FILE__) . '/latest_winrar.rar' .
|
||||
"#1.txt", "r");
|
||||
print_r(array_slice(fstat($stream), 13));
|
||||
|
||||
echo "Done.\n";
|
||||
--EXPECTF--
|
||||
Array
|
||||
(
|
||||
[dev] => 0
|
||||
[ino] => 0
|
||||
[mode] => 33206
|
||||
[nlink] => 1
|
||||
[uid] => 0
|
||||
[gid] => 0
|
||||
[rdev] => 0
|
||||
[size] => 5
|
||||
[atime] => 0
|
||||
[mtime] => 1086944839
|
||||
[ctime] => 0
|
||||
[blksize] => %s
|
||||
[blocks] => %s
|
||||
)
|
||||
Done.
|
||||
21
tests/057.phpt
Normal file
21
tests/057.phpt
Normal file
@@ -0,0 +1,21 @@
|
||||
--TEST--
|
||||
RAR file stream stat consistency with url stat
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if(!extension_loaded("rar")) die("skip");
|
||||
--FILE--
|
||||
<?php
|
||||
$u = "rar://" .
|
||||
dirname(__FILE__) . '/latest_winrar.rar' .
|
||||
"#1.txt";
|
||||
$stream = fopen($u, "r");
|
||||
$fs = (fstat($stream));
|
||||
|
||||
$us = stat($u);
|
||||
|
||||
var_dump($fs == $us);
|
||||
|
||||
echo "Done.\n";
|
||||
--EXPECTF--
|
||||
bool(true)
|
||||
Done.
|
||||
24
tests/058.phpt
Normal file
24
tests/058.phpt
Normal file
@@ -0,0 +1,24 @@
|
||||
--TEST--
|
||||
RAR file stream stat applied to directory consistency with url stat
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if(!extension_loaded("rar")) die("skip");
|
||||
--FILE--
|
||||
<?php
|
||||
$u = "rar://" .
|
||||
dirname(__FILE__) . '/dirlink_unix.rar' .
|
||||
"#emptydir";
|
||||
$stream = fopen($u, "r");
|
||||
$fs = (fstat($stream));
|
||||
|
||||
$us = stat($u);
|
||||
|
||||
var_dump($fs == $us);
|
||||
|
||||
var_dump(is_dir($u));
|
||||
|
||||
echo "Done.\n";
|
||||
--EXPECTF--
|
||||
bool(true)
|
||||
bool(true)
|
||||
Done.
|
||||
136
tests/059.phpt
Normal file
136
tests/059.phpt
Normal file
@@ -0,0 +1,136 @@
|
||||
--TEST--
|
||||
url stat test
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if(!extension_loaded("rar")) die("skip");
|
||||
--ENV--
|
||||
TZ=Europe/Lisbon
|
||||
--FILE--
|
||||
<?php
|
||||
umask(0);
|
||||
$inex_rar = "rar://" .
|
||||
dirname(__FILE__) . '/not_found.rar' .
|
||||
"#emptydir";
|
||||
|
||||
echo "RAR not found:\n";
|
||||
var_dump(stat($inex_rar));
|
||||
|
||||
$inex_entry = "rar://" .
|
||||
dirname(__FILE__) . '/dirlink_unix.rar' .
|
||||
"#inexistent entry";
|
||||
|
||||
echo "\nRAR entry not found:\n";
|
||||
var_dump(stat($inex_entry));
|
||||
|
||||
$root1 = "rar://" .
|
||||
dirname(__FILE__) . '/dirlink_unix.rar';
|
||||
|
||||
echo "\nRAR root:\n";
|
||||
$statr1 = stat($root1);
|
||||
print_r(array_slice($statr1, 13));
|
||||
echo "\nRAR root is dir:\n";
|
||||
var_dump(is_dir($root1));
|
||||
|
||||
$root2 = "rar://" .
|
||||
dirname(__FILE__) . '/dirlink_unix.rar#';
|
||||
|
||||
echo "\nRAR root variant 2 matches:\n";
|
||||
var_dump(stat($root2) == $statr1);
|
||||
|
||||
$root3 = "rar://" .
|
||||
dirname(__FILE__) . '/dirlink_unix.rar#/';
|
||||
echo "\nRAR root variant 3 matches:\n";
|
||||
var_dump(stat($root3) == $statr1);
|
||||
|
||||
$file = "rar://" .
|
||||
dirname(__FILE__) . '/dirlink_unix.rar' .
|
||||
"#file";
|
||||
|
||||
echo "\nRegular file:\n";
|
||||
print_r(array_slice(stat($file), 13));
|
||||
|
||||
$dir = "rar://" .
|
||||
dirname(__FILE__) . '/dirlink_unix.rar' .
|
||||
"#emptydir";
|
||||
echo "\nRegular file:\n";
|
||||
print_r(array_slice(stat($dir), 13));
|
||||
|
||||
echo "Done.\n";
|
||||
--EXPECTF--
|
||||
RAR not found:
|
||||
|
||||
Warning: stat(): Failed to open %snot_found.rar: ERAR_EOPEN (file open error) in %s on line %d
|
||||
|
||||
Warning: stat(): stat failed for rar://%s/not_found.rar#emptydir in %s on line %d
|
||||
bool(false)
|
||||
|
||||
RAR entry not found:
|
||||
|
||||
Warning: stat(): Found no entry inexistent entry in archive %sdirlink_unix.rar in %s on line %d
|
||||
|
||||
Warning: stat(): stat failed for rar://%s/dirlink_unix.rar#inexistent entry in %s on line %d
|
||||
bool(false)
|
||||
|
||||
RAR root:
|
||||
Array
|
||||
(
|
||||
[dev] => 0
|
||||
[ino] => 0
|
||||
[mode] => 16895
|
||||
[nlink] => 1
|
||||
[uid] => 0
|
||||
[gid] => 0
|
||||
[rdev] => 0
|
||||
[size] => 0
|
||||
[atime] => 0
|
||||
[mtime] => 312768000
|
||||
[ctime] => 0
|
||||
[blksize] => %s
|
||||
[blocks] => %s
|
||||
)
|
||||
|
||||
RAR root is dir:
|
||||
bool(true)
|
||||
|
||||
RAR root variant 2 matches:
|
||||
bool(true)
|
||||
|
||||
RAR root variant 3 matches:
|
||||
bool(true)
|
||||
|
||||
Regular file:
|
||||
Array
|
||||
(
|
||||
[dev] => 0
|
||||
[ino] => 0
|
||||
[mode] => 33188
|
||||
[nlink] => 1
|
||||
[uid] => 0
|
||||
[gid] => 0
|
||||
[rdev] => 0
|
||||
[size] => 8
|
||||
[atime] => 0
|
||||
[mtime] => 1259625512
|
||||
[ctime] => 0
|
||||
[blksize] => %s
|
||||
[blocks] => %s
|
||||
)
|
||||
|
||||
Regular file:
|
||||
Array
|
||||
(
|
||||
[dev] => 0
|
||||
[ino] => 0
|
||||
[mode] => 16877
|
||||
[nlink] => 1
|
||||
[uid] => 0
|
||||
[gid] => 0
|
||||
[rdev] => 0
|
||||
[size] => 0
|
||||
[atime] => 0
|
||||
[mtime] => 1259625807
|
||||
[ctime] => 0
|
||||
[blksize] => %s
|
||||
[blocks] => %s
|
||||
)
|
||||
Done.
|
||||
61
tests/060.phpt
Normal file
61
tests/060.phpt
Normal file
@@ -0,0 +1,61 @@
|
||||
--TEST--
|
||||
RAR directory stream basic test
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if(!extension_loaded("rar")) die("skip");
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
echo "Root entries unencoded:\n";
|
||||
$u = "rar://" .
|
||||
dirname(__FILE__) . '/dirs_and_extra_headers.rar*';
|
||||
|
||||
$d = dir($u);
|
||||
while (false !== ($entry = $d->read())) {
|
||||
echo $entry."\n";
|
||||
}
|
||||
$d->close();
|
||||
|
||||
echo "\nRoot entries encoded:\n";
|
||||
$u = "rar://" .
|
||||
dirname(__FILE__) . '/dirs_and_extra_headers.rar';
|
||||
|
||||
$d = dir($u);
|
||||
while (false !== ($entry = $d->read())) {
|
||||
echo $entry."\n";
|
||||
}
|
||||
$d->close();
|
||||
|
||||
echo "\nSub-root directory entries unencoded:\n";
|
||||
$u = "rar://" .
|
||||
dirname(__FILE__) . '/dirs_and_extra_headers.rar*#%EF%AC%B0';
|
||||
|
||||
$d = dir($u);
|
||||
while (false !== ($entry = $d->read())) {
|
||||
echo $entry."\n";
|
||||
}
|
||||
|
||||
echo "\nDone.\n";
|
||||
--EXPECTF--
|
||||
Root entries unencoded:
|
||||
allow_everyone_ni
|
||||
file1.txt
|
||||
file2_אּ.txt
|
||||
with_streams.txt
|
||||
אּ
|
||||
|
||||
Root entries encoded:
|
||||
allow_everyone_ni
|
||||
file1.txt
|
||||
file2_%EF%AC%B0.txt
|
||||
with_streams.txt
|
||||
%EF%AC%B0
|
||||
|
||||
Sub-root directory entries unencoded:
|
||||
%2Fempty%2E
|
||||
empty
|
||||
file3.txt
|
||||
file4_אּ.txt
|
||||
אּ_2
|
||||
|
||||
Done.
|
||||
17
tests/061.phpt
Normal file
17
tests/061.phpt
Normal file
@@ -0,0 +1,17 @@
|
||||
--TEST--
|
||||
RAR directory stream attempt on file
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if(!extension_loaded("rar")) die("skip");
|
||||
--FILE--
|
||||
<?php
|
||||
$u = "rar://" .
|
||||
dirname(__FILE__) . '/dirlink_unix.rar' .
|
||||
"#file";
|
||||
var_dump(opendir($u));
|
||||
|
||||
echo "Done.\n";
|
||||
--EXPECTF--
|
||||
Warning: opendir(rar://%sdirlink_unix.rar#file): failed to open dir: Archive %sdirlink_unix.rar has an entry named file, but it is not a directory in %s on line %d
|
||||
bool(false)
|
||||
Done.
|
||||
63
tests/062.phpt
Normal file
63
tests/062.phpt
Normal file
@@ -0,0 +1,63 @@
|
||||
--TEST--
|
||||
RAR directory stream stat
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if(!extension_loaded("rar")) die("skip");
|
||||
--ENV--
|
||||
TZ=Europe/Lisbon
|
||||
--FILE--
|
||||
<?php
|
||||
umask(0);
|
||||
|
||||
echo "Root:\n";
|
||||
|
||||
$u = "rar://" .
|
||||
dirname(__FILE__) . '/dirs_and_extra_headers.rar';
|
||||
|
||||
print_r(array_slice(fstat(opendir($u)), 13));
|
||||
|
||||
echo "\nSub-root directory:\n";
|
||||
|
||||
$u = "rar://" .
|
||||
dirname(__FILE__) . '/dirs_and_extra_headers.rar#%EF%AC%B0';
|
||||
|
||||
print_r(array_slice(fstat(opendir($u)), 13));
|
||||
|
||||
echo "Done.\n";
|
||||
--EXPECTF--
|
||||
Root:
|
||||
Array
|
||||
(
|
||||
[dev] => 0
|
||||
[ino] => 0
|
||||
[mode] => 16895
|
||||
[nlink] => 1
|
||||
[uid] => 0
|
||||
[gid] => 0
|
||||
[rdev] => 0
|
||||
[size] => 0
|
||||
[atime] => 0
|
||||
[mtime] => 312768000
|
||||
[ctime] => 0
|
||||
[blksize] => %s
|
||||
[blocks] => %s
|
||||
)
|
||||
|
||||
Sub-root directory:
|
||||
Array
|
||||
(
|
||||
[dev] => 0
|
||||
[ino] => 0
|
||||
[mode] => 16895
|
||||
[nlink] => 1
|
||||
[uid] => 0
|
||||
[gid] => 0
|
||||
[rdev] => 0
|
||||
[size] => 0
|
||||
[atime] => 1272935043
|
||||
[mtime] => 1272935043
|
||||
[ctime] => 1272809570
|
||||
[blksize] => %s
|
||||
[blocks] => %s
|
||||
)
|
||||
Done.
|
||||
30
tests/063.phpt
Normal file
30
tests/063.phpt
Normal file
@@ -0,0 +1,30 @@
|
||||
--TEST--
|
||||
RAR directory stream stat consistency with url stat
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if(!extension_loaded("rar")) die("skip");
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
echo "Root:\n";
|
||||
|
||||
$u = "rar://" .
|
||||
dirname(__FILE__) . '/dirs_and_extra_headers.rar';
|
||||
|
||||
var_dump(fstat(opendir($u)) == stat($u));
|
||||
|
||||
echo "\nSub-root directory:\n";
|
||||
|
||||
$u = "rar://" .
|
||||
dirname(__FILE__) . '/dirs_and_extra_headers.rar#%EF%AC%B0';
|
||||
|
||||
var_dump(fstat(opendir($u)) == stat($u));
|
||||
|
||||
echo "Done.\n";
|
||||
--EXPECTF--
|
||||
Root:
|
||||
bool(true)
|
||||
|
||||
Sub-root directory:
|
||||
bool(true)
|
||||
Done.
|
||||
51
tests/064.phpt
Normal file
51
tests/064.phpt
Normal file
@@ -0,0 +1,51 @@
|
||||
--TEST--
|
||||
RAR directory-aware traversal with directory streams
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if(!extension_loaded("rar")) die("skip");
|
||||
--FILE--
|
||||
<?php
|
||||
$a = "rar://" . dirname(__FILE__) . '/dirs_and_extra_headers.rar';
|
||||
$stack = array();
|
||||
$dh = opendir($a);
|
||||
if ($dh) {
|
||||
array_push($stack, array("", $dh));
|
||||
}
|
||||
$indent = 0;
|
||||
while (!empty($stack)) {
|
||||
$arr = array_pop($stack);
|
||||
$prefix = $arr[0];
|
||||
$cd = $arr[1];
|
||||
while (($file = readdir($cd)) !== false) {
|
||||
$u = $a . "#" . $prefix . "/" . $file;
|
||||
$isdir = is_dir($u);
|
||||
echo str_repeat(" ", $indent) .
|
||||
"- ".rawurldecode($file)." ". ($isdir?"(dir)":""). "\n";
|
||||
if ($isdir) {
|
||||
if (($dh = opendir($u)) === false)
|
||||
die("could not open $u");
|
||||
$indent++;
|
||||
array_push($stack, array($prefix, $cd));
|
||||
$cd = $dh;
|
||||
$prefix = $prefix . "/" . $file;
|
||||
}
|
||||
}
|
||||
$indent--;
|
||||
}
|
||||
|
||||
echo "Done.\n";
|
||||
--EXPECTF--
|
||||
- allow_everyone_ni (dir)
|
||||
- file1.txt
|
||||
- file2_אּ.txt
|
||||
- with_streams.txt
|
||||
- אּ (dir)
|
||||
- %2Fempty%2E (dir)
|
||||
- file7.txt
|
||||
- empty (dir)
|
||||
- file3.txt
|
||||
- file4_אּ.txt
|
||||
- אּ_2 (dir)
|
||||
- file5.txt
|
||||
- file6_אּ.txt
|
||||
Done.
|
||||
57
tests/065.phpt
Normal file
57
tests/065.phpt
Normal file
@@ -0,0 +1,57 @@
|
||||
--TEST--
|
||||
Directory streams compatibility with RecursiveDirectoryIterator
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if(!extension_loaded("rar")) die("skip");
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$a = "rar://" . dirname(__FILE__) . '/dirs_and_extra_headers.rar#';
|
||||
$it = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($a),
|
||||
RecursiveIteratorIterator::LEAVES_ONLY);
|
||||
|
||||
$it->rewind();
|
||||
while($it->valid()) {
|
||||
if (!$it->isDot()) {
|
||||
echo 'SubPathName: ' . rawurldecode($it->getSubPathName()) . "\n";
|
||||
echo 'SubPath: ' . rawurldecode($it->getSubPath()) . "\n";
|
||||
echo 'Key: ' . $it->key() . "\n\n";
|
||||
}
|
||||
$it->next();
|
||||
}
|
||||
|
||||
echo "Done.\n";
|
||||
--EXPECTF--
|
||||
SubPathName: file1.txt
|
||||
SubPath:
|
||||
Key: rar://%s/dirs_and_extra_headers.rar#%sfile1.txt
|
||||
|
||||
SubPathName: file2_אּ.txt
|
||||
SubPath:
|
||||
Key: rar://%s/dirs_and_extra_headers.rar#%sfile2_%EF%AC%B0.txt
|
||||
|
||||
SubPathName: with_streams.txt
|
||||
SubPath:
|
||||
Key: rar://%s/dirs_and_extra_headers.rar#%swith_streams.txt
|
||||
|
||||
SubPathName: אּ%s%2Fempty%2E%sfile7.txt
|
||||
SubPath: אּ%s%2Fempty%2E
|
||||
Key: rar://%s/dirs_and_extra_headers.rar#%s%EF%AC%B0%s%252Fempty%252E%sfile7.txt
|
||||
|
||||
SubPathName: אּ%sfile3.txt
|
||||
SubPath: אּ
|
||||
Key: rar://%s/dirs_and_extra_headers.rar#%s%EF%AC%B0%sfile3.txt
|
||||
|
||||
SubPathName: אּ%sfile4_אּ.txt
|
||||
SubPath: אּ
|
||||
Key: rar://%s/dirs_and_extra_headers.rar#%s%EF%AC%B0%sfile4_%EF%AC%B0.txt
|
||||
|
||||
SubPathName: אּ%sאּ_2%sfile5.txt
|
||||
SubPath: אּ%sאּ_2
|
||||
Key: rar://%s/dirs_and_extra_headers.rar#%s%EF%AC%B0%s%EF%AC%B0_2%sfile5.txt
|
||||
|
||||
SubPathName: אּ%sאּ_2%sfile6_אּ.txt
|
||||
SubPath: אּ%sאּ_2
|
||||
Key: rar://%s/dirs_and_extra_headers.rar#%s%EF%AC%B0%s%EF%AC%B0_2%sfile6_%EF%AC%B0.txt
|
||||
|
||||
Done.
|
||||
58
tests/066.phpt
Normal file
58
tests/066.phpt
Normal file
@@ -0,0 +1,58 @@
|
||||
--TEST--
|
||||
RarEntry::extract() (file level password)
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip"; ?>
|
||||
--CLEAN--
|
||||
@unlink(dirname(__FILE__).'/extract_temp');
|
||||
--FILE--
|
||||
<?php
|
||||
$dest = dirname(__FILE__).'/extract_temp';
|
||||
|
||||
echo "--> should fail (no password):\n";
|
||||
$rar_file1 = rar_open(dirname(__FILE__).'/encrypted_only_files.rar');
|
||||
$entries = rar_list($rar_file1);
|
||||
var_dump(count($entries));
|
||||
var_dump($entries[0]->extract(false, $dest));
|
||||
echo "\n";
|
||||
|
||||
echo "--> success (password is the same as the one given on rar_open):\n";
|
||||
$rar_file2 = rar_open(dirname(__FILE__).'/encrypted_only_files.rar', 'samplepassword');
|
||||
$entries = rar_list($rar_file2);
|
||||
var_dump($entries[0]->extract(false, $dest));
|
||||
echo file_get_contents($dest);
|
||||
unlink($dest);
|
||||
echo "\n\n";
|
||||
|
||||
echo "--> should fail (password of 2nd file different from the one given on rar_open):\n";
|
||||
var_dump($entries[1]->extract(false, $dest));
|
||||
echo "\n\n";
|
||||
|
||||
echo "--> should give correct data (password of 2nd file is specified):\n";
|
||||
var_dump($entries[1]->extract(false, $dest, 'samplepassword2'));
|
||||
echo file_get_contents($dest);
|
||||
unlink($dest);
|
||||
echo "\n\n";
|
||||
|
||||
echo "Done\n";
|
||||
--EXPECTF--
|
||||
--> should fail (no password):
|
||||
int(2)
|
||||
|
||||
Warning: RarEntry::extract(): ERAR_MISSING_PASSWORD (password needed but not specified) in %s on line %d
|
||||
bool(false)
|
||||
|
||||
--> success (password is the same as the one given on rar_open):
|
||||
bool(true)
|
||||
Encrypted file 1 contents.
|
||||
|
||||
--> should fail (password of 2nd file different from the one given on rar_open):
|
||||
|
||||
Warning: RarEntry::extract(): ERAR_BAD_DATA in %s on line %d
|
||||
bool(false)
|
||||
|
||||
|
||||
--> should give correct data (password of 2nd file is specified):
|
||||
bool(true)
|
||||
Encrypted file 1 contents.
|
||||
|
||||
Done
|
||||
51
tests/067.phpt
Normal file
51
tests/067.phpt
Normal file
@@ -0,0 +1,51 @@
|
||||
--TEST--
|
||||
RarEntry::extract() process extended (Windows)
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) die("skip");
|
||||
die("skip test is not working under run-tests");
|
||||
if (PHP_OS != 'WINNT') die("skip test for Windows NT");
|
||||
exec('cacls ' . escapeshellarg(dirname(__FILE__)), $perms);
|
||||
function concat($a,$b) { return $a.$b; }
|
||||
$perms = array_reduce($perms, 'concat');
|
||||
if (preg_match('/.* Everyone:\\(OI\\)\\(CI\\)F/i', $perms))
|
||||
die("skip directory has permissions that conflict with this test");
|
||||
?>
|
||||
--CLEAN--
|
||||
@rmdir(dirname(__FILE__).'/temp_directory');
|
||||
--FILE--
|
||||
<?php
|
||||
$fn1 = dirname(__FILE__) . '/dirs_and_extra_headers.rar';
|
||||
$dest = dirname(__FILE__).'/temp_directory';
|
||||
function concat($a,$b) { return $a.$b; }
|
||||
|
||||
@rmdir($dest);
|
||||
|
||||
echo "--> should have default permissions:\n";
|
||||
$rarF = RarArchive::open($fn1);
|
||||
$t = $rarF->getEntry('allow_everyone_ni');
|
||||
$t->extract(false, $dest, NULL);
|
||||
exec('cacls ' . escapeshellarg($dest), $perms);
|
||||
$perms = array_reduce($perms, 'concat');
|
||||
var_dump(preg_match('/.* Everyone:\\(OI\\)\\(CI\\)F/i', $perms));
|
||||
@rmdir($dest);
|
||||
echo "\n";
|
||||
|
||||
echo "--> should have permissions for everyone:\n";
|
||||
$rarF = RarArchive::open($fn1);
|
||||
$t = $rarF->getEntry('allow_everyone_ni');
|
||||
$t->extract(false, $dest, NULL, true);
|
||||
exec('cacls ' . escapeshellarg($dest), $perms);
|
||||
$perms = array_reduce($perms, 'concat');
|
||||
var_dump(preg_match('/.* Everyone:\\(OI\\)\\(CI\\)F/i', $perms));
|
||||
echo "\n";
|
||||
@rmdir($dest);
|
||||
|
||||
echo "Done\n";
|
||||
--EXPECTF--
|
||||
--> should have default permissions:
|
||||
int(0)
|
||||
|
||||
--> should have permissions for everyone:
|
||||
int(1)
|
||||
|
||||
Done
|
||||
12
tests/068.phpt
Normal file
12
tests/068.phpt
Normal file
@@ -0,0 +1,12 @@
|
||||
--TEST--
|
||||
RarArchive direct instantiation does not crash
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) die("skip");
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
new RarArchive();
|
||||
|
||||
echo "Done\n";
|
||||
--EXPECTF--
|
||||
Fatal error: Call to private RarArchive::__construct() from invalid context in %s on line %d
|
||||
12
tests/069.phpt
Normal file
12
tests/069.phpt
Normal file
@@ -0,0 +1,12 @@
|
||||
--TEST--
|
||||
RarEntry direct instantiation does not crash
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) die("skip");
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
new RarEntry();
|
||||
|
||||
echo "Done\n";
|
||||
--EXPECTF--
|
||||
Fatal error: Call to private RarEntry::__construct() from invalid context in %s on line %d
|
||||
17
tests/070.phpt
Normal file
17
tests/070.phpt
Normal file
@@ -0,0 +1,17 @@
|
||||
--TEST--
|
||||
URL stat PHP_STREAM_URL_STAT_QUIET does not leak memory
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip"; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$file = "rar://" .
|
||||
dirname(__FILE__) . '/dirlink_unix.rar' .
|
||||
"#non_existant_file";
|
||||
|
||||
var_dump(is_dir($file));
|
||||
|
||||
echo "Done.\n";
|
||||
--EXPECTF--
|
||||
bool(false)
|
||||
Done.
|
||||
21
tests/071.phpt
Normal file
21
tests/071.phpt
Normal file
@@ -0,0 +1,21 @@
|
||||
--TEST--
|
||||
RarEntry::getPosition() test
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip"; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$file = RarArchive::open(dirname(__FILE__) . '/multi.part1.rar');
|
||||
|
||||
foreach ($file as $e) {
|
||||
echo $e->getPosition() . ". $e\n";
|
||||
}
|
||||
echo "\n";
|
||||
|
||||
echo "Done.\n";
|
||||
--EXPECTF--
|
||||
0. RarEntry for file "file1.txt" (52b28202)
|
||||
1. RarEntry for file "file2.txt" (f2c79881)
|
||||
2. RarEntry for file "file3.txt" (bcbce32e)
|
||||
|
||||
Done.
|
||||
21
tests/072.phpt
Normal file
21
tests/072.phpt
Normal file
@@ -0,0 +1,21 @@
|
||||
--TEST--
|
||||
rar_list handles files with non-unique entry names
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip"; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$file = RarArchive::open(dirname(__FILE__) . '/repeated_name.rar');
|
||||
|
||||
$entries = rar_list($file);
|
||||
foreach ($entries as $e) {
|
||||
echo $e->getPosition() . ". $e\n";
|
||||
}
|
||||
echo "\n";
|
||||
|
||||
echo "Done.\n";
|
||||
--EXPECTF--
|
||||
0. RarEntry for file "file.txt" (ae2a88a7)
|
||||
1. RarEntry for file "file.txt" (771df243)
|
||||
|
||||
Done.
|
||||
25
tests/073.phpt
Normal file
25
tests/073.phpt
Normal file
@@ -0,0 +1,25 @@
|
||||
--TEST--
|
||||
RarEntry::getStream handles files with non-unique entry names
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip"; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$file = RarArchive::open(dirname(__FILE__) . '/repeated_name.rar');
|
||||
|
||||
foreach ($file as $e) {
|
||||
$stream = $e->getStream();
|
||||
if ($stream) {
|
||||
echo $e->getPosition() . ". $e\n";
|
||||
echo stream_get_contents($stream);
|
||||
echo "\n";
|
||||
}
|
||||
}
|
||||
|
||||
echo "Done.\n";
|
||||
--EXPECTF--
|
||||
0. RarEntry for file "file.txt" (ae2a88a7)
|
||||
Content of first file.
|
||||
1. RarEntry for file "file.txt" (771df243)
|
||||
Content of second file.
|
||||
Done.
|
||||
33
tests/074.phpt
Normal file
33
tests/074.phpt
Normal file
@@ -0,0 +1,33 @@
|
||||
--TEST--
|
||||
RarEntry::extract handles files with non-unique entry names
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip"; ?>
|
||||
--CLEAN--
|
||||
<?php
|
||||
$dest = dirname(__FILE__) . "temp_file";
|
||||
@unlink($dest);
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$file = RarArchive::open(dirname(__FILE__) . '/repeated_name.rar');
|
||||
$dest = dirname(__FILE__) . "temp_file";
|
||||
|
||||
foreach ($file as $e) {
|
||||
$res = $e->extract("", $dest);
|
||||
if ($res) {
|
||||
echo $e->getPosition() . ". $e\n";
|
||||
echo file_get_contents($dest);
|
||||
echo "\n";
|
||||
}
|
||||
else {
|
||||
die("failed extraction");
|
||||
}
|
||||
}
|
||||
|
||||
echo "Done.\n";
|
||||
--EXPECTF--
|
||||
0. RarEntry for file "file.txt" (ae2a88a7)
|
||||
Content of first file.
|
||||
1. RarEntry for file "file.txt" (771df243)
|
||||
Content of second file.
|
||||
Done.
|
||||
52
tests/075.phpt
Normal file
52
tests/075.phpt
Normal file
@@ -0,0 +1,52 @@
|
||||
--TEST--
|
||||
RarEntry::getStream NULL can be given to indicate there's no password
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip"; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$file = RarArchive::open(dirname(__FILE__) . '/encrypted_only_files.rar');
|
||||
|
||||
foreach ($file as $e) {
|
||||
echo "* No password given:\n";
|
||||
$stream = $e->getStream();
|
||||
var_dump($stream);
|
||||
|
||||
echo "\n* NULL given (should have the same effect as no password):\n";
|
||||
$stream = $e->getStream(NULL);
|
||||
var_dump($stream);
|
||||
|
||||
echo "\n* empty string given as password (should have the same effect; "
|
||||
. "rar disallows empty passwords):\n";
|
||||
$stream = $e->getStream('');
|
||||
var_dump($stream);
|
||||
|
||||
echo "\n* non-empty password given; should give stream:\n";
|
||||
$stream = $e->getStream('bugabuga');
|
||||
var_dump($stream);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
echo "\n";
|
||||
echo "Done.\n";
|
||||
--EXPECTF--
|
||||
* No password given:
|
||||
|
||||
Warning: RarEntry::getStream(): ERAR_MISSING_PASSWORD (password needed but not specified) in %s on line %d
|
||||
bool(false)
|
||||
|
||||
* NULL given (should have the same effect as no password):
|
||||
|
||||
Warning: RarEntry::getStream(): ERAR_MISSING_PASSWORD (password needed but not specified) in %s on line %d
|
||||
bool(false)
|
||||
|
||||
* empty string given as password (should have the same effect; rar disallows empty passwords):
|
||||
|
||||
Warning: RarEntry::getStream(): ERAR_MISSING_PASSWORD (password needed but not specified) in %s on line %d
|
||||
bool(false)
|
||||
|
||||
* non-empty password given; should give stream:
|
||||
resource(%d) of type (stream)
|
||||
|
||||
Done.
|
||||
60
tests/076.phpt
Normal file
60
tests/076.phpt
Normal file
@@ -0,0 +1,60 @@
|
||||
--TEST--
|
||||
RarEntry::extract NULL can be given to indicate there's no password
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip"; ?>
|
||||
--CLEAN--
|
||||
<?php
|
||||
$dest = dirname(__FILE__) . "temp_file";
|
||||
@unlink($dest);
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$file = RarArchive::open(dirname(__FILE__) . '/encrypted_only_files.rar');
|
||||
|
||||
$dest = dirname(__FILE__) . "temp_file";
|
||||
|
||||
foreach ($file as $e) {
|
||||
echo "* No password given:\n";
|
||||
$result = $e->extract('', $dest);
|
||||
var_dump($result);
|
||||
|
||||
echo "\n* NULL given (should have the same effect as no password):\n";
|
||||
$result = $e->extract('', $dest, NULL);
|
||||
var_dump($result);
|
||||
|
||||
echo "\n* empty string given as password (should have the same ".
|
||||
"effect as no password):\n";
|
||||
$result = $e->extract('', $dest, '');
|
||||
var_dump($result);
|
||||
|
||||
echo "\n* password given; a wrong one:\n";
|
||||
$result = $e->extract('', $dest, 'wrongpassword');
|
||||
var_dump($result);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
echo "\n";
|
||||
echo "Done.\n";
|
||||
--EXPECTF--
|
||||
* No password given:
|
||||
|
||||
Warning: RarEntry::extract(): ERAR_MISSING_PASSWORD (password needed but not specified) in %s on line %d
|
||||
bool(false)
|
||||
|
||||
* NULL given (should have the same effect as no password):
|
||||
|
||||
Warning: RarEntry::extract(): ERAR_MISSING_PASSWORD (password needed but not specified) in %s on line %d
|
||||
bool(false)
|
||||
|
||||
* empty string given as password (should have the same effect as no password):
|
||||
|
||||
Warning: RarEntry::extract(): ERAR_MISSING_PASSWORD (password needed but not specified) in %s on line %d
|
||||
bool(false)
|
||||
|
||||
* password given; a wrong one:
|
||||
|
||||
Warning: RarEntry::extract(): ERAR_BAD_DATA in %s on line %d
|
||||
bool(false)
|
||||
|
||||
Done.
|
||||
42
tests/077.phpt
Normal file
42
tests/077.phpt
Normal file
@@ -0,0 +1,42 @@
|
||||
--TEST--
|
||||
RarArchive::open NULL can be given to indicate there's no password
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip"; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$f = dirname(__FILE__) . '/encrypted_headers.rar';
|
||||
|
||||
echo "* No password given:\n";
|
||||
$file = RarArchive::open($f);
|
||||
rar_list($file);
|
||||
|
||||
echo "* NULL given:\n";
|
||||
$file = RarArchive::open($f, NULL);
|
||||
rar_list($file);
|
||||
|
||||
echo "* empty string given:\n";
|
||||
$file = RarArchive::open($f, '');
|
||||
rar_list($file);
|
||||
|
||||
echo "* wrong password given:\n";
|
||||
$file = RarArchive::open($f, "wrongpassword");
|
||||
rar_list($file);
|
||||
|
||||
echo "\n";
|
||||
echo "Done.\n";
|
||||
--EXPECTF--
|
||||
* No password given:
|
||||
|
||||
Warning: rar_list(): ERAR_MISSING_PASSWORD (password needed but not specified) in %s on line %d
|
||||
* NULL given:
|
||||
|
||||
Warning: rar_list(): ERAR_MISSING_PASSWORD (password needed but not specified) in %s on line %d
|
||||
* empty string given:
|
||||
|
||||
Warning: rar_list(): ERAR_MISSING_PASSWORD (password needed but not specified) in %s on line %d
|
||||
* wrong password given:
|
||||
|
||||
Warning: rar_list(): ERAR_BAD_DATA in %s on line %d
|
||||
|
||||
Done.
|
||||
67
tests/078.phpt
Normal file
67
tests/078.phpt
Normal file
@@ -0,0 +1,67 @@
|
||||
--TEST--
|
||||
Traversal of volume with only an archive continue from last volume
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip"; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$f = dirname(__FILE__) . "/garbage.part03.rar";
|
||||
|
||||
echo "Traversal with rar_list:\n";
|
||||
$a = RarArchive::open($f);
|
||||
var_dump(rar_list($a));
|
||||
|
||||
echo "Traversal with rar_list (again with the same object):\n";
|
||||
var_dump(rar_list($a));
|
||||
|
||||
echo "\nTraversal with foreach:\n";
|
||||
$a = RarArchive::open($f);
|
||||
foreach ($a as $e) {
|
||||
die("should not get here");
|
||||
}
|
||||
echo "Success.\n";
|
||||
|
||||
echo "\nUsage of RarArchive::getEntry:\n";
|
||||
$a = RarArchive::open($f);
|
||||
var_dump($a->getEntry("garbage.txt"));
|
||||
|
||||
echo "\nUsage of directory stream:\n";
|
||||
$it = new DirectoryIterator("rar://" . rawurlencode($f));
|
||||
foreach ($it as $e) {
|
||||
die("should not get here");
|
||||
}
|
||||
echo "Success.\n";
|
||||
|
||||
echo "\nUsage of static url stat:\n";
|
||||
stat("rar://" . rawurlencode($f) . "#not_there");
|
||||
echo "Success.\n";
|
||||
|
||||
echo "\n";
|
||||
echo "Done.\n";
|
||||
--EXPECTF--
|
||||
Traversal with rar_list:
|
||||
array(0) {
|
||||
}
|
||||
Traversal with rar_list (again with the same object):
|
||||
array(0) {
|
||||
}
|
||||
|
||||
Traversal with foreach:
|
||||
Success.
|
||||
|
||||
Usage of RarArchive::getEntry:
|
||||
|
||||
Warning: RarArchive::getEntry(): cannot find file "garbage.txt" in Rar archive "%sgarbage.part03.rar" in %s on line %d
|
||||
bool(false)
|
||||
|
||||
Usage of directory stream:
|
||||
Success.
|
||||
|
||||
Usage of static url stat:
|
||||
|
||||
Warning: stat(): Found no entry not_there in archive %sgarbage.part03.rar in %s on line %d
|
||||
|
||||
Warning: stat(): stat failed for rar://%sgarbage.part03.rar#not_there in %s on line %d
|
||||
Success.
|
||||
|
||||
Done.
|
||||
65
tests/079.phpt
Normal file
65
tests/079.phpt
Normal file
@@ -0,0 +1,65 @@
|
||||
--TEST--
|
||||
RarArchive count elements handler test
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip"; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$f = dirname(__FILE__) . "/dirs_and_extra_headers.rar";
|
||||
$fempty = dirname(__FILE__) . "/garbage.part03.rar";
|
||||
|
||||
echo "* Normal test:\n";
|
||||
$a = RarArchive::open($f);
|
||||
echo "Count: " . count($a) . "\n";
|
||||
|
||||
echo "\n* Closed file test (1):\n";
|
||||
$a = RarArchive::open($f);
|
||||
$a->close();
|
||||
var_dump(count($a));
|
||||
|
||||
echo "\n* Closed file test (2):\n";
|
||||
$a = RarArchive::open($f);
|
||||
$a->getEntries();
|
||||
$a->close();
|
||||
var_dump(count($a));
|
||||
|
||||
echo "\n* Closed file test (3, exceptions):\n";
|
||||
$a = RarArchive::open($f);
|
||||
RarException::setUsingExceptions(true);
|
||||
$a->getEntries();
|
||||
$a->close();
|
||||
try {
|
||||
var_dump(count($a));
|
||||
} catch (RarException $e) {
|
||||
echo "OK, threw exception with message \"".$e->getMessage()."\"\n";
|
||||
}
|
||||
RarException::setUsingExceptions(false);
|
||||
|
||||
echo "\n* Empty file:\n";
|
||||
|
||||
$a = RarArchive::open($fempty);
|
||||
echo "Count: " . count($a) . "\n";
|
||||
|
||||
echo "\n";
|
||||
echo "Done.\n";
|
||||
--EXPECTF--
|
||||
* Normal test:
|
||||
Count: 13
|
||||
|
||||
* Closed file test (1):
|
||||
|
||||
Warning: count(): The archive is already closed in %s on line %d
|
||||
int(0)
|
||||
|
||||
* Closed file test (2):
|
||||
|
||||
Warning: count(): The archive is already closed in %s on line %d
|
||||
int(0)
|
||||
|
||||
* Closed file test (3, exceptions):
|
||||
OK, threw exception with message "The archive is already closed"
|
||||
|
||||
* Empty file:
|
||||
Count: 0
|
||||
|
||||
Done.
|
||||
109
tests/080.phpt
Normal file
109
tests/080.phpt
Normal file
@@ -0,0 +1,109 @@
|
||||
--TEST--
|
||||
File stream EOF behavior
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip"; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$a = RarArchive::open(dirname(__FILE__) . "/multi.part1.rar");
|
||||
$a2 = RarArchive::open(dirname(__FILE__) . "/4mb.rar");
|
||||
|
||||
function echoeof($stream) {
|
||||
echo feof($stream)?"At eof":"Not at eof";
|
||||
echo "\n";
|
||||
}
|
||||
|
||||
echo "* First fread is given file size:\n";
|
||||
$stream = $a->getEntry("file1.txt")->getStream();
|
||||
echoeof($stream);
|
||||
var_dump(fread($stream, 18));
|
||||
echoeof($stream);
|
||||
var_dump(fread($stream, 1));
|
||||
echoeof($stream);
|
||||
|
||||
echo "\n* First fread is given size - 1:\n";
|
||||
$stream = $a->getEntry("file1.txt")->getStream();
|
||||
echoeof($stream);
|
||||
var_dump(fread($stream, 17));
|
||||
echoeof($stream);
|
||||
var_dump(fread($stream, 1));
|
||||
echoeof($stream);
|
||||
var_dump(fread($stream, 1));
|
||||
echoeof($stream);
|
||||
|
||||
echo "\n* First fread is given size + 1:\n";
|
||||
$stream = $a->getEntry("file1.txt")->getStream();
|
||||
echoeof($stream);
|
||||
var_dump(fread($stream, 19));
|
||||
echoeof($stream);
|
||||
|
||||
echo "\n* Read is aligned with dictionary, buffer and file size:\n";
|
||||
$stream = $a2->getEntry("4mb.txt")->getStream();
|
||||
echoeof($stream);
|
||||
var_dump(strlen(fread($stream, 4194304)));
|
||||
echoeof($stream);
|
||||
var_dump(strlen(fread($stream, 1)));
|
||||
echoeof($stream);
|
||||
|
||||
echo "\n* Read is dictionary, buffer and file size - 1:\n";
|
||||
$stream = $a2->getEntry("4mb.txt")->getStream();
|
||||
echoeof($stream);
|
||||
var_dump(strlen(fread($stream, 4194303)));
|
||||
echoeof($stream);
|
||||
var_dump(strlen(fread($stream, 1)));
|
||||
echoeof($stream);
|
||||
var_dump(strlen(fread($stream, 1)));
|
||||
echoeof($stream);
|
||||
|
||||
echo "\n* Read is dictionary, buffer and file size + 1:\n";
|
||||
$stream = $a2->getEntry("4mb.txt")->getStream();
|
||||
echoeof($stream);
|
||||
var_dump(strlen(fread($stream, 4194305)));
|
||||
echoeof($stream);
|
||||
|
||||
echo "\n";
|
||||
echo "Done.\n";
|
||||
--EXPECTF--
|
||||
* First fread is given file size:
|
||||
Not at eof
|
||||
string(18) "contents of file 1"
|
||||
Not at eof
|
||||
string(0) ""
|
||||
At eof
|
||||
|
||||
* First fread is given size - 1:
|
||||
Not at eof
|
||||
string(17) "contents of file "
|
||||
Not at eof
|
||||
string(1) "1"
|
||||
Not at eof
|
||||
string(0) ""
|
||||
At eof
|
||||
|
||||
* First fread is given size + 1:
|
||||
Not at eof
|
||||
string(18) "contents of file 1"
|
||||
At eof
|
||||
|
||||
* Read is aligned with dictionary, buffer and file size:
|
||||
Not at eof
|
||||
int(4194304)
|
||||
Not at eof
|
||||
int(0)
|
||||
At eof
|
||||
|
||||
* Read is dictionary, buffer and file size - 1:
|
||||
Not at eof
|
||||
int(4194303)
|
||||
Not at eof
|
||||
int(1)
|
||||
Not at eof
|
||||
int(0)
|
||||
At eof
|
||||
|
||||
* Read is dictionary, buffer and file size + 1:
|
||||
Not at eof
|
||||
int(4194304)
|
||||
At eof
|
||||
|
||||
Done.
|
||||
92
tests/081.phpt
Normal file
92
tests/081.phpt
Normal file
@@ -0,0 +1,92 @@
|
||||
--TEST--
|
||||
rar_list et al. give consistent results if called twice
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip"; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$f = dirname(__FILE__) . "/multi_broken.part1.rar";
|
||||
|
||||
echo "* rar_list():\n";
|
||||
$a = RarArchive::open($f);
|
||||
var_dump(rar_list($a));
|
||||
var_dump(rar_list($a));
|
||||
|
||||
echo "\n* rar_entry_get():\n";
|
||||
$a = RarArchive::open($f);
|
||||
var_dump($a->getEntry("file1.txt"));
|
||||
var_dump($a->getEntry("file1.txt"));
|
||||
|
||||
echo "\n* dimension access:\n";
|
||||
$a = RarArchive::open($f);
|
||||
var_dump($a[0]);
|
||||
var_dump($a[0]);
|
||||
|
||||
echo "\n* foreach access:\n";
|
||||
$a = RarArchive::open($f);
|
||||
foreach ($a as $e) { echo "shouldn't happen: $e\n"; };
|
||||
foreach ($a as $e) { echo "shouldn't happen: $e\n"; };
|
||||
|
||||
echo "\n* url stat:\n";
|
||||
var_dump(stat("rar://".rawurlencode($f)."#file1.txt"));
|
||||
var_dump(stat("rar://".rawurlencode($f)."#file1.txt"));
|
||||
//no need to test directory open, _rar_get_cachable_rararch handles it too
|
||||
|
||||
echo "\n";
|
||||
echo "Done.\n";
|
||||
--EXPECTF--
|
||||
* rar_list():
|
||||
|
||||
Warning: rar_list(): Volume %smulti_broken.part2.rar was not found in %s on line %d
|
||||
|
||||
Warning: rar_list(): ERAR_EOPEN (file open error) in %s on line %d
|
||||
bool(false)
|
||||
|
||||
Warning: rar_list(): ERAR_EOPEN (file open error) in %s on line %d
|
||||
bool(false)
|
||||
|
||||
* rar_entry_get():
|
||||
|
||||
Warning: RarArchive::getEntry(): Volume %smulti_broken.part2.rar was not found in %s on line %d
|
||||
|
||||
Warning: RarArchive::getEntry(): ERAR_EOPEN (file open error) in %s on line %d
|
||||
bool(false)
|
||||
|
||||
Warning: RarArchive::getEntry(): ERAR_EOPEN (file open error) in %s on line %d
|
||||
bool(false)
|
||||
|
||||
* dimension access:
|
||||
|
||||
Warning: main(): Volume %smulti_broken.part2.rar was not found in %s on line %d
|
||||
|
||||
Warning: main(): ERAR_EOPEN (file open error) in %s on line %d
|
||||
NULL
|
||||
|
||||
Warning: main(): ERAR_EOPEN (file open error) in %s on line %d
|
||||
NULL
|
||||
|
||||
* foreach access:
|
||||
|
||||
Warning: main(): Volume %smulti_broken.part2.rar was not found in %s on line %d
|
||||
|
||||
Warning: main(): ERAR_EOPEN (file open error) in %s on line %d
|
||||
|
||||
Warning: main(): ERAR_EOPEN (file open error) in %s on line %d
|
||||
|
||||
* url stat:
|
||||
|
||||
Warning: stat(): Volume %smulti_broken.part2.rar was not found in %s on line %d
|
||||
|
||||
Warning: stat(): Error reading entries of archive %smulti_broken.part1.rar: ERAR_EOPEN (file open error) in %s on line %d
|
||||
|
||||
Warning: stat(): stat failed for rar://%smulti_broken.part1.rar#file1.txt in %s on line %s
|
||||
bool(false)
|
||||
|
||||
Warning: stat(): Volume %smulti_broken.part2.rar was not found in %s on line %d
|
||||
|
||||
Warning: stat(): Error reading entries of archive %smulti_broken.part1.rar: ERAR_EOPEN (file open error) in %s on line %d
|
||||
|
||||
Warning: stat(): stat failed for rar://%smulti_broken.part1.rar#file1.txt in %s on line %d
|
||||
bool(false)
|
||||
|
||||
Done.
|
||||
36
tests/082.phpt
Normal file
36
tests/082.phpt
Normal file
@@ -0,0 +1,36 @@
|
||||
--TEST--
|
||||
RarArchive read_property handler basic test
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip"; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
//see also test #81 for broken archives
|
||||
|
||||
$f1 = dirname(__FILE__) . "/latest_winrar.rar";
|
||||
$f2 = dirname(__FILE__) . "/multi.part1.rar";
|
||||
|
||||
echo "* latest_winrar.rar:\n";
|
||||
$a = RarArchive::open($f1);
|
||||
for ($i = 0; $i < 2; $i++) {
|
||||
echo ($i + 1) . ". $a[$i]\n";
|
||||
}
|
||||
|
||||
echo "\n* multi.part1.rar:\n";
|
||||
$a = RarArchive::open($f2);
|
||||
for ($i = 0; $i < 2; $i++) {
|
||||
echo ($i + 1) . ". $a[$i]\n";
|
||||
}
|
||||
|
||||
echo "\n";
|
||||
echo "Done.\n";
|
||||
--EXPECTF--
|
||||
* latest_winrar.rar:
|
||||
1. RarEntry for file "1.txt" (a0de71c0)
|
||||
2. RarEntry for file "2.txt" (45a918de)
|
||||
|
||||
* multi.part1.rar:
|
||||
1. RarEntry for file "file1.txt" (52b28202)
|
||||
2. RarEntry for file "file2.txt" (f2c79881)
|
||||
|
||||
Done.
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user