78 Commits

Author SHA1 Message Date
Jean-Baptiste Nahan
1a623543c4 Merge pull request #2 from php-win-ext/clean_repo
📝 clean repo and add some informations
2026-02-25 09:32:08 +01:00
macintoshplus
cfffb63b5a 📝 clean repo and add some informations 2026-02-25 00:48:39 +01:00
Jean-Baptiste Nahan
c99b6925ad Merge pull request #1 from php-win-ext/add_build_release
Update Code and Tests
2026-02-25 00:37:02 +01:00
macintoshplus
792c622f3e remove php 8.1 limitation for Windows test 2026-02-25 00:28:11 +01:00
macintoshplus
3f507ce2db update test for Windows x86 platform 2026-02-25 00:25:46 +01:00
macintoshplus
7ba9c28e15 try fix test 092 on Windows 2026-02-25 00:05:22 +01:00
macintoshplus
717d75ec8e add dump in test for debug test on windows 2026-02-24 23:49:33 +01:00
macintoshplus
498286b7af 👷 fix Windows test 041 fail 2026-02-24 23:35:48 +01:00
macintoshplus
d1c7fcd5a1 👷 fix test for Windows 2026-02-24 23:33:42 +01:00
macintoshplus
55d30dfa5d enable window CI for branches 2026-02-24 23:23:26 +01:00
macintoshplus
52f8a34342 🔧 update gitignore 2026-02-24 23:20:57 +01:00
macintoshplus
5a930a03aa 💚 fix CI PHP TS value 2026-02-24 23:18:14 +01:00
macintoshplus
234a78c2f7 💚 fix CI for PHP 8.5 2026-02-24 23:15:05 +01:00
macintoshplus
19b94313c2 update code for PHP 8.2+ 2026-02-24 22:48:56 +01:00
macintoshplus
7b2749af57 Add GitHub workflow and PIE Configuration 2026-02-24 22:11:42 +01:00
Gustavo Lopes
ab26d28575 Fixes for PHP 8.1 2021-08-16 01:28:05 +01:00
Gustavo Lopes
488dd3caaa Release 4.2.0 2020-12-06 19:57:33 +00:00
Gustavo Lopes
1dc896be94 Merge branch 'unrar', with unrar 6.0.2 2020-12-06 19:46:49 +00:00
Gustavo Lopes
36345d004e Added unrar 6.0.2 2020-12-06 19:45:17 +00:00
Gustavo Lopes
8f070c282f Added unrar 6.0.1 2020-12-06 19:45:04 +00:00
Gustavo Lopes
91ed5b09a0 Publish coverage on codecov 2020-12-06 19:38:25 +00:00
Gustavo Lopes
d95cab037b Support PHP 8 2020-12-06 19:18:01 +00:00
Gustavo Lopes
7cff10aa2c Suppress warnings in PHP header files 2020-12-06 19:18:01 +00:00
Gustavo Lopes
5b94797037 Backport PHP8's run-tests.php 2020-12-06 19:18:01 +00:00
Gustavo Lopes
4ff664b2b0 Merge pull request #9 from Alexander1000/remove-never-used
remove never used piece of code
2020-11-25 14:31:21 +00:00
Aleksandr Dankovtsev
2e13165bdb remove never used piece of code 2020-11-23 22:01:33 +03:00
Gustavo Lopes
d0cd509090 Release 4.1.0 2020-10-11 19:18:11 +01:00
Gustavo Lopes
bd65eab735 Compile with -fvisibility=hidden 2020-10-11 19:01:59 +01:00
Gustavo Lopes
45742b94ab Update to unrar 5.9.4 2020-10-11 18:56:44 +01:00
Gustavo Lopes
6545fdd215 Added unrar 5.9.4 2020-10-11 18:54:32 +01:00
Gustavo Lopes
08f8190e49 Added unrar 5.9.3 2020-10-11 18:54:32 +01:00
Gustavo Lopes
095b4cdd58 Fix PHP 7.4 valgrind tests 2020-10-11 18:38:57 +01:00
Gustavo Lopes
da32228c34 The buffer must be at least as big as the window size 2020-10-11 17:30:15 +01:00
Gustavo Lopes
2788a30227 Warn when we read more data than the file's declared size
Last commit changed how data is read for solid files, but this had a
side effect in that the data returned by the unrar lib was no longer
limited to the size of the file, as declared in its header.

Still keep this new behavior, but add a warning when this happens.
2020-10-11 17:30:15 +01:00
Gustavo Lopes
e0c6c97ef0 Fix bug 76592: streaming unpacking of uncompressed files incomplete 2020-10-11 17:30:15 +01:00
Gustavo Lopes
2322542282 Fixup CI 2020-10-01 09:39:56 +01:00
Gustavo Lopes
2b12de7a8f 7.4 fixes 2020-09-28 09:44:36 +01:00
Gustavo Lopes
23430540f1 Travis to Azure 2020-09-28 09:43:30 +01:00
Gustavo Lopes
e3f3ecd1ab Update to unrar 5.9.2 2020-09-27 23:36:29 +01:00
Gustavo Lopes
544f55920a Add unrar 5.9.2 2020-04-29 20:12:36 +01:00
Gustavo Lopes
24b421e0e6 Add unrar 5.9.1 2020-04-29 20:12:36 +01:00
Gustavo Lopes
05a48cbbeb Added unrar 5.8.5 2020-04-29 20:12:36 +01:00
Gustavo Lopes
6d0e583ef9 Added unrar 5.8.4 2020-04-29 20:12:36 +01:00
Gustavo Lopes
714f15cb06 Added unrar 5.8.3 2020-04-29 20:12:36 +01:00
Gustavo Lopes
58bb195ae3 Added unrar 5.8.2 2020-04-29 20:12:36 +01:00
Gustavo Lopes
5293a8f07e Added unrar 5.8.1 2020-04-29 20:12:36 +01:00
Gustavo Lopes
61edb08973 Added unrar 5.7.5 2020-04-29 20:12:36 +01:00
Gustavo Lopes
adc9fe7d39 Added unrar 5.7.4 2020-04-29 20:12:36 +01:00
Gustavo Lopes
5eb1055447 Added unrar 5.7.3 2020-04-29 20:12:36 +01:00
Gustavo Lopes
7ca7561e09 Added unrar 5.7.2 2020-04-29 20:12:36 +01:00
Gustavo Lopes
61eca15136 Added unrar 5.7.1 2020-04-29 20:12:36 +01:00
Gustavo Lopes
dc8ee65999 Added unrar 5.6.8 2020-04-29 20:12:36 +01:00
Gustavo Lopes
656c3fa69d Added unrar 5.6.7 2020-04-29 20:12:36 +01:00
Gustavo Lopes
a6bea8fec8 Added unrar 5.6.6 2020-04-29 20:12:36 +01:00
Gustavo Lopes
3b405bea8e Added unrar 5.6.5 2020-04-29 20:12:36 +01:00
Gustavo Lopes
18cd0568aa Added unrar 5.6.4 2020-04-29 20:12:36 +01:00
Gustavo Lopes
dc298847c7 Added unrar 5.6.3 2020-04-29 20:12:36 +01:00
Gustavo Lopes
246a80fdeb Added unrar 5.6.2 2020-04-29 20:12:36 +01:00
Gustavo Lopes
4b6fd31d08 Added unrar 5.6.1 2020-04-29 20:12:36 +01:00
Gustavo Lopes
44e35b8f6a Added unrar 5.5.8 2020-04-29 20:12:36 +01:00
Gustavo Lopes
fe4a94305b Added unrar 5.5.7 2020-04-29 20:12:36 +01:00
Gustavo Lopes
0453380858 Suppress some warnings on unrar code 2020-04-29 19:40:03 +01:00
Gustavo Lopes
957fc7702d Merge pull request #4 from remicollet/issue-php73
Fix for PHP 7.3
2018-11-14 18:19:29 +00:00
Remi Collet
5a0cd32191 new constant names in 7.3 2018-08-16 14:52:03 +02:00
Remi Collet
5ca8d78562 fix for iterator changes in 7.3.0alpha4 2018-07-18 11:02:14 +02:00
Remi Collet
1225c9240e relax tests for 7.3 (bool/boolean, main/count) 2018-06-26 15:22:42 +02:00
Gustavo Lopes
10932c2450 Release 4.0.0 2017-07-22 04:00:29 +01:00
Gustavo Lopes
b79f595379 Add tests for RarEntry functions w/out one 2017-07-22 02:33:25 +01:00
Gustavo Lopes
479372f714 Fix redir functions; add test 2017-07-22 02:33:25 +01:00
Gustavo Lopes
121310f696 Refactor time functions to rar_time.c 2017-07-22 02:33:25 +01:00
Gustavo Lopes
43589ad851 Add badges 2017-07-21 18:48:04 +01:00
Gustavo Lopes
b3145c9883 Fix stat times not being in UTC
They depended on the system timezone, because the unrar lib returns them
in the local time.
2017-07-21 18:41:06 +01:00
Gustavo Lopes
5a9886a844 Windows support and appveyor 2017-07-21 18:41:06 +01:00
Gustavo Lopes
bdd4ce2357 Add redirection functions to RarEntry 2017-07-21 18:41:06 +01:00
Gustavo Lopes
2fd19b59ca Fix cloning of RarArchive being allowed 2017-07-21 18:41:06 +01:00
Gustavo Lopes
83756881c2 Rework to support 7.0 and 7.1 2017-07-21 18:40:58 +01:00
Gustavo Lopes
cc7edac87b Ignore unrar/.libs 2017-07-21 18:39:06 +01:00
Gustavo Lopes
a05875667e Travis: add one non-ZTS build 2017-07-18 03:57:34 +01:00
184 changed files with 8607 additions and 2904 deletions

27
.github/workflows/ci.yml vendored Normal file
View File

@@ -0,0 +1,27 @@
name: CI
on:
push:
branches: ['*']
jobs:
test-linux:
runs-on: ubuntu-latest
strategy:
fail-fast: true
matrix:
php-rel: ['8.2', '8.3', '8.4', '8.5']
ts-state: [ts, nts]
steps:
- uses: actions/checkout@v5
- name: Setup PHP
id: setup-php
uses: shivammathur/setup-php@v2
with:
php-version: '${{ matrix.php-rel }}'
env:
phpts: '${{ matrix.ts-state }}'
- name: build extension
run: phpize && ./configure --enable-rar && make
- name: run tests
run: rm run-tests.php && cp run-tests8.php run-tests.php && make test

49
.github/workflows/windows.yml vendored Normal file
View File

@@ -0,0 +1,49 @@
name: Publish Windows Releases
on:
release:
types: [created]
push:
branches: ['*']
permissions:
contents: write
jobs:
get-extension-matrix:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.extension-matrix.outputs.matrix }}
steps:
- name: Checkout
uses: actions/checkout@v5
- name: Get the extension matrix
id: extension-matrix
uses: php/php-windows-builder/extension-matrix@v1
build:
needs: get-extension-matrix
runs-on: ${{ matrix.os }}
continue-on-error: false
strategy:
fail-fast: true
matrix: ${{fromJson(needs.get-extension-matrix.outputs.matrix)}}
steps:
- name: Checkout
uses: actions/checkout@v5
- name: Build the extension
uses: php/php-windows-builder/extension@v1
with:
php-version: ${{ matrix.php-version }}
arch: ${{ matrix.arch }}
ts: ${{ matrix.ts }}
args: '--enable-rar'
test-runner: 'run-tests8.php'
release:
runs-on: ubuntu-latest
needs: build
if: ${{ github.event_name == 'release' }}
steps:
- name: Upload artifact to the release
uses: php/php-windows-builder/release@v1
with:
release: ${{ github.event.release.tag_name }}
# token: ${{ secrets.GITHUB_TOKEN }}

8
.gitignore vendored
View File

@@ -11,6 +11,7 @@
/modules
/missing
/.deps
*.dep
/.libs
/Makefile
/Makefile.fragments
@@ -23,12 +24,14 @@
/config.guess
/config.h
/config.h.in
/config.h.in~
/config.log
/config.nice
/config.status
/config.sub
/configure
/configure.in
/configure.ac
/install-sh
/intl.la
/libtool
@@ -40,3 +43,8 @@
/pecl-rar.*
/rar.la
*.autosave
/unrar/.libs
/tmp-php.ini
/php-rar.creator.user
/compile_commands.json
/.clangd

View File

@@ -1,23 +0,0 @@
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

6
Makefile.frag Normal file
View File

@@ -0,0 +1,6 @@
replace-run-tests:
@if ! grep -q 'Minimum required PHP version: 5\.3\.0' run-tests.php; then \
cp run-tests8.php run-tests.php; \
fi
test: replace-run-tests

12
README
View File

@@ -1,12 +0,0 @@
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
README.md Normal file
View File

@@ -0,0 +1,42 @@
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.
| Version | Status |
|---------|------------------------------|
| master | unmaintened :x: |
| v4.x | maintened :white_check_mark: |
Maintained PHP Versions compatibility:
| PHP Version | Status |
|-------------|------------------------|
| 5.x | no :x: |
| 7.x | no :x: |
| 8.0 | yes :white_check_mark: |
| 8.1 | yes :white_check_mark: |
| 8.2 | yes :white_check_mark: |
| 8.3 | yes :white_check_mark: |
| 8.4 | yes :white_check_mark: |
| 8.5 | yes :white_check_mark: |
Installation system support:
| Platform | Status |
|----------|------------------------|
| PECL | no :x: |
| PIE | yes :white_check_mark: |
To install the extension, use PIE (PHP Installer Extension) with a command like:
```bash
pie install php-win-ext/rar
```

21
composer.json Normal file
View File

@@ -0,0 +1,21 @@
{
"name": "php-win-ext/rar",
"type": "php-ext",
"license": [
"PHP-3.01"
],
"authors": [
{
"name": "Gustavo Lopes",
"email": "cataphract@php.net"
},
{
"name": "Antony Dovgal",
"email": "tony@daylessday.org"
}
],
"require": {
"php": ">= 8.0.0"
},
"description": "rar extension"
}

View File

@@ -31,12 +31,43 @@ unrar_sources="unrar/sha256.cpp unrar/qopen.cpp \
unrar/encname.cpp unrar/file.cpp \
unrar/secpassword.cpp unrar/options.cpp"
AC_LANG_PUSH([C++])
cxxflags_null=""
AC_DEFUN([CXXC_FLAG_CHECK],
[
ac_saved_cxxflags="$CXXFLAGS"
CXXFLAGS="$1 -Werror"
flag_to_add=m4_default([$2],[$1])
AC_MSG_CHECKING([whether the C++ compiler supports $1])
AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM([])],
[AC_MSG_RESULT([yes])]
[cxxflags_null="$cxxflags_null $flag_to_add"],
[AC_MSG_RESULT([no])]
)
CXXFLAGS="$ac_saved_cxxflags"
])
CXXC_FLAG_CHECK([-Wparentheses], [-Wno-parentheses])
CXXC_FLAG_CHECK([-Wswitch], [-Wno-switch])
CXXC_FLAG_CHECK([-Wdangling-else], [-Wno-dangling-else])
CXXC_FLAG_CHECK([-Wunused-function], [-Wno-unused-function])
CXXC_FLAG_CHECK([-Wunused-variable], [-Wno-unused-variable])
CXXC_FLAG_CHECK([-Wsign-compare], [-Wno-sign-compare])
CXXC_FLAG_CHECK([-Wmisleading-indentation], [-Wno-misleading-indentation])
AC_LANG_POP([C++])
extra_cxxflags="$cxxflags_null"
echo "EXTRA_CXXFLAGS := \$(EXTRA_CXXFLAGS) $extra_cxxflags" >> Makefile.fragments
cat Makefile.frag >> Makefile.fragments
INCLUDES=`echo "$INCLUDES" | sed 's/-I/-isystem /g'`
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_NEW_EXTENSION(rar, rar.c rar_error.c rararch.c rarentry.c rar_stream.c rar_navigation.c rar_time.c $unrar_sources, $ext_shared,,-DRARDLL -DSILENT -Wno-write-strings -Wall -fvisibility=hidden -I@ext_srcdir@/unrar)
PHP_ADD_BUILD_DIR($ext_builddir/unrar)
fi

View File

@@ -4,26 +4,34 @@
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");
EXTENSION("rar", "rar.c rar_error.c rararch.c rarentry.c rar_stream.c rar_navigation.c rar_time.c", PHP_RAR_SHARED, "/DRARDLL /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");
"sha256.cpp qopen.cpp \
blake2s.cpp recvol.cpp \
headers.cpp match.cpp \
find.cpp \
resource.cpp \
pathfn.cpp \
dll.cpp threadpool.cpp volume.cpp \
unpack.cpp \
extract.cpp errhnd.cpp \
crc.cpp rijndael.cpp crypt.cpp \
rawread.cpp \
rs.cpp smallfn.cpp \
isnt.cpp rar.cpp consio.cpp \
scantree.cpp archive.cpp strfn.cpp \
strlist.cpp \
getbits.cpp hash.cpp \
filestr.cpp \
extinfo.cpp ui.cpp rarvm.cpp \
timefn.cpp sha1.cpp \
rdwrfn.cpp rs16.cpp cmddata.cpp \
extractchunk.cpp system.cpp \
unicode.cpp filcreat.cpp \
arcread.cpp filefn.cpp \
global.cpp list.cpp \
encname.cpp file.cpp \
secpassword.cpp options.cpp", "rar", "unrar_obj");
AC_DEFINE("HAVE_RAR", 1, "Rar support");
}

View File

@@ -23,11 +23,11 @@ http://pear.php.net/dtd/package-2.0.xsd">
<active>no</active>
</developer>
<date>2013-10-11</date>
<time>13:00:00</time>
<date>2020-12-06</date>
<time>20:00:00</time>
<version>
<release>3.0.2</release>
<api>3.0.0</api>
<release>4.2.0</release>
<api>4.2.0</api>
</version>
<stability>
@@ -36,8 +36,9 @@ http://pear.php.net/dtd/package-2.0.xsd">
</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>- Support PHP 8.
- Merge unrar 6.0.2.
- RarArchive implements IteratorAggregate (PHP 8 only).
</notes>
<contents>
<dir name="/">
@@ -142,6 +143,22 @@ http://pear.php.net/dtd/package-2.0.xsd">
<file role="test" name="097.phpt"/>
<file role="test" name="098.phpt"/>
<file role="test" name="099.phpt"/>
<file role="test" name="100.phpt"/>
<file role="test" name="101.phpt"/>
<file role="test" name="102.phpt"/>
<file role="test" name="103.phpt"/>
<file role="test" name="104.phpt"/>
<file role="test" name="105.phpt"/>
<file role="test" name="106.phpt"/>
<file role="test" name="107.phpt"/>
<file role="test" name="108.phpt"/>
<file role="test" name="109.phpt"/>
<file role="test" name="110.phpt"/>
<file role="test" name="111.phpt"/>
<file role="test" name="112.phpt"/>
<file role="test" name="113.phpt"/>
<file role="test" name="114.phpt"/>
<file role="test" name="115.phpt"/>
<file role="test" name="commented.rar"/>
<file role="test" name="corrupted.rar"/>
<file role="test" name="directories.rar"/>
@@ -157,6 +174,7 @@ http://pear.php.net/dtd/package-2.0.xsd">
<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="php8compat.php.inc"/>
<file role="test" name="rar_notrar.rar"/>
<file role="test" name="rar_unicode.rar"/>
<file role="test" name="repeated_name.rar"/>
@@ -165,6 +183,9 @@ http://pear.php.net/dtd/package-2.0.xsd">
<file role="test" name="solid.rar"/>
<file role="test" name="sparsefiles_rar.rar"/>
<file role="test" name="store_method.rar"/>
<file role="test" name="rar5-links.rar"/>
<file role="test" name="rar5_multi.part1.rar"/>
<file role="test" name="rar5_multi.part2.rar"/>
</dir> <!-- /tests -->
<dir name="unrar">
<file name="acknow.txt" role="doc" />
@@ -173,9 +194,14 @@ http://pear.php.net/dtd/package-2.0.xsd">
<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="blake2s.cpp" role="src" />
<file name="blake2s.hpp" role="src" />
<file name="blake2s_sse.cpp" role="src" />
<file name="blake2sp.cpp" role="src" />
<file name="cmddata.cpp" role="src" />
<file name="cmddata.hpp" role="src" />
<file name="cmdfilter.cpp" role="src" />
<file name="cmdmix.cpp" role="src" />
<file name="coder.cpp" role="src" />
<file name="coder.hpp" role="src" />
<file name="compress.hpp" role="src" />
@@ -185,6 +211,10 @@ http://pear.php.net/dtd/package-2.0.xsd">
<file name="crc.hpp" role="src" />
<file name="crypt.cpp" role="src" />
<file name="crypt.hpp" role="src" />
<file name="crypt1.cpp" role="src" />
<file name="crypt2.cpp" role="src" />
<file name="crypt3.cpp" role="src" />
<file name="crypt5.cpp" role="src" />
<file name="dll.cpp" role="src" />
<file name="dll.hpp" role="src" />
<file name="encname.cpp" role="src" />
@@ -210,7 +240,12 @@ http://pear.php.net/dtd/package-2.0.xsd">
<file name="getbits.hpp" role="src" />
<file name="global.cpp" role="src" />
<file name="global.hpp" role="src" />
<file name="hardlinks.cpp" role="src" />
<file name="hash.cpp" role="src" />
<file name="hash.hpp" role="src" />
<file name="headers.cpp" role="src" />
<file name="headers.hpp" role="src" />
<file name="headers5.hpp" role="src" />
<file name="isnt.cpp" role="src" />
<file name="isnt.hpp" role="src" />
<file name="LICENSE.txt" role="doc" />
@@ -226,9 +261,10 @@ http://pear.php.net/dtd/package-2.0.xsd">
<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="qopen.cpp" role="src" />
<file name="qopen.hpp" role="src" />
<file name="rar.cpp" role="src" />
<file name="rar.hpp" role="src" />
<file name="rardefs.hpp" role="src" />
@@ -237,11 +273,31 @@ http://pear.php.net/dtd/package-2.0.xsd">
<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="rawint.hpp" 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="recvol3.cpp" role="src" />
<file name="recvol5.cpp" role="src" />
<file name="rs16.cpp" role="src" />
<file name="rs16.hpp" role="src" />
<file name="sha256.cpp" role="src" />
<file name="sha256.hpp" role="src" />
<file name="threadmisc.cpp" role="src" />
<file name="threadpool.cpp" role="src" />
<file name="threadpool.hpp" role="src" />
<file name="ui.cpp" role="src" />
<file name="ui.hpp" role="src" />
<file name="uicommon.cpp" role="src" />
<file name="uiconsole.cpp" role="src" />
<file name="uisilent.cpp" role="src" />
<file name="unpack30.cpp" role="src" />
<file name="unpack50.cpp" role="src" />
<file name="unpack50frag.cpp" role="src" />
<file name="unpack50mt.cpp" role="src" />
<file name="unpackinline.cpp" role="src" />
<file name="win32lnk.cpp" role="src" />
<file name="README.txt" role="doc" />
<file name="recvol.cpp" role="src" />
<file name="recvol.hpp" role="src" />
@@ -251,7 +307,6 @@ http://pear.php.net/dtd/package-2.0.xsd">
<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" />
@@ -272,10 +327,8 @@ http://pear.php.net/dtd/package-2.0.xsd">
<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" />
@@ -287,18 +340,23 @@ http://pear.php.net/dtd/package-2.0.xsd">
<file name="win32acl.cpp" role="src" />
<file name="win32stm.cpp" role="src" />
</dir> <!-- /unrar -->
<file name="config.m4" role="src" />
<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="Makefile.frag" role="src" />
<file name="README.md" role="doc" />
<file name="example.php" role="doc" />
<file name="php_compat.h" role="src" />
<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 name="rar_time.c" role="src" />
<file name="run-tests8.php" role="test" />
<file role="src" name="rar_navigation.c"/>
</dir> <!-- / -->
</contents>
@@ -306,7 +364,7 @@ http://pear.php.net/dtd/package-2.0.xsd">
<dependencies>
<required>
<php>
<min>5.2.0</min>
<min>5.3.0</min>
</php>
<pearinstaller>
<min>1.4.0</min>
@@ -317,8 +375,58 @@ http://pear.php.net/dtd/package-2.0.xsd">
<providesextension>rar</providesextension>
<extsrcrelease />
<changelog>
<release>
<version>
<release>4.1.0</release>
<api>4.0.0</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<date>2020-10-11</date>
<notes>Changes in this version:
- Merge changes made to unrar up to version 5.5.6.
- Support PHP 7.2, PHP 7.3 and PHP 7.4.
- Update to unrar 5.9.4.
- Fix bug #76592: streaming unpacking of uncompressed files incomplete.
</notes>
</release>
<release>
<version>
<release>4.0.0</release>
<api>4.0.0</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<date>2017-07-22</date>
<notes>Changes in this version:
- Added functions RarEntry::getRedirType(), RarEntry::isRedirectToDirectory() and RarEntry::getRedirTarget(), as well as the following constants on RarEntry: FSREDIR_UNIXSYMLINK, FSREDIR_WINSYMLINK, FSREDIR_JUNCTION, FSREDIR_HARDLINK and FSREDIR_FILECOPY.
- Changed stat handler to return UTC time for creation, modification and access time (does not work reliably on Windows).
- Fix cloning of RarArchive being allowed.
</notes>
</release>
<release>
<version>
<release>3.0.2</release>
<api>3.0.0</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<date>2013-10-11</date>
<notes>Changes in this version:
- Fixed build with PHP 5.5.
- Upgraded bundled unrar to version 4.2.4.
</notes>
</release>
<release>
<version>
<release>3.0.1</release>
@@ -406,7 +514,7 @@ Other changes:
- A lot of refactoring and compilation as C, not C++.
</notes>
</release>
<release>
<version>
<release>1.0.0</release>

11
php-rar.config Normal file
View File

@@ -0,0 +1,11 @@
// Add predefined macros for your project here. For example:
// #define THE_ANSWER 42
#define RARDLL 1
#define HAVE_CONFIG_H 1
#define _Float32 float
#define _Float32x float
#define _Float64 double
#define _Float64x double
#define _Float128 long double
#define _Float128x long double
#define _BITS_FLOATN_H

1
php-rar.creator Normal file
View File

@@ -0,0 +1 @@
[General]

161
php-rar.files Normal file
View File

@@ -0,0 +1,161 @@
config.h
php_compat.h
php_compat.h
php_rar.h
rar.c
rar_error.c
rar_navigation.c
rar_stream.c
rar_time.c
rararch.c
rarentry.c
unrar/arccmt.cpp
unrar/archive.cpp
unrar/archive.hpp
unrar/arcread.cpp
unrar/array.hpp
unrar/blake2s.cpp
unrar/blake2s.hpp
unrar/blake2s_sse.cpp
unrar/blake2sp.cpp
unrar/cmddata.cpp
unrar/cmddata.hpp
unrar/cmdfilter.cpp
unrar/cmdmix.cpp
unrar/coder.cpp
unrar/coder.hpp
unrar/compress.hpp
unrar/consio.cpp
unrar/consio.hpp
unrar/crc.cpp
unrar/crc.hpp
unrar/crypt.cpp
unrar/crypt.hpp
unrar/crypt1.cpp
unrar/crypt2.cpp
unrar/crypt3.cpp
unrar/crypt5.cpp
unrar/dll.cpp
unrar/dll.hpp
unrar/encname.cpp
unrar/encname.hpp
unrar/errhnd.cpp
unrar/errhnd.hpp
unrar/extinfo.cpp
unrar/extinfo.hpp
unrar/extract.cpp
unrar/extract.hpp
unrar/extractchunk.cpp
unrar/filcreat.cpp
unrar/filcreat.hpp
unrar/file.cpp
unrar/file.hpp
unrar/filefn.cpp
unrar/filefn.hpp
unrar/filestr.cpp
unrar/filestr.hpp
unrar/find.cpp
unrar/find.hpp
unrar/getbits.cpp
unrar/getbits.hpp
unrar/global.cpp
unrar/global.hpp
unrar/hardlinks.cpp
unrar/hash.cpp
unrar/hash.hpp
unrar/headers.cpp
unrar/headers.hpp
unrar/headers5.hpp
unrar/isnt.cpp
unrar/isnt.hpp
unrar/list.cpp
unrar/list.hpp
unrar/loclang.hpp
unrar/log.cpp
unrar/log.hpp
unrar/match.cpp
unrar/match.hpp
unrar/model.cpp
unrar/model.hpp
unrar/options.cpp
unrar/options.hpp
unrar/os.hpp
unrar/pathfn.cpp
unrar/pathfn.hpp
unrar/qopen.cpp
unrar/qopen.hpp
unrar/rar.cpp
unrar/rar.hpp
unrar/rardefs.hpp
unrar/rarlang.hpp
unrar/raros.hpp
unrar/rartypes.hpp
unrar/rarvm.cpp
unrar/rarvm.hpp
unrar/rarvmtbl.cpp
unrar/rawint.hpp
unrar/rawread.cpp
unrar/rawread.hpp
unrar/rdwrfn.cpp
unrar/rdwrfn.hpp
unrar/recvol.cpp
unrar/recvol.hpp
unrar/recvol3.cpp
unrar/recvol5.cpp
unrar/resource.cpp
unrar/resource.hpp
unrar/rijndael.cpp
unrar/rijndael.hpp
unrar/rs.cpp
unrar/rs.hpp
unrar/rs16.cpp
unrar/rs16.hpp
unrar/savepos.hpp
unrar/scantree.cpp
unrar/scantree.hpp
unrar/secpassword.cpp
unrar/secpassword.hpp
unrar/sha1.cpp
unrar/sha1.hpp
unrar/sha256.cpp
unrar/sha256.hpp
unrar/smallfn.cpp
unrar/smallfn.hpp
unrar/strfn.cpp
unrar/strfn.hpp
unrar/strlist.cpp
unrar/strlist.hpp
unrar/suballoc.cpp
unrar/suballoc.hpp
unrar/system.cpp
unrar/system.hpp
unrar/threadmisc.cpp
unrar/threadpool.cpp
unrar/threadpool.hpp
unrar/timefn.cpp
unrar/timefn.hpp
unrar/ui.cpp
unrar/ui.hpp
unrar/uicommon.cpp
unrar/uiconsole.cpp
unrar/uisilent.cpp
unrar/ulinks.cpp
unrar/ulinks.hpp
unrar/unicode.cpp
unrar/unicode.hpp
unrar/unpack.cpp
unrar/unpack.hpp
unrar/unpack15.cpp
unrar/unpack20.cpp
unrar/unpack30.cpp
unrar/unpack50.cpp
unrar/unpack50frag.cpp
unrar/unpack50mt.cpp
unrar/unpackinline.cpp
unrar/uowners.cpp
unrar/version.hpp
unrar/volume.cpp
unrar/volume.hpp
unrar/win32acl.cpp
unrar/win32lnk.cpp
unrar/win32stm.cpp

4
php-rar.includes Normal file
View File

@@ -0,0 +1,4 @@
/home/glopes/repos/php-src/Zend
/home/glopes/repos/php-src/TSRM
/home/glopes/repos/php-src/main
/home/glopes/repos/php-src

72
php_compat.h Normal file
View File

@@ -0,0 +1,72 @@
#include <php.h>
#if PHP_MAJOR_VERSION >= 8
# define TSRMLS_DC
# define TSRMLS_D
# define TSRMLS_CC
# define TSRMLS_C
# define TSRMLS_FETCH()
# define IS_CALLABLE_STRICT 0
# define zend_qsort zend_sort
# define ZV_TO_THIS_FOR_HANDLER(zv) (Z_OBJ_P(zv))
typedef zend_object handler_this_t;
#else
# define ZV_TO_THIS_FOR_HANDLER(zv) (zv)
typedef zval handler_this_t;
#endif
#if PHP_MAJOR_VERSION >= 7
typedef zend_object* rar_obj_ref;
#define rar_zval_add_ref(ppzv) zval_add_ref(*ppzv)
#define ZVAL_ALLOC_DUP(dst, src) \
do { \
dst = (zval*) emalloc(sizeof(zval)); \
ZVAL_DUP(dst, src); \
} while (0)
#define RAR_RETURN_STRINGL(s, l, duplicate) \
do { \
RETVAL_STRINGL(s, l); \
if (duplicate == 0) { \
efree(s); \
} \
return; \
} while (0)
#define RAR_ZVAL_STRING(z, s, duplicate) \
do { \
ZVAL_STRING(z, s); \
if (duplicate == 0) { \
efree(s); \
} \
} while (0)
typedef size_t zpp_s_size_t;
#define MAKE_STD_ZVAL(zv_p) \
do { \
(zv_p) = emalloc(sizeof(zval)); \
ZVAL_NULL(zv_p); \
} while (0)
#define INIT_ZVAL(zv) ZVAL_UNDEF(&zv)
#define ZEND_ACC_FINAL_CLASS ZEND_ACC_FINAL
#else /* PHP 5.x */
typedef zend_object_handle rar_obj_ref;
#define rar_zval_add_ref zval_add_ref
#define ZVAL_ALLOC_DUP(dst, src) \
do { \
zval *z_src = src; \
dst = z_src; \
zval_add_ref(&dst); \
SEPARATE_ZVAL(&dst); \
} while (0)
#define RAR_ZVAL_STRING ZVAL_STRING
#define RAR_RETURN_STRINGL(s, l, duplicate) RETURN_STRINGL(s, l, duplicate)
typedef int zpp_s_size_t;
#define zend_hash_str_del zend_hash_del
#endif

View File

@@ -46,10 +46,12 @@
#ifndef PHP_RAR_H
#define PHP_RAR_H
#include <php.h>
extern zend_module_entry rar_module_entry;
#define phpext_rar_ptr &rar_module_entry
#define PHP_RAR_VERSION "4.0.0"
#define PHP_RAR_VERSION "4.2.1"
#ifdef PHP_WIN32
#define PHP_RAR_API __declspec(dllexport)
@@ -61,6 +63,8 @@ extern zend_module_entry rar_module_entry;
#include "TSRM.h"
#endif
#include "php_compat.h"
/* causes linking errors (multiple definitions) in functions
that were requested inlining but were not inlined by the compiler */
/* #include "unrar/rar.hpp */
@@ -77,6 +81,10 @@ enum HOST_SYSTEM {
HOST_MSDOS=0,HOST_OS2=1,HOST_WIN32=2,HOST_UNIX=3,HOST_MACOS=4,
HOST_BEOS=5,HOST_MAX
};
enum FILE_SYSTEM_REDIRECT {
FSREDIR_NONE=0, FSREDIR_UNIXSYMLINK, FSREDIR_WINSYMLINK, FSREDIR_JUNCTION,
FSREDIR_HARDLINK, FSREDIR_FILECOPY
};
/* maximum comment size if 64KB */
#define RAR_MAX_COMMENT_SIZE 65536
@@ -87,7 +95,7 @@ typedef struct _rar_cb_user_data {
} rar_cb_user_data;
typedef struct rar {
zend_object_handle id;
rar_obj_ref obj_ref;
struct _rar_entries *entries;
struct RAROpenArchiveDataEx *list_open_data;
struct RAROpenArchiveDataEx *extract_open_data;
@@ -99,7 +107,7 @@ typedef struct rar {
} rar_file_t;
/* Misc */
#ifdef ZTS
#if defined(ZTS) && PHP_MAJOR_VERSION < 7
# define RAR_TSRMLS_TC , void ***
#else
# define RAR_TSRMLS_TC
@@ -134,7 +142,7 @@ typedef struct _rar_contents_cache {
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);
zval *(*get)(const char *, uint, zval * RAR_TSRMLS_TC);
} rar_contents_cache;
/* Module globals, currently used for dir wrappers cache */
@@ -169,6 +177,15 @@ ZEND_EXTERN_MODULE_GLOBALS(rar);
#endif
/* Other compatibility quirks */
/* PHP 5.3 doesn't have ZVAL_COPY_VALUE */
#if !defined(ZEND_COPY_VALUE) && PHP_MAJOR_VERSION == 5
#define ZVAL_COPY_VALUE(z, v) \
do { \
(z)->value = (v)->value; \
Z_TYPE_P(z) = Z_TYPE_P(v); \
} while (0)
#endif
#if !defined(HAVE_STRNLEN) || !HAVE_STRNLEN
size_t _rar_strnlen(const char *s, size_t maxlen);
# define strnlen _rar_strnlen
@@ -261,8 +278,9 @@ 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);
int _rar_get_file_resource_zv(zval *zv_file, rar_file_t **rar_file TSRMLS_DC);
int _rar_get_file_resource_zv_ex(zval *zv_file, rar_file_t **rar_file, int silent TSRMLS_DC);
int _rar_get_file_resource_ex(rar_obj_ref objref_file, rar_file_t **rar_file, int silent TSRMLS_DC);
void minit_rararch(TSRMLS_D);
PHP_FUNCTION(rar_open);
@@ -290,6 +308,12 @@ php_stream *php_stream_rar_open(char *arc_name,
STREAMS_DC TSRMLS_DC);
extern php_stream_wrapper php_stream_rar_wrapper;
/* rar_time.c */
void rar_time_convert(unsigned low, unsigned high, time_t *to);
int rar_dos_time_convert(unsigned dos_time, time_t *to);
#ifdef PHP_WIN32
#define timegm _mkgmtime
#endif
#endif /* PHP_RAR_H */

77
rar.c
View File

@@ -160,8 +160,14 @@ void _rar_destroy_userdata(rar_cb_user_data *udata) /* {{{ */
efree(udata->password);
}
if (udata->callable != NULL)
if (udata->callable != NULL) {
#if PHP_MAJOR_VERSION < 7
zval_ptr_dtor(&udata->callable);
#else
zval_ptr_dtor(udata->callable);
efree(udata->callable);
#endif
}
udata->password = NULL;
udata->callable = NULL;
@@ -404,7 +410,7 @@ PHP_FUNCTION(rar_wrapper_cache_stats) /* {{{ */
len = spprintf(&result, 0, "%u/%u (hits/misses)",
RAR_G(contents_cache).hits, RAR_G(contents_cache).misses);
RETURN_STRINGL(result, len, 0);
RAR_RETURN_STRINGL(result, len, 0);
}
/* }}} */
/* }}} */
@@ -441,27 +447,50 @@ static int _rar_unrar_volume_user_callback(char* dst_buffer,
zend_fcall_info_cache *cache
TSRMLS_DC) /* {{{ */
{
#if PHP_MAJOR_VERSION < 7
zval *failed_vol,
*retval_ptr = NULL,
**params;
#else
zval failed_vol,
retval,
*params,
*const retval_ptr = &retval;
#endif
int ret = -1;
#if PHP_MAJOR_VERSION < 7
MAKE_STD_ZVAL(failed_vol);
ZVAL_STRING(failed_vol, dst_buffer, 1);
RAR_ZVAL_STRING(failed_vol, dst_buffer, 1);
params = &failed_vol;
fci->retval_ptr_ptr = &retval_ptr;
fci->params = &params;
#else
ZVAL_STRING(&failed_vol, dst_buffer);
ZVAL_NULL(&retval);
params = &failed_vol;
fci->retval = &retval;
fci->params = params;
#endif
fci->param_count = 1;
#if PHP_MAJOR_VERSION < 7
if (zend_call_function(fci, cache TSRMLS_CC) != SUCCESS ||
fci->retval_ptr_ptr == NULL ||
*fci->retval_ptr_ptr == NULL) {
#else
if (zend_call_function(fci, cache TSRMLS_CC) != SUCCESS || EG(exception)) {
#endif
php_error_docref(NULL TSRMLS_CC, E_WARNING,
"Failure to call volume find callback");
goto cleanup;
}
#if PHP_MAJOR_VERSION < 7
assert(*fci->retval_ptr_ptr == retval_ptr);
#else
assert(fci->retval == &retval);
#endif
if (Z_TYPE_P(retval_ptr) == IS_NULL) {
/* let return -1 */
}
@@ -500,9 +529,15 @@ static int _rar_unrar_volume_user_callback(char* dst_buffer,
}
cleanup:
#if PHP_MAJOR_VERSION < 7
zval_ptr_dtor(&failed_vol);
if (retval_ptr != NULL)
if (retval_ptr != NULL) {
zval_ptr_dtor(&retval_ptr);
}
#else
zval_ptr_dtor(&failed_vol);
zval_ptr_dtor(&retval);
#endif
return ret;
}
/* }}} */
@@ -616,12 +651,15 @@ static zend_function_entry rar_functions[] = {
/* {{{ Globals' related activities */
ZEND_DECLARE_MODULE_GLOBALS(rar);
#if PHP_MAJOR_VERSION < 7
static int _rar_array_apply_remove_first(void *pDest TSRMLS_DC)
#else
static int _rar_array_apply_remove_first(zval *pDest TSRMLS_DC)
#endif
{
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)
@@ -634,21 +672,38 @@ static void _rar_contents_cache_put(const char *key,
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);
rar_zval_add_ref(&zv);
#if PHP_MAJOR_VERSION < 7
assert(Z_REFCOUNT_P(zv) > 1);
SEPARATE_ZVAL(&zv); /* ensure we store a heap allocated copy */
zend_hash_update(cc->data, key, key_len, &zv, sizeof(zv), NULL);
#else
zend_hash_str_update(cc->data, key, key_len, zv);
#endif
}
static zval *_rar_contents_cache_get(const char *key,
uint key_len TSRMLS_DC)
uint key_len,
zval *rv TSRMLS_DC)
{
rar_contents_cache *cc = &RAR_G(contents_cache);
zval **element = NULL;
zend_hash_find(cc->data, key, key_len, (void **) &element);
zval *element = NULL;
#if PHP_MAJOR_VERSION < 7
zval **element_p = NULL;
zend_hash_find(cc->data, key, key_len, (void **) &element_p);
if (element_p) {
element = *element_p;
}
#else
element = zend_hash_str_find(cc->data, key, key_len);
#endif
if (element != NULL) {
cc->hits++;
zval_add_ref(element);
return *element;
INIT_ZVAL(*rv);
ZVAL_COPY_VALUE(rv, element);
zval_copy_ctor(rv);
return rv;
}
else {
cc->misses++;

View File

@@ -70,7 +70,7 @@ void _rar_handle_ext_error(const char *format TSRMLS_DC, ...) /* {{{ */
va_list arg;
char *message;
#ifdef ZTS
#if defined(ZTS) && PHP_MAJOR_VERSION < 7
va_start(arg, TSRMLS_C);
#else
va_start(arg, format);
@@ -91,9 +91,13 @@ 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);
#if PHP_MAJOR_VERSION < 7
assert(Z_TYPE_P(pval) == IS_BOOL);
return Z_BVAL_P(pval);
#else
assert(Z_TYPE_P(pval) == IS_TRUE || Z_TYPE_P(pval) == IS_FALSE);
return Z_TYPE_P(pval) == IS_TRUE;
#endif
}
/* returns a string or NULL if not an error */
@@ -182,7 +186,11 @@ PHP_METHOD(rarexception, setUsingExceptions)
Return whether exceptions are being used */
PHP_METHOD(rarexception, isUsingExceptions)
{
#if PHP_MAJOR_VERSION < 7
zval **pval;
#else
zval *pval;
#endif
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE ) {
return;
@@ -192,15 +200,25 @@ PHP_METHOD(rarexception, isUsingExceptions)
#if PHP_VERSION_ID < 50399
pval = zend_std_get_static_property(rarexception_ce_ptr, "usingExceptions",
sizeof("usingExceptions") -1, (zend_bool) 0 TSRMLS_CC);
#else
#elif PHP_MAJOR_VERSION < 7
pval = zend_std_get_static_property(rarexception_ce_ptr, "usingExceptions",
sizeof("usingExceptions") -1, (zend_bool) 0, NULL TSRMLS_CC);
#else
zend_string *prop_name =
zend_string_init("usingExceptions", sizeof("usingExceptions") - 1, 0);
pval = zend_std_get_static_property(rarexception_ce_ptr, prop_name,
(zend_bool) 0);
zend_string_release(prop_name);
#endif
/* property always exists */
assert(pval != NULL);
#if PHP_MAJOR_VERSION < 7
assert(Z_TYPE_PP(pval) == IS_BOOL);
RETURN_ZVAL(*pval, 0, 0);
#else
assert(Z_TYPE_P(pval) == IS_TRUE || Z_TYPE_P(pval) == IS_FALSE);
RETURN_ZVAL(pval, 0, 0);
#endif
}
/* }}} */
@@ -224,12 +242,17 @@ void minit_rarerror(TSRMLS_D) /* {{{ */
zend_class_entry ce;
INIT_CLASS_ENTRY(ce, "RarException", php_rarexception_class_functions);
#if PHP_MAJOR_VERSION < 7
rarexception_ce_ptr = zend_register_internal_class_ex(&ce,
zend_exception_get_default(TSRMLS_C), NULL TSRMLS_CC);
#else
rarexception_ce_ptr = zend_register_internal_class_ex(&ce,
zend_ce_exception);
#endif
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);
ZEND_ACC_STATIC TSRMLS_CC);
}
/* }}} */

View File

@@ -73,6 +73,9 @@ static void _rar_nav_get_depth_and_length(wchar_t *filenamew, const size_t file_
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);
#if PHP_MAJOR_VERSION >= 7
static void _rar_nav_swap_entries(void *op1, void *op2);
#endif
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,
@@ -113,9 +116,15 @@ void _rar_entry_search_start(rar_file_t *rar,
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]);
#if PHP_MAJOR_VERSION < 7
zend_qsort(rar->entries->entries_array_s, rar->entries->num_entries,
sizeof *rar->entries->entries_array_s, _rar_nav_compare_entries
TSRMLS_CC);
#else
zend_qsort(rar->entries->entries_array_s, rar->entries->num_entries,
sizeof *rar->entries->entries_array_s, _rar_nav_compare_entries,
_rar_nav_swap_entries);
#endif
}
}
/* }}} */
@@ -137,7 +146,11 @@ void _rar_entry_search_seek(rar_find_output *state, size_t pos)
/* {{{ _rar_entry_search_end */
void _rar_entry_search_end(rar_find_output *state)
{
efree(state);
if (state) {
/* may not have been initialized due to error conditions
* in rararch_it_get_iterator that jumped out of the function */
efree(state);
}
}
/* }}} */
@@ -300,6 +313,9 @@ void _rar_delete_entries(rar_file_t *rar TSRMLS_DC)
if (rar->entries->entries_array != NULL) {
size_t i;
for (i = 0; i < rar->entries->num_entries; i++) {
if (rar->entries->entries_array[i]->entry.RedirName != NULL) {
efree(rar->entries->entries_array[i]->entry.RedirName);
}
efree(rar->entries->entries_array[i]);
}
efree(rar->entries->entries_array);
@@ -340,7 +356,11 @@ int _rar_list_files(rar_file_t *rar TSRMLS_DC) /* {{{ */
ents->last_accessed = NULL;
while (result == 0) {
struct _rar_unique_entry *ue;
struct RARHeaderDataEx entry = {0};
wchar_t redir_name[1024] = L"";
entry.RedirName = redir_name;
entry.RedirNameSize = sizeof(redir_name) / sizeof(redir_name[0]);
result = RARReadHeaderEx(rar->arch_handle, &entry);
/* value of 2nd argument is irrelevant in RAR_OM_LIST_[SPLIT] mode */
if (result == 0) {
@@ -388,16 +408,22 @@ int _rar_list_files(rar_file_t *rar TSRMLS_DC) /* {{{ */
}
assert(capacity > ents->num_entries);
ents->entries_array[ents->num_entries] =
ents->entries_array[ents->num_entries] = ue =
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;
memcpy(&ue->entry, &entry, sizeof ents->entries_array[0]->entry);
ue->id = ents->num_entries;
ue->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);
&ue->depth, &ue->name_wlen TSRMLS_CC);
if (redir_name[0] != L'\0') {
size_t size = (wcslen(redir_name) + 1) * sizeof(redir_name[0]);
ue->entry.RedirName = emalloc(size);
memcpy(ue->entry.RedirName, redir_name, size);
} else {
ue->entry.RedirName = NULL;
ue->entry.RedirNameSize = 0;
}
ents->num_entries++;
}
@@ -476,6 +502,21 @@ static int _rar_nav_compare_entries(const void *op1, const void *op2 TSRMLS_DC)
}
/* }}} */
#if PHP_MAJOR_VERSION >= 7
static void _rar_nav_swap_entries(void *op1, void *op2) /* {{{ */
{
/* just swaps two pointer values */
struct _rar_unique_entry **a = op1,
**b = op2,
*tmp;
tmp = *a;
*a = *b;
*b = tmp;
}
/* }}} */
#endif
static int _rar_nav_compare_entries_std(const void *op1, const void *op2) /* {{{ */
{
const struct _rar_unique_entry *a = *((struct _rar_unique_entry **) op1),

View File

@@ -41,7 +41,6 @@ extern "C" {
#include <wchar.h>
#include "php_rar.h"
#include "unrar/rartypes.hpp"
#include <php_streams.h>
#include <ext/standard/url.h>
@@ -52,10 +51,11 @@ typedef struct php_rar_stream_data_t {
struct RAROpenArchiveDataEx open_data;
struct RARHeaderDataEx header_data;
HANDLE rar_handle;
size_t file_size;
/* TODO: consider encapsulating a php memory/tmpfile stream */
unsigned char *buffer;
size_t buffer_size;
size_t buffer_cont_size; /* content size */
size_t buffer_read_size; /* content size */
size_t buffer_pos;
uint64 cursor;
int no_more_data;
@@ -64,7 +64,7 @@ typedef struct php_rar_stream_data_t {
} php_rar_stream_data, *php_rar_stream_data_P;
typedef struct php_rar_dir_stream_data_t {
zval *rar_obj;
zval rar_obj;
rar_find_output *state;
struct RARHeaderDataEx *self_header; /* NULL for root */
wchar_t *directory;
@@ -99,7 +99,11 @@ static char *_rar_wide_to_utf_with_alloc(const wchar_t *wide, int len)
/* {{{ RAR file streams */
/* {{{ php_rar_ops_read */
#if PHP_VERSION_ID < 70400
static size_t php_rar_ops_read(php_stream *stream, char *buf, size_t count TSRMLS_DC)
#else
static ssize_t php_rar_ops_read(php_stream *stream, char *buf, size_t count)
#endif
{
size_t n = 0;
STREAM_DATA_FROM_STREAM
@@ -114,12 +118,12 @@ static size_t php_rar_ops_read(php_stream *stream, char *buf, size_t count TSRML
while (left > 0) {
size_t this_read_size;
/* if nothing in the buffer or buffer already read, fill buffer */
if (/*self->buffer_cont_size == 0 || > condition not necessary */
self->buffer_pos == self->buffer_cont_size)
if (/*self->buffer_read_size == 0 || > condition not necessary */
self->buffer_pos == self->buffer_read_size)
{
int res;
self->buffer_pos = 0;
self->buffer_cont_size = 0;
self->buffer_read_size = 0;
/* Note: this condition is important, you cannot rely on
* having a call to RARProcessFileChunk return no data and
* break on the condition self->buffer_cont_size == 0 because
@@ -129,25 +133,25 @@ static size_t php_rar_ops_read(php_stream *stream, char *buf, size_t count TSRML
if (self->no_more_data)
break;
res = RARProcessFileChunk(self->rar_handle, self->buffer,
self->buffer_size, &self->buffer_cont_size,
self->buffer_size, &self->buffer_read_size,
&self->no_more_data);
if (_rar_handle_error(res TSRMLS_CC) == FAILURE) {
break; /* finish in case of failure */
}
assert(self->buffer_cont_size <= self->buffer_size);
assert(self->buffer_read_size <= self->buffer_size);
/* we did not read anything. no need to continue */
if (self->buffer_cont_size == 0)
if (self->buffer_read_size == 0)
break;
}
/* if we get here we have data to be read in the buffer */
this_read_size = MIN(left,
self->buffer_cont_size - self->buffer_pos);
self->buffer_read_size - self->buffer_pos);
assert(this_read_size > 0);
memcpy(&buf[count-left], &self->buffer[self->buffer_pos],
this_read_size);
left -= this_read_size;
n += this_read_size;
self->buffer_pos += this_read_size;
self->buffer_pos += this_read_size;
assert(left >= 0);
}
@@ -156,9 +160,16 @@ static size_t php_rar_ops_read(php_stream *stream, char *buf, size_t count TSRML
/* no more data upstream (for sure), buffer already read and
* caller asked for more data than we're giving */
if (self->no_more_data && self->buffer_pos == self->buffer_cont_size &&
((size_t) n) < count)
if (self->no_more_data && self->buffer_pos == self->buffer_read_size &&
n < count && stream->eof != 1) {
stream->eof = 1;
if (self->cursor > self->file_size) {
php_error_docref(NULL TSRMLS_CC, E_WARNING,
"The file size is supposed to be %lu bytes, but "
"we read more: %lu bytes (corruption/wrong pwd)",
self->file_size, self->cursor);
}
}
/* we should only give no data if we have no more */
if (!self->no_more_data && n == 0) {
@@ -168,17 +179,29 @@ static size_t php_rar_ops_read(php_stream *stream, char *buf, size_t count TSRML
stream->eof = 1;
}
#if PHP_VERSION_ID < 50400
return n;
#else
return (ssize_t) n;
#endif
}
/* }}} */
/* {{{ php_rar_ops_write */
#if PHP_VERSION_ID < 70400
static size_t php_rar_ops_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC)
#else
static ssize_t php_rar_ops_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC)
#endif
{
php_error_docref(NULL TSRMLS_CC, E_WARNING,
"Write operation not supported for RAR streams.");
if (!stream) {
#if PHP_VERSION_ID < 70400
return 0;
#else
return -1;
#endif
}
return count;
@@ -280,25 +303,6 @@ static mode_t _rar_convert_file_attrs(unsigned os_attrs,
}
/* }}} */
static void _rar_time_convert(unsigned low, unsigned high, time_t *to) /* {{{ */
{
time_t default_ = (time_t) 0;
if (high == 0U && low == 0U) {
*to = default_;
return;
}
/* 11644473600000000000 - number of ns between 01-01-1601 and 01-01-1970. */
uint64 ushift=INT32TO64(0xA1997B0B,0x4C6A0000);
/* value is in 10^-7 seconds since 01-01-1601 */
/* convert to nanoseconds, shift to 01-01-1970 and convert to seconds */
*to = (time_t) ((INT32TO64(high, low) * 100 - ushift) / 1000000000);
return;
}
/* }}} */
static int _rar_stat_from_header(struct RARHeaderDataEx *header,
php_stream_statbuf *ssb) /* {{{ */
{
@@ -313,7 +317,7 @@ static int _rar_stat_from_header(struct RARHeaderDataEx *header,
* SUBHEAD_TYPE_UOWNER), but it is not exposed in unRAR */
ssb->sb.st_uid = 0;
ssb->sb.st_gid = 0;
#ifdef HAVE_ST_RDEV
#if defined(HAVE_ST_RDEV) || defined(HAVE_STRUCT_STAT_ST_RDEV)
ssb->sb.st_rdev = 0;
#endif
/* never mind signedness, we'll never get sizes big enough for that to
@@ -328,35 +332,26 @@ static int _rar_stat_from_header(struct RARHeaderDataEx *header,
ssb->sb.st_size = (long) (unsigned long) (int64) unp_size;
}
_rar_time_convert(header->AtimeLow, header->AtimeHigh, &ssb->sb.st_atime);
_rar_time_convert(header->CtimeLow, header->CtimeHigh, &ssb->sb.st_ctime);
rar_time_convert(header->AtimeLow, header->AtimeHigh, &ssb->sb.st_atime);
rar_time_convert(header->CtimeLow, header->CtimeHigh, &ssb->sb.st_ctime);
if (header->MtimeLow == 0 && header->MtimeHigh == 0) {
/* high precision mod time undefined */
struct tm time_s = {0};
time_t time;
unsigned dos_time = header->FileTime;
time_s.tm_sec = (dos_time & 0x1f)*2;
time_s.tm_min = (dos_time>>5) & 0x3f;
time_s.tm_hour = (dos_time>>11) & 0x1f;
time_s.tm_mday = (dos_time>>16) & 0x1f;
time_s.tm_mon = ((dos_time>>21) & 0x0f) - 1;
time_s.tm_year = (dos_time>>25) + 80;
if ((time = mktime(&time_s)) == -1)
if (rar_dos_time_convert(header->FileTime, &time) == FAILURE) {
return FAILURE;
}
ssb->sb.st_mtime = time;
}
else {
_rar_time_convert(header->MtimeLow, header->MtimeHigh,
rar_time_convert(header->MtimeLow, header->MtimeHigh,
&ssb->sb.st_mtime);
}
#ifdef HAVE_ST_BLKSIZE
#if defined(HAVE_ST_BLKSIZE) || defined(HAVE_STRUCT_STAT_ST_BLKSIZE)
ssb->sb.st_blksize = 0;
#endif
#ifdef HAVE_ST_BLOCKS
#if defined(HAVE_ST_BLOCKS) || defined (HAVE_STRUCT_STAT_ST_BLOCKS)
ssb->sb.st_blocks = 0;
#endif
/* php_stat in filestat.c doesn't check this one, so don't touch it */
@@ -392,19 +387,32 @@ static php_stream_ops php_stream_rario_ops = {
/* {{{ RAR directory streams */
/* {{{ php_rar_dir_ops_read */
#if PHP_VERSION_ID < 70400
static size_t php_rar_dir_ops_read(php_stream *stream, char *buf, size_t count TSRMLS_DC)
#else
static ssize_t php_rar_dir_ops_read(php_stream *stream, char *buf, size_t count TSRMLS_DC)
#endif
{
php_stream_dirent entry;
int offset;
size_t offset;
STREAM_DIR_DATA_FROM_STREAM
if (count != sizeof(entry))
if (count != sizeof(entry)) {
#if PHP_VERSION_ID < 70400
return 0;
#else
return -1;
#endif
}
_rar_entry_search_advance(self->state, self->directory, self->dir_size, 1);
if (!self->state->found) {
stream->eof = 1;
#if PHP_VERSION_ID < 70400
return 0;
#else
return -1;
#endif
}
if (self->dir_size == 1) /* root */
@@ -416,12 +424,19 @@ static size_t php_rar_dir_ops_read(php_stream *stream, char *buf, size_t count T
entry.d_name, sizeof entry.d_name);
if (!self->no_encode) { /* urlencode entry */
#if PHP_MAJOR_VERSION < 7
int new_len;
char *encoded_name;
encoded_name = php_url_encode(entry.d_name, strlen(entry.d_name),
&new_len);
strlcpy(entry.d_name, encoded_name, sizeof entry.d_name);
efree(encoded_name);
#else
zend_string *encoded_name =
php_url_encode(entry.d_name, strlen(entry.d_name));
strlcpy(entry.d_name, encoded_name->val, sizeof entry.d_name);
zend_string_release(encoded_name);
#endif
}
@@ -437,7 +452,11 @@ static int php_rar_dir_ops_close(php_stream *stream, int close_handle TSRMLS_DC)
{
STREAM_DIR_DATA_FROM_STREAM
#if PHP_MAJOR_VERSION < 7
zval_dtor(&self->rar_obj);
#else
zval_ptr_dtor(&self->rar_obj);
#endif
efree(self->directory);
efree(self->state);
efree(self);
@@ -449,7 +468,11 @@ static int php_rar_dir_ops_close(php_stream *stream, int close_handle TSRMLS_DC)
/* }}} */
/* {{{ php_rar_dir_ops_rewind */
#if PHP_VERSION_ID < 70400
static int php_rar_dir_ops_rewind(php_stream *stream, off_t offset, int whence, off_t *newoffset TSRMLS_DC)
#else
static int php_rar_dir_ops_rewind(php_stream *stream, zend_off_t offset, int whence, zend_off_t *newoffset)
#endif
{
STREAM_DIR_DATA_FROM_STREAM
@@ -511,8 +534,7 @@ php_stream *php_stream_rar_open(char *arc_name,
if (cb_udata_ptr->password != NULL)
self->cb_userdata.password = estrdup(cb_udata_ptr->password);
if (cb_udata_ptr->callable != NULL) {
self->cb_userdata.callable = cb_udata_ptr->callable;
zval_add_ref(&self->cb_userdata.callable);
ZVAL_ALLOC_DUP(self->cb_userdata.callable, cb_udata_ptr->callable);
}
result = _rar_find_file_p(&self->open_data, position, &self->cb_userdata,
@@ -527,16 +549,18 @@ php_stream *php_stream_rar_open(char *arc_name,
TSRMLS_CC, position, arc_name);
else {
/* no need to allocate a buffer bigger than the file uncomp size */
size_t buffer_size = (size_t)
MIN((uint64) RAR_CHUNK_BUFFER_SIZE,
INT32TO64(self->header_data.UnpSizeHigh,
self->header_data.UnpSize));
size_t file_size = INT32TO64(self->header_data.UnpSizeHigh,
self->header_data.UnpSize);
size_t buffer_size = MIN(
MAX(RAR_CHUNK_BUFFER_SIZE, self->header_data.WinSize),
file_size);
int process_result = RARProcessFileChunkInit(self->rar_handle);
if (_rar_handle_error(process_result TSRMLS_CC) == FAILURE) {
goto cleanup;
}
self->file_size = file_size;
self->buffer = emalloc(buffer_size);
self->buffer_size = buffer_size;
stream = php_stream_alloc(&php_stream_rario_ops, self, NULL, "rb");
@@ -633,7 +657,10 @@ static void php_rar_process_context(php_stream_context *context,
char **file_password, /* can be NULL */
zval **volume_cb TSRMLS_DC)
{
zval **ctx_opt = NULL;
zval *ctx_opt;
#if PHP_MAJOR_VERSION < 7
zval **ctx_opt_p = NULL;
#endif
assert(context != NULL);
assert(open_password != NULL);
@@ -643,32 +670,50 @@ static void php_rar_process_context(php_stream_context *context,
/* TODO: don't know if I can log errors and not fail. check that */
if (php_stream_context_get_option(context, "rar", "open_password", &ctx_opt) ==
SUCCESS) {
if (Z_TYPE_PP(ctx_opt) != IS_STRING)
#if PHP_MAJOR_VERSION < 7
if (php_stream_context_get_option(
context, "rar", "open_password", &ctx_opt_p) == SUCCESS) {
ctx_opt = *ctx_opt_p;
#else
if ((ctx_opt = php_stream_context_get_option(
context, "rar", "open_password"))) {
#endif
if (Z_TYPE_P(ctx_opt) != IS_STRING)
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC,
"RAR open password was provided, but not a string.");
else
*open_password = Z_STRVAL_PP(ctx_opt);
*open_password = Z_STRVAL_P(ctx_opt);
}
#if PHP_MAJOR_VERSION < 7
if (file_password != NULL && php_stream_context_get_option(context, "rar",
"file_password", &ctx_opt) == SUCCESS) {
if (Z_TYPE_PP(ctx_opt) != IS_STRING)
"file_password", &ctx_opt_p) == SUCCESS) {
ctx_opt = *ctx_opt_p;
#else
if (file_password != NULL && (ctx_opt = php_stream_context_get_option(
context, "rar", "file_password"))) {
#endif
if (Z_TYPE_P(ctx_opt) != IS_STRING)
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC,
"RAR file password was provided, but not a string.");
else
*file_password = Z_STRVAL_PP(ctx_opt);
*file_password = Z_STRVAL_P(ctx_opt);
}
#if PHP_MAJOR_VERSION < 7
if (php_stream_context_get_option(context, "rar", "volume_callback",
&ctx_opt) == SUCCESS) {
#if PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION == 2
if (zend_is_callable(*ctx_opt, IS_CALLABLE_STRICT, NULL)) {
&ctx_opt_p) == SUCCESS) {
ctx_opt = *ctx_opt_p;
#else
if (zend_is_callable(*ctx_opt, IS_CALLABLE_STRICT, NULL TSRMLS_CC)) {
if ((ctx_opt = php_stream_context_get_option(
context, "rar", "volume_callback"))) {
#endif
*volume_cb = *ctx_opt;
#if PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION == 2
if (zend_is_callable(ctx_opt, IS_CALLABLE_STRICT, NULL)) {
#else
if (zend_is_callable(ctx_opt, IS_CALLABLE_STRICT, NULL TSRMLS_CC)) {
#endif
*volume_cb = ctx_opt;
}
else
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC,
@@ -736,7 +781,23 @@ static int _rar_get_archive_and_fragment(php_stream_wrapper *wrapper,
if (!(options & STREAM_ASSUME_REALPATH)) {
if (options & USE_PATH) {
#if PHP_MAJOR_VERSION < 7
*archive = zend_resolve_path(tmp_archive, tmp_arch_len TSRMLS_CC);
#else
# if PHP_VERSION_ID < 80100
zend_string *arc_str = zend_resolve_path(tmp_archive, tmp_arch_len);
# else
zend_string *tmp_archive_str = zend_string_init_fast(tmp_archive, tmp_arch_len);
zend_string *arc_str = zend_resolve_path(tmp_archive_str);
zend_string_free(tmp_archive_str);
# endif
if (arc_str != NULL) {
*archive = estrndup(arc_str->val, arc_str->len);
} else {
*archive = NULL;
}
zend_string_release(arc_str);
#endif
}
if (*archive == NULL) {
if ((*archive = expand_filepath(tmp_archive, NULL TSRMLS_CC))
@@ -804,10 +865,17 @@ cleanup:
/* {{{ php_stream_rar_opener */
static php_stream *php_stream_rar_opener(php_stream_wrapper *wrapper,
#if PHP_MAJOR_VERSION < 7
char *filename,
char *mode,
int options,
char **opened_path,
#else
const char *filename,
const char *mode,
int options,
zend_string **opened_path,
#endif
php_stream_context *context
STREAMS_DC TSRMLS_DC)
{
@@ -854,9 +922,7 @@ static php_stream *php_stream_rar_opener(php_stream_wrapper *wrapper,
if (open_passwd != NULL)
self->cb_userdata.password = estrdup(open_passwd);
if (volume_cb != NULL) {
self->cb_userdata.callable = volume_cb;
zval_add_ref(&self->cb_userdata.callable);
SEPARATE_ZVAL(&self->cb_userdata.callable);
ZVAL_ALLOC_DUP(self->cb_userdata.callable, volume_cb);
}
rar_result = _rar_find_file_w(&self->open_data, fragment,
@@ -892,21 +958,23 @@ static php_stream *php_stream_rar_opener(php_stream_wrapper *wrapper,
{
/* no need to allocate a buffer bigger than the file uncomp size */
size_t buffer_size = (size_t)
MIN((uint64) RAR_CHUNK_BUFFER_SIZE,
INT32TO64(self->header_data.UnpSizeHigh,
self->header_data.UnpSize));
size_t file_size = INT32TO64(self->header_data.UnpSizeHigh,
self->header_data.UnpSize);
size_t buffer_size = MIN(
MAX(RAR_CHUNK_BUFFER_SIZE, self->header_data.WinSize),
file_size);
rar_result = RARProcessFileChunkInit(self->rar_handle);
if ((rar_error = _rar_error_to_string(rar_result)) != NULL) {
char *mb_entry = _rar_wide_to_utf_with_alloc(fragment, -1);
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC,
"Error opening file %s inside RAR archive %s: %s",
mb_entry, tmp_open_path, rar_error);
"Error opening file %s inside RAR archive %s: %s",
mb_entry, tmp_open_path, rar_error);
efree(mb_entry);
goto cleanup;
}
self->file_size = file_size;
self->buffer = emalloc(buffer_size);
self->buffer_size = buffer_size;
stream = php_stream_alloc(&php_stream_rario_ops, self, NULL, mode);
@@ -918,10 +986,16 @@ static php_stream *php_stream_rar_opener(php_stream_wrapper *wrapper,
cleanup:
if (tmp_open_path != NULL) {
if (opened_path != NULL)
if (opened_path != NULL) {
#if PHP_MAJOR_VERSION < 7
*opened_path = tmp_open_path;
else
#else
*opened_path =
zend_string_init(tmp_open_path, strlen(tmp_open_path), 0);
#endif
} else {
efree(tmp_open_path);
}
}
if (fragment != NULL)
efree(fragment);
@@ -964,25 +1038,30 @@ static int _rar_get_cachable_rararch(php_stream_wrapper *wrapper,
const char* arch_path,
const char* open_passwd,
zval *volume_cb,
zval **rar_obj,
zval *rar_obj, /* output */
rar_file_t **rar TSRMLS_DC) /* {{{ */
{
char *cache_key = NULL;
uint cache_key_len;
int err_code,
ret = FAILURE;
zval *cache_zv;
assert(rar_obj != NULL);
#if PHP_MAJOR_VERSION < 7
INIT_ZVAL(*rar_obj);
#else
ZVAL_UNDEF(rar_obj);
#endif
_rar_arch_cache_get_key(arch_path, open_passwd, volume_cb, &cache_key,
&cache_key_len);
*rar_obj = RAR_G(contents_cache).get(cache_key, cache_key_len TSRMLS_CC);
if (*rar_obj == NULL) { /* cache miss */
ALLOC_INIT_ZVAL(*rar_obj);
cache_zv = RAR_G(contents_cache).get(
cache_key, cache_key_len, rar_obj TSRMLS_CC);
if (cache_zv == NULL) { /* cache miss */
if (_rar_create_rararch_obj(arch_path, open_passwd, volume_cb,
*rar_obj, &err_code TSRMLS_CC) == FAILURE) {
rar_obj, &err_code TSRMLS_CC) == FAILURE) {
const char *err_str = _rar_error_to_string(err_code);
if (err_str == NULL)
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC,
@@ -999,7 +1078,7 @@ static int _rar_get_cachable_rararch(php_stream_wrapper *wrapper,
int res;
const char *err_str;
if (_rar_get_file_resource_ex(*rar_obj, rar, 1 TSRMLS_CC)
if (_rar_get_file_resource_zv_ex(rar_obj, rar, 1 TSRMLS_CC)
== FAILURE) {
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC,
"Bug: could not retrieve RarArchive object from zval");
@@ -1015,15 +1094,15 @@ static int _rar_get_cachable_rararch(php_stream_wrapper *wrapper,
err_str);
goto cleanup;
}
RAR_G(contents_cache).put(cache_key, cache_key_len, *rar_obj
RAR_G(contents_cache).put(cache_key, cache_key_len, rar_obj
TSRMLS_CC);
_rar_close_file_resource(*rar);
}
}
else { /* cache hit */
/* refcount of rar_obj already incremented by cache get */
if (_rar_get_file_resource_ex(*rar_obj, rar, 1 TSRMLS_CC)
== FAILURE) {
/* cache get already put the value in rar_obj and incremented the
* refcount of the object */
if (_rar_get_file_resource_zv_ex(rar_obj, rar, 1 TSRMLS_CC) == FAILURE) {
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC,
"Bug: could not retrieve RarArchive object from zval");
goto cleanup;
@@ -1035,9 +1114,14 @@ cleanup:
if (cache_key != NULL)
efree(cache_key);
if (ret != SUCCESS && *rar_obj != NULL) {
if (ret != SUCCESS && Z_TYPE_P(rar_obj) == IS_OBJECT) {
#if PHP_MAJOR_VERSION < 7
zval_dtor(rar_obj);
Z_TYPE_P(rar_obj) = IS_NULL;
#else
zval_ptr_dtor(rar_obj);
*rar_obj = NULL;
ZVAL_UNDEF(rar_obj);
#endif
}
return ret;
@@ -1067,16 +1151,20 @@ static void _rar_stream_tidy_wrapper_error_log(php_stream_wrapper *wrapper TSRML
#else
static void _rar_stream_tidy_wrapper_error_log(php_stream_wrapper *wrapper TSRMLS_DC)
{
if (wrapper && FG(wrapper_errors)) {
zend_hash_del(FG(wrapper_errors), (const char*)&wrapper, sizeof wrapper);
}
if (wrapper && FG(wrapper_errors)) {
zend_hash_str_del(FG(wrapper_errors), (const char*)&wrapper, sizeof wrapper);
}
}
#endif
/* }}} */
/* {{{ php_stream_rar_stater */
static int php_stream_rar_stater(php_stream_wrapper *wrapper,
#if PHP_MAJOR_VERSION < 7
char *url,
#else
const char *url,
#endif
int flags,
php_stream_statbuf *ssb,
php_stream_context *context TSRMLS_DC)
@@ -1090,11 +1178,17 @@ static int php_stream_rar_stater(php_stream_wrapper *wrapper,
zval *volume_cb = NULL;
size_t fragment_len;
rar_file_t *rar;
zval *rararch = NULL;
zval rararch;
rar_find_output *state = NULL;
int ret = FAILURE;
/* {{{ preliminaries */
#if PHP_MAJOR_VERSION < 7
Z_TYPE(rararch) = IS_NULL;
#else
ZVAL_UNDEF(&rararch);
#endif
if (_rar_get_archive_and_fragment(wrapper, url, options, 1,
&open_path, &fragment, NULL TSRMLS_CC) == FAILURE) {
goto cleanup;
@@ -1135,16 +1229,24 @@ static int php_stream_rar_stater(php_stream_wrapper *wrapper,
ret = SUCCESS;
cleanup:
if (open_path != NULL)
if (open_path != NULL) {
efree(open_path);
}
if (fragment != NULL)
if (fragment != NULL) {
efree(fragment);
}
if (rararch != NULL)
if (Z_TYPE(rararch) == IS_OBJECT) {
#if PHP_MAJOR_VERSION < 7
zval_dtor(&rararch);
#else
zval_ptr_dtor(&rararch);
if (state != NULL)
#endif
}
if (state != NULL) {
_rar_entry_search_end(state);
}
/* note PHP_STREAM_URL_STAT_QUIET is not equivalent to ~REPORT_ERRORS.
* ~REPORT_ERRORS instead of emitting a notice, stores the error in the
@@ -1153,8 +1255,9 @@ cleanup:
* consistency, I treat both the same way but clean the wrapper in the end
* if necessary
*/
if (flags & PHP_STREAM_URL_STAT_QUIET)
if (flags & PHP_STREAM_URL_STAT_QUIET) {
_rar_stream_tidy_wrapper_error_log(wrapper TSRMLS_CC);
}
return ret;
}
@@ -1162,10 +1265,17 @@ cleanup:
/* {{{ php_stream_rar_dir_opener */
static php_stream *php_stream_rar_dir_opener(php_stream_wrapper *wrapper,
#if PHP_MAJOR_VERSION < 7
char *filename,
char *mode,
int options,
char **opened_path,
#else
const char *filename,
const char *mode,
int options,
zend_string **opened_path,
#endif
php_stream_context *context
STREAMS_DC TSRMLS_DC)
{
@@ -1263,22 +1373,35 @@ static php_stream *php_stream_rar_dir_opener(php_stream_wrapper *wrapper,
cleanup:
if (tmp_open_path != NULL) {
if (opened_path != NULL)
if (opened_path != NULL) {
#if PHP_MAJOR_VERSION < 7
*opened_path = tmp_open_path;
else
#else
*opened_path =
zend_string_init(tmp_open_path, strlen(tmp_open_path), 0);
#endif
} else {
efree(tmp_open_path);
}
}
if (fragment != NULL)
efree(fragment);
if (stream == NULL) { /* failed */
if (self != NULL) {
if (self->rar_obj != NULL)
if (Z_TYPE(self->rar_obj) == IS_OBJECT) {
#if PHP_MAJOR_VERSION < 7
zval_dtor(&self->rar_obj);
#else
zval_ptr_dtor(&self->rar_obj);
if (self->directory != NULL)
#endif
}
if (self->directory != NULL) {
efree(self->directory);
if (self->state != NULL)
}
if (self->state != NULL) {
_rar_entry_search_end(self->state);
}
efree(self);
}
}

63
rar_time.c Normal file
View File

@@ -0,0 +1,63 @@
#ifdef __cplusplus
extern "C" {
#endif
#include <php.h>
#include "php_rar.h"
void rar_time_convert(unsigned low, unsigned high, time_t *to) /* {{{ */
{
time_t default_ = (time_t) 0,
local_time;
struct tm tm = {0};
TSRMLS_FETCH();
if (high == 0U && low == 0U) {
*to = default_;
return;
}
/* 11644473600000000000 - number of ns between 01-01-1601 and 01-01-1970. */
uint64 ushift=INT32TO64(0xA1997B0B,0x4C6A0000);
/* value is in 10^-7 seconds since 01-01-1601 */
/* convert to nanoseconds, shift to 01-01-1970 and convert to seconds */
local_time = (time_t) ((INT32TO64(high, low) * 100 - ushift) / 1000000000);
/* now we have the time in... I don't know what. It gives UTC - tz offset */
/* we need to try and convert it to UTC */
/* abuse gmtime, which is supposed to work with UTC */
if (php_gmtime_r(&local_time, &tm) == NULL) {
php_error_docref(NULL TSRMLS_CC, E_WARNING,
"Could not convert time to UTC, using local time");
*to = local_time;
}
tm.tm_isdst = -1;
*to = local_time + (local_time - mktime(&tm));
}
/* }}} */
int rar_dos_time_convert(unsigned dos_time, time_t *to) /* {{{ */
{
struct tm time_s = {0};
time_s.tm_sec = (dos_time & 0x1f)*2;
time_s.tm_min = (dos_time>>5) & 0x3f;
time_s.tm_hour = (dos_time>>11) & 0x1f;
time_s.tm_mday = (dos_time>>16) & 0x1f;
time_s.tm_mon = ((dos_time>>21) & 0x0f) - 1;
time_s.tm_year = (dos_time>>25) + 80;
/* the dos times that unrar gives out seem to be already in UTC.
* Or at least they don't depend on TZ */
if ((*to = timegm(&time_s)) == (time_t) -1) {
return FAILURE;
}
return SUCCESS;
}
/* }}} */
#ifdef __cplusplus
}
#endif

495
rararch.c
View File

@@ -27,28 +27,42 @@
/* $Id$ */
#include "zend_types.h"
#include <zend_API.h>
#ifdef __cplusplus
extern "C" {
#endif
#define _GNU_SOURCE
#ifndef _GNU_SOURCE
# define _GNU_SOURCE
#endif
#include <string.h>
#include <wchar.h>
#include <php.h>
#include <zend_interfaces.h>
#include "php_rar.h"
#include "php_compat.h"
/* {{{ Type definitions reserved for this translation unit */
typedef struct _ze_rararch_object {
#if PHP_MAJOR_VERSION < 7
zend_object parent;
rar_file_t *rar_file;
#else
rar_file_t *rar_file;
zend_object parent;
#endif
} ze_rararch_object;
typedef struct _rararch_iterator {
zend_object_iterator parent;
rar_find_output *state;
#if PHP_MAJOR_VERSION < 7
zval *value;
#else
zval value;
#endif
int empty_iterator; /* iterator should give nothing */
} rararch_iterator;
/* }}} */
@@ -72,26 +86,59 @@ static zend_object_handlers rararch_object_handlers;
/* }}} */
/* {{{ Function prototypes for functions with internal linkage */
static inline rar_obj_ref rar_obj_ref_fetch(zval *zv);
static inline void rar_obj_ref_make_zv(rar_obj_ref zo, zval *zv TSRMLS_DC);
#if PHP_MAJOR_VERSION >= 7
static inline ze_rararch_object *rararch_object_fetch(zend_object *zobj);
static ze_rararch_object *rararch_object_from_zv(const zval *zv);
static ze_rararch_object *rararch_object_from_ref(const rar_obj_ref ref);
static zend_object *rararch_ce_create_object(zend_class_entry *ce);
static void rararch_ce_free_object_storage(zend_object *zobj);
#else
#define rararch_object_from_zv zend_object_store_get_object
#define rararch_object_from_ref(ref) zend_object_store_get_object_by_handle((ref) TSRMLS_CC)
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);
#endif
/* }}} */
/* {{{ RarArchive handlers */
static int rararch_handlers_preamble(zval *object, rar_file_t **rar TSRMLS_DC);
static int rararch_handlers_preamble(handler_this_t *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 int rararch_count_elements(handler_this_t *object, long *count TSRMLS_DC);
#if PHP_MAJOR_VERSION < 7
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);
#else
static zval *rararch_read_dimension(handler_this_t *object, zval *offset, int type, zval *rv);
#endif
static void rararch_write_dimension(handler_this_t *object, zval *offset, zval *value TSRMLS_DC);
static int rararch_has_dimension(handler_this_t *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) /* {{{ */
int _rar_get_file_resource_zv(zval *zv, rar_file_t **rar_file TSRMLS_DC) /* {{{ */
{
return _rar_get_file_resource_ex(zval_file, rar_file, FALSE TSRMLS_CC);
return _rar_get_file_resource_ex(rar_obj_ref_fetch(zv),
rar_file, FALSE TSRMLS_CC);
}
int _rar_get_file_resource_zv_ex(zval *zv, rar_file_t **rar_file, int allow_closed TSRMLS_DC)
{
return _rar_get_file_resource_ex(rar_obj_ref_fetch(zv),
rar_file, allow_closed TSRMLS_CC);
}
/* }}} */
static int _rar_get_file_resource_handler(handler_this_t *thiz,
rar_file_t **rar_file TSRMLS_DC)
{
#if PHP_MAJOR_VERSION < 8
return _rar_get_file_resource_zv(thiz, rar_file TSRMLS_CC);
#else
return _rar_get_file_resource_ex(thiz, rar_file, FALSE);
#endif
}
/* Creates a RarArchive object, all three in args will be dupped */
int _rar_create_rararch_obj(const char* resolved_path,
const char* open_password,
@@ -124,15 +171,13 @@ int _rar_create_rararch_obj(const char* resolved_path,
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);
ZVAL_ALLOC_DUP(rar->cb_userdata.callable, volume_callback);
}
object_init_ex(object, rararch_ce_ptr);
zobj = zend_object_store_get_object(object TSRMLS_CC);
zobj = rararch_object_from_zv(object TSRMLS_CC);
zobj->rar_file = rar;
rar->id = Z_OBJ_HANDLE_P(object);
rar->obj_ref = rar_obj_ref_fetch(object);
RARSetCallback(rar->arch_handle, _rar_unrar_callback,
(LPARAM) &rar->cb_userdata);
@@ -159,20 +204,21 @@ void _rar_close_file_resource(rar_file_t *rar) /* {{{ */
/* 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. */
* to NULL. This is checked by _rar_get_file_resource_zv. */
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
* If allow_closed 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) /* {{{ */
int _rar_get_file_resource_ex(rar_obj_ref zobjref_file, rar_file_t **rar_file,
int allow_closed TSRMLS_DC) /* {{{ */
{
ze_rararch_object *zobj;
zobj = zend_object_store_get_object(zval_file TSRMLS_CC);
zobj = rararch_object_from_ref(zobjref_file);
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.");
@@ -180,7 +226,7 @@ int _rar_get_file_resource_ex(zval *zval_file, rar_file_t **rar_file, int silent
}
*rar_file = zobj->rar_file;
if ((*rar_file)->arch_handle == NULL && !silent) { /* rar_close was called */
if ((*rar_file)->arch_handle == NULL && !allow_closed) { /* rar_close was called */
_rar_handle_ext_error("The archive is already closed" TSRMLS_CC);
return FAILURE;
}
@@ -196,16 +242,10 @@ int _rar_get_file_resource_ex(zval *zval_file, rar_file_t **rar_file, int silent
static void _rar_raw_entries_to_array(rar_file_t *rar, zval *target TSRMLS_DC) /* {{{ */
{
rar_find_output *state;
zval *rararch_obj;
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);
/* make zval point to the RarArchive object */
rar_obj_ref_make_zv(rar->obj_ref, &rararch_obj TSRMLS_CC);
_rar_entry_search_start(rar, RAR_SEARCH_TRAVERSE, &state TSRMLS_CC);
do {
@@ -214,22 +254,74 @@ static void _rar_raw_entries_to_array(rar_file_t *rar, zval *target TSRMLS_DC) /
zval *entry_obj;
MAKE_STD_ZVAL(entry_obj);
_rar_entry_to_zval(rararch_obj, state->header, state->packed_size,
_rar_entry_to_zval(&rararch_obj, state->header, state->packed_size,
state->position, entry_obj TSRMLS_CC);
add_next_index_zval(target, entry_obj);
#if PHP_MAJOR_VERSION >= 7
/* PHP 7 copies the zval (but without increasing the refcount of the
* obj), while 5.x simply copies the pointer. Only for PHP 5.x do we
* keep the allocation) */
efree(entry_obj);
#endif
}
} 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 */
#if PHP_MAJOR_VERSION < 7
zval_dtor(&rararch_obj);
#else
zval_ptr_dtor(&rararch_obj);
#endif
}
/* }}} */
static zend_object_value rararch_ce_create_object(zend_class_entry *class_type TSRMLS_DC) /* {{{ */
#if PHP_MAJOR_VERSION >=7
static inline rar_obj_ref rar_obj_ref_fetch(zval *zv)
{
return Z_OBJ(*zv);
}
static inline void rar_obj_ref_make_zv(rar_obj_ref zo, zval *zv TSRMLS_DC)
{
ZVAL_OBJ(zv, zo);
zval_addref_p(zv);
}
#else
inline rar_obj_ref rar_obj_ref_fetch(zval *zv)
{
return Z_OBJ_HANDLE_P(zv);
}
inline void rar_obj_ref_make_zv(rar_obj_ref zoh, zval *zv TSRMLS_DC)
{
INIT_ZVAL(*zv);
Z_TYPE_P(zv) = IS_OBJECT;
Z_OBJ_HANDLE_P(zv) = zoh;
Z_OBJ_HT_P(zv) = &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(zoh TSRMLS_CC);
}
#endif
#if PHP_MAJOR_VERSION >=7
static inline ze_rararch_object *rararch_object_fetch(zend_object *zobj)
{
return (ze_rararch_object *)
((char *) zobj - XtOffsetOf(ze_rararch_object, parent));
}
static ze_rararch_object *rararch_object_from_zv(const zval *zv)
{
return rararch_object_fetch(Z_OBJ_P(zv));
}
static ze_rararch_object *rararch_object_from_ref(const rar_obj_ref ref)
{
return rararch_object_fetch(ref);
}
#endif
/* {{{ */
#if PHP_MAJOR_VERSION < 7
static zend_object_value rararch_ce_create_object(zend_class_entry *class_type TSRMLS_DC)
{
zend_object_value zov;
ze_rararch_object *zobj;
@@ -253,10 +345,30 @@ static zend_object_value rararch_ce_create_object(zend_class_entry *class_type T
zov.handlers = &rararch_object_handlers;
return zov;
}
#else
static zend_object *rararch_ce_create_object(zend_class_entry *ce)
{
ze_rararch_object *zobj =
emalloc(sizeof(*zobj) + zend_object_properties_size(ce));
zobj->rar_file = NULL;
zend_object_std_init(&zobj->parent, ce);
zobj->parent.handlers = &rararch_object_handlers;
return &zobj->parent;
}
#endif
/* }}} */
static void rararch_ce_free_object_storage(ze_rararch_object *object TSRMLS_DC) /* {{{ */
/* {{{ */
#if PHP_MAJOR_VERSION < 7
static void rararch_ce_free_object_storage(ze_rararch_object *object TSRMLS_DC)
{
#else
static void rararch_ce_free_object_storage(zend_object *zobj)
{
ze_rararch_object *object = rararch_object_fetch(zobj);
#endif
rar_file_t *rar = object->rar_file;
/* may be NULL if the user did new RarArchive() */
@@ -279,19 +391,22 @@ static void rararch_ce_free_object_storage(ze_rararch_object *object TSRMLS_DC)
/* 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);
zend_object_std_dtor(&object->parent TSRMLS_CC);
#if PHP_MAJOR_VERSION < 7
efree(object);
#endif
}
/* }}} */
/* }}} */
/* {{{ RarArchive handlers */
static int rararch_handlers_preamble(zval *object, rar_file_t **rar TSRMLS_DC) /* {{{ */
static int rararch_handlers_preamble(handler_this_t *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) {
* _rar_get_file_resource_zv checks if the archive was closed */
if (_rar_get_file_resource_handler(object, rar TSRMLS_CC) == FAILURE) {
return FAILURE;
}
@@ -329,7 +444,7 @@ static int rararch_dimensions_preamble(rar_file_t *rar,
return FAILURE;
}
else if (type == IS_DOUBLE) {
if (d > LONG_MAX || d < LONG_MIN) {
if (d > (double) LONG_MAX || d < (double) LONG_MIN) {
RAR_DOCREF_IF_UNQUIET(NULL TSRMLS_CC, E_WARNING,
"Dimension index is out of integer bounds");
return FAILURE;
@@ -339,7 +454,8 @@ static int rararch_dimensions_preamble(rar_file_t *rar,
}
}
else if (Z_TYPE_P(offset) == IS_DOUBLE) {
if (Z_DVAL_P(offset) > LONG_MAX || Z_DVAL_P(offset) < LONG_MIN) {
if (Z_DVAL_P(offset) > (double) LONG_MAX ||
Z_DVAL_P(offset) < (double) LONG_MIN) {
RAR_DOCREF_IF_UNQUIET(NULL TSRMLS_CC, E_WARNING,
"Dimension index is out of integer bounds");
return FAILURE;
@@ -347,11 +463,20 @@ static int rararch_dimensions_preamble(rar_file_t *rar,
*index = (long) Z_DVAL_P(offset);
}
else if (Z_TYPE_P(offset) == IS_OBJECT) {
#if PHP_MAJOR_VERSION < 8
if (Z_OBJ_HT_P(offset)->get) {
/* get handler cannot return NULL */
zval *newoffset = Z_OBJ_HT_P(offset)->get(offset TSRMLS_CC);
zval *newoffset = NULL;
int ret;
# if PHP_MAJOR_VERSION < 7
newoffset = Z_OBJ_HT_P(offset)->get(offset TSRMLS_CC);
# else
zval zv_holder;
ZVAL_NULL(&zv_holder);
newoffset = Z_OBJ_HT_P(offset)->get(offset, &zv_holder);
# endif
/* get handler cannot return NULL */
assert(newoffset != NULL);
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 "
@@ -361,8 +486,32 @@ static int rararch_dimensions_preamble(rar_file_t *rar,
ret = rararch_dimensions_preamble(rar, newoffset, index, quiet
TSRMLS_CC);
FREE_ZVAL(newoffset);
# if PHP_MAJOR_VERSION < 7
zval_ptr_dtor(&newoffset);
# else
zval_ptr_dtor(newoffset);
# endif
return ret;
} else
#endif // PHP < 8
if (Z_OBJ_HT_P(offset)->cast_object) {
zval newoffset;
int res = Z_OBJ_HT_P(offset)->cast_object(
ZV_TO_THIS_FOR_HANDLER(offset), &newoffset, IS_LONG TSRMLS_CC);
if (res == FAILURE) {
RAR_DOCREF_IF_UNQUIET(NULL TSRMLS_CC, E_WARNING,
"Could not convert object given as dimension index into "
"an integer (cast_object failed)");
return FAILURE;
}
if (Z_TYPE(newoffset) != IS_LONG) {
zval_dtor(&newoffset);
RAR_DOCREF_IF_UNQUIET(NULL TSRMLS_CC, E_WARNING,
"Could not convert object given as dimension index into "
"an integer (cast_object did not return int as asked)");
return FAILURE;
}
*index = Z_LVAL(newoffset);
}
else {
RAR_DOCREF_IF_UNQUIET(NULL TSRMLS_CC, E_WARNING,
@@ -395,7 +544,8 @@ static int rararch_dimensions_preamble(rar_file_t *rar,
/* }}} */
/* {{{ RarArchive count_elements handler */
static int rararch_count_elements(zval *object, long *count TSRMLS_DC)
static int rararch_count_elements(zend_object *object, zend_long *count TSRMLS_DC)
{
rar_file_t *rar = NULL;
size_t entry_count;
@@ -406,17 +556,21 @@ static int rararch_count_elements(zval *object, long *count TSRMLS_DC)
}
entry_count = _rar_entry_count(rar);
if (entry_count > LONG_MAX)
entry_count = (size_t) LONG_MAX;
if (entry_count > ZEND_LONG_MAX)
entry_count = ZEND_LONG_MAX;
*count = (long) entry_count;
*count = (zend_long) entry_count;
return SUCCESS;
}
/* }}} */
/* {{{ RarArchive read_dimension handler */
#if PHP_MAJOR_VERSION < 7
static zval *rararch_read_dimension(zval *object, zval *offset, int type TSRMLS_DC)
#else
static zval *rararch_read_dimension(handler_this_t *object, zval *offset, int type, zval *rv)
#endif
{
long index;
rar_file_t *rar = NULL;
@@ -439,17 +593,31 @@ static zval *rararch_read_dimension(zval *object, zval *offset, int type TSRMLS_
_rar_entry_search_seek(out, (size_t) index);
_rar_entry_search_advance(out, NULL, 0, 0);
assert(out->found);
#if PHP_MAJOR_VERSION < 7
ALLOC_INIT_ZVAL(ret);
#else
ret = rv;
#endif
#if PHP_MAJOR_VERSION >= 8
zval object_zv;
ZVAL_OBJ(&object_zv, object);
_rar_entry_to_zval(&object_zv, out->header, out->packed_size, out->position,
ret TSRMLS_CC);
#else
_rar_entry_to_zval(object, out->header, out->packed_size, out->position,
ret TSRMLS_CC);
#endif
_rar_entry_search_end(out);
#if PHP_MAJOR_VERSION < 7
Z_DELREF_P(ret); /* set refcount to 0 */
#endif
return ret;
}
/* }}} */
/* {{{ RarArchive write_dimension handler */
static void rararch_write_dimension(zval *object, zval *offset, zval *value TSRMLS_DC)
static void rararch_write_dimension(handler_this_t *object, zval *offset, zval *value TSRMLS_DC)
{
php_error_docref(NULL TSRMLS_CC, E_ERROR,
"A RarArchive object is not writable");
@@ -457,7 +625,7 @@ static void rararch_write_dimension(zval *object, zval *offset, zval *value TSRM
/* }}} */
/* {{{ RarArchive has_dimension handler */
static int rararch_has_dimension(zval *object, zval *offset, int check_empty TSRMLS_DC)
static int rararch_has_dimension(handler_this_t *object, zval *offset, int check_empty TSRMLS_DC)
{
long index;
rar_file_t *rar = NULL;
@@ -474,7 +642,7 @@ static int rararch_has_dimension(zval *object, zval *offset, int check_empty TSR
/* }}} */
/* {{{ RarArchive unset_dimension handler */
static void rararch_unset_dimension(zval *object, zval *offset TSRMLS_DC)
static void rararch_unset_dimension(handler_this_t *object, zval *offset TSRMLS_DC)
{
php_error_docref(NULL TSRMLS_CC, E_ERROR,
"A RarArchive object is not writable");
@@ -492,8 +660,8 @@ PHP_FUNCTION(rar_open)
char *filename;
char *password = NULL;
char resolved_path[MAXPATHLEN];
int filename_len;
int password_len = 0;
zpp_s_size_t filename_len,
password_len; /* both ignored */
zval *callable = NULL;
int err_code;
@@ -553,7 +721,7 @@ PHP_FUNCTION(rar_list)
RAR_THIS_OR_NO_ARGS(file);
if (_rar_get_file_resource(file, &rar TSRMLS_CC) == FAILURE) {
if (_rar_get_file_resource_zv(file, &rar TSRMLS_CC) == FAILURE) {
RETURN_FALSE;
}
@@ -573,7 +741,7 @@ PHP_FUNCTION(rar_entry_get)
zval *file = getThis();
char *filename;
rar_file_t *rar = NULL;
int filename_len;
zpp_s_size_t filename_len;
wchar_t *filename_c = NULL;
rar_find_output *sstate;
@@ -588,7 +756,7 @@ PHP_FUNCTION(rar_entry_get)
return;
}
if (_rar_get_file_resource(file, &rar TSRMLS_CC) == FAILURE) {
if (_rar_get_file_resource_zv(file, &rar TSRMLS_CC) == FAILURE) {
RETURN_FALSE;
}
@@ -625,7 +793,7 @@ PHP_FUNCTION(rar_solid_is)
RAR_THIS_OR_NO_ARGS(file);
if (_rar_get_file_resource(file, &rar TSRMLS_CC) == FAILURE) {
if (_rar_get_file_resource_zv(file, &rar TSRMLS_CC) == FAILURE) {
RETURN_FALSE;
}
@@ -643,7 +811,7 @@ PHP_FUNCTION(rar_comment_get)
RAR_THIS_OR_NO_ARGS(file);
if (_rar_get_file_resource(file, &rar TSRMLS_CC) == FAILURE) {
if (_rar_get_file_resource_zv(file, &rar TSRMLS_CC) == FAILURE) {
RETURN_FALSE;
}
@@ -657,7 +825,7 @@ PHP_FUNCTION(rar_comment_get)
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_RETURN_STRINGL(rar->list_open_data->CmtBuf,
rar->list_open_data->CmtSize - 1, 1);
}
}
@@ -674,7 +842,7 @@ PHP_FUNCTION(rar_broken_is)
RAR_THIS_OR_NO_ARGS(file);
if (_rar_get_file_resource(file, &rar TSRMLS_CC) == FAILURE) {
if (_rar_get_file_resource_zv(file, &rar TSRMLS_CC) == FAILURE) {
RETURN_FALSE;
}
@@ -705,7 +873,7 @@ PHP_FUNCTION(rar_allow_broken_set)
return;
}
if (_rar_get_file_resource(file, &rar TSRMLS_CC) == FAILURE) {
if (_rar_get_file_resource_zv(file, &rar TSRMLS_CC) == FAILURE) {
RETURN_FALSE;
}
@@ -723,7 +891,7 @@ PHP_FUNCTION(rar_close)
RAR_THIS_OR_NO_ARGS(file);
if (_rar_get_file_resource(file, &rar TSRMLS_CC) == FAILURE) {
if (_rar_get_file_resource_zv(file, &rar TSRMLS_CC) == FAILURE) {
RETURN_FALSE;
}
@@ -747,7 +915,8 @@ PHP_METHOD(rararch, __toString)
RAR_RETNULL_ON_ARGS();
if (_rar_get_file_resource_ex(arch_obj, &rar, TRUE TSRMLS_CC) == FAILURE) {
if (_rar_get_file_resource_zv_ex(arch_obj, &rar, TRUE TSRMLS_CC)
== FAILURE) {
RETURN_FALSE; /* should never happen */
}
@@ -764,10 +933,22 @@ PHP_METHOD(rararch, __toString)
is_closed?closed:"");
restring[restring_size - 1] = '\0'; /* just to be safe */
RETURN_STRINGL(restring, (int) restring_size - 1, 0);
RAR_RETURN_STRINGL(restring, (int) restring_size - 1, 0);
}
/* }}} */
/* {{{ proto string RarEntry::getIterator() */
#if PHP_MAJOR_VERSION >= 8
PHP_METHOD(rararch, getIterator)
{
if (zend_parse_parameters_none() == FAILURE) {
return;
}
zend_create_internal_iterator_zval(return_value, getThis());
}
#endif
/* }}} */
/* {{{ arginfo */
ZEND_BEGIN_ARG_INFO_EX(arginfo_rararchive_open, 0, 0, 1)
ZEND_ARG_INFO(0, filename)
@@ -783,8 +964,20 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_rararchive_setallowbroken, 0, 0, 1)
ZEND_ARG_INFO(0, allow_broken)
ZEND_END_ARG_INFO()
#if PHP_MAJOR_VERSION >= 8
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_rararchive_getiterator, 0, 0, Traversable, 0)
ZEND_END_ARG_INFO()
#endif
ZEND_BEGIN_ARG_INFO(arginfo_rararchive_void, 0)
ZEND_END_ARG_INFO()
#if PHP_VERSION_ID >= 80200
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_rararchive_tostring, 0, 0, IS_STRING, 0)
ZEND_END_ARG_INFO()
#else
#define arginfo_rararchive_tostring arginfo_rararchive_void
#endif
/* }}} */
static zend_function_entry php_rararch_class_functions[] = {
@@ -799,8 +992,11 @@ static zend_function_entry php_rararch_class_functions[] = {
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(rararch, __toString, arginfo_rararchive_tostring, ZEND_ACC_PUBLIC)
PHP_ME_MAPPING(__construct, rar_bogus_ctor, arginfo_rararchive_void, ZEND_ACC_PRIVATE | ZEND_ACC_CTOR)
#if PHP_MAJOR_VERSION >= 8
PHP_ME(rararch, getIterator, arginfo_rararchive_getiterator, ZEND_ACC_PUBLIC)
#endif
{NULL, NULL, NULL}
};
@@ -814,60 +1010,29 @@ static zend_object_iterator *rararch_it_get_iterator(zend_class_entry *ce,
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);
#if PHP_MAJOR_VERSION < 7
static void rararch_it_current_data(zend_object_iterator *iter,
zval ***data TSRMLS_DC);
#else
static zval *rararch_it_current_data(zend_object_iterator *iter);
#endif
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 PHP_MAJOR_VERSION < 7
if (it->value != NULL) {
zval_ptr_dtor(&it->value);
it->value = NULL;
}
#else
zval_ptr_dtor(&it->value);
ZVAL_UNDEF(&it->value);
#endif
}
/* }}} */
@@ -878,10 +1043,16 @@ static void rararch_it_dtor(zend_object_iterator *iter TSRMLS_DC)
rararch_it_invalidate_current((zend_object_iterator *) it TSRMLS_CC);
#if PHP_MAJOR_VERSION < 7
zval_ptr_dtor((zval**) &it->parent.data); /* decrease refcount on zval object */
#else
zval_ptr_dtor(&it->parent.data);
#endif
_rar_entry_search_end(it->state);
#if PHP_MAJOR_VERSION < 7
efree(it);
#endif
}
/* }}} */
@@ -890,40 +1061,72 @@ static void rararch_it_fetch(rararch_iterator *it TSRMLS_DC)
{
rar_file_t *rar_file;
int res;
zval *robj;
#if PHP_MAJOR_VERSION < 7
assert(it->value == NULL);
#else
assert(Z_TYPE(it->value) == IS_UNDEF);
#endif
if (it->empty_iterator) {
#if PHP_MAJOR_VERSION < 7
MAKE_STD_ZVAL(it->value);
ZVAL_FALSE(it->value);
#else
ZVAL_FALSE(&it->value);
#endif
return;
}
res = _rar_get_file_resource_ex(it->parent.data, &rar_file, 1 TSRMLS_CC);
#if PHP_MAJOR_VERSION < 7
robj = it->parent.data;
#else
robj = &it->parent.data;
#endif
res = _rar_get_file_resource_zv_ex(robj, &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);
#if PHP_MAJOR_VERSION < 7
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
_rar_entry_to_zval(robj, it->state->header, it->state->packed_size,
it->state->position, it->value TSRMLS_CC);
else {
ZVAL_FALSE(it->value);
}
#else
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);
}
#endif
}
/* }}} */
/* {{{ rararch_it_valid */
static int rararch_it_valid(zend_object_iterator *iter TSRMLS_DC)
{
#if PHP_MAJOR_VERSION < 7
zval *value = ((rararch_iterator *) iter)->value;
assert(value != NULL);
return (Z_TYPE_P(value) != IS_BOOL)?SUCCESS:FAILURE;
#else
zval *value = &((rararch_iterator *) iter)->value;
assert(Z_TYPE_P(value) != IS_UNDEF);
return Z_TYPE_P(value) != IS_FALSE ? SUCCESS : FAILURE;
#endif
}
/* }}} */
/* {{{ rararch_it_current_data */
#if PHP_MAJOR_VERSION < 7
static void rararch_it_current_data(zend_object_iterator *iter,
zval ***data TSRMLS_DC)
{
@@ -931,6 +1134,15 @@ static void rararch_it_current_data(zend_object_iterator *iter,
assert(*value != NULL);
*data = value;
}
#else
static zval *rararch_it_current_data(zend_object_iterator *iter)
{
zval *ret;
ret = &((rararch_iterator *) iter)->value;
assert(Z_TYPE_P(ret) != IS_UNDEF);
return ret;
}
#endif
/* }}} */
/* {{{ rararch_it_move_forward */
@@ -938,7 +1150,11 @@ 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);
#if PHP_MAJOR_VERSION < 7
it->value = NULL;
#else
ZVAL_UNDEF(&it->value);
#endif
rararch_it_fetch(it TSRMLS_CC);
}
/* }}} */
@@ -949,7 +1165,6 @@ 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);
}
/* }}} */
@@ -966,6 +1181,61 @@ static zend_object_iterator_funcs rararch_it_funcs = {
};
/* }}} */
/* {{{ rararch_it_get_iterator */
static zend_object_iterator *rararch_it_get_iterator(zend_class_entry *ce,
zval *object,
int by_ref TSRMLS_DC)
{
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");
}
res = _rar_get_file_resource_zv_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");
}
rararch_iterator *it = emalloc(sizeof *it);
#if PHP_MAJOR_VERSION < 7
zval_add_ref(&object);
it->parent.data = object;
it->value = NULL;
#else
zend_iterator_init((zend_object_iterator *) it);
ZVAL_COPY(&it->parent.data, object);
ZVAL_UNDEF(&it->value);
#endif
#if PHP_VERSION_ID < 70300
it->parent.funcs = ce->iterator_funcs.funcs;
#else
it->parent.funcs = &rararch_it_funcs;
#endif
it->state = NULL;
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;
_rar_entry_search_start(rar, RAR_SEARCH_TRAVERSE, &it->state TSRMLS_CC);
return (zend_object_iterator*) it;
}
/* }}} */
void minit_rararch(TSRMLS_D)
{
zend_class_entry ce;
@@ -977,6 +1247,11 @@ void minit_rararch(TSRMLS_D)
rararch_object_handlers.write_dimension = rararch_write_dimension;
rararch_object_handlers.has_dimension = rararch_has_dimension;
rararch_object_handlers.unset_dimension = rararch_unset_dimension;
rararch_object_handlers.clone_obj = NULL;
#if PHP_MAJOR_VERSION >= 7
rararch_object_handlers.free_obj = rararch_ce_free_object_storage;
rararch_object_handlers.offset = XtOffsetOf(ze_rararch_object, parent);
#endif
INIT_CLASS_ENTRY(ce, "RarArchive", php_rararch_class_functions);
rararch_ce_ptr = zend_register_internal_class(&ce TSRMLS_CC);
@@ -984,8 +1259,14 @@ void minit_rararch(TSRMLS_D)
rararch_ce_ptr->clone = NULL;
rararch_ce_ptr->create_object = &rararch_ce_create_object;
rararch_ce_ptr->get_iterator = rararch_it_get_iterator;
#if PHP_VERSION_ID < 70300
rararch_ce_ptr->iterator_funcs.funcs = &rararch_it_funcs;
#endif
#if PHP_MAJOR_VERSION >= 8
zend_class_implements(rararch_ce_ptr TSRMLS_CC, 1, zend_ce_aggregate);
#else
zend_class_implements(rararch_ce_ptr TSRMLS_CC, 1, zend_ce_traversable);
#endif
}
#ifdef __cplusplus

View File

@@ -27,11 +27,10 @@
/* $Id$ */
#ifdef __cplusplus
extern "C" {
#include <zend_types.h>
#ifndef _GNU_SOURCE
# define _GNU_SOURCE
#endif
#define _GNU_SOURCE
#include <string.h>
#include <php.h>
@@ -41,39 +40,58 @@ extern "C" {
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);
static void _rar_dos_date_to_text(unsigned dos_time, char *date_string);
/* }}} */
/* {{{ 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 */
/* parent is zval to RarArchive object. The object (not the zval, in PHP 5.x)
* will have its refcount increased */
void _rar_entry_to_zval(zval *parent,
struct RARHeaderDataEx *entry,
unsigned long packed_size,
size_t position,
zval *object TSRMLS_DC) /* {{{ */
zval *object TSRMLS_DC)
/* {{{ */
{
char tmp_s [MAX_LENGTH_OF_LONG + 1];
char time[50];
char *filename;
int filename_size, filename_len;
int filename_size,
filename_len;
#if PHP_MAJOR_VERSION >= 7
zend_long unp_size; /* zval stores PHP ints as zend_long, so use that here */
#else
long unp_size; /* zval stores PHP ints as long, so use that here */
#endif
zval *parent_copy = parent;
#if PHP_MAJOR_VERSION < 7
/* allocate zval on the heap */
zval_addref_p(parent_copy);
SEPARATE_ZVAL(&parent_copy);
/* set refcount to 0; zend_update_property will increase it */
Z_DELREF_P(parent_copy);
#endif
object_init_ex(object, rar_class_entry_ptr);
zend_update_property(rar_class_entry_ptr, object, "rarfile",
sizeof("rararch") - 1, parent TSRMLS_CC);
#if PHP_MAJOR_VERSION >= 8
zend_object *obj = Z_OBJ_P(object);
#else
zval *obj = object;
#endif
#if ULONG_MAX > 0xffffffffUL
zend_update_property(rar_class_entry_ptr, obj, "rarfile",
sizeof("rararch") - 1, parent_copy TSRMLS_CC);
#if PHP_MAJOR_VERSION >= 7 && ZEND_ENABLE_ZVAL_LONG64
unp_size = ((zend_long) entry->UnpSize) + (((zend_long) entry->UnpSizeHigh) << 32);
#elif PHP_MAJOR_VERSION < 7 && ULONG_MAX > 0xffffffffUL
unp_size = ((long) entry->UnpSize) + (((long) entry->UnpSizeHigh) << 32);
#else
/* for 32-bit long, at least don't give negative values */
@@ -84,7 +102,7 @@ void _rar_entry_to_zval(zval *parent, /* zval to RarArchive object, will have it
unp_size = (long) entry->UnpSize;
#endif
filename_size = sizeof(entry->FileNameW) * sizeof(wchar_t);
filename_size = sizeof(entry->FileNameW) * 4;
filename = (char*) emalloc(filename_size);
if (packed_size > (unsigned long) LONG_MAX)
@@ -96,34 +114,56 @@ void _rar_entry_to_zval(zval *parent, /* zval to RarArchive object, will have it
* 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",
zend_update_property_long(rar_class_entry_ptr, obj, "position",
sizeof("position") - 1, (long) position TSRMLS_CC);
zend_update_property_stringl(rar_class_entry_ptr, object, "name",
zend_update_property_stringl(rar_class_entry_ptr, obj, "name",
sizeof("name") - 1, filename, filename_len TSRMLS_CC);
zend_update_property_long(rar_class_entry_ptr, object, "unpacked_size",
zend_update_property_long(rar_class_entry_ptr, obj, "unpacked_size",
sizeof("unpacked_size") - 1, unp_size TSRMLS_CC);
zend_update_property_long(rar_class_entry_ptr, object, "packed_size",
zend_update_property_long(rar_class_entry_ptr, obj, "packed_size",
sizeof("packed_size") - 1, packed_size TSRMLS_CC);
zend_update_property_long(rar_class_entry_ptr, object, "host_os",
zend_update_property_long(rar_class_entry_ptr, obj, "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",
zend_update_property_string(rar_class_entry_ptr, obj, "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",
zend_update_property_string(rar_class_entry_ptr, obj, "crc",
sizeof("crc") - 1, tmp_s TSRMLS_CC);
zend_update_property_long(rar_class_entry_ptr, object, "attr",
zend_update_property_long(rar_class_entry_ptr, obj, "attr",
sizeof("attr") - 1, entry->FileAttr TSRMLS_CC);
zend_update_property_long(rar_class_entry_ptr, object, "version",
zend_update_property_long(rar_class_entry_ptr, obj, "version",
sizeof("version") - 1, entry->UnpVer TSRMLS_CC);
zend_update_property_long(rar_class_entry_ptr, object, "method",
zend_update_property_long(rar_class_entry_ptr, obj, "method",
sizeof("method") - 1, entry->Method TSRMLS_CC);
zend_update_property_long(rar_class_entry_ptr, object, "flags",
zend_update_property_long(rar_class_entry_ptr, obj, "flags",
sizeof("flags") - 1, entry->Flags TSRMLS_CC);
zend_update_property_long(rar_class_entry_ptr, obj, "redir_type",
sizeof("redir_type") - 1, entry->RedirType TSRMLS_CC);
if (entry->RedirName) {
char *redir_target = NULL;
size_t redir_target_size;
zend_update_property_bool(rar_class_entry_ptr, obj,
"redir_to_directory", sizeof("redir_to_directory") - 1,
!!entry->DirTarget TSRMLS_CC);
redir_target_size = entry->RedirNameSize * 4;
redir_target = emalloc(redir_target_size);
assert(redir_target_size > 0);
_rar_wide_to_utf(entry->RedirName, redir_target, redir_target_size);
zend_update_property_string(rar_class_entry_ptr, obj, "redir_target",
sizeof("redir_target") - 1, redir_target TSRMLS_CC);
efree(redir_target);
}
efree(filename);
}
/* }}} */
@@ -152,81 +192,98 @@ 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) /* {{{ */
{
#if PHP_MAJOR_VERSION < 7
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);
#else
zval property;
zend_string *name_str,
*doc_str;
int ret;
ZVAL_NULL(&property);
name_str = zend_string_init(name, (size_t) name_length, 1);
doc_str = zend_string_init(doc_comment, (size_t) doc_comment_len, 1);
# if PHP_MAJOR_VERSION >= 8
zend_declare_property_ex(ce, name_str, &property, ZEND_ACC_PRIVATE,
doc_str);
ret = SUCCESS;
# else
ret = zend_declare_property_ex(ce, name_str, &property, ZEND_ACC_PRIVATE,
doc_str);
#endif
zend_string_release(name_str);
zend_string_release(doc_str);
return ret;
#endif
}
/* }}} */
static zval *_rar_entry_get_property(zval *entry_obj, char *name, int namelen TSRMLS_DC) /* {{{ */
{
zval *tmp;
#if PHP_MAJOR_VERSION >= 7
zval zv;
#endif
#if PHP_VERSION_ID < 70100
zend_class_entry *orig_scope = EG(scope);
EG(scope) = rar_class_entry_ptr;
#endif
#if PHP_MAJOR_VERSION >= 8
tmp = zend_read_property(Z_OBJCE_P(entry_obj), Z_OBJ_P(entry_obj), name, namelen, 1, &zv);
#elif PHP_MAJOR_VERSION >= 7
tmp = zend_read_property(Z_OBJCE_P(entry_obj), entry_obj, name, namelen, 1, &zv);
#else
tmp = zend_read_property(Z_OBJCE_P(entry_obj), entry_obj, name, namelen, 1 TSRMLS_CC);
#endif
if (tmp == NULL) {
php_error_docref(NULL TSRMLS_CC, E_WARNING,
"Bug: unable to find property '%s'. Please report.", name);
}
#if PHP_VERSION_ID < 70100
EG(scope) = orig_scope;
#endif
return tmp;
}
/* }}} */
static void _rar_dos_date_to_text(int dos_time, char *date_string) /* {{{ */
static void _rar_dos_date_to_text(unsigned 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);
}
/* }}} */
time_t time = 0;
struct tm tm = {0};
int res;
static zend_object_value rarentry_ce_create_object(zend_class_entry *class_type TSRMLS_DC) /* {{{ */
{
zend_object_value zov;
zend_object *zobj;
res = rar_dos_time_convert(dos_time, &time) != FAILURE &&
php_gmtime_r(&time, &tm) != NULL;
zobj = emalloc(sizeof *zobj);
zend_object_std_init(zobj, class_type TSRMLS_CC);
if (!res) {
sprintf(date_string, "%s", "time conversion failure");
}
#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;
sprintf(date_string, "%u-%02u-%02u %02u:%02u:%02u",
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min,
tm.tm_sec);
}
/* }}} */
/* }}} */
/* {{{ Methods */
/* {{{ proto bool RarEntry::extract(string dir [, string filepath = ''
[, string password = NULL [, bool extended_data = FALSE]])
/* {{{ public function extract(?string $dir, ?string $filepath = '',
?string $password = null, bool $extended_data = false): void {}
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,
zpp_s_size_t dir_len,
filepath_len = 0,
password_len = 0;
char *considered_path;
@@ -246,14 +303,14 @@ PHP_METHOD(rarentry, extract)
* 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,
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s!|s!s!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) {
if (_rar_get_file_resource_zv(tmp, &rar TSRMLS_CC) == FAILURE) {
RETURN_FALSE;
}
@@ -360,7 +417,7 @@ PHP_METHOD(rarentry, getName)
RAR_GET_PROPERTY(tmp, "name");
RETURN_STRINGL(Z_STRVAL_P(tmp), Z_STRLEN_P(tmp), 1);
RAR_RETURN_STRINGL(Z_STRVAL_P(tmp), Z_STRLEN_P(tmp), 1);
}
/* }}} */
@@ -422,7 +479,7 @@ PHP_METHOD(rarentry, getFileTime)
RAR_GET_PROPERTY(tmp, "file_time");
RETURN_STRINGL(Z_STRVAL_P(tmp), Z_STRLEN_P(tmp), 1);
RAR_RETURN_STRINGL(Z_STRVAL_P(tmp), Z_STRLEN_P(tmp), 1);
}
/* }}} */
@@ -437,7 +494,7 @@ PHP_METHOD(rarentry, getCrc)
RAR_GET_PROPERTY(tmp, "crc");
RETURN_STRINGL(Z_STRVAL_P(tmp), Z_STRLEN_P(tmp), 1);
RAR_RETURN_STRINGL(Z_STRVAL_P(tmp), Z_STRLEN_P(tmp), 1);
}
/* }}} */
@@ -496,7 +553,7 @@ PHP_METHOD(rarentry, getStream)
zval *entry_obj = getThis();
php_stream *stream = NULL;
char *password = NULL;
int password_len; /* ignored */
zpp_s_size_t password_len; /* ignored */
rar_cb_user_data cb_udata = {NULL};
@@ -507,7 +564,7 @@ PHP_METHOD(rarentry, getStream)
RAR_GET_PROPERTY(position, "position");
RAR_GET_PROPERTY(tmp, "rarfile");
if (_rar_get_file_resource(tmp, &rar TSRMLS_CC) == FAILURE) {
if (_rar_get_file_resource_zv(tmp, &rar TSRMLS_CC) == FAILURE) {
RETURN_FALSE;
}
@@ -566,6 +623,60 @@ PHP_METHOD(rarentry, isEncrypted)
}
/* }}} */
/* {{{ proto int RarEntry::getRedirType()
Returns the redirection type, or NULL if there's none */
PHP_METHOD(rarentry, getRedirType)
{
zval *tmp;
zval *entry_obj = getThis();
RAR_RETNULL_ON_ARGS();
RAR_GET_PROPERTY(tmp, "redir_type");
if (Z_TYPE_P(tmp) != IS_LONG) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "bad redir type stored");
RETURN_FALSE;
}
if (Z_LVAL_P(tmp) == FSREDIR_NONE) {
RETURN_NULL();
}
RETURN_LONG(Z_LVAL_P(tmp));
}
/* }}} */
/* {{{ proto bool RarEntry::isRedirectToDirectory()
Returns true if there is redirection and the target is a directory,
null if there is no redirection, false otherwise */
PHP_METHOD(rarentry, isRedirectToDirectory)
{
zval *tmp;
zval *entry_obj = getThis();
RAR_RETNULL_ON_ARGS();
RAR_GET_PROPERTY(tmp, "redir_to_directory");
RETURN_ZVAL(tmp, 1, 0);
}
/* }}} */
/* {{{ proto bool RarEntry::getRedirTarget()
Returns the redirection target, encoded as UTF-8, or NULL */
PHP_METHOD(rarentry, getRedirTarget)
{
zval *tmp;
zval *entry_obj = getThis();
RAR_RETNULL_ON_ARGS();
RAR_GET_PROPERTY(tmp, "redir_target");
RETURN_ZVAL(tmp, 1, 0);
}
/* }}} */
/* {{{ proto string RarEntry::__toString()
Return string representation for entry */
PHP_METHOD(rarentry, __toString)
@@ -579,7 +690,7 @@ PHP_METHOD(rarentry, __toString)
char *name,
*crc;
char *restring;
int restring_len;
int restring_size;
const char format[] = "RarEntry for %s \"%s\" (%s)";
RAR_RETNULL_ON_ARGS();
@@ -595,25 +706,34 @@ PHP_METHOD(rarentry, __toString)
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) +
restring_size = (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",
restring = emalloc(restring_size);
snprintf(restring, restring_size, format, is_dir?"directory":"file",
name, crc);
restring[restring_len - 1] = '\0'; /* just to be safe */
restring[restring_size - 1] = '\0'; /* just to be safe */
RETURN_STRING(restring, 0);
RAR_RETURN_STRINGL(restring, strlen(restring), 0);
}
/* }}} */
/* }}} */
/* {{{ arginfo */
#if PHP_MAJOR_VERSION < 8
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()
#else
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_rarentry_extract, 0, 1, _IS_BOOL, 0)
ZEND_ARG_TYPE_INFO(0, dir, IS_STRING, 1)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, filepath, IS_STRING, 1, "\'\'")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, password, IS_STRING, 1, "null")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, extended_data, _IS_BOOL, 0, "false")
ZEND_END_ARG_INFO()
#endif
ZEND_BEGIN_ARG_INFO_EX(arginfo_rarentry_getstream, 0, 0, 0)
ZEND_ARG_INFO(0, password)
@@ -621,6 +741,13 @@ ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO(arginfo_rar_void, 0)
ZEND_END_ARG_INFO()
#if PHP_VERSION_ID >= 80200
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_rar_tostring, 0, 0, IS_STRING, 0)
ZEND_END_ARG_INFO()
#else
#define arginfo_rar_tostring arginfo_rar_void
#endif
/* }}} */
static zend_function_entry php_rar_class_functions[] = {
@@ -638,7 +765,10 @@ static zend_function_entry php_rar_class_functions[] = {
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(rarentry, getRedirType, arginfo_rar_void, ZEND_ACC_PUBLIC)
PHP_ME(rarentry, isRedirectToDirectory, arginfo_rar_void, ZEND_ACC_PUBLIC)
PHP_ME(rarentry, getRedirTarget, arginfo_rar_void, ZEND_ACC_PUBLIC)
PHP_ME(rarentry, __toString, arginfo_rar_tostring, ZEND_ACC_PUBLIC)
PHP_ME_MAPPING(__construct, rar_bogus_ctor, arginfo_rar_void, ZEND_ACC_PRIVATE | ZEND_ACC_CTOR)
{NULL, NULL, NULL}
};
@@ -647,15 +777,10 @@ 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");
@@ -669,6 +794,9 @@ void minit_rarentry(TSRMLS_D)
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_PROPERTY("redir_type", "The type of redirection or NULL");
REG_RAR_PROPERTY("redir_to_directory", "Whether the redirection target is a directory");
REG_RAR_PROPERTY("redir_target", "Target of the redirectory");
REG_RAR_CLASS_CONST_LONG("HOST_MSDOS", HOST_MSDOS);
REG_RAR_CLASS_CONST_LONG("HOST_OS2", HOST_OS2);
@@ -677,6 +805,12 @@ void minit_rarentry(TSRMLS_D)
REG_RAR_CLASS_CONST_LONG("HOST_MACOS", HOST_MACOS);
REG_RAR_CLASS_CONST_LONG("HOST_BEOS", HOST_BEOS);
REG_RAR_CLASS_CONST_LONG("FSREDIR_UNIXSYMLINK", FSREDIR_UNIXSYMLINK);
REG_RAR_CLASS_CONST_LONG("FSREDIR_WINSYMLINK", FSREDIR_WINSYMLINK);
REG_RAR_CLASS_CONST_LONG("FSREDIR_JUNCTION", FSREDIR_JUNCTION);
REG_RAR_CLASS_CONST_LONG("FSREDIR_HARDLINK", FSREDIR_HARDLINK);
REG_RAR_CLASS_CONST_LONG("FSREDIR_FILECOPY", FSREDIR_FILECOPY);
/* see WinNT.h */
REG_RAR_CLASS_CONST_LONG("ATTRIBUTE_WIN_READONLY", 0x00001L);
REG_RAR_CLASS_CONST_LONG("ATTRIBUTE_WIN_HIDDEN", 0x00002L);
@@ -716,7 +850,3 @@ void minit_rarentry(TSRMLS_D)
REG_RAR_CLASS_CONST_LONG("ATTRIBUTE_UNIX_SYM_LINK", 0x0A000L);
REG_RAR_CLASS_CONST_LONG("ATTRIBUTE_UNIX_SOCKET", 0x0C000L);
}
#ifdef __cplusplus
}
#endif

0
report.xml Normal file
View File

3811
run-tests8.php Normal file

File diff suppressed because it is too large Load Diff

70
test_funcs.sh Normal file
View File

@@ -0,0 +1,70 @@
#!/bin/bash -e
JOBS=3
function package_name {
local readonly version=$1 zts=$2
local zts_suffix=''
if [[ $zts = 'true' ]]; then
zts_suffix='-zts'
fi
echo "php-${version}${zts_suffix}-bare-dbg"
}
function prefix {
local readonly version=$1 zts=$2
echo "/opt/$(package_name $version $zts)"
}
function build_ext {
local readonly version=$1 zts=$2 coverage=$3
local readonly prefix=$(prefix $1 $2)
local cflags= cxxflags= ldflags=
"$prefix"/bin/phpize
if [[ $coverage == true ]]; then
cflags=--coverage
cxxflags=--coverage
ldflags=--coverage
fi
CFLAGS="$cflags" CXXFLAGS="$cxxflags" LDFLAGS="$ldflags" \
./configure --with-php-config="$prefix/bin/php-config"
make -j $JOBS
}
function do_tests {
local readonly prefix=$1
local found_leaks= dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
local ret=0
sed -i s/-@if/@if/ Makefile
TEST_PHP_EXECUTABLE="$prefix/bin/php" \
TEST_PHP_JUNIT=report.xml \
REPORT_EXIT_STATUS=1 \
NO_INTERACTION=1 \
TESTS="--set-timeout 300 --show-diff $RUN_TESTS_FLAGS" make test \
|| ret=$?
found_leaks=$(find tests -name '*.mem' | wc -l)
if [[ $found_leaks -gt 0 ]]; then
echo "Found $found_leaks leaks. Failing."
find tests -name "*.mem" -print -exec cat {} \;
fi
return $ret
}
function install_php {
local readonly version=$1 zts=$2
local readonly url="$MIRROR/php-$version.tar.gz"
sudo apt-get install -y gnupg
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv 5D98E7264E3F3D89463B314B12229434A9F003C9
echo deb [arch=amd64] http://artefacto-test.s3.amazonaws.com/php-bare-dbg bionic main | sudo tee -a /etc/apt/sources.list
sudo apt-get update
sudo apt-get install -y $(package_name $version $zts)
}
function run_tests {
set -e
set -o pipefail
do_tests "$(prefix $1 $2)"
}

View File

@@ -5,6 +5,7 @@ rar_list() function
--FILE--
<?php
require __DIR__ . "/php8compat.php.inc";
$rar_file1 = rar_open(dirname(__FILE__).'/linux_rar.rar');
$list1 = rar_list($rar_file1);
var_dump($list1);
@@ -14,8 +15,7 @@ $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);
argerr(function() use ($rar_file3) { rar_list($rar_file3); });
echo "Done\n";
?>
@@ -48,6 +48,12 @@ array(2) {
int(51)
["flags%sprivate%s=>
int(0)
["redir_type%sprivate]=>
int(0)
["redir_to_directory%sprivate]=>
NULL
["redir_target%sprivate]=>
NULL
}
[1]=>
object(RarEntry)#%d (%d) {
@@ -76,6 +82,12 @@ array(2) {
int(51)
["flags%sprivate%s=>
int(0)
["redir_type%sprivate]=>
int(0)
["redir_to_directory%sprivate]=>
NULL
["redir_target%sprivate]=>
NULL
}
}
array(2) {
@@ -106,6 +118,12 @@ array(2) {
int(53)
["flags%sprivate%s=>
int(0)
["redir_type%sprivate]=>
int(0)
["redir_to_directory%sprivate]=>
NULL
["redir_target%sprivate]=>
NULL
}
[1]=>
object(RarEntry)#%d (%d) {
@@ -134,11 +152,16 @@ array(2) {
int(53)
["flags%sprivate%s=>
int(16)
["redir_type%sprivate]=>
int(0)
["redir_to_directory%sprivate]=>
NULL
["redir_target%sprivate]=>
NULL
}
}
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
Warning: rar_list() expects parameter 1 to be RarArchive, %s given in %s on line %d
Done

View File

@@ -5,6 +5,7 @@ rar_entry_get() function
--FILE--
<?php
require __DIR__ . "/php8compat.php.inc";
$rar_file1 = rar_open(dirname(__FILE__).'/linux_rar.rar');
$entry1 = rar_entry_get($rar_file1, 'test file with whitespaces.txt');
var_dump($entry1);
@@ -14,8 +15,9 @@ $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);
argerr(function() use ($rar_file3) {
rar_entry_get($rar_file3, '2.txt');
});
echo "Done\n";
?>
@@ -46,6 +48,12 @@ object(RarEntry)#%d (%d) {
int(51)
["flags%sprivate%s=>
int(0)
["redir_type%sprivate%s=>
int(0)
["redir_to_directory%sprivate%s=>
NULL
["redir_target%sprivate%s=>
NULL
}
object(RarEntry)#%d (%d) {
["rarfile%sprivate%s=>
@@ -73,10 +81,15 @@ object(RarEntry)#%d (%d) {
int(53)
["flags%sprivate%s=>
int(16)
["redir_type%sprivate%s=>
int(0)
["redir_to_directory%sprivate%s=>
NULL
["redir_target%sprivate%s=>
NULL
}
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
Warning: rar_entry_get() expects parameter 1 to be RarArchive, %s given in %s on line %d
Done

View File

@@ -79,6 +79,12 @@ object(RarEntry)#%d (%d) {
int(53)
["flags%sprivate%s=>
int(16)
["redir_type%sprivate%s=>
int(0)
["redir_to_directory%sprivate%s=>
NULL
["redir_target%sprivate%s=>
NULL
}
bool(true)
Done

View File

@@ -5,6 +5,8 @@ rar_entry_get() function
--FILE--
<?php
require __DIR__ . "/php8compat.php.inc";
$rar_file1 = rar_open(dirname(__FILE__).'/multi.part1.rar');
$entry = rar_entry_get($rar_file1, "file1.txt");
echo "$entry\n";
@@ -13,8 +15,9 @@ var_dump($entry);
echo "\n";
$rar_file2 = rar_open(dirname(__FILE__).'/nonexistent.rar');
$entry = rar_entry_get($rar_file2, "file1.txt");
var_dump($entry);
argerr(function() use ($rar_file2) {
rar_entry_get($rar_file2, "file1.txt");
});
echo "\n";
echo "Done\n";
@@ -28,7 +31,6 @@ 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
Warning: rar_entry_get() expects parameter 1 to be RarArchive, %s given in %s on line %d
Done

View File

@@ -9,10 +9,6 @@ $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) {
@@ -25,7 +21,7 @@ foreach ($entries as $e) {
$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 strtoupper(hash("crc32b", $a))."\n\n"; //you can confirm they're equal to those given by $e->getCrc()
}
echo "Done\n";

View File

@@ -33,9 +33,9 @@ echo "Done\n";
--EXPECTF--
51 files (will test only the first 4):
test/C￾:5B': The great battle of Gunprex versus Optiter!!!!!1
test%s: The great battle of Gunprex versus Optiter!!!!!1
Gunprex, Fire!
So long, Optiter!
test/Sbv=Ð￾:
test%s
Done

View File

@@ -9,10 +9,6 @@ $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().": ";
@@ -21,7 +17,7 @@ foreach ($entries as $e) {
$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 strtoupper(hash("crc32b", $a))."\n\n"; //you can confirm they're equal to those given by $e->getCrc()
}
echo "Done\n";

View File

@@ -9,10 +9,6 @@ $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().": ";
@@ -21,7 +17,7 @@ foreach ($entries as $e) {
$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 strtoupper(hash("crc32b", $a))."\n\n"; //you can confirm they're equal to those given by $e->getCrc()
}
echo "Done\n";

View File

@@ -4,6 +4,9 @@ RarArchive get iterator on closed file
<?php if(!extension_loaded("rar")) print "skip"; ?>
--FILE--
<?php
if (PHP_VERSION_ID>=80500){
ini_set('fatal_error_backtraces', 'Off');
}
$rarF = RarArchive::open(dirname(__FILE__) . '/latest_winrar.rar');
$rarF->close();
foreach ($rarF as $k => $rarE) {

View File

@@ -7,9 +7,9 @@ if(!extension_loaded("rar")) die("skip");
<?php
chdir(dirname(__FILE__));
function volume_callback($vol) {
if (preg_match('/_fail/', $vol))
if (strpos($vol, '_fail') !== false)
$ret = basename(str_replace('_fail', '', $vol));
elseif (preg_match('/_broken/', $vol))
elseif (strpos($vol, '_broken') !== false)
$ret = basename(str_replace('_broken', '_fail', $vol));
else
$ret = null;

View File

@@ -5,6 +5,7 @@ rar_open() with invalid volume callback
if(!extension_loaded("rar")) die("skip");
--FILE--
<?php
require __DIR__ . "/php8compat.php.inc";
class A {
public static function resolve($vol) {
@@ -29,12 +30,16 @@ $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();
$rar = RarArchive::open($fn, null, 'strpos');
argerr(function() use ($rar) {
$rar->getEntries();
});
echo "\nGiven callback that takes another kind of arguments:\n";
$rar = RarArchive::open($fn, null, 'ksort');
$rar->getEntries();
$rar = RarArchive::open($fn, null, 'array_keys');
argerr(function() use ($rar) {
$rar->getEntries();
});
echo "\nGiven callback that returns another kind of arguments:\n";
function testA($vol) { return true; }
@@ -52,7 +57,7 @@ try {
}
echo "Done.\n";
--EXPECTF--
--EXPECTF_DYNAMIC--
Not given a callback:
Warning: RarArchive::open(): Expected the third argument, if provided, to be a valid callback in %s on line %d
@@ -64,18 +69,34 @@ bool(false)
Given callback that takes more arguments:
Warning: array_walk() expects at least %d parameters, 1 given in %s on line %d
<?php if (PHP_VERSION_ID >= 80000) { ?>
Warning: RarArchive::getEntries(): Failure to call volume find callback in %s on line %d
<?php } ?>
<?php if (PHP_VERSION_ID >= 80000) { ?>
Warning: RarArchive::getEntries(): ERAR_EOPEN (file open error) in %s on line %d
Warning: strpos() expects at least %d parameters, 1 given in %s on line %d
<?php } else { ?>
Warning: strpos() 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
<?php } ?>
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
<?php if (PHP_VERSION_ID >= 80000) { ?>
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
Warning: array_keys() expects parameter 1 to be array, string given in %s on line %d
<?php } else { ?>
Warning: array_keys() expects parameter 1 to be array, string given in %s on line %d
Warning: RarArchive::getEntries(): ERAR_EOPEN (file open error) in %s on line %d
<?php } ?>
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

View File

@@ -10,10 +10,6 @@ function resolve($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();
@@ -23,7 +19,7 @@ foreach ($rar_file1 as $e) {
$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 strtoupper(hash("crc32b", $a))."\n\n"; //you can confirm they're equal to those given by $e->getCrc()
}
echo "Done\n";

View File

@@ -10,10 +10,6 @@ function resolve($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');
@@ -22,7 +18,7 @@ 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 strtoupper(hash("crc32b", file_get_contents(dirname(__FILE__) . "/temp_file2.txt")));
echo "\n";
echo "Done\n";
?>

View File

@@ -50,11 +50,11 @@ 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
Warning: fopen(rar://tmp.rar#1.txt): %cailed 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
Warning: fopen(rar://tmp.rar#1.txt): %cailed to open stream: Error opening RAR archive %stmp.rar: ERAR_EOPEN (file open error) in %s on line %d
Should succeed:
string(5) "11111"

View File

@@ -20,9 +20,9 @@ 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
Warning: fopen(rar://%snot_found.rar#1.txt): %cailed 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.
Warning: fopen(rar://%slatest_winrar.rar#not_found.txt): %cailed to open stream: Can't file not_found.txt in RAR archive %s on line %d
Done.

View File

@@ -27,21 +27,21 @@ 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
Warning: fopen(rar://): %cailed 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
Warning: fopen(rar://file.rar): %cailed 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
Warning: fopen(rar://file.rar#): %cailed 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
Warning: fopen(rar://#frag): %cailed 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
Warning: fopen(rar://#): %cailed 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.

View File

@@ -55,11 +55,11 @@ 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
Warning: fopen(rar://%sencrypted_headers.rar#encfile1.txt): %cailed 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
Warning: fopen(rar://%sencrypted_headers.rar#encfile1.txt): %cailed 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."
@@ -67,11 +67,11 @@ 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
Warning: fopen(rar://%sencrypted_only_files.rar#encfile1.txt): %cailed 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
Warning: fopen(rar://%sencrypted_only_files.rar#encfile1.txt): %cailed 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."

View File

@@ -11,17 +11,13 @@ function resolve($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 strtoupper(hash("crc32b", $a))."\n\n"; //you can confirm they're equal to those given by $e->getCrc()
echo "Done.\n";
--EXPECTF--
17704 bytes, CRC F2C79881

View File

@@ -4,14 +4,20 @@ RAR file stream stat
<?php
if(!extension_loaded("rar")) die("skip");
--ENV--
TZ=Europe/Lisbon
TZ=Asia/Tokyo
--FILE--
<?php
umask(0);
$stream = fopen("rar://" .
dirname(__FILE__) . '/latest_winrar.rar' .
"#1.txt", "r");
print_r(array_slice(fstat($stream), 13));
$r = array_slice(fstat($stream), 13);
if (PHP_OS == 'WINNT') {
// we don't return the correct value on windows
$r['mtime'] = 1086948439;
}
print_r($r);
echo "Done.\n";
--EXPECTF--
@@ -26,7 +32,7 @@ Array
[rdev] => 0
[size] => 5
[atime] => 0
[mtime] => 1086944839
[mtime] => 1086948439
[ctime] => 0
[blksize] => %s
[blocks] => %s

View File

@@ -12,6 +12,6 @@ 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
Warning: opendir(rar://%sdirlink_unix.rar#file): %cailed to open dir%S: Archive %sdirlink_unix.rar has an entry named file, but it is not a directory in %s on line %d
bool(false)
Done.

View File

@@ -21,7 +21,14 @@ 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));
$r = array_slice(fstat(opendir($u)), 13);
if (PHP_OS == 'WINNT') {
// we don't give the correct values on windows
$r['atime'] = 1272938643;
$r['mtime'] = 1272938643;
$r['ctime'] = 1272813170;
}
print_r($r);
echo "Done.\n";
--EXPECTF--
@@ -54,9 +61,9 @@ Array
[gid] => 0
[rdev] => 0
[size] => 0
[atime] => 1272935043
[mtime] => 1272935043
[ctime] => 1272809570
[atime] => 1272938643
[mtime] => 1272938643
[ctime] => 1272813170
[blksize] => %s
[blocks] => %s
)

View File

@@ -1,7 +1,10 @@
--TEST--
RarArchive direct instantiation does not crash
RarArchive direct instantiation does not crash (PHP 5.x)
--SKIPIF--
<?php if(!extension_loaded("rar")) die("skip");
<?php
if (!extension_loaded("rar")) die("skip");
if (!defined('PHP_VERSION_ID') || PHP_VERSION_ID >= 70000) die("skip for PHP 5.x");
if (key_exists('USE_ZEND_ALLOC', $_ENV) && PHP_VERSION_ID < 70000) die('skip do not use with valgrind in PHP <7');
--FILE--
<?php

View File

@@ -1,7 +1,9 @@
--TEST--
RarEntry direct instantiation does not crash
RarEntry direct instantiation does not crash (PHP 5.x)
--SKIPIF--
<?php if(!extension_loaded("rar")) die("skip");
if (!defined('PHP_VERSION_ID') || PHP_VERSION_ID >= 70000) die("skip for PHP 5.x");
if (key_exists('USE_ZEND_ALLOC', $_ENV) && PHP_VERSION_ID < 70000) die('skip do not use with valgrind in PHP <7');
--FILE--
<?php

View File

@@ -48,12 +48,12 @@ Count: 13
* Closed file test (1):
Warning: count(): The archive is already closed in %s on line %d
Warning: %s(): 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
Warning: %s(): The archive is already closed in %s on line %d
int(0)
* Closed file test (3, exceptions):

View File

@@ -15,10 +15,12 @@ echo "string (\"0.001\"). {$a['0.001']}\n";
echo "\n";
echo "Done.\n";
--EXPECTF--
--EXPECTF_DYNAMIC--
string ("0"). RarEntry for file "1.txt" (a0de71c0)
<?php if (PHP_VERSION_ID < 80000) { ?>
Notice: A non well formed numeric value encountered in %s on line %d
<?php } ?>
string ("1abc"). RarEntry for file "2.txt" (45a918de)
float (0.001). RarEntry for file "1.txt" (a0de71c0)
string ("0.001"). RarEntry for file "1.txt" (a0de71c0)

View File

@@ -42,7 +42,7 @@ echo $a[new stdClass()];
echo "\n";
echo "Done.\n";
--EXPECTF--
--EXPECTF_DYNAMIC--
* -1 (int):
Warning: main(): Dimension index must be non-negative, given -1 in %s on line %d
@@ -81,6 +81,11 @@ Warning: main(): Attempt to use a non-numeric dimension to access a RarArchive o
* new stdClass():
Warning: main(): Attempt to use an object with no get handler as a dimension to access a RarArchive object in %s on line %d
<?php if (PHP_VERSION_ID >= 80000) { ?>
Warning: main(): Could not convert object given as dimension index into an integer (cast_object failed) in %s on line %d
<?php } else { ?>
Notice: Object of class stdClass could not be converted to int in %s on line %d
RarEntry for file "2.txt" (45a918de)
<?php } ?>
Done.

View File

@@ -1,9 +1,15 @@
--TEST--
RarArchive write_property gives a fatal error
--SKIPIF--
<?php if(!extension_loaded("rar")) print "skip"; ?>
<?php
if(!extension_loaded("rar")) die("skip");
if (key_exists('USE_ZEND_ALLOC', $_ENV) && PHP_VERSION_ID < 70000) die('skip do not use with valgrind in PHP <7');
?>
--FILE--
<?php
if (PHP_VERSION_ID>=80500){
ini_set('fatal_error_backtraces', 'Off');
}
$f1 = dirname(__FILE__) . "/latest_winrar.rar";
$a = RarArchive::open($f1);

View File

@@ -4,6 +4,9 @@ RarArchive read_property gives a fatal error on a write context
<?php if(!extension_loaded("rar")) print "skip"; ?>
--FILE--
<?php
if (PHP_VERSION_ID>=80500){
ini_set('fatal_error_backtraces', 'Off');
}
$f1 = dirname(__FILE__) . "/latest_winrar.rar";
$a = RarArchive::open($f1);

View File

@@ -1,9 +1,15 @@
--TEST--
RarArchive write_property gives a fatal error
--SKIPIF--
<?php if(!extension_loaded("rar")) print "skip"; ?>
<?php
if(!extension_loaded("rar")) die("skip");
if (key_exists('USE_ZEND_ALLOC', $_ENV) && PHP_VERSION_ID < 70000) die('skip do not use with valgrind in PHP <7')
?>
--FILE--
<?php
if (PHP_VERSION_ID>=80500){
ini_set('fatal_error_backtraces', 'Off');
}
$f1 = dirname(__FILE__) . "/latest_winrar.rar";
$a = RarArchive::open($f1);

View File

@@ -4,6 +4,9 @@ RarArchive unset_property gives a fatal error
<?php if(!extension_loaded("rar")) print "skip"; ?>
--FILE--
<?php
if (PHP_VERSION_ID>=80500){
ini_set('fatal_error_backtraces', 'Off');
}
$f1 = dirname(__FILE__) . "/latest_winrar.rar";
$a = RarArchive::open($f1);

View File

@@ -5,13 +5,18 @@ RarArchive::isBroken/rar_broken_is test
--FILE--
<?php
require __DIR__ . "/php8compat.php.inc";
$f = dirname(__FILE__) . "/latest_winrar.rar";
$b = dirname(__FILE__) . "/multi_broken.part1.rar";
echo "\n* unbroken file; bad arguments\n";
$a = RarArchive::open($f);
var_dump($a->isBroken("jjj"));
var_dump(rar_broken_is($a, "jjj"));
argerr(function() use ($a) {
$a->isBroken("jjj");
});
argerr(function() use ($a) {
rar_broken_is($a, "jjj");
});
echo "\n* unbroken file; as first call\n";
var_dump($a->isBroken());
@@ -46,10 +51,8 @@ echo "Done.\n";
* unbroken file; bad arguments
Warning: RarArchive::isBroken() expects exactly 0 parameters, 1 given in %s on line %d
NULL
Warning: rar_broken_is() expects exactly 1 parameter, 2 given in %s on line %d
NULL
* unbroken file; as first call
bool(false)

View File

@@ -5,13 +5,18 @@ RarArchive::setAllowBroken has the desired effect
--FILE--
<?php
require __DIR__ . "/php8compat.php.inc";
function retnull() { return null; }
$b = dirname(__FILE__) . "/multi_broken.part1.rar";
echo "* broken file; bad arguments\n";
$a = RarArchive::open($b, null, 'retnull');
$a->setAllowBroken();
rar_allow_broken_set($a);
argerr(function() use ($a) {
$a->setAllowBroken();
});
argerr(function() use ($a) {
rar_allow_broken_set($a);
});
echo "\n* broken file; do not allow broken (default)\n";
$a = RarArchive::open($b, null, 'retnull');
@@ -54,7 +59,7 @@ Warning: rar_allow_broken_set() expects exactly 2 parameters, 1 given in %s on l
Warning: RarArchive::getEntries(): ERAR_EOPEN (file open error) in %s on line %d
bool(false)
Warning: count(): ERAR_EOPEN (file open error) in %s on line %d
Warning: %s(): ERAR_EOPEN (file open error) in %s on line %d
int(0)
* broken file; do not allow broken (explicit)
@@ -62,7 +67,7 @@ int(0)
Warning: RarArchive::getEntries(): ERAR_EOPEN (file open error) in %s on line %d
bool(false)
Warning: count(): ERAR_EOPEN (file open error) in %s on line %d
Warning: %s(): ERAR_EOPEN (file open error) in %s on line %d
int(0)
* broken file; allow broken

View File

@@ -4,6 +4,9 @@ Traversal of RarArchive with foreach by reference gives error
<?php if(!extension_loaded("rar")) print "skip"; ?>
--FILE--
<?php
if (PHP_VERSION_ID>=80500){
ini_set('fatal_error_backtraces', 'Off');
}
$f1 = dirname(__FILE__) . "/latest_winrar.rar";
$a = RarArchive::open($f1);

View File

@@ -5,6 +5,7 @@ Wrapper cache exaustion test
--FILE--
<?php
require __DIR__ . "/php8compat.php.inc";
$f = array();
$f[] = dirname(__FILE__) . "/latest_winrar.rar";
$f[] = dirname(__FILE__) . "/directories.rar";
@@ -18,7 +19,9 @@ function printstats() {
}
echo "* Invalid call to rar_wrapper_cache_stats():\n";
var_dump(rar_wrapper_cache_stats("sfddf"));
argerr(function() {
rar_wrapper_cache_stats("sfddf");
});
echo "\n* Initial stats:\n";
printstats();
@@ -75,7 +78,6 @@ echo "Done.\n";
* Invalid call to rar_wrapper_cache_stats():
Warning: rar_wrapper_cache_stats() expects exactly 0 parameters, 1 given in %s on line %d
NULL
* Initial stats:
Stats: 0/0 (hits/misses)

View File

@@ -10,7 +10,9 @@ phpinfo(INFO_MODULES);
$phpinfo = ob_get_contents();
ob_end_clean();
$phpinfo = preg_replace('/\r\n?/', "\n", $phpinfo); //normalize line endings
//normalize line endings
$phpinfo = str_replace("\r\n", "\n", $phpinfo);
$phpinfo = str_replace("\r", "\n", $phpinfo);
$phpinfo = explode("\n", $phpinfo);

View File

@@ -16,7 +16,10 @@ foreach ($rar as $rar_file) {
echo "\nDone.\n";
--EXPECTF--
int(2279)
int(1316)
Warning: stream_get_contents(): The file size is supposed to be 2279 bytes, but we read more: 2288 bytes (corruption/wrong pwd) in %s on line %d
int(2288)
Done.
Warning: stream_get_contents(): The file size is supposed to be 1316 bytes, but we read more: 1328 bytes (corruption/wrong pwd) in %s on line %d
int(1328)
Done.

View File

@@ -32,6 +32,6 @@ opened
Testing 'r+'
Warning: fopen(%s): failed to open stream: Only the "r" and "rb" open modes are permitted, given r+ in %s on line %d
Warning: fopen(%s): %cailed to open stream: Only the "r" and "rb" open modes are permitted, given r+ in %s on line %d
Done.

View File

@@ -1,13 +1,16 @@
--TEST--
Supports version 5 RAR files
--SKIPIF--
<?php if(!extension_loaded("rar")) print "skip"; ?>
<?php if(!extension_loaded("rar")) die("skip");
if (isset($_ENV['APPVEYOR'])) die("skip failing on appveyor");
if ($_ENV['RUNNER_OS'] === 'Windows') die("skip failing on Windows runner on GitHub Action");
--FILE--
<?php
RarException::setUsingExceptions(true);
$file = dirname(__FILE__) . '/rar5_multi.part1.rar';
$rar = RarArchive::open($file);
$entry = $rar->getEntry('usr/bin/text2image');
$entry = $rar->getEntry('usr' . DIRECTORY_SEPARATOR . 'bin' .
DIRECTORY_SEPARATOR . 'text2image');
var_dump($entry);
$stream = $entry->getStream('passw0rd');
$contents = stream_get_contents($stream);
@@ -22,7 +25,7 @@ object(RarEntry)#%d (%d) {
["position%sprivate%s=>
int(0)
["name%sprivate%s=>
string(18) "usr/bin/text2image"
string(18) "usr%sbin%stext2image"
["unpacked_size%sprivate%s=>
int(147528)
["packed_size%sprivate%s=>
@@ -36,11 +39,17 @@ object(RarEntry)#%d (%d) {
["attr%sprivate%s=>
int(33261)
["version%sprivate%s=>
int(200)
int(50)
["method%sprivate%s=>
int(51)
["flags%sprivate%s=>
int(5)
["redir_type%sprivate%s=>
int(0)
["redir_to_directory%sprivate%s=>
NULL
["redir_target%sprivate%s=>
NULL
}
(unpacked) MD5: c07ce36ec260848f47fe8ac1408f938f
Done.

17
tests/102.phpt Normal file
View File

@@ -0,0 +1,17 @@
--TEST--
RarArchive direct instantiation does not crash (PHP 7)
--SKIPIF--
<?php
if (!extension_loaded("rar")) die("skip");
if (!defined('PHP_VERSION_ID') || PHP_VERSION_ID < 70000) die("skip for PHP >= 7");
--FILE--
<?php
new RarArchive();
echo "Done\n";
--EXPECTF--
Fatal error: Uncaught Error: Call to private RarArchive::__construct() from %s in %s:%d
Stack trace:
#0 {main}
thrown in %s on line %d

16
tests/103.phpt Normal file
View File

@@ -0,0 +1,16 @@
--TEST--
RarEntry direct instantiation does not crash (PHP 7)
--SKIPIF--
<?php if(!extension_loaded("rar")) die("skip");
if (!defined('PHP_VERSION_ID') || PHP_VERSION_ID < 70000) die("skip for PHP >= 7");
--FILE--
<?php
new RarEntry();
echo "Done\n";
--EXPECTF--
Fatal error: Uncaught Error: Call to private RarEntry::__construct() from %s in %s:%d
Stack trace:
#0 {main}
thrown in %s on line %d

19
tests/104.phpt Normal file
View File

@@ -0,0 +1,19 @@
--TEST--
Clone of RarArchive is forbidden (PHP 7)
--SKIPIF--
<?php if(!extension_loaded("rar")) print "skip";
if (!defined('PHP_VERSION_ID') || PHP_VERSION_ID < 70000) die("skip for PHP >= 7");
--FILE--
<?php
RarException::setUsingExceptions(true);
$file = dirname(__FILE__) . '/rar5_multi.part1.rar';
$rar = RarArchive::open($file);
$rar2 = clone $rar;
$rar2->getEntries();
echo "Never reached.\n";
?>
--EXPECTF--
Fatal error: Uncaught Error: Trying to clone an uncloneable object of class RarArchive in %s:5
Stack trace:
#0 {main}
thrown in %s on line %d

16
tests/105.phpt Normal file
View File

@@ -0,0 +1,16 @@
--TEST--
Clone of RarArchive is forbidden (PHP 5.x)
--SKIPIF--
<?php if(!extension_loaded("rar")) print "skip";
if (!defined('PHP_VERSION_ID') || PHP_VERSION_ID >= 70000) die("skip for PHP 5.x");
--FILE--
<?php
RarException::setUsingExceptions(true);
$file = dirname(__FILE__) . '/rar5_multi.part1.rar';
$rar = RarArchive::open($file);
$rar2 = clone $rar;
$rar2->getEntries();
echo "Never reached.\n";
?>
--EXPECTF--
Fatal error: Trying to clone an uncloneable object of class RarArchive in %s on line %d

19
tests/106.phpt Normal file
View File

@@ -0,0 +1,19 @@
--TEST--
Stat times don't depend on timezone (cf. 056.phpt)
--SKIPIF--
<?php
if(!extension_loaded("rar")) die("skip");
--ENV--
TZ=UTC
--FILE--
<?php
umask(0);
$stream = fopen("rar://" .
dirname(__FILE__) . '/latest_winrar.rar' .
"#1.txt", "r");
$fs = fstat($stream);
echo $fs['mtime'], "\n";
echo "Done.\n";
--EXPECTF--
1086948439
Done.

53
tests/107.phpt Normal file
View File

@@ -0,0 +1,53 @@
--TEST--
Redirection functions
--SKIPIF--
<?php
if(!extension_loaded("rar")) die("skip");
--FILE--
<?php
$m = array(
RarEntry::FSREDIR_UNIXSYMLINK => 'FSREDIR_UNIXSYMLINK',
RarEntry::FSREDIR_WINSYMLINK => 'FSREDIR_WINSYMLINK',
RarEntry::FSREDIR_JUNCTION => 'FSREDIR_JUNCTION',
RarEntry::FSREDIR_HARDLINK => 'FSREDIR_HARDLINK',
RarEntry::FSREDIR_FILECOPY => 'FSREDIR_FILECOPY',
);
$a = rar_open(dirname(__FILE__) . '/rar5-links.rar');
$i = 0;
foreach ($a as $e) {
if ($i++ != 0) echo "\n";
echo "$i. ", $e->getName(), "\n";
$type = $e->getRedirType();
$type = $type ? $m[$type] : $type;
echo "redir type: ", var_export($type, true), "\n";
echo "redir to dir: ", var_export($e->isRedirectToDirectory(), true), "\n";
echo "redir target: ", var_export($e->getRedirTarget(), true), "\n";
// break;
}
echo "Done.\n";
--EXPECTF--
1. file1-hardlink.txt
redir type: NULL
redir to dir: NULL
redir target: NULL
2. file1.txt
redir type: 'FSREDIR_HARDLINK'
redir to dir: false
redir target: 'file1-hardlink.txt'
3. dir-link
redir type: 'FSREDIR_UNIXSYMLINK'
redir to dir: true
redir target: 'dir'
4. file1-link.txt
redir type: 'FSREDIR_UNIXSYMLINK'
redir to dir: false
redir target: 'file1.txt'
5. dir
redir type: NULL
redir to dir: NULL
redir target: NULL
Done.

14
tests/108.phpt Normal file
View File

@@ -0,0 +1,14 @@
--TEST--
RarEntry::getPackedSize()
--SKIPIF--
<?php
if(!extension_loaded("rar")) die("skip");
--FILE--
<?php
$a = rar_open(dirname(__FILE__) . '/4mb.rar');
$e = $a->getEntry('4mb.txt');
var_dump($e->getPackedSize());
echo "Done.\n";
--EXPECTF--
int(2444)
Done.

16
tests/109.phpt Normal file
View File

@@ -0,0 +1,16 @@
--TEST--
RarEntry::getHostOs()
--SKIPIF--
<?php
if(!extension_loaded("rar")) die("skip");
--FILE--
<?php
$a = rar_open(dirname(__FILE__) . '/4mb.rar');
$e = $a->getEntry('4mb.txt');
var_dump($e->getHostOs());
var_dump(RarEntry::HOST_WIN32);
echo "Done.\n";
--EXPECTF--
int(2)
int(2)
Done.

14
tests/110.phpt Normal file
View File

@@ -0,0 +1,14 @@
--TEST--
RarEntry::getFileTime()
--SKIPIF--
<?php
if(!extension_loaded("rar")) die("skip");
--FILE--
<?php
$a = rar_open(dirname(__FILE__) . '/4mb.rar');
$e = $a->getEntry('4mb.txt');
var_dump($e->getFileTime());
echo "Done.\n";
--EXPECTF--
string(19) "2010-05-30 01:22:00"
Done.

14
tests/111.phpt Normal file
View File

@@ -0,0 +1,14 @@
--TEST--
RarEntry::getVersion()
--SKIPIF--
<?php
if(!extension_loaded("rar")) die("skip");
--FILE--
<?php
$a = rar_open(dirname(__FILE__) . '/rar5-links.rar');
$e = $a->getEntry('file1.txt');
var_dump($e->getVersion());
echo "Done.\n";
--EXPECTF--
int(50)
Done.

14
tests/112.phpt Normal file
View File

@@ -0,0 +1,14 @@
--TEST--
RarEntry::getMethod()
--SKIPIF--
<?php
if(!extension_loaded("rar")) die("skip");
--FILE--
<?php
$a = rar_open(dirname(__FILE__) . '/rar5-links.rar');
$e = $a->getEntry('file1.txt');
var_dump($e->getMethod());
echo "Done.\n";
--EXPECTF--
int(48)
Done.

19
tests/113.phpt Normal file
View File

@@ -0,0 +1,19 @@
--TEST--
RarEntry::isEncrypted()
--SKIPIF--
<?php
if(!extension_loaded("rar")) die("skip");
--FILE--
<?php
$a = rar_open(dirname(__FILE__) . '/rar5-links.rar');
$e = $a->getEntry('file1.txt');
var_dump($e->isEncrypted());
$a = rar_open(dirname(__FILE__) . '/encrypted_only_files.rar');
$e = $a->getEntry('encfile1.txt');
var_dump($e->isEncrypted());
echo "Done.\n";
--EXPECTF--
bool(false)
bool(true)
Done.

50
tests/114.phpt Normal file
View File

@@ -0,0 +1,50 @@
--TEST--
Bug 76592: solid files are partially extracted
--SKIPIF--
<?php
if (!extension_loaded("rar")) die("skip");
if (PHP_OS != 'Linux') die('skip for linux');
if (PHP_VERSION_ID < 50400) die("skip for PHP 5.4+");
--FILE--
<?php
$before = hex2bin('526172211a07010030f8db480d01050900080101c5808085800093f4589f2e02030b80808085800004808080858000b483020000000080380108746573742e6461740a031389bf735fa302a31c');
$after = hex2bin('a6e7161b0e0306be0000be000080000102514fe6dcc40b3900b38080053393f4589f2e02030b80808085800004808080858000b483020000000080380108746573742e6461740a031389bf735fa302a31c1d77565103050400');
$middle = file_get_contents('/dev/urandom', false, null, 0, 10 * 1024 * 1024) or die('failed file_get_contents');
$crc32hexbe = crc32($middle);
$crc32le = pack('V', $crc32hexbe);
$before = substr($before, 0, 50) . $crc32le . substr($before, 54);
$after = substr($after, 0, 56) . $crc32le . substr($after, 60);
$data = $before . $middle . $after;
$file = tempnam('/tmp', 'rar');
file_put_contents($file, $data) or die('failed file_put contents');
$rar = \RarArchive::open($file) or die('Unable to open archive');
$rar->setAllowBroken(true); // we don't fixup the headers checksum, only the contents. Ignore the error
$entry = $rar->getEntry('test.dat') or die('Unable to get entry');
$contents = stream_get_contents($entry->getStream(), $entry->getUnpackedSize());
$crc32_rar = $entry->getCrc();
$crc32_cont = dechex(crc32($contents));
$crc32_orig_content = dechex(crc32($contents));
unlink($file);
echo 'orig content size: ', strlen($middle), "\n";
echo 'read content size: ', strlen($contents), "\n";
if ($crc32_rar !== $crc32_cont) {
die("CRC values do not match");
}
if ($crc32_rar !== $crc32_orig_content) {
die("CRC values do not match (2)");
}
?>
==DONE==
--EXPECT--
orig content size: 10485760
read content size: 10485760
==DONE==

25
tests/115.phpt Normal file
View File

@@ -0,0 +1,25 @@
--TEST--
getIterator() (PHP 8+)
--SKIPIF--
<?php
if (!extension_loaded("rar")) die("skip");
if (PHP_VERSION_ID < 80000) print "skip for PHP 8";
?>
--FILE--
<?php
$a = rar_open(dirname(__FILE__).'/linux_rar.rar');
$it = $a->getIterator();
var_dump($it);
foreach ($it as $e) {
echo $e->getName(), "\n";
}
echo "Done\n";
?>
--EXPECT--
object(InternalIterator)#3 (0) {
}
plain.txt
test file with whitespaces.txt
Done

17
tests/php8compat.php.inc Normal file
View File

@@ -0,0 +1,17 @@
<?php
ini_set('pcre.jit', '0'); // avoid some valgrind errors
function argerr($cl) {
try {
return $cl();
} catch (TypeError $err) {
$msg = $err->getMessage();
$msg = "Warning: $msg in {$err->getFile()} on line {$err->getLine()}";
$msg = preg_replace('/: Argument #(\d) \(\$\S+\) must be of type/',
' expects parameter \1 to be', $msg);
$msg = preg_replace('/expects (.+) (\d) argument/',
'expects \1 \2 parameter', $msg);
echo "\n", $msg, "\n";
}
}

BIN
tests/rar5-links.rar Normal file

Binary file not shown.

View File

@@ -1,75 +0,0 @@
#!/bin/bash -e
BUILDS_DIR=$HOME/php_builds
MIRROR=${MIRROR:-http://us1.php.net/distributions}
JOBS=3
function prefix {
local readonly version=$1 zts=$2
local zts_suffix=''
if [[ $zts = 'yes' ]]; then
zts_suffix='-zts'
fi
echo "$BUILDS_DIR/${version}$zts_suffix"
}
function install_php {
local readonly version=$1 zts=$2
local readonly url="$MIRROR/php-$version.tar.gz" \
extract_dir="/tmp/php-$version" prefix=$(prefix $version $zts)
local extra_flags=''
mkdir -p "$extract_dir"
wget -O - "$url" | tar -C "$extract_dir" --strip-components=1 -xzf -
pushd "$extract_dir"
if [[ $zts = 'yes' ]]; then
extra_flags="$extra_flags --enable-maintainer-zts"
fi
./configure --prefix="$prefix" --disable-all --enable-cli \
$extra_flags
make -j $JOBS install
popd
}
function build_ext {
local readonly prefix=$1
"$prefix"/bin/phpize
./configure --with-php-config="$prefix/bin/php-config"
make -j $JOBS
}
function do_tests {
local readonly prefix=$1
TEST_PHP_EXECUTABLE="$prefix/bin/php" REPORT_EXIT_STATUS=1 \
"$prefix/bin/php" "$prefix"/lib/php/build/run-tests.php \
-q -d extension=modules/rar.so --set-timeout 300 --show-diff \
$RUN_TESTS_FLAGS tests
}
# public functions below
function maybe_install_php {
set -e
set -o pipefail
local readonly version=$1 zts=$2
local readonly prefix=$(prefix $version $zts)
if [[ ! -d $prefix ]]; then
install_php $version $zts
fi
}
function build {
set -e
set -o pipefail
if [[ ! -f modules/rar.so ]]; then
build_ext "$(prefix $1 $2)"
fi
}
function run_tests {
set -e
set -o pipefail
do_tests "$(prefix $1 $2)"
}

View File

@@ -1,876 +0,0 @@
<?xml version="1.0" encoding="windows-1251"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9,00"
Name="UnRAR"
ProjectGUID="{E815C46C-36C4-499F-BBC2-E772C6B17971}"
RootNamespace="UnRAR"
Keyword="Win32Proj"
TargetFrameworkVersion="196613"
>
<Platforms>
<Platform
Name="Win32"
/>
<Platform
Name="x64"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="build\unrardll32\$(ConfigurationName)"
IntermediateDirectory="build\unrardll32\$(ConfigurationName)\obj"
ConfigurationType="2"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/MP"
Optimization="0"
PreprocessorDefinitions="RARDLL;UNRAR;SILENT"
MinimalRebuild="false"
ExceptionHandling="1"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
StructMemberAlignment="3"
RuntimeTypeInfo="false"
UsePrecompiledHeader="2"
PrecompiledHeaderThrough="rar.hpp"
WarningLevel="3"
DebugInformationFormat="4"
CallingConvention="0"
DisableSpecificWarnings="4007;4996"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
OutputFile="$(OutDir)\unrar.dll"
LinkIncremental="2"
GenerateManifest="true"
ModuleDefinitionFile="dll.def"
GenerateDebugInformation="true"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Debug|x64"
OutputDirectory="build\unrardll64\$(ConfigurationName)"
IntermediateDirectory="build\unrardll64\$(ConfigurationName)\obj"
ConfigurationType="2"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
TargetEnvironment="3"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/MP"
Optimization="0"
PreprocessorDefinitions="RARDLL;UNRAR;SILENT"
MinimalRebuild="false"
ExceptionHandling="1"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
StructMemberAlignment="3"
RuntimeTypeInfo="false"
UsePrecompiledHeader="2"
PrecompiledHeaderThrough="rar.hpp"
WarningLevel="3"
DebugInformationFormat="3"
CallingConvention="0"
DisableSpecificWarnings="4007;4996"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
OutputFile="$(OutDir)\unrar64.dll"
LinkIncremental="2"
GenerateManifest="true"
ModuleDefinitionFile="dll.def"
GenerateDebugInformation="true"
SubSystem="1"
TargetMachine="17"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="build\unrardll32\$(ConfigurationName)"
IntermediateDirectory="build\unrardll32\$(ConfigurationName)\obj"
ConfigurationType="2"
CharacterSet="2"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/MP"
Optimization="2"
EnableIntrinsicFunctions="true"
FavorSizeOrSpeed="0"
OmitFramePointers="true"
WholeProgramOptimization="false"
PreprocessorDefinitions="RARDLL;UNRAR;SILENT"
MinimalRebuild="false"
ExceptionHandling="1"
RuntimeLibrary="0"
StructMemberAlignment="3"
BufferSecurityCheck="true"
EnableFunctionLevelLinking="true"
EnableEnhancedInstructionSet="0"
FloatingPointModel="0"
RuntimeTypeInfo="false"
UsePrecompiledHeader="2"
PrecompiledHeaderThrough="rar.hpp"
WarningLevel="3"
DebugInformationFormat="3"
CallingConvention="0"
DisableSpecificWarnings="4007;4996"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalOptions="/SAFESEH"
OutputFile="$(OutDir)\unrar.dll"
LinkIncremental="1"
GenerateManifest="true"
ModuleDefinitionFile="dll.def"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
LinkTimeCodeGeneration="0"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|x64"
OutputDirectory="build\unrardll64\$(ConfigurationName)"
IntermediateDirectory="build\unrardll64\$(ConfigurationName)\obj"
ConfigurationType="2"
CharacterSet="2"
WholeProgramOptimization="0"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
TargetEnvironment="3"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/MP"
Optimization="2"
EnableIntrinsicFunctions="true"
FavorSizeOrSpeed="0"
OmitFramePointers="true"
WholeProgramOptimization="false"
PreprocessorDefinitions="RARDLL;UNRAR;SILENT"
StringPooling="false"
MinimalRebuild="false"
ExceptionHandling="1"
RuntimeLibrary="0"
StructMemberAlignment="3"
BufferSecurityCheck="true"
EnableFunctionLevelLinking="true"
RuntimeTypeInfo="false"
UsePrecompiledHeader="2"
PrecompiledHeaderThrough="rar.hpp"
WarningLevel="3"
DebugInformationFormat="3"
CallingConvention="0"
DisableSpecificWarnings="4007;4996"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
OutputFile="$(OutDir)\unrar64.dll"
LinkIncremental="1"
GenerateManifest="true"
ModuleDefinitionFile="dll.def"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
LinkTimeCodeGeneration="0"
TargetMachine="17"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="release_nocrypt|Win32"
OutputDirectory="build\unrardll32\$(ConfigurationName)"
IntermediateDirectory="build\unrardll32\$(ConfigurationName)\obj"
ConfigurationType="2"
CharacterSet="2"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/MP"
Optimization="2"
EnableIntrinsicFunctions="true"
FavorSizeOrSpeed="0"
OmitFramePointers="true"
WholeProgramOptimization="false"
PreprocessorDefinitions="RARDLL;UNRAR;SILENT;RAR_NOCRYPT"
MinimalRebuild="false"
ExceptionHandling="1"
RuntimeLibrary="0"
StructMemberAlignment="3"
BufferSecurityCheck="true"
EnableFunctionLevelLinking="true"
EnableEnhancedInstructionSet="0"
FloatingPointModel="0"
RuntimeTypeInfo="false"
UsePrecompiledHeader="2"
PrecompiledHeaderThrough="rar.hpp"
WarningLevel="3"
DebugInformationFormat="3"
CallingConvention="0"
DisableSpecificWarnings="4007;4996"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalOptions="/SAFESEH"
OutputFile="$(OutDir)\unrar_nocrypt.dll"
LinkIncremental="1"
GenerateManifest="true"
ModuleDefinitionFile="dll_nocrypt.def"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
LinkTimeCodeGeneration="0"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="release_nocrypt|x64"
OutputDirectory="build\unrardll64\$(ConfigurationName)"
IntermediateDirectory="build\unrardll64\$(ConfigurationName)\obj"
ConfigurationType="2"
CharacterSet="2"
WholeProgramOptimization="0"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
TargetEnvironment="3"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/MP"
Optimization="2"
EnableIntrinsicFunctions="true"
FavorSizeOrSpeed="0"
OmitFramePointers="true"
WholeProgramOptimization="false"
PreprocessorDefinitions="RARDLL;UNRAR;SILENT;RAR_NOCRYPT"
StringPooling="false"
MinimalRebuild="false"
ExceptionHandling="1"
RuntimeLibrary="0"
StructMemberAlignment="3"
BufferSecurityCheck="true"
EnableFunctionLevelLinking="true"
RuntimeTypeInfo="false"
UsePrecompiledHeader="2"
PrecompiledHeaderThrough="rar.hpp"
WarningLevel="3"
DebugInformationFormat="3"
CallingConvention="2"
DisableSpecificWarnings="4007;4996"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
OutputFile="$(OutDir)\unrar64_nocrypt.dll"
LinkIncremental="1"
GenerateManifest="true"
ModuleDefinitionFile="dll_nocrypt.def"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
LinkTimeCodeGeneration="0"
TargetMachine="17"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath="archive.cpp"
>
</File>
<File
RelativePath="arcread.cpp"
>
</File>
<File
RelativePath="blake2s.cpp"
>
</File>
<File
RelativePath="cmddata.cpp"
>
</File>
<File
RelativePath="consio.cpp"
>
</File>
<File
RelativePath="crc.cpp"
>
</File>
<File
RelativePath="crypt.cpp"
>
</File>
<File
RelativePath="dll.cpp"
>
</File>
<File
RelativePath="encname.cpp"
>
</File>
<File
RelativePath="errhnd.cpp"
>
</File>
<File
RelativePath="extinfo.cpp"
>
</File>
<File
RelativePath="extract.cpp"
>
</File>
<File
RelativePath="filcreat.cpp"
>
</File>
<File
RelativePath="file.cpp"
>
</File>
<File
RelativePath="filefn.cpp"
>
</File>
<File
RelativePath="filestr.cpp"
>
</File>
<File
RelativePath="find.cpp"
>
</File>
<File
RelativePath="getbits.cpp"
>
</File>
<File
RelativePath="global.cpp"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"
/>
</FileConfiguration>
<FileConfiguration
Name="Debug|x64"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"
/>
</FileConfiguration>
<FileConfiguration
Name="release_nocrypt|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"
/>
</FileConfiguration>
<FileConfiguration
Name="release_nocrypt|x64"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"
/>
</FileConfiguration>
</File>
<File
RelativePath="hash.cpp"
>
</File>
<File
RelativePath="headers.cpp"
>
</File>
<File
RelativePath="isnt.cpp"
>
</File>
<File
RelativePath="match.cpp"
>
</File>
<File
RelativePath="options.cpp"
>
</File>
<File
RelativePath="pathfn.cpp"
>
</File>
<File
RelativePath="qopen.cpp"
>
</File>
<File
RelativePath="rar.cpp"
>
</File>
<File
RelativePath="rarpch.cpp"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
<FileConfiguration
Name="Debug|x64"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
<FileConfiguration
Name="release_nocrypt|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
<FileConfiguration
Name="release_nocrypt|x64"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
</File>
<File
RelativePath="rarvm.cpp"
>
</File>
<File
RelativePath="rawread.cpp"
>
</File>
<File
RelativePath="rdwrfn.cpp"
>
</File>
<File
RelativePath="rijndael.cpp"
>
</File>
<File
RelativePath="rs.cpp"
>
</File>
<File
RelativePath="rs16.cpp"
>
</File>
<File
RelativePath="scantree.cpp"
>
</File>
<File
RelativePath="secpassword.cpp"
>
</File>
<File
RelativePath="sha1.cpp"
>
</File>
<File
RelativePath="sha256.cpp"
>
</File>
<File
RelativePath="smallfn.cpp"
>
</File>
<File
RelativePath="strfn.cpp"
>
</File>
<File
RelativePath="strlist.cpp"
>
</File>
<File
RelativePath="system.cpp"
>
</File>
<File
RelativePath="threadpool.cpp"
>
</File>
<File
RelativePath="timefn.cpp"
>
</File>
<File
RelativePath="ui.cpp"
>
</File>
<File
RelativePath="unicode.cpp"
>
</File>
<File
RelativePath="unpack.cpp"
>
</File>
<File
RelativePath="volume.cpp"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
RelativePath="rar.hpp"
>
</File>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
<File
RelativePath="dll.rc"
>
</File>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

@@ -4,10 +4,17 @@ bool Archive::GetComment(Array<wchar> *CmtData)
{
if (!MainComment)
return false;
SaveFilePos SavePos(*this);
int64 SavePos=Tell();
bool Success=DoGetComment(CmtData);
Seek(SavePos,SEEK_SET);
return Success;
}
bool Archive::DoGetComment(Array<wchar> *CmtData)
{
#ifndef SFX_MODULE
ushort CmtLength;
uint CmtLength;
if (Format==RARFMT14)
{
Seek(SFXSize+SIZEOF_MAINHEAD14,SEEK_SET);
@@ -22,7 +29,8 @@ bool Archive::GetComment(Array<wchar> *CmtData)
// Old style (RAR 2.9) archive comment embedded into the main
// archive header.
Seek(SFXSize+SIZEOF_MARKHEAD3+SIZEOF_MAINHEAD3,SEEK_SET);
ReadHeader();
if (!ReadHeader() || GetHeaderType()!=HEAD3_CMT)
return false;
}
else
{
@@ -33,7 +41,7 @@ bool Archive::GetComment(Array<wchar> *CmtData)
#ifndef SFX_MODULE
// Old style (RAR 2.9) comment header embedded into the main
// archive header.
if (BrokenHeader)
if (BrokenHeader || CommHead.HeadSize<SIZEOF_COMMHEAD)
{
uiMsg(UIERROR_CMTBROKEN,FileName);
return false;
@@ -52,10 +60,12 @@ bool Archive::GetComment(Array<wchar> *CmtData)
if (Format==RARFMT14)
{
#ifdef RAR_NOCRYPT
return(false);
return false;
#else
UnpCmtLength=GetByte();
UnpCmtLength+=(GetByte()<<8);
if (CmtLength<2)
return false;
CmtLength-=2;
DataIO.SetCmt13Encryption();
CommHead.UnpVer=15;
@@ -67,6 +77,7 @@ bool Archive::GetComment(Array<wchar> *CmtData)
DataIO.EnableShowProgress(false);
DataIO.SetPackedSizeToRead(CmtLength);
DataIO.UnpHash.Init(HASH_CRC32,1);
DataIO.SetNoFileHeader(true); // this->FileHead is not filled yet.
Unpack CmtUnpack(&DataIO);
CmtUnpack.Init(0x10000,false);
@@ -83,6 +94,8 @@ bool Archive::GetComment(Array<wchar> *CmtData)
byte *UnpData;
size_t UnpDataSize;
DataIO.GetUnpackedData(&UnpData,&UnpDataSize);
if (UnpDataSize>0)
{
#ifdef _WIN_ALL
// If we ever decide to extend it to Android, we'll need to alloc
// 4x memory for OEM to UTF-8 output here.
@@ -94,11 +107,19 @@ bool Archive::GetComment(Array<wchar> *CmtData)
CmtData->Alloc(wcslen(CmtData->Addr(0)));
}
}
}
else
{
if (CmtLength==0)
return false;
Array<byte> CmtRaw(CmtLength);
Read(&CmtRaw[0],CmtLength);
int ReadSize=Read(&CmtRaw[0],CmtLength);
if (ReadSize>=0 && (uint)ReadSize<CmtLength) // Comment is shorter than declared.
{
CmtLength=ReadSize;
CmtRaw.Alloc(CmtLength);
}
if (Format!=RARFMT14 && CommHead.CommCRC!=(~CRC32(0xffffffff,&CmtRaw[0],CmtLength)&0xffff))
{
uiMsg(UIERROR_CMTBROKEN,FileName);
@@ -111,9 +132,9 @@ bool Archive::GetComment(Array<wchar> *CmtData)
// 4x memory for OEM to UTF-8 output here.
OemToCharA((char *)&CmtRaw[0],(char *)&CmtRaw[0]);
#endif
CharToWide((char *)&CmtRaw[0],CmtData->Addr(0),CmtLength);
CharToWide((char *)&CmtRaw[0],CmtData->Addr(0),CmtData->Size());
CmtData->Alloc(wcslen(CmtData->Addr(0)));
}
}
#endif
return CmtData->Size() > 0;
}
@@ -122,7 +143,7 @@ bool Archive::GetComment(Array<wchar> *CmtData)
bool Archive::ReadCommentData(Array<wchar> *CmtData)
{
Array<byte> CmtRaw;
if (!ReadSubData(&CmtRaw,NULL))
if (!ReadSubData(&CmtRaw,NULL,false))
return false;
size_t CmtSize=CmtRaw.Size();
CmtRaw.Push(0);
@@ -131,12 +152,12 @@ bool Archive::ReadCommentData(Array<wchar> *CmtData)
UtfToWide((char *)&CmtRaw[0],CmtData->Addr(0),CmtData->Size());
else
if ((SubHead.SubFlags & SUBHEAD_FLAGS_CMT_UNICODE)!=0)
{
{
RawToWide(&CmtRaw[0],CmtData->Addr(0),CmtSize/2);
(*CmtData)[CmtSize/2]=0;
}
else
else
{
CharToWide((char *)&CmtRaw[0],CmtData->Addr(0),CmtData->Size());
}

View File

@@ -30,8 +30,6 @@ Archive::Archive(RAROptions *InitCmd)
CurBlockPos=0;
NextBlockPos=0;
RecoverySize=-1;
RecoveryPercent=-1;
memset(&MainHead,0,sizeof(MainHead));
memset(&CryptHead,0,sizeof(CryptHead));
@@ -48,6 +46,10 @@ Archive::Archive(RAROptions *InitCmd)
SilentOpen=false;
#ifdef USE_QOPEN
ProhibitQOpen=false;
#endif
}
@@ -114,7 +116,7 @@ RARFORMAT Archive::IsSignature(const byte *D,size_t Size)
if (D[6]==1)
Type=RARFMT50;
else
if (D[6]==2)
if (D[6]>1 && D[6]<5)
Type=RARFMT_FUTURE;
}
return Type;
@@ -175,8 +177,7 @@ bool Archive::IsArchive(bool EnableBroken)
}
if (Format==RARFMT50) // RAR 5.0 signature is by one byte longer.
{
Read(MarkHead.Mark+SIZEOF_MARKHEAD3,1);
if (MarkHead.Mark[SIZEOF_MARKHEAD3]!=0)
if (Read(MarkHead.Mark+SIZEOF_MARKHEAD3,1)!=1 || MarkHead.Mark[SIZEOF_MARKHEAD3]!=0)
return false;
MarkHead.HeadSize=SIZEOF_MARKHEAD5;
}
@@ -192,27 +193,31 @@ bool Archive::IsArchive(bool EnableBroken)
SilentOpen=true;
#endif
bool HeadersLeft; // Any headers left to read.
bool StartFound=false; // Main or encryption headers found.
// Skip the archive encryption header if any and read the main header.
while (ReadHeader()!=0)
while ((HeadersLeft=(ReadHeader()!=0))==true) // Additional parentheses to silence Clang.
{
SeekToNext();
HEADER_TYPE Type=GetHeaderType();
// In RAR 5.0 we need to quit after reading HEAD_CRYPT if we wish to
// avoid the password prompt.
if (Type==HEAD_MAIN || SilentOpen && Type==HEAD_CRYPT)
StartFound=Type==HEAD_MAIN || SilentOpen && Type==HEAD_CRYPT;
if (StartFound)
break;
SeekToNext();
}
// This check allows to make RS based recovery even if password is incorrect.
// But we should not do it for EnableBroken or we'll get 'not RAR archive'
// We should not do it for EnableBroken or we'll get 'not RAR archive'
// messages when extracting encrypted archives with wrong password.
if (FailedHeaderDecryption && !EnableBroken)
return false;
SeekToNext();
if (BrokenHeader) // Main archive header is corrupt.
if (BrokenHeader || !StartFound) // Main archive header is corrupt or missing.
{
uiMsg(UIERROR_MHEADERBROKEN,FileName);
if (!FailedHeaderDecryption) // If not reported a wrong password already.
uiMsg(UIERROR_MHEADERBROKEN,FileName);
if (!EnableBroken)
return false;
}
@@ -226,9 +231,9 @@ bool Archive::IsArchive(bool EnableBroken)
// first file header to set "comment" flag when reading service header.
// Unless we are in silent mode, we need to know about presence of comment
// immediately after IsArchive call.
if (!SilentOpen || !Encrypted)
if (HeadersLeft && (!SilentOpen || !Encrypted))
{
SaveFilePos SavePos(*this);
int64 SavePos=Tell();
int64 SaveCurBlockPos=CurBlockPos,SaveNextBlockPos=NextBlockPos;
HEADER_TYPE SaveCurHeaderType=CurHeaderType;
@@ -257,9 +262,10 @@ bool Archive::IsArchive(bool EnableBroken)
CurBlockPos=SaveCurBlockPos;
NextBlockPos=SaveNextBlockPos;
CurHeaderType=SaveCurHeaderType;
Seek(SavePos,SEEK_SET);
}
if (!Volume || FirstVolume)
wcscpy(FirstVolumeName,FileName);
wcsncpyz(FirstVolumeName,FileName,ASIZE(FirstVolumeName));
return true;
}

View File

@@ -20,13 +20,15 @@ enum ADDSUBDATA_FLAGS
ASDF_CRYPTIFHEADERS = 8 // Encrypt data after subheader only in -hp mode.
};
// RAR5 headers must not exceed 2 MB.
#define MAX_HEADER_SIZE_RAR5 0x200000
class Archive:public File
{
private:
void UpdateLatestTime(FileHeader *CurBlock);
void ConvertNameCase(wchar *Name);
void ConvertFileHeader(FileHeader *hd);
void WriteBlock50(HEADER_TYPE HeaderType,BaseBlock *wb,bool OnlySetSize,bool NonFinalWrite);
size_t ReadHeader14();
size_t ReadHeader15();
size_t ReadHeader50();
@@ -34,8 +36,8 @@ class Archive:public File
void RequestArcPassword();
void UnexpEndArcMsg();
void BrokenHeaderMsg();
void UnkEncVerMsg(const wchar *Name);
void UnkEncVerMsg();
void UnkEncVerMsg(const wchar *Name,const wchar *Info);
bool DoGetComment(Array<wchar> *CmtData);
bool ReadCommentData(Array<wchar> *CmtData);
#if !defined(RAR_NOCRYPT)
@@ -45,8 +47,6 @@ class Archive:public File
bool DummyCmd;
RAROptions *Cmd;
int64 RecoverySize;
int RecoveryPercent;
RarTime LatestTime;
int LastReadBlock;
@@ -55,6 +55,7 @@ class Archive:public File
bool SilentOpen;
#ifdef USE_QOPEN
QuickOpen QOpen;
bool ProhibitQOpen;
#endif
public:
Archive(RAROptions *InitCmd=NULL);
@@ -64,8 +65,6 @@ class Archive:public File
size_t SearchBlock(HEADER_TYPE HeaderType);
size_t SearchSubBlock(const wchar *Type);
size_t SearchRR();
void WriteBlock(HEADER_TYPE HeaderType,BaseBlock *wb=NULL,bool OnlySetSize=false,bool NonFinalWrite=false);
void SetBlockSize(HEADER_TYPE HeaderType,BaseBlock *wb=NULL) {WriteBlock(HeaderType,wb,true);}
size_t ReadHeader();
void CheckArc(bool EnableBroken);
void CheckOpen(const wchar *Name);
@@ -82,8 +81,8 @@ class Archive:public File
int64 GetStartPos();
void AddSubData(byte *SrcData,uint64 DataSize,File *SrcFile,
const wchar *Name,uint Flags);
bool ReadSubData(Array<byte> *UnpData,File *DestFile);
HEADER_TYPE GetHeaderType() {return CurHeaderType;};
bool ReadSubData(Array<byte> *UnpData,File *DestFile,bool TestMode);
HEADER_TYPE GetHeaderType() {return CurHeaderType;}
RAROptions* GetRAROptions() {return Cmd;}
void SetSilentOpen(bool Mode) {SilentOpen=Mode;}
#if 0
@@ -95,6 +94,7 @@ class Archive:public File
void Seek(int64 Offset,int Method);
int64 Tell();
void QOpenUnload() {QOpen.Unload();}
void SetProhibitQOpen(bool Mode) {ProhibitQOpen=Mode;}
#endif
BaseBlock ShortBlock;
@@ -107,10 +107,7 @@ class Archive:public File
FileHeader SubHead;
CommentHeader CommHead;
ProtectHeader ProtectHead;
AVHeader AVHead;
SignHeader SignHead;
UnixOwnersHeader UOHead;
MacFInfoHeader MACHead;
EAHeader EAHead;
StreamHeader StreamHead;

View File

@@ -10,7 +10,10 @@ size_t Archive::ReadHeader()
CurBlockPos=Tell();
size_t ReadSize;
// Other developers asked us to initialize it to suppress "may be used
// uninitialized" warning in code below in some compilers.
size_t ReadSize=0;
switch(Format)
{
#ifndef SFX_MODULE
@@ -26,11 +29,18 @@ size_t Archive::ReadHeader()
break;
}
// It is important to check ReadSize>0 here, because it is normal
// for RAR2 and RAR3 archives without end of archive block to have
// NextBlockPos==CurBlockPos after the end of archive has reached.
if (ReadSize>0 && NextBlockPos<=CurBlockPos)
{
BrokenHeaderMsg();
return 0;
ReadSize=0;
}
if (ReadSize==0)
CurHeaderType=HEAD_UNKNOWN;
return ReadSize;
}
@@ -106,13 +116,24 @@ void Archive::BrokenHeaderMsg()
}
void Archive::UnkEncVerMsg(const wchar *Name)
void Archive::UnkEncVerMsg(const wchar *Name,const wchar *Info)
{
uiMsg(UIERROR_UNKNOWNENCMETHOD,FileName,Name);
uiMsg(UIERROR_UNKNOWNENCMETHOD,FileName,Name,Info);
ErrHandler.SetErrorCode(RARX_WARNING);
}
// Return f in case of signed integer overflow or negative parameters
// or v1+v2 otherwise. We use it for file offsets, which are signed
// for compatibility with off_t in POSIX file functions and third party code.
// Signed integer overflow is the undefined behavior according to
// C++ standard and it causes fuzzers to complain.
inline int64 SafeAdd(int64 v1,int64 v2,int64 f)
{
return v1>=0 && v2>=0 && v1<=MAX_INT64-v2 ? v1+v2 : f;
}
size_t Archive::ReadHeader15()
{
RawRead Raw(this);
@@ -246,10 +267,15 @@ size_t Archive::ReadHeader15()
uint FileTime=Raw.Get4();
hd->UnpVer=Raw.Get1();
hd->Method=Raw.Get1()-0x30;
size_t NameSize=Raw.Get2();
hd->FileAttr=Raw.Get4();
// RAR15 did not use the special dictionary size to mark dirs.
if (hd->UnpVer<20 && (hd->FileAttr & 0x10)!=0)
hd->Dir=true;
hd->CryptMethod=CRYPT_NONE;
if (hd->Encrypted)
switch(hd->UnpVer)
@@ -308,17 +334,17 @@ size_t Archive::ReadHeader15()
if (FileBlock)
{
*hd->FileName=0;
if ((hd->Flags & LHD_UNICODE)!=0)
{
EncodeFileName NameCoder;
size_t Length=strlen(FileName);
Length++;
NameCoder.Decode(FileName,(byte *)FileName+Length,
NameSize-Length,hd->FileName,
if (ReadNameSize>Length)
NameCoder.Decode(FileName,ReadNameSize,(byte *)FileName+Length,
ReadNameSize-Length,hd->FileName,
ASIZE(hd->FileName));
}
else
*hd->FileName=0;
if (*hd->FileName==0)
ArcCharToWide(FileName,hd->FileName,ASIZE(hd->FileName),ACTW_OEM);
@@ -343,18 +369,8 @@ size_t Archive::ReadHeader15()
// They are stored after the file name and before salt.
hd->SubData.Alloc(DataSize);
Raw.GetB(&hd->SubData[0],DataSize);
if (hd->CmpName(SUBHEAD_TYPE_RR))
{
byte *D=&hd->SubData[8];
RecoverySize=D[0]+((uint)D[1]<<8)+((uint)D[2]<<16)+((uint)D[3]<<24);
RecoverySize*=512; // Sectors to size.
int64 CurPos=Tell();
RecoveryPercent=ToPercent(RecoverySize,CurPos);
// Round fractional percent exceeding .5 to upper value.
if (ToPercent(RecoverySize+CurPos/200,CurPos)>RecoveryPercent)
RecoveryPercent++;
}
}
if (hd->CmpName(SUBHEAD_TYPE_CMT))
MainComment=true;
@@ -386,8 +402,8 @@ size_t Archive::ReadHeader15()
if (rmode & 4)
rlt.Second++;
rlt.Reminder=0;
int count=rmode&3;
for (int J=0;J<count;J++)
uint count=rmode&3;
for (uint J=0;J<count;J++)
{
byte CurByte=Raw.Get1();
rlt.Reminder|=(((uint)CurByte)<<((J+3-count)*8));
@@ -397,7 +413,9 @@ size_t Archive::ReadHeader15()
CurTime->SetLocal(&rlt);
}
}
NextBlockPos+=hd->PackSize;
// Set to 0 in case of overflow, so end of ReadHeader cares about it.
NextBlockPos=SafeAdd(NextBlockPos,hd->PackSize,0);
bool CRCProcessedOnly=hd->CommentInHeader;
ushort HeaderCRC=Raw.GetCRC15(CRCProcessedOnly);
if (hd->HeadCRC!=HeaderCRC)
@@ -434,19 +452,6 @@ size_t Archive::ReadHeader15()
CommHead.Method=Raw.Get1();
CommHead.CommCRC=Raw.Get2();
break;
case HEAD3_SIGN:
*(BaseBlock *)&SignHead=ShortBlock;
SignHead.CreationTime=Raw.Get4();
SignHead.ArcNameSize=Raw.Get2();
SignHead.UserNameSize=Raw.Get2();
break;
case HEAD3_AV:
*(BaseBlock *)&AVHead=ShortBlock;
AVHead.UnpVer=Raw.Get1();
AVHead.Method=Raw.Get1();
AVHead.AVVer=Raw.Get1();
AVHead.AVInfoCRC=Raw.Get4();
break;
case HEAD3_PROTECT:
*(BaseBlock *)&ProtectHead=ShortBlock;
ProtectHead.DataSize=Raw.Get4();
@@ -455,9 +460,8 @@ size_t Archive::ReadHeader15()
ProtectHead.TotalBlocks=Raw.Get4();
Raw.GetB(ProtectHead.Mark,8);
NextBlockPos+=ProtectHead.DataSize;
RecoverySize=ProtectHead.RecSectors*512;
break;
case HEAD3_OLDSERVICE:
case HEAD3_OLDSERVICE: // RAR 2.9 and earlier.
*(BaseBlock *)&SubBlockHead=ShortBlock;
SubBlockHead.DataSize=Raw.Get4();
NextBlockPos+=SubBlockHead.DataSize;
@@ -478,13 +482,6 @@ size_t Archive::ReadHeader15()
UOHead.OwnerName[UOHead.OwnerNameSize]=0;
UOHead.GroupName[UOHead.GroupNameSize]=0;
break;
case MAC_HEAD:
*(SubBlockHeader *)&MACHead=SubBlockHead;
MACHead.fileType=Raw.Get4();
MACHead.fileCreator=Raw.Get4();
break;
case EA_HEAD:
case BEEA_HEAD:
case NTACL_HEAD:
*(SubBlockHeader *)&EAHead=SubBlockHead;
EAHead.UnpSize=Raw.Get4();
@@ -524,7 +521,6 @@ size_t Archive::ReadHeader15()
{
// Last 7 bytes of recovered volume can contain zeroes, because
// REV files store its own information (volume number, etc.) here.
SaveFilePos SavePos(*this);
int64 Length=Tell();
Seek(Length-7,SEEK_SET);
Recovered=true;
@@ -546,12 +542,6 @@ size_t Archive::ReadHeader15()
}
}
if (NextBlockPos<=CurBlockPos)
{
BrokenHeaderMsg();
return 0;
}
return Raw.Size();
}
@@ -567,7 +557,6 @@ size_t Archive::ReadHeader50()
#if defined(RAR_NOCRYPT)
return 0;
#else
RequestArcPassword();
byte HeadersInitV[SIZE_INITV];
if (Read(HeadersInitV,SIZE_INITV)!=SIZE_INITV)
@@ -576,24 +565,57 @@ size_t Archive::ReadHeader50()
return 0;
}
// We repeat the password request only for manually entered passwords
// and not for -p<pwd>. Wrong password can be intentionally provided
// in -p<pwd> to not stop batch processing for encrypted archives.
bool GlobalPassword=Cmd->Password.IsSet() || uiIsGlobalPasswordSet();
while (true) // Repeat the password prompt for wrong passwords.
{
RequestArcPassword();
byte PswCheck[SIZE_PSWCHECK];
HeadersCrypt.SetCryptKeys(false,CRYPT_RAR50,&Cmd->Password,CryptHead.Salt,HeadersInitV,CryptHead.Lg2Count,NULL,PswCheck);
// Verify password validity.
if (CryptHead.UsePswCheck && memcmp(PswCheck,CryptHead.PswCheck,SIZE_PSWCHECK)!=0)
{
uiMsg(UIERROR_BADPSW,FileName);
if (GlobalPassword) // For -p<pwd> or Ctrl+P.
{
// This message is used by Android GUI to reset cached passwords.
// Update appropriate code if changed.
uiMsg(UIERROR_BADPSW,FileName,FileName);
FailedHeaderDecryption=true;
ErrHandler.SetErrorCode(RARX_BADPWD);
return 0;
}
else // For passwords entered manually.
{
// This message is used by Android GUI and Windows GUI and SFX to
// reset cached passwords. Update appropriate code if changed.
uiMsg(UIWAIT_BADPSW,FileName,FileName);
Cmd->Password.Clean();
}
#ifdef RARDLL
// Avoid new requests for unrar.dll to prevent the infinite loop
// if app always returns the same password.
ErrHandler.SetErrorCode(RARX_BADPWD);
Cmd->DllError=ERAR_BAD_PASSWORD;
ErrHandler.Exit(RARX_BADPWD);
#else
continue; // Request a password again.
#endif
}
break;
}
Raw.SetCrypt(&HeadersCrypt);
#endif
}
// Header size must not occupy more than 3 variable length integer bytes
// resulting in 2 MB maximum header size, so here we read 4 byte CRC32
// followed by 3 bytes or less of header size.
// resulting in 2 MB maximum header size (MAX_HEADER_SIZE_RAR5),
// so here we read 4 byte CRC32 followed by 3 bytes or less of header size.
const size_t FirstReadSize=7; // Smallest possible block size.
if (Raw.Read(FirstReadSize)<FirstReadSize)
{
@@ -670,7 +692,9 @@ size_t Archive::ReadHeader50()
if ((ShortBlock.Flags & HFL_DATA)!=0)
DataSize=Raw.GetV();
NextBlockPos=CurBlockPos+FullHeaderSize(ShortBlock.HeadSize)+DataSize;
NextBlockPos=CurBlockPos+FullHeaderSize(ShortBlock.HeadSize);
// Set to 0 in case of overflow, so end of ReadHeader cares about it.
NextBlockPos=SafeAdd(NextBlockPos,DataSize,0);
switch(ShortBlock.HeaderType)
{
@@ -680,7 +704,9 @@ size_t Archive::ReadHeader50()
uint CryptVersion=(uint)Raw.GetV();
if (CryptVersion>CRYPT_VERSION)
{
UnkEncVerMsg(FileName);
wchar Info[20];
swprintf(Info,ASIZE(Info),L"h%u",CryptVersion);
UnkEncVerMsg(FileName,Info);
return 0;
}
uint EncFlags=(uint)Raw.GetV();
@@ -688,9 +714,12 @@ size_t Archive::ReadHeader50()
CryptHead.Lg2Count=Raw.Get1();
if (CryptHead.Lg2Count>CRYPT5_KDF_LG2_COUNT_MAX)
{
UnkEncVerMsg(FileName);
wchar Info[20];
swprintf(Info,ASIZE(Info),L"hc%u",CryptHead.Lg2Count);
UnkEncVerMsg(FileName,Info);
return 0;
}
Raw.GetB(CryptHead.Salt,SIZE_SALT50);
if (CryptHead.UsePswCheck)
{
@@ -734,7 +763,7 @@ size_t Archive::ReadHeader50()
ProcessExtra50(&Raw,(size_t)ExtraSize,&MainHead);
#ifdef USE_QOPEN
if (MainHead.Locator && MainHead.QOpenOffset>0 && Cmd->QOpenMode!=QOPEN_NONE)
if (!ProhibitQOpen && MainHead.Locator && MainHead.QOpenOffset>0 && Cmd->QOpenMode!=QOPEN_NONE)
{
// We seek to QO block in the end of archive when processing
// QOpen.Load, so we need to preserve current block positions
@@ -793,6 +822,8 @@ size_t Archive::ReadHeader50()
// but it was already used in RAR 1.5 and Unpack needs to distinguish
// them.
hd->UnpVer=(CompInfo & 0x3f) + 50;
if (hd->UnpVer!=50) // Only 5.0 compression is known now.
hd->UnpVer=VER_UNKNOWN;
hd->HostOS=(byte)Raw.GetV();
size_t NameSize=(size_t)Raw.GetV();
@@ -868,11 +899,6 @@ size_t Archive::ReadHeader50()
break;
}
if (NextBlockPos<=CurBlockPos)
{
BrokenHeaderMsg();
return 0;
}
return Raw.Size();
}
@@ -908,11 +934,10 @@ void Archive::RequestArcPassword()
ErrHandler.Exit(RARX_USERBREAK);
}
#else
if (!uiGetPassword(UIPASSWORD_ARCHIVE,FileName,&Cmd->Password) ||
!Cmd->Password.IsSet())
if (!uiGetPassword(UIPASSWORD_ARCHIVE,FileName,&Cmd->Password))
{
Close();
uiMsg(UIERROR_INCERRCOUNT);
uiMsg(UIERROR_INCERRCOUNT); // Prevent archive deleting if delete after extraction is on.
ErrHandler.Exit(RARX_USERBREAK);
}
#endif
@@ -931,14 +956,17 @@ void Archive::ProcessExtra50(RawRead *Raw,size_t ExtraSize,BaseBlock *bb)
Raw->SetPos(ExtraStart);
while (Raw->DataLeft()>=2)
{
int64 FieldSize=Raw->GetV();
if (FieldSize==0 || Raw->DataLeft()==0 || FieldSize>(int64)Raw->DataLeft())
int64 FieldSize=Raw->GetV(); // Needs to be signed for check below and can be negative.
if (FieldSize<=0 || Raw->DataLeft()==0 || FieldSize>(int64)Raw->DataLeft())
break;
size_t NextPos=size_t(Raw->GetPos()+FieldSize);
uint64 FieldType=Raw->GetV();
FieldSize=int64(NextPos-Raw->GetPos()); // Field size without size and type fields.
if (FieldSize<0) // FieldType is longer than expected extra field size.
break;
if (bb->HeaderType==HEAD_MAIN)
{
MainHeader *hd=(MainHeader *)bb;
@@ -971,7 +999,11 @@ void Archive::ProcessExtra50(RawRead *Raw,size_t ExtraSize,BaseBlock *bb)
FileHeader *hd=(FileHeader *)bb;
uint EncVersion=(uint)Raw->GetV();
if (EncVersion > CRYPT_VERSION)
UnkEncVerMsg(hd->FileName);
{
wchar Info[20];
swprintf(Info,ASIZE(Info),L"x%u",EncVersion);
UnkEncVerMsg(hd->FileName,Info);
}
else
{
uint Flags=(uint)Raw->GetV();
@@ -979,7 +1011,11 @@ void Archive::ProcessExtra50(RawRead *Raw,size_t ExtraSize,BaseBlock *bb)
hd->UseHashKey=(Flags & FHEXTRA_CRYPT_HASHMAC)!=0;
hd->Lg2Count=Raw->Get1();
if (hd->Lg2Count>CRYPT5_KDF_LG2_COUNT_MAX)
UnkEncVerMsg(hd->FileName);
{
wchar Info[20];
swprintf(Info,ASIZE(Info),L"xc%u",hd->Lg2Count);
UnkEncVerMsg(hd->FileName,Info);
}
Raw->GetB(hd->Salt,SIZE_SALT50);
Raw->GetB(hd->InitV,SIZE_INITV);
if (hd->UsePswCheck)
@@ -1070,7 +1106,7 @@ void Archive::ProcessExtra50(RawRead *Raw,size_t ExtraSize,BaseBlock *bb)
wchar VerText[20];
swprintf(VerText,ASIZE(VerText),L";%u",Version);
wcsncatz(FileHead.FileName,VerText,ASIZE(FileHead.FileName));
wcsncatz(hd->FileName,VerText,ASIZE(hd->FileName));
}
}
break;
@@ -1136,7 +1172,7 @@ void Archive::ProcessExtra50(RawRead *Raw,size_t ExtraSize,BaseBlock *bb)
// required. It did not hurt extraction, because UnRAR 5.21
// and earlier ignored this field and set FieldSize as data left
// in entire extra area. But now we set the correct field size
// and set FieldSize based on actual extra record size,
// and set FieldSize based on the actual extra record size,
// so we need to adjust it for those older archives here.
// FHEXTRA_SUBDATA in those archives always belongs to HEAD_SERVICE
// and always is last in extra area. So since its size is by 1
@@ -1145,6 +1181,9 @@ void Archive::ProcessExtra50(RawRead *Raw,size_t ExtraSize,BaseBlock *bb)
if (bb->HeaderType==HEAD_SERVICE && Raw->Size()-NextPos==1)
FieldSize++;
// We cannot allocate too much memory here, because above
// we check FieldSize againt Raw size and we control that Raw size
// is sensible when reading headers.
hd->SubData.Alloc((size_t)FieldSize);
Raw->GetB(hd->SubData.Addr(0),(size_t)FieldSize);
}
@@ -1168,6 +1207,8 @@ size_t Archive::ReadHeader14()
byte Mark[4];
Raw.GetB(Mark,4);
uint HeadSize=Raw.Get2();
if (HeadSize<7)
return false;
byte Flags=Raw.Get1();
NextBlockPos=CurBlockPos+HeadSize;
CurHeaderType=HEAD_MAIN;
@@ -1189,6 +1230,8 @@ size_t Archive::ReadHeader14()
FileHead.FileHash.Type=HASH_RAR14;
FileHead.FileHash.CRC32=Raw.Get2();
FileHead.HeadSize=Raw.Get2();
if (FileHead.HeadSize<21)
return false;
uint FileTime=Raw.Get4();
FileHead.FileAttr=Raw.Get1();
FileHead.Flags=Raw.Get1()|LONG_BLOCK;
@@ -1203,17 +1246,23 @@ size_t Archive::ReadHeader14()
FileHead.PackSize=FileHead.DataSize;
FileHead.WinSize=0x10000;
FileHead.Dir=(FileHead.FileAttr & 0x10)!=0;
FileHead.HostOS=HOST_MSDOS;
FileHead.HSType=HSYS_WINDOWS;
FileHead.mtime.SetDos(FileTime);
Raw.Read(NameSize);
char FileName[NM];
Raw.GetB((byte *)FileName,Min(NameSize,ASIZE(FileName)));
FileName[NameSize]=0;
size_t ReadNameSize=Min(NameSize,ASIZE(FileName)-1);
Raw.GetB((byte *)FileName,ReadNameSize);
FileName[ReadNameSize]=0;
IntToExt(FileName,FileName,ASIZE(FileName));
CharToWide(FileName,FileHead.FileName,ASIZE(FileHead.FileName));
ConvertNameCase(FileHead.FileName);
ConvertFileHeader(&FileHead);
if (Raw.Size()!=0)
NextBlockPos=CurBlockPos+FileHead.HeadSize+FileHead.PackSize;
@@ -1308,8 +1357,6 @@ void Archive::ConvertAttributes()
void Archive::ConvertFileHeader(FileHeader *hd)
{
if (Format==RARFMT15 && hd->UnpVer<20 && (hd->FileAttr & 0x10))
hd->Dir=true;
if (hd->HSType==HSYS_UNKNOWN)
if (hd->Dir)
hd->FileAttr=0x10;
@@ -1369,7 +1416,7 @@ int64 Archive::GetStartPos()
}
bool Archive::ReadSubData(Array<byte> *UnpData,File *DestFile)
bool Archive::ReadSubData(Array<byte> *UnpData,File *DestFile,bool TestMode)
{
if (BrokenHeader)
{
@@ -1402,9 +1449,9 @@ bool Archive::ReadSubData(Array<byte> *UnpData,File *DestFile)
SubDataIO.SetTestMode(true);
else
{
UnpData->Alloc((size_t)SubHead.UnpSize);
SubDataIO.SetUnpackToMemory(&(*UnpData)[0],(uint)SubHead.UnpSize);
}
UnpData->Alloc((size_t)SubHead.UnpSize);
SubDataIO.SetUnpackToMemory(&(*UnpData)[0],(uint)SubHead.UnpSize);
}
}
if (SubHead.Encrypted)
if (Cmd->Password.IsSet())
@@ -1417,6 +1464,7 @@ bool Archive::ReadSubData(Array<byte> *UnpData,File *DestFile)
SubDataIO.SetPackedSizeToRead(SubHead.PackSize);
SubDataIO.EnableShowProgress(false);
SubDataIO.SetFiles(this,DestFile);
SubDataIO.SetTestMode(TestMode);
SubDataIO.UnpVolume=SubHead.SplitAfter;
SubDataIO.SetSubHeader(&SubHead,NULL);
Unpack.SetDestSize(SubHead.UnpSize);

View File

@@ -3,6 +3,7 @@
#define _RAR_BLAKE2_
#define BLAKE2_DIGEST_SIZE 32
#define BLAKE2_THREADS_NUMBER 8
enum blake2s_constant
{

View File

@@ -1,5 +1,8 @@
#include "rar.hpp"
#include "cmdfilter.cpp"
#include "cmdmix.cpp"
CommandData::CommandData()
{
Init();
@@ -13,6 +16,7 @@ void CommandData::Init()
*Command=0;
*ArcName=0;
FileLists=false;
NoMoreSwitches=false;
ListMode=RCLM_AUTO;
@@ -52,7 +56,6 @@ void CommandData::ParseCommandLine(bool Preprocess,int argc, char *argv[])
// In Windows we may prefer to implement our own command line parser
// to avoid replacing \" by " in standard parser. Such replacing corrupts
// destination paths like "dest path\" in extraction commands.
// Also our own parser is Unicode compatible.
const wchar *CmdLine=GetCommandLine();
wchar *Par;
@@ -96,7 +99,7 @@ void CommandData::ParseArg(wchar *Arg)
else
if (*Command==0)
{
wcsncpy(Command,Arg,ASIZE(Command));
wcsncpyz(Command,Arg,ASIZE(Command));
*Command=toupperw(*Command);
@@ -119,6 +122,7 @@ void CommandData::ParseArg(wchar *Arg)
wchar CmdChar=toupperw(*Command);
bool Add=wcschr(L"AFUM",CmdChar)!=NULL;
bool Extract=CmdChar=='X' || CmdChar=='E';
bool Repair=CmdChar=='R' && Command[1]==0;
if (EndSeparator && !Add)
wcsncpyz(ExtrPath,Arg,ASIZE(ExtrPath));
else
@@ -129,25 +133,15 @@ void CommandData::ParseArg(wchar *Arg)
FindData FileData;
bool Found=FindFile::FastFind(Arg,&FileData);
if ((!Found || ListMode==RCLM_ACCEPT_LISTS) &&
ListMode!=RCLM_REJECT_LISTS && *Arg=='@' && !IsWildcard(Arg))
ListMode!=RCLM_REJECT_LISTS && *Arg=='@' && !IsWildcard(Arg+1))
{
FileLists=true;
RAR_CHARSET Charset=FilelistCharset;
#if defined(_WIN_ALL)
// for compatibility reasons we use OEM encoding
// in Win32 console version by default
// if (Charset==RCH_DEFAULT)
// Charset=RCH_OEM;
#endif
ReadTextFile(Arg+1,&FileArgs,false,true,Charset,true,true,true);
ReadTextFile(Arg+1,&FileArgs,false,true,FilelistCharset,true,true,true);
}
else
if (Found && FileData.IsDir && Extract && *ExtrPath==0)
else // We use 'destpath\' when extracting and reparing.
if (Found && FileData.IsDir && (Extract || Repair) && *ExtrPath==0)
{
wcsncpyz(ExtrPath,Arg,ASIZE(ExtrPath));
AddEndSlash(ExtrPath,ASIZE(ExtrPath));
@@ -248,7 +242,7 @@ void CommandData::ReadConfig()
if (C0=='R' && (C1=='R' || C1=='V'))
Cmd[2]=0;
wchar SwName[16+ASIZE(Cmd)];
swprintf(SwName,ASIZE(SwName),L"switches_%s=",Cmd);
swprintf(SwName,ASIZE(SwName),L"switches_%ls=",Cmd);
size_t Length=wcslen(SwName);
if (wcsnicomp(Str,SwName,Length)==0)
ProcessSwitchesString(Str+Length);
@@ -289,13 +283,23 @@ void CommandData::ProcessSwitch(const wchar *Switch)
ClearArc=true;
break;
case 'D':
AppendArcNameToPath=true;
if (Switch[2]==0)
AppendArcNameToPath=APPENDARCNAME_DESTPATH;
else
if (Switch[2]=='1')
AppendArcNameToPath=APPENDARCNAME_OWNSUBDIR;
else
if (Switch[2]=='2')
AppendArcNameToPath=APPENDARCNAME_OWNDIR;
break;
#ifndef SFX_MODULE
case 'G':
if (Switch[2]=='-' && Switch[3]==0)
GenerateArcName=0;
else
if (toupperw(Switch[2])=='F')
wcsncpyz(DefGenerateMask,Switch+3,ASIZE(DefGenerateMask));
else
{
GenerateArcName=true;
wcsncpyz(GenerateMask,Switch+2,ASIZE(GenerateMask));
@@ -311,7 +315,7 @@ void CommandData::ProcessSwitch(const wchar *Switch)
AddArcOnly=true;
break;
case 'P':
wcscpy(ArcPath,Switch+2);
wcsncpyz(ArcPath,Switch+2,ASIZE(ArcPath));
break;
case 'S':
SyncFiles=true;
@@ -374,11 +378,11 @@ void CommandData::ProcessSwitch(const wchar *Switch)
default:
if (Switch[1]=='+')
{
InclFileAttr|=GetExclAttr(Switch+2);
InclFileAttr|=GetExclAttr(Switch+2,InclDir);
InclAttrSet=true;
}
else
ExclFileAttr|=GetExclAttr(Switch+1);
ExclFileAttr|=GetExclAttr(Switch+1,ExclDir);
break;
}
break;
@@ -416,14 +420,17 @@ void CommandData::ProcessSwitch(const wchar *Switch)
wcsncpyz(LogName,Switch[4]!=0 ? Switch+4:DefLogName,ASIZE(LogName));
break;
}
if (wcsicomp(Switch+1,L"SND")==0)
if (wcsnicomp(Switch+1,L"SND",3)==0)
{
Sound=true;
Sound=Switch[4]=='-' ? SOUND_NOTIFY_OFF : SOUND_NOTIFY_ON;
break;
}
if (wcsicomp(Switch+1,L"ERR")==0)
{
MsgStream=MSG_STDERR;
// Set it immediately when parsing the command line, so it also
// affects messages issued while parsing the command line.
SetConsoleMsgStream(MSG_STDERR);
break;
}
if (wcsnicomp(Switch+1,L"EML",3)==0)
@@ -431,9 +438,15 @@ void CommandData::ProcessSwitch(const wchar *Switch)
wcsncpyz(EmailTo,Switch[4]!=0 ? Switch+4:L"@",ASIZE(EmailTo));
break;
}
if (wcsicomp(Switch+1,L"M")==0) // For compatibility with pre-WinRAR 6.0 -im syntax. Replaced with -idv.
{
VerboseOutput=true;
break;
}
if (wcsicomp(Switch+1,L"NUL")==0)
{
MsgStream=MSG_NULL;
SetConsoleMsgStream(MSG_NULL);
break;
}
if (toupperw(Switch[1])=='D')
@@ -443,6 +456,7 @@ void CommandData::ProcessSwitch(const wchar *Switch)
{
case 'Q':
MsgStream=MSG_ERRONLY;
SetConsoleMsgStream(MSG_ERRONLY);
break;
case 'C':
DisableCopyright=true;
@@ -453,12 +467,33 @@ void CommandData::ProcessSwitch(const wchar *Switch)
case 'P':
DisablePercentage=true;
break;
case 'N':
DisableNames=true;
break;
case 'V':
VerboseOutput=true;
break;
}
break;
}
if (wcsicomp(Switch+1,L"OFF")==0)
if (wcsnicomp(Switch+1,L"OFF",3)==0)
{
Shutdown=true;
switch(Switch[4])
{
case 0:
case '1':
Shutdown=POWERMODE_OFF;
break;
case '2':
Shutdown=POWERMODE_HIBERNATE;
break;
case '3':
Shutdown=POWERMODE_SLEEP;
break;
case '4':
Shutdown=POWERMODE_RESTART;
break;
}
break;
}
if (wcsicomp(Switch+1,L"VER")==0)
@@ -512,7 +547,6 @@ void CommandData::ProcessSwitch(const wchar *Switch)
case 'D': Type=FILTER_DELTA; break;
case 'A': Type=FILTER_AUDIO; break;
case 'C': Type=FILTER_RGB; break;
case 'I': Type=FILTER_ITANIUM; break;
case 'R': Type=FILTER_ARM; break;
}
if (*Str=='+' || *Str=='-')
@@ -574,19 +608,7 @@ void CommandData::ProcessSwitch(const wchar *Switch)
{
StringList *Args=toupperw(Switch[0])=='N' ? &InclArgs:&ExclArgs;
if (Switch[1]=='@' && !IsWildcard(Switch))
{
RAR_CHARSET Charset=FilelistCharset;
#if defined(_WIN_ALL)
// for compatibility reasons we use OEM encoding
// in Win32 console version by default
// if (Charset==RCH_DEFAULT)
// Charset=RCH_OEM;
#endif
ReadTextFile(Switch+2,Args,false,true,Charset,true,true,true);
}
ReadTextFile(Switch+2,Args,false,true,FilelistCharset,true,true,true);
else
Args->AddString(Switch+1);
}
@@ -783,6 +805,9 @@ void CommandData::ProcessSwitch(const wchar *Switch)
AlreadyBad=true;
break;
}
// Set it immediately when parsing the command line, so it also
// affects messages issued while parsing the command line.
SetConsoleRedirectCharset(RedirectCharset);
}
break;
@@ -798,52 +823,20 @@ void CommandData::ProcessSwitch(const wchar *Switch)
ArcTime=ARCTIME_LATEST;
break;
case 'O':
FileTimeBefore.SetAgeText(Switch+2);
SetTimeFilters(Switch+2,true,true);
break;
case 'N':
FileTimeAfter.SetAgeText(Switch+2);
SetTimeFilters(Switch+2,false,true);
break;
case 'B':
FileTimeBefore.SetIsoText(Switch+2);
SetTimeFilters(Switch+2,true,false);
break;
case 'A':
FileTimeAfter.SetIsoText(Switch+2);
SetTimeFilters(Switch+2,false,false);
break;
case 'S':
{
EXTTIME_MODE Mode=EXTTIME_HIGH3;
bool CommonMode=Switch[2]>='0' && Switch[2]<='4';
if (CommonMode)
Mode=(EXTTIME_MODE)(Switch[2]-'0');
if (Mode==EXTTIME_HIGH1 || Mode==EXTTIME_HIGH2) // '2' and '3' not supported anymore.
Mode=EXTTIME_HIGH3;
if (Switch[2]=='-')
Mode=EXTTIME_NONE;
if (CommonMode || Switch[2]=='-' || Switch[2]=='+' || Switch[2]==0)
xmtime=xctime=xatime=Mode;
else
{
if (Switch[3]>='0' && Switch[3]<='4')
Mode=(EXTTIME_MODE)(Switch[3]-'0');
if (Mode==EXTTIME_HIGH1 || Mode==EXTTIME_HIGH2) // '2' and '3' not supported anymore.
Mode=EXTTIME_HIGH3;
if (Switch[3]=='-')
Mode=EXTTIME_NONE;
switch(toupperw(Switch[2]))
{
case 'M':
xmtime=Mode;
SetStoreTimeMode(Switch+2);
break;
case 'C':
xctime=Mode;
break;
case 'A':
xatime=Mode;
break;
}
}
}
break;
case '-':
Test=false;
break;
@@ -890,7 +883,7 @@ void CommandData::ProcessSwitch(const wchar *Switch)
if (Switch[1]==0)
{
// If comment file is not specified, we read data from stdin.
wcscpy(CommentFile,L"stdin");
wcsncpyz(CommentFile,L"stdin",ASIZE(CommentFile));
}
else
wcsncpyz(CommentFile,Switch+1,ASIZE(CommentFile));
@@ -915,311 +908,6 @@ void CommandData::BadSwitch(const wchar *Switch)
#endif
void CommandData::OutTitle()
{
if (BareOutput || DisableCopyright)
return;
#if defined(__GNUC__) && defined(SFX_MODULE)
mprintf(St(MCopyrightS));
#else
#ifndef SILENT
static bool TitleShown=false;
if (TitleShown)
return;
TitleShown=true;
wchar Version[80];
if (RARVER_BETA!=0)
swprintf(Version,ASIZE(Version),L"%d.%02d %ls %d",RARVER_MAJOR,RARVER_MINOR,St(MBeta),RARVER_BETA);
else
swprintf(Version,ASIZE(Version),L"%d.%02d",RARVER_MAJOR,RARVER_MINOR);
#if defined(_WIN_32) || defined(_WIN_64)
wcsncatz(Version,L" ",ASIZE(Version));
#endif
#ifdef _WIN_32
wcsncatz(Version,St(Mx86),ASIZE(Version));
#endif
#ifdef _WIN_64
wcsncatz(Version,St(Mx64),ASIZE(Version));
#endif
if (PrintVersion)
{
mprintf(L"%s",Version);
exit(0);
}
mprintf(St(MUCopyright),Version,RARVER_YEAR);
#endif
#endif
}
inline bool CmpMSGID(MSGID i1,MSGID i2)
{
#ifdef MSGID_INT
return i1==i2;
#else
// If MSGID is const char*, we cannot compare pointers only.
// Pointers to different instances of same string can differ,
// so we need to compare complete strings.
return wcscmp(i1,i2)==0;
#endif
}
void CommandData::OutHelp(RAR_EXIT ExitCode)
{
#if !defined(SILENT)
OutTitle();
static MSGID Help[]={
#ifdef SFX_MODULE
// Console SFX switches definition.
MCHelpCmd,MSHelpCmdE,MSHelpCmdT,MSHelpCmdV
#else
// UnRAR switches definition.
MUNRARTitle1,MRARTitle2,MCHelpCmd,MCHelpCmdE,MCHelpCmdL,
MCHelpCmdP,MCHelpCmdT,MCHelpCmdV,MCHelpCmdX,MCHelpSw,MCHelpSwm,
MCHelpSwAT,MCHelpSwAC,MCHelpSwAD,MCHelpSwAG,MCHelpSwAI,MCHelpSwAP,
MCHelpSwCm,MCHelpSwCFGm,MCHelpSwCL,MCHelpSwCU,
MCHelpSwDH,MCHelpSwEP,MCHelpSwEP3,MCHelpSwF,MCHelpSwIDP,MCHelpSwIERR,
MCHelpSwINUL,MCHelpSwIOFF,MCHelpSwKB,MCHelpSwN,MCHelpSwNa,MCHelpSwNal,
MCHelpSwO,MCHelpSwOC,MCHelpSwOL,MCHelpSwOR,MCHelpSwOW,MCHelpSwP,
MCHelpSwPm,MCHelpSwR,MCHelpSwRI,MCHelpSwSC,MCHelpSwSL,MCHelpSwSM,
MCHelpSwTA,MCHelpSwTB,MCHelpSwTN,MCHelpSwTO,MCHelpSwTS,MCHelpSwU,
MCHelpSwVUnr,MCHelpSwVER,MCHelpSwVP,MCHelpSwX,MCHelpSwXa,MCHelpSwXal,
MCHelpSwY
// RAR switches definition.
//removed in 3.9.7
#endif
};
for (uint I=0;I<ASIZE(Help);I++)
{
#ifndef SFX_MODULE
if (CmpMSGID(Help[I],MCHelpSwV))
continue;
#ifndef _WIN_ALL
static MSGID Win32Only[]={
MCHelpSwIEML,MCHelpSwVD,MCHelpSwAO,MCHelpSwOS,MCHelpSwIOFF,
MCHelpSwEP2,MCHelpSwOC,MCHelpSwONI,MCHelpSwDR,MCHelpSwRI
};
bool Found=false;
for (int J=0;J<sizeof(Win32Only)/sizeof(Win32Only[0]);J++)
if (CmpMSGID(Help[I],Win32Only[J]))
{
Found=true;
break;
}
if (Found)
continue;
#endif
#if !defined(_UNIX) && !defined(_WIN_ALL)
if (CmpMSGID(Help[I],MCHelpSwOW))
continue;
#endif
#if !defined(_WIN_ALL) && !defined(_EMX)
if (CmpMSGID(Help[I],MCHelpSwAC))
continue;
#endif
#ifndef SAVE_LINKS
if (CmpMSGID(Help[I],MCHelpSwOL))
continue;
#endif
#ifndef RAR_SMP
if (CmpMSGID(Help[I],MCHelpSwMT))
continue;
#endif
#endif
mprintf(St(Help[I]));
}
mprintf(L"\n");
ErrHandler.Exit(ExitCode);
#endif
}
// Return 'true' if we need to exclude the file from processing as result
// of -x switch. If CheckInclList is true, we also check the file against
// the include list created with -n switch.
bool CommandData::ExclCheck(const wchar *CheckName,bool Dir,bool CheckFullPath,bool CheckInclList)
{
if (CheckArgs(&ExclArgs,Dir,CheckName,CheckFullPath,MATCH_WILDSUBPATH))
return true;
if (!CheckInclList || InclArgs.ItemsCount()==0)
return false;
if (CheckArgs(&InclArgs,Dir,CheckName,CheckFullPath,MATCH_WILDSUBPATH))
return false;
return true;
}
bool CommandData::CheckArgs(StringList *Args,bool Dir,const wchar *CheckName,bool CheckFullPath,int MatchMode)
{
wchar *Name=ConvertPath(CheckName,NULL);
wchar FullName[NM];
wchar CurMask[NM];
*FullName=0;
Args->Rewind();
while (Args->GetString(CurMask,ASIZE(CurMask)))
{
wchar *LastMaskChar=PointToLastChar(CurMask);
bool DirMask=IsPathDiv(*LastMaskChar); // Mask for directories only.
if (Dir)
{
// CheckName is a directory.
if (DirMask)
{
// We process the directory and have the directory exclusion mask.
// So let's convert "mask\" to "mask" and process it normally.
*LastMaskChar=0;
}
else
{
// REMOVED, we want -npath\* to match empty folders too.
// If mask has wildcards in name part and does not have the trailing
// '\' character, we cannot use it for directories.
// if (IsWildcard(PointToName(CurMask)))
// continue;
}
}
else
{
// If we process a file inside of directory excluded by "dirmask\".
// we want to exclude such file too. So we convert "dirmask\" to
// "dirmask\*". It is important for operations other than archiving
// with -x. When archiving with -x, directory matched by "dirmask\"
// is excluded from further scanning.
if (DirMask)
wcsncatz(CurMask,L"*",ASIZE(CurMask));
}
#ifndef SFX_MODULE
if (CheckFullPath && IsFullPath(CurMask))
{
// We do not need to do the special "*\" processing here, because
// unlike the "else" part of this "if", now we convert names to full
// format, so they all include the path, which is matched by "*\"
// correctly. Moreover, removing "*\" from mask would break
// the comparison, because now all names have the path.
if (*FullName==0)
ConvertNameToFull(CheckName,FullName,ASIZE(FullName));
if (CmpName(CurMask,FullName,MatchMode))
return true;
}
else
#endif
{
wchar NewName[NM+2],*CurName=Name;
// Important to convert before "*\" check below, so masks like
// d:*\something are processed properly.
wchar *CmpMask=ConvertPath(CurMask,NULL);
if (CmpMask[0]=='*' && IsPathDiv(CmpMask[1]))
{
// We want "*\name" to match 'name' not only in subdirectories,
// but also in the current directory. We convert the name
// from 'name' to '.\name' to be matched by "*\" part even if it is
// in current directory.
NewName[0]='.';
NewName[1]=CPATHDIVIDER;
wcsncpyz(NewName+2,Name,ASIZE(NewName)-2);
CurName=NewName;
}
if (CmpName(CmpMask,CurName,MatchMode))
return true;
}
}
return false;
}
#ifndef SFX_MODULE
// Now this function performs only one task and only in Windows version:
// it skips symlinks to directories if -e1024 switch is specified.
// Symlinks are skipped in ScanTree class, so their entire contents
// is skipped too. Without this function we would check the attribute
// only directly before archiving, so we would skip the symlink record,
// but not the contents of symlinked directory.
bool CommandData::ExclDirByAttr(uint FileAttr)
{
#ifdef _WIN_ALL
if ((FileAttr & FILE_ATTRIBUTE_REPARSE_POINT)!=0 &&
(ExclFileAttr & FILE_ATTRIBUTE_REPARSE_POINT)!=0)
return true;
#endif
return false;
}
#endif
#ifndef SFX_MODULE
// Return 'true' if we need to exclude the file from processing.
bool CommandData::TimeCheck(RarTime &ft)
{
if (FileTimeBefore.IsSet() && ft>=FileTimeBefore)
return true;
if (FileTimeAfter.IsSet() && ft<=FileTimeAfter)
return true;
return false;
}
#endif
#ifndef SFX_MODULE
// Return 'true' if we need to exclude the file from processing.
bool CommandData::SizeCheck(int64 Size)
{
if (FileSizeLess!=INT64NDF && Size>=FileSizeLess)
return(true);
if (FileSizeMore!=INT64NDF && Size<=FileSizeMore)
return(true);
return(false);
}
#endif
int CommandData::IsProcessFile(FileHeader &FileHead,bool *ExactMatch,int MatchType,
wchar *MatchedArg,uint MatchedArgSize)
{
if (MatchedArg!=NULL && MatchedArgSize>0)
*MatchedArg=0;
if (wcslen(FileHead.FileName)>=NM)
return 0;
bool Dir=FileHead.Dir;
if (ExclCheck(FileHead.FileName,Dir,false,true))
return 0;
#ifndef SFX_MODULE
if (TimeCheck(FileHead.mtime))
return 0;
if ((FileHead.FileAttr & ExclFileAttr)!=0 || InclAttrSet && (FileHead.FileAttr & InclFileAttr)==0)
return 0;
if (!Dir && SizeCheck(FileHead.UnpSize))
return 0;
#endif
wchar *ArgName;
FileArgs.Rewind();
for (int StringCount=1;(ArgName=FileArgs.GetString())!=NULL;StringCount++)
if (CmpName(ArgName,FileHead.FileName,MatchType))
{
if (ExactMatch!=NULL)
*ExactMatch=wcsicompc(ArgName,FileHead.FileName)==0;
if (MatchedArg!=NULL)
wcsncpyz(MatchedArg,ArgName,MatchedArgSize);
return StringCount;
}
return 0;
}
void CommandData::ProcessCommand()
{
#ifndef SFX_MODULE
@@ -1250,7 +938,10 @@ void CommandData::ProcessCommand()
if (wcschr(L"AFUMD",*Command)==NULL)
{
if (GenerateArcName)
GenerateArchiveName(ArcName,ASIZE(ArcName),GenerateMask,false);
{
const wchar *Mask=*GenerateMask!=0 ? GenerateMask:DefGenerateMask;
GenerateArchiveName(ArcName,ASIZE(ArcName),Mask,false);
}
StringList ArcMasks;
ArcMasks.AddString(ArcName);
@@ -1269,7 +960,6 @@ void CommandData::ProcessCommand()
case 'X':
case 'E':
case 'T':
case 'I':
{
CmdExtract Extract(this);
Extract.DoExtract();
@@ -1312,7 +1002,7 @@ bool CommandData::IsSwitch(int Ch)
#ifndef SFX_MODULE
uint CommandData::GetExclAttr(const wchar *Str)
uint CommandData::GetExclAttr(const wchar *Str,bool &Dir)
{
if (IsDigit(*Str))
return wcstol(Str,NULL,0);
@@ -1322,10 +1012,10 @@ uint CommandData::GetExclAttr(const wchar *Str)
{
switch(toupperw(*Str))
{
#ifdef _UNIX
case 'D':
Attr|=S_IFDIR;
Dir=true;
break;
#ifdef _UNIX
case 'V':
Attr|=S_IFCHR;
break;
@@ -1339,9 +1029,6 @@ uint CommandData::GetExclAttr(const wchar *Str)
case 'S':
Attr|=0x4;
break;
case 'D':
Attr|=0x10;
break;
case 'A':
Attr|=0x20;
break;

View File

@@ -6,13 +6,18 @@
enum RAR_CMD_LIST_MODE {RCLM_AUTO,RCLM_REJECT_LISTS,RCLM_ACCEPT_LISTS};
enum IS_PROCESS_FILE_FLAGS {IPFF_EXCLUDE_PARENT=1};
class CommandData:public RAROptions
{
private:
void ProcessSwitchesString(const wchar *Str);
void ProcessSwitch(const wchar *Switch);
void BadSwitch(const wchar *Switch);
uint GetExclAttr(const wchar *Str);
uint GetExclAttr(const wchar *Str,bool &Dir);
#if !defined(SFX_MODULE)
void SetTimeFilters(const wchar *Mod,bool Before,bool Age);
void SetStoreTimeMode(const wchar *S);
#endif
bool FileLists;
bool NoMoreSwitches;
@@ -28,17 +33,18 @@ class CommandData:public RAROptions
void ParseEnvVar();
void ReadConfig();
void PreprocessArg(const wchar *Arg);
void ProcessSwitchesString(const wchar *Str);
void OutTitle();
void OutHelp(RAR_EXIT ExitCode);
bool IsSwitch(int Ch);
bool ExclCheck(const wchar *CheckName,bool Dir,bool CheckFullPath,bool CheckInclList);
static bool CheckArgs(StringList *Args,bool Dir,const wchar *CheckName,bool CheckFullPath,int MatchMode);
bool ExclDirByAttr(uint FileAttr);
bool TimeCheck(RarTime &ft);
bool TimeCheck(RarTime &ftm,RarTime &ftc,RarTime &fta);
bool SizeCheck(int64 Size);
bool AnyFiltersActive();
int IsProcessFile(FileHeader &FileHead,bool *ExactMatch=NULL,int MatchType=MATCH_WILDSUBPATH,
wchar *MatchedArg=NULL,uint MatchedArgSize=0);
int IsProcessFile(FileHeader &FileHead,bool *ExactMatch,int MatchType,
bool Flags,wchar *MatchedArg,uint MatchedArgSize);
void ProcessCommand();
void AddArcName(const wchar *Name);
bool GetArcName(wchar *Name,int MaxSize);

352
unrar/cmdfilter.cpp Normal file
View File

@@ -0,0 +1,352 @@
// Return 'true' if we need to exclude the file from processing as result
// of -x switch. If CheckInclList is true, we also check the file against
// the include list created with -n switch.
bool CommandData::ExclCheck(const wchar *CheckName,bool Dir,bool CheckFullPath,bool CheckInclList)
{
if (CheckArgs(&ExclArgs,Dir,CheckName,CheckFullPath,MATCH_WILDSUBPATH))
return true;
if (!CheckInclList || InclArgs.ItemsCount()==0)
return false;
if (CheckArgs(&InclArgs,Dir,CheckName,CheckFullPath,MATCH_WILDSUBPATH))
return false;
return true;
}
bool CommandData::CheckArgs(StringList *Args,bool Dir,const wchar *CheckName,bool CheckFullPath,int MatchMode)
{
wchar *Name=ConvertPath(CheckName,NULL,0);
wchar FullName[NM];
wchar CurMask[NM];
*FullName=0;
Args->Rewind();
while (Args->GetString(CurMask,ASIZE(CurMask)))
{
wchar *LastMaskChar=PointToLastChar(CurMask);
bool DirMask=IsPathDiv(*LastMaskChar); // Mask for directories only.
if (Dir)
{
// CheckName is a directory.
if (DirMask)
{
// We process the directory and have the directory exclusion mask.
// So let's convert "mask\" to "mask" and process it normally.
*LastMaskChar=0;
}
else
{
// REMOVED, we want -npath\* to match empty folders too.
// If mask has wildcards in name part and does not have the trailing
// '\' character, we cannot use it for directories.
// if (IsWildcard(PointToName(CurMask)))
// continue;
}
}
else
{
// If we process a file inside of directory excluded by "dirmask\".
// we want to exclude such file too. So we convert "dirmask\" to
// "dirmask\*". It is important for operations other than archiving
// with -x. When archiving with -x, directory matched by "dirmask\"
// is excluded from further scanning.
if (DirMask)
wcsncatz(CurMask,L"*",ASIZE(CurMask));
}
#ifndef SFX_MODULE
if (CheckFullPath && IsFullPath(CurMask))
{
// We do not need to do the special "*\" processing here, because
// unlike the "else" part of this "if", now we convert names to full
// format, so they all include the path, which is matched by "*\"
// correctly. Moreover, removing "*\" from mask would break
// the comparison, because now all names have the path.
if (*FullName==0)
ConvertNameToFull(CheckName,FullName,ASIZE(FullName));
if (CmpName(CurMask,FullName,MatchMode))
return true;
}
else
#endif
{
wchar NewName[NM+2],*CurName=Name;
// Important to convert before "*\" check below, so masks like
// d:*\something are processed properly.
wchar *CmpMask=ConvertPath(CurMask,NULL,0);
if (CmpMask[0]=='*' && IsPathDiv(CmpMask[1]))
{
// We want "*\name" to match 'name' not only in subdirectories,
// but also in the current directory. We convert the name
// from 'name' to '.\name' to be matched by "*\" part even if it is
// in current directory.
NewName[0]='.';
NewName[1]=CPATHDIVIDER;
wcsncpyz(NewName+2,Name,ASIZE(NewName)-2);
CurName=NewName;
}
if (CmpName(CmpMask,CurName,MatchMode))
return true;
}
}
return false;
}
#ifndef SFX_MODULE
// Now this function performs only one task and only in Windows version:
// it skips symlinks to directories if -e1024 switch is specified.
// Symlinks are skipped in ScanTree class, so their entire contents
// is skipped too. Without this function we would check the attribute
// only directly before archiving, so we would skip the symlink record,
// but not the contents of symlinked directory.
bool CommandData::ExclDirByAttr(uint FileAttr)
{
#ifdef _WIN_ALL
if ((FileAttr & FILE_ATTRIBUTE_REPARSE_POINT)!=0 &&
(ExclFileAttr & FILE_ATTRIBUTE_REPARSE_POINT)!=0)
return true;
#endif
return false;
}
#endif
#if !defined(SFX_MODULE)
void CommandData::SetTimeFilters(const wchar *Mod,bool Before,bool Age)
{
bool ModeOR=false,TimeMods=false;
const wchar *S=Mod;
// Check if any 'mca' modifiers are present, set OR mode if 'o' is present,
// skip modifiers and set S to beginning of time string. Be sure to check
// *S!=0, because termination 0 is a part of string for wcschr.
for (;*S!=0 && wcschr(L"MCAOmcao",*S)!=NULL;S++)
if (*S=='o' || *S=='O')
ModeOR=true;
else
TimeMods=true;
if (!TimeMods) // Assume 'm' if no modifiers are specified.
Mod=L"m";
// Set the specified time for every modifier. Be sure to check *Mod!=0,
// because termination 0 is a part of string for wcschr. This check is
// important when we set Mod to "m" above.
for (;*Mod!=0 && wcschr(L"MCAOmcao",*Mod)!=NULL;Mod++)
switch(toupperw(*Mod))
{
case 'M':
if (Before)
{
Age ? FileMtimeBefore.SetAgeText(S):FileMtimeBefore.SetIsoText(S);
FileMtimeBeforeOR=ModeOR;
}
else
{
Age ? FileMtimeAfter.SetAgeText(S):FileMtimeAfter.SetIsoText(S);
FileMtimeAfterOR=ModeOR;
}
break;
case 'C':
if (Before)
{
Age ? FileCtimeBefore.SetAgeText(S):FileCtimeBefore.SetIsoText(S);
FileCtimeBeforeOR=ModeOR;
}
else
{
Age ? FileCtimeAfter.SetAgeText(S):FileCtimeAfter.SetIsoText(S);
FileCtimeAfterOR=ModeOR;
}
break;
case 'A':
if (Before)
{
Age ? FileAtimeBefore.SetAgeText(S):FileAtimeBefore.SetIsoText(S);
FileAtimeBeforeOR=ModeOR;
}
else
{
Age ? FileAtimeAfter.SetAgeText(S):FileAtimeAfter.SetIsoText(S);
FileAtimeAfterOR=ModeOR;
}
break;
}
}
#endif
#ifndef SFX_MODULE
// Return 'true' if we need to exclude the file from processing.
bool CommandData::TimeCheck(RarTime &ftm,RarTime &ftc,RarTime &fta)
{
bool FilterOR=false;
if (FileMtimeBefore.IsSet()) // Filter present.
if (ftm>=FileMtimeBefore) // Condition not matched.
if (FileMtimeBeforeOR)
FilterOR=true; // Not matched OR filter is present.
else
return true; // Exclude file in AND mode.
else // Condition matched.
if (FileMtimeBeforeOR)
return false; // Include file in OR mode.
if (FileMtimeAfter.IsSet()) // Filter present.
if (ftm<FileMtimeAfter) // Condition not matched.
if (FileMtimeAfterOR)
FilterOR=true; // Not matched OR filter is present.
else
return true; // Exclude file in AND mode.
else // Condition matched.
if (FileMtimeAfterOR)
return false; // Include file in OR mode.
if (FileCtimeBefore.IsSet()) // Filter present.
if (ftc>=FileCtimeBefore) // Condition not matched.
if (FileCtimeBeforeOR)
FilterOR=true; // Not matched OR filter is present.
else
return true; // Exclude file in AND mode.
else // Condition matched.
if (FileCtimeBeforeOR)
return false; // Include file in OR mode.
if (FileCtimeAfter.IsSet()) // Filter present.
if (ftc<FileCtimeAfter) // Condition not matched.
if (FileCtimeAfterOR)
FilterOR=true; // Not matched OR filter is present.
else
return true; // Exclude file in AND mode.
else // Condition matched.
if (FileCtimeAfterOR)
return false; // Include file in OR mode.
if (FileAtimeBefore.IsSet()) // Filter present.
if (fta>=FileAtimeBefore) // Condition not matched.
if (FileAtimeBeforeOR)
FilterOR=true; // Not matched OR filter is present.
else
return true; // Exclude file in AND mode.
else // Condition matched.
if (FileAtimeBeforeOR)
return false; // Include file in OR mode.
if (FileAtimeAfter.IsSet()) // Filter present.
if (fta<FileAtimeAfter) // Condition not matched.
if (FileAtimeAfterOR)
FilterOR=true; // Not matched OR filter is present.
else
return true; // Exclude file in AND mode.
else // Condition matched.
if (FileAtimeAfterOR)
return false; // Include file in OR mode.
return FilterOR; // Exclude if all OR filters are not matched.
}
#endif
#ifndef SFX_MODULE
// Return 'true' if we need to exclude the file from processing.
bool CommandData::SizeCheck(int64 Size)
{
if (FileSizeLess!=INT64NDF && Size>=FileSizeLess)
return true;
if (FileSizeMore!=INT64NDF && Size<=FileSizeMore)
return true;
return false;
}
#endif
// Return 0 if file must not be processed or a number of matched parameter otherwise.
int CommandData::IsProcessFile(FileHeader &FileHead,bool *ExactMatch,int MatchType,
bool Flags,wchar *MatchedArg,uint MatchedArgSize)
{
if (MatchedArg!=NULL && MatchedArgSize>0)
*MatchedArg=0;
bool Dir=FileHead.Dir;
if (ExclCheck(FileHead.FileName,Dir,false,true))
return 0;
#ifndef SFX_MODULE
if (TimeCheck(FileHead.mtime,FileHead.ctime,FileHead.atime))
return 0;
if ((FileHead.FileAttr & ExclFileAttr)!=0 || FileHead.Dir && ExclDir)
return 0;
if (InclAttrSet && (!FileHead.Dir && (FileHead.FileAttr & InclFileAttr)==0 ||
FileHead.Dir && !InclDir))
return 0;
if (!Dir && SizeCheck(FileHead.UnpSize))
return 0;
#endif
wchar *ArgName;
FileArgs.Rewind();
for (int StringCount=1;(ArgName=FileArgs.GetString())!=NULL;StringCount++)
if (CmpName(ArgName,FileHead.FileName,MatchType))
{
if (ExactMatch!=NULL)
*ExactMatch=wcsicompc(ArgName,FileHead.FileName)==0;
if (MatchedArg!=NULL)
wcsncpyz(MatchedArg,ArgName,MatchedArgSize);
return StringCount;
}
return 0;
}
#if !defined(SFX_MODULE)
void CommandData::SetStoreTimeMode(const wchar *S)
{
if (*S==0 || IsDigit(*S) || *S=='-' || *S=='+')
{
// Apply -ts, -ts1, -ts-, -ts+ to all 3 times.
// Handle obsolete -ts[2,3,4] as ts+.
EXTTIME_MODE Mode=EXTTIME_MAX;
if (*S=='-')
Mode=EXTTIME_NONE;
if (*S=='1')
Mode=EXTTIME_1S;
xmtime=xctime=xatime=Mode;
S++;
}
while (*S!=0)
{
EXTTIME_MODE Mode=EXTTIME_MAX;
if (S[1]=='-')
Mode=EXTTIME_NONE;
if (S[1]=='1')
Mode=EXTTIME_1S;
switch(toupperw(*S))
{
case 'M':
xmtime=Mode;
break;
case 'C':
xctime=Mode;
break;
case 'A':
xatime=Mode;
break;
case 'P':
PreserveAtime=true;
break;
}
S++;
}
}
#endif

118
unrar/cmdmix.cpp Normal file
View File

@@ -0,0 +1,118 @@
void CommandData::OutTitle()
{
if (BareOutput || DisableCopyright)
return;
#if defined(__GNUC__) && defined(SFX_MODULE)
mprintf(St(MCopyrightS));
#else
#ifndef SILENT
static bool TitleShown=false;
if (TitleShown)
return;
TitleShown=true;
wchar Version[80];
if (RARVER_BETA!=0)
swprintf(Version,ASIZE(Version),L"%d.%02d %ls %d",RARVER_MAJOR,RARVER_MINOR,St(MBeta),RARVER_BETA);
else
swprintf(Version,ASIZE(Version),L"%d.%02d",RARVER_MAJOR,RARVER_MINOR);
#if defined(_WIN_32) || defined(_WIN_64)
wcsncatz(Version,L" ",ASIZE(Version));
#endif
#ifdef _WIN_32
wcsncatz(Version,St(Mx86),ASIZE(Version));
#endif
#ifdef _WIN_64
wcsncatz(Version,St(Mx64),ASIZE(Version));
#endif
if (PrintVersion)
{
mprintf(L"%s",Version);
exit(0);
}
mprintf(St(MUCopyright),Version,RARVER_YEAR);
#endif
#endif
}
inline bool CmpMSGID(MSGID i1,MSGID i2)
{
#ifdef MSGID_INT
return i1==i2;
#else
// If MSGID is const char*, we cannot compare pointers only.
// Pointers to different instances of same string can differ,
// so we need to compare complete strings.
return wcscmp(i1,i2)==0;
#endif
}
void CommandData::OutHelp(RAR_EXIT ExitCode)
{
#if !defined(SILENT)
OutTitle();
static MSGID Help[]={
#ifdef SFX_MODULE
// Console SFX switches definition.
MCHelpCmd,MSHelpCmdE,MSHelpCmdT,MSHelpCmdV
#else
// UnRAR switches definition.
MUNRARTitle1,MRARTitle2,MCHelpCmd,MCHelpCmdE,MCHelpCmdL,
MCHelpCmdP,MCHelpCmdT,MCHelpCmdV,MCHelpCmdX,MCHelpSw,MCHelpSwm,
MCHelpSwAT,MCHelpSwAC,MCHelpSwAD,MCHelpSwAG,MCHelpSwAI,MCHelpSwAP,
MCHelpSwCm,MCHelpSwCFGm,MCHelpSwCL,MCHelpSwCU,
MCHelpSwDH,MCHelpSwEP,MCHelpSwEP3,MCHelpSwF,MCHelpSwIDP,MCHelpSwIERR,
MCHelpSwINUL,MCHelpSwIOFF,MCHelpSwKB,MCHelpSwN,MCHelpSwNa,MCHelpSwNal,
MCHelpSwO,MCHelpSwOC,MCHelpSwOL,MCHelpSwOR,MCHelpSwOW,MCHelpSwP,
MCHelpSwPm,MCHelpSwR,MCHelpSwRI,MCHelpSwSC,MCHelpSwSL,MCHelpSwSM,
MCHelpSwTA,MCHelpSwTB,MCHelpSwTN,MCHelpSwTO,MCHelpSwTS,MCHelpSwU,
MCHelpSwVUnr,MCHelpSwVER,MCHelpSwVP,MCHelpSwX,MCHelpSwXa,MCHelpSwXal,
MCHelpSwY
#endif
};
for (uint I=0;I<ASIZE(Help);I++)
{
#ifndef SFX_MODULE
if (CmpMSGID(Help[I],MCHelpSwV))
continue;
#ifndef _WIN_ALL
static MSGID Win32Only[]={
MCHelpSwIEML,MCHelpSwVD,MCHelpSwAO,MCHelpSwOS,MCHelpSwIOFF,
MCHelpSwEP2,MCHelpSwOC,MCHelpSwONI,MCHelpSwDR,MCHelpSwRI
};
bool Found=false;
for (uint J=0;J<ASIZE(Win32Only);J++)
if (CmpMSGID(Help[I],Win32Only[J]))
{
Found=true;
break;
}
if (Found)
continue;
#endif
#if !defined(_UNIX) && !defined(_WIN_ALL)
if (CmpMSGID(Help[I],MCHelpSwOW))
continue;
#endif
#if !defined(_WIN_ALL) && !defined(_EMX)
if (CmpMSGID(Help[I],MCHelpSwAC))
continue;
#endif
#ifndef SAVE_LINKS
if (CmpMSGID(Help[I],MCHelpSwOL))
continue;
#endif
#ifndef RAR_SMP
if (CmpMSGID(Help[I],MCHelpSwMT))
continue;
#endif
#endif
mprintf(St(Help[I]));
}
mprintf(L"\n");
ErrHandler.Exit(ExitCode);
#endif
}

View File

@@ -6,7 +6,16 @@
class PackDef
{
public:
// Maximum LZ match length we can encode even for short distances.
static const uint MAX_LZ_MATCH = 0x1001;
// We increment LZ match length for longer distances, because shortest
// matches are not allowed for them. Maximum length increment is 3
// for distances larger than 256KB (0x40000). Here we define the maximum
// incremented LZ match. Normally packer does not use it, but we must be
// ready to process it in corrupt archives.
static const uint MAX_INC_LZ_MATCH = MAX_LZ_MATCH + 3;
static const uint MAX3_LZ_MATCH = 0x101; // Maximum match length for RAR v3.
static const uint LOW_DIST_REP_COUNT = 16;

View File

@@ -49,9 +49,14 @@ void InitConsole()
}
void InitConsoleOptions(MESSAGE_TYPE MsgStream,RAR_CHARSET RedirectCharset)
void SetConsoleMsgStream(MESSAGE_TYPE MsgStream)
{
::MsgStream=MsgStream;
}
void SetConsoleRedirectCharset(RAR_CHARSET RedirectCharset)
{
::RedirectCharset=RedirectCharset;
}
@@ -159,7 +164,7 @@ static void GetPasswordText(wchar *Str,uint MaxLength)
SetConsoleMode(hConIn,ConInMode);
SetConsoleMode(hConOut,ConOutMode);
#else
char StrA[MAXPASSWORD];
char StrA[MAXPASSWORD*4]; // "*4" for multibyte UTF-8 characters.
#if defined(_EMX) || defined (__VMS)
fgets(StrA,ASIZE(StrA)-1,stdin);
#elif defined(__sun)
@@ -243,6 +248,12 @@ bool getwstr(wchar *str,size_t n)
ErrHandler.Exit(RARX_USERBREAK);
}
StrA[ReadSize]=0;
// We expect ANSI encoding here, but "echo text|rar ..." to pipe to RAR,
// such as send passwords, we get OEM encoding by default, unless we
// use "chcp" in console. But we avoid OEM to ANSI conversion,
// because we also want to handle ANSI files redirection correctly,
// like "rar ... < ansifile.txt".
CharToWide(&StrA[0],str,n);
cleandata(&StrA[0],StrA.Size()); // We can use this function to enter passwords.
}
@@ -300,7 +311,7 @@ int Ask(const wchar *AskStr)
for (int I=0;I<NumItems;I++)
{
eprintf(I==0 ? (NumItems>4 ? L"\n":L" "):L", ");
eprintf(I==0 ? (NumItems>3 ? L"\n":L" "):L", ");
int KeyPos=ItemKeyPos[I];
for (int J=0;J<KeyPos;J++)
eprintf(L"%c",Item[I][J]);

View File

@@ -2,7 +2,8 @@
#define _RAR_CONSIO_
void InitConsole();
void InitConsoleOptions(MESSAGE_TYPE MsgStream,RAR_CHARSET RedirectCharset);
void SetConsoleMsgStream(MESSAGE_TYPE MsgStream);
void SetConsoleRedirectCharset(RAR_CHARSET RedirectCharset);
void OutComment(const wchar *Comment,size_t Size);
#ifndef SILENT

View File

@@ -66,14 +66,14 @@ uint CRC32(uint StartCRC,const void *Addr,size_t Size)
uint NextData = Data[4]|(Data[5] << 8)|(Data[6] << 16)|(Data[7] << 24);
#else
StartCRC ^= *(uint32 *) Data;
uint NextData = *(uint32 *) (Data +4);
uint NextData = *(uint32 *) (Data+4);
#endif
StartCRC = crc_tables[7][(byte) StartCRC ] ^
crc_tables[6][(byte)(StartCRC >> 8) ] ^
crc_tables[5][(byte)(StartCRC >> 16)] ^
crc_tables[4][(byte)(StartCRC >> 24)] ^
crc_tables[3][(byte) NextData ] ^
crc_tables[2][(byte)(NextData >>8 ) ] ^
crc_tables[2][(byte)(NextData >> 8) ] ^
crc_tables[1][(byte)(NextData >> 16)] ^
crc_tables[0][(byte)(NextData >> 24)];
}

View File

@@ -28,8 +28,8 @@ void CryptData::SetKey30(bool Encrypt,SecPassword *Password,const wchar *PwdW,co
sha1_context c;
sha1_init(&c);
const int HashRounds=0x40000;
for (int I=0;I<HashRounds;I++)
const uint HashRounds=0x40000;
for (uint I=0;I<HashRounds;I++)
{
sha1_process_rar29( &c, RawPsw, RawLength );
byte PswNum[3];
@@ -47,8 +47,8 @@ void CryptData::SetKey30(bool Encrypt,SecPassword *Password,const wchar *PwdW,co
}
uint32 digest[5];
sha1_done( &c, digest );
for (int I=0;I<4;I++)
for (int J=0;J<4;J++)
for (uint I=0;I<4;I++)
for (uint J=0;J<4;J++)
AESKey[I*4+J]=(byte)(digest[I]>>(J*8));
KDF3Cache[KDF3CachePos].Pwd=*Password;

View File

@@ -35,11 +35,14 @@ HANDLE PASCAL RAROpenArchiveEx(struct RAROpenArchiveDataEx *r)
DataSet *Data=NULL;
try
{
ErrHandler.Clean();
r->OpenResult=0;
Data=new DataSet;
Data->Cmd.DllError=0;
Data->OpenMode=r->OpenMode;
Data->Cmd.FileArgs.AddString(L"*");
Data->Cmd.KeepBroken=(r->OpFlags&ROADOF_KEEPBROKEN)!=0;
char AnsiArcName[NM];
*AnsiArcName=0;
@@ -48,7 +51,7 @@ HANDLE PASCAL RAROpenArchiveEx(struct RAROpenArchiveDataEx *r)
strncpyz(AnsiArcName,r->ArcName,ASIZE(AnsiArcName));
#ifdef _WIN_ALL
if (!AreFileApisANSI())
{
{
OemToCharBuffA(r->ArcName,AnsiArcName,ASIZE(AnsiArcName));
AnsiArcName[ASIZE(AnsiArcName)-1]=0;
}
@@ -90,39 +93,53 @@ HANDLE PASCAL RAROpenArchiveEx(struct RAROpenArchiveDataEx *r)
return NULL;
}
r->Flags=0;
if (Data->Arc.Volume)
r->Flags|=0x01;
r->Flags|=ROADF_VOLUME;
if (Data->Arc.MainComment)
r->Flags|=ROADF_COMMENT;
if (Data->Arc.Locked)
r->Flags|=0x04;
r->Flags|=ROADF_LOCK;
if (Data->Arc.Solid)
r->Flags|=0x08;
r->Flags|=ROADF_SOLID;
if (Data->Arc.NewNumbering)
r->Flags|=0x10;
r->Flags|=ROADF_NEWNUMBERING;
if (Data->Arc.Signed)
r->Flags|=0x20;
r->Flags|=ROADF_SIGNED;
if (Data->Arc.Protected)
r->Flags|=0x40;
r->Flags|=ROADF_RECOVERY;
if (Data->Arc.Encrypted)
r->Flags|=0x80;
r->Flags|=ROADF_ENCHEADERS;
if (Data->Arc.FirstVolume)
r->Flags|=0x100;
r->Flags|=ROADF_FIRSTVOLUME;
Array<wchar> CmtDataW;
if (r->CmtBufSize!=0 && Data->Arc.GetComment(&CmtDataW))
{
if (r->CmtBufW!=NULL)
{
CmtDataW.Push(0);
size_t Size=wcslen(&CmtDataW[0])+1;
r->CmtState=Size>r->CmtBufSize ? ERAR_SMALL_BUF:1;
r->CmtSize=(uint)Min(Size,r->CmtBufSize);
memcpy(r->CmtBufW,&CmtDataW[0],(r->CmtSize-1)*sizeof(*r->CmtBufW));
r->CmtBufW[r->CmtSize-1]=0;
}
else
if (r->CmtBuf!=NULL)
{
Array<char> CmtData(CmtDataW.Size()*4+1);
memset(&CmtData[0],0,CmtData.Size());
WideToChar(&CmtDataW[0],&CmtData[0],CmtData.Size()-1);
size_t Size=strlen(&CmtData[0])+1;
r->Flags|=2;
r->CmtState=Size>r->CmtBufSize ? ERAR_SMALL_BUF:1;
r->CmtSize=(uint)Min(Size,r->CmtBufSize);
memcpy(r->CmtBuf,&CmtData[0],r->CmtSize-1);
if (Size<=r->CmtBufSize)
r->CmtBuf[r->CmtSize-1]=0;
}
}
else
r->CmtState=r->CmtSize=0;
Data->Extract.ExtractArchiveInit(Data->Arc);
@@ -151,10 +168,17 @@ HANDLE PASCAL RAROpenArchiveEx(struct RAROpenArchiveDataEx *r)
int PASCAL RARCloseArchive(HANDLE hArcData)
{
DataSet *Data=(DataSet *)hArcData;
try
{
bool Success=Data==NULL ? false:Data->Arc.Close();
delete Data;
return Success ? ERAR_SUCCESS : ERAR_ECLOSE;
}
catch (RAR_EXIT ErrCode)
{
return Data->Cmd.DllError!=0 ? Data->Cmd.DllError : RarErrorToDll(ErrCode);
}
}
int PASCAL RARReadHeader(HANDLE hArcData,struct RARHeaderData *D)
@@ -243,9 +267,6 @@ int PASCAL RARReadHeaderEx(HANDLE hArcData,struct RARHeaderDataEx *D)
D->UnpSize=uint(hd->UnpSize & 0xffffffff);
D->UnpSizeHigh=uint(hd->UnpSize>>32);
D->HostOS=hd->HSType==HSYS_WINDOWS ? HOST_WIN32:HOST_UNIX;
if (Data->Arc.Format==RARFMT50)
D->UnpVer=Data->Arc.FileHead.UnpVer==0 ? 50 : 200; // If it is not 0, just set it to something big.
else
D->UnpVer=Data->Arc.FileHead.UnpVer;
D->FileCRC=hd->FileHash.CRC32;
D->FileTime=hd->mtime.GetDos();
@@ -291,6 +312,9 @@ int PASCAL RARReadHeaderEx(HANDLE hArcData,struct RARHeaderDataEx *D)
D->RedirNameSize>0 && D->RedirNameSize<100000)
wcsncpyz(D->RedirName,hd->RedirName,D->RedirNameSize);
D->DirTarget=hd->DirTarget;
/* added by me */
D->WinSize = hd->WinSize;
}
catch (RAR_EXIT ErrCode)
{
@@ -379,7 +403,7 @@ int PASCAL ProcessFile(HANDLE hArcData, int Operation, char *DestPath,
if (DestNameW!=NULL)
wcsncpyz(Data->Cmd.DllDestName,DestNameW,ASIZE(Data->Cmd.DllDestName));
wcscpy(Data->Cmd.Command,Operation==RAR_EXTRACT ? L"X":L"T");
wcsncpyz(Data->Cmd.Command,Operation==RAR_EXTRACT ? L"X":L"T",ASIZE(Data->Cmd.Command));
Data->Cmd.Test=Operation!=RAR_EXTRACT;
if (Operation == RAR_EXTRACT_CHUNK)
{
@@ -393,7 +417,7 @@ int PASCAL ProcessFile(HANDLE hArcData, int Operation, char *DestPath,
bool Repeat=false;
if (Operation != RAR_EXTRACT_CHUNK)
Data->Extract.ExtractCurrentFile(Data->Arc,Data->HeaderSize,Repeat);
Data->Extract.ExtractCurrentFile(Data->Arc,Data->HeaderSize,Repeat);
else
{
if (InitDataIO) //chunk, init
@@ -432,7 +456,7 @@ int PASCAL ProcessFile(HANDLE hArcData, int Operation, char *DestPath,
}
Data->Arc.Seek(Data->Arc.CurBlockPos,SEEK_SET);
}
}
}
}
catch (std::bad_alloc&)
{
@@ -448,15 +472,15 @@ int PASCAL ProcessFile(HANDLE hArcData, int Operation, char *DestPath,
int PASCAL RARProcessFile(HANDLE hArcData,int Operation,char *DestPath,char *DestName)
{
return(ProcessFile(hArcData,Operation,DestPath,DestName,NULL,NULL,NULL,0,
NULL,false,NULL));
return ProcessFile(hArcData,Operation,DestPath,DestName,NULL,NULL,NULL,0,
NULL,false,NULL);
}
int PASCAL RARProcessFileW(HANDLE hArcData,int Operation,wchar *DestPath,wchar *DestName)
{
return(ProcessFile(hArcData,Operation,NULL,NULL,DestPath,DestName,NULL,0,
NULL,false,NULL));
return ProcessFile(hArcData,Operation,NULL,NULL,DestPath,DestName,NULL,0,
NULL,false,NULL);
}
int PASCAL RARProcessFileChunkInit(HANDLE hArcData)
@@ -505,16 +529,16 @@ void PASCAL RARSetProcessDataProc(HANDLE hArcData,PROCESSDATAPROC ProcessDataPro
}
#ifndef RAR_NOCRYPT
void PASCAL RARSetPassword(HANDLE hArcData,char *Password)
{
#ifndef RAR_NOCRYPT
DataSet *Data=(DataSet *)hArcData;
wchar PasswordW[MAXPASSWORD];
GetWideName(Password,NULL,PasswordW,ASIZE(PasswordW));
Data->Cmd.Password.Set(PasswordW);
cleandata(PasswordW,sizeof(PasswordW));
}
#endif
}
int PASCAL RARGetDllVersion()
@@ -528,6 +552,7 @@ static int RarErrorToDll(RAR_EXIT ErrCode)
switch(ErrCode)
{
case RARX_FATAL:
case RARX_READ:
return ERAR_EREAD;
case RARX_CRC:
return ERAR_BAD_DATA;

View File

@@ -1,7 +1,7 @@
#ifndef _UNRAR_DLL_
#define _UNRAR_DLL_
#pragma pack(1)
#pragma pack(push, 1)
#define ERAR_SUCCESS 0
#define ERAR_END_ARCHIVE 10
@@ -39,9 +39,11 @@
#define RAR_HASH_CRC32 1
#define RAR_HASH_BLAKE2 2
//Must be the same as MAXWINSIZE
//not in original
#define RAR_CHUNK_BUFFER_SIZE 0x400000
// should be a multiple of 16 becasue this buffer is passed
// directly to UnpRead (bypassing UnstoreFile) and 16 is the size
// of crypt blocks
#define RAR_CHUNK_BUFFER_SIZE 0x100000UL
#ifdef _UNIX
#define CALLBACK
@@ -131,6 +133,8 @@ struct RARHeaderDataEx
/* removed by me: we don't need to retain binary compatibility in case new
* fields are added, so we avoid wasting space here */
/* unsigned int Reserved[988]; */
/* added by me */
size_t WinSize; /* window size */
};
@@ -157,6 +161,8 @@ typedef int (CALLBACK *UNRARCALLBACK)(UINT msg,LPARAM UserData,LPARAM P1,LPARAM
#define ROADF_ENCHEADERS 0x0080
#define ROADF_FIRSTVOLUME 0x0100
#define ROADOF_KEEPBROKEN 0x0001
struct RAROpenArchiveDataEx
{
char *ArcName;
@@ -170,8 +176,10 @@ struct RAROpenArchiveDataEx
unsigned int Flags;
UNRARCALLBACK Callback;
LPARAM UserData;
unsigned int OpFlags;
wchar_t *CmtBufW;
/* removed by me */
/* unsigned int Reserved[28]; */
/* unsigned int Reserved[25]; */
};
enum UNRARCALLBACK_MESSAGES {
@@ -206,6 +214,6 @@ int PASCAL RARGetDllVersion();
}
#endif
#pragma pack()
#pragma pack(pop)
#endif

View File

@@ -2,8 +2,8 @@
#include <commctrl.h>
VS_VERSION_INFO VERSIONINFO
FILEVERSION 5, 50, 5, 2378
PRODUCTVERSION 5, 50, 5, 2378
FILEVERSION 6, 0, 2, 3610
PRODUCTVERSION 6, 0, 2, 3610
FILEOS VOS__WINDOWS32
FILETYPE VFT_APP
{
@@ -14,9 +14,9 @@ FILETYPE VFT_APP
VALUE "CompanyName", "Alexander Roshal\0"
VALUE "ProductName", "RAR decompression library\0"
VALUE "FileDescription", "RAR decompression library\0"
VALUE "FileVersion", "5.50.5\0"
VALUE "ProductVersion", "5.50.5\0"
VALUE "LegalCopyright", "Copyright © Alexander Roshal 1993-2017\0"
VALUE "FileVersion", "6.0.2\0"
VALUE "ProductVersion", "6.0.2\0"
VALUE "LegalCopyright", "Copyright © Alexander Roshal 1993-2020\0"
VALUE "OriginalFilename", "Unrar.dll\0"
}
}

Some files were not shown because too many files have changed in this diff Show More