148 Commits

Author SHA1 Message Date
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
Gustavo Lopes
6bb74bf820 Fix swapped param order in extractchunk 2017-07-18 03:55:44 +01:00
Gustavo Lopes
1a2f9f5104 Fix tests/101.phpt 2017-07-18 03:55:44 +01:00
Gustavo Lopes
0fd6896a25 Remoe unneeded destructor 2017-07-18 03:55:44 +01:00
Gustavo Lopes
d2a8a89e64 Add travis files. 2017-07-18 03:55:44 +01:00
Gustavo Lopes
d95d7a794f Fix uninitialized struct passed to RARReadHeaderEx 2017-07-17 19:15:44 +01:00
Gustavo Lopes
9129dab024 Change compiler switches, remove unused variable 2017-07-17 17:31:41 +01:00
Gustavo Lopes
897139b2ce Remove & ignore autosave files 2017-07-17 17:23:21 +01:00
Gustavo Lopes
2a29f7e763 Remove now unneeded function 2017-07-17 17:22:52 +01:00
Gustavo Lopes
3a830bc07c Move to version 4 2017-07-17 17:10:11 +01:00
Gustavo Lopes
119722d581 Merge branch 'unrar', with unrar 5.5.6 2017-07-17 17:09:44 +01:00
Gustavo Lopes
4f821913ad Added unrar 5.5.6 2017-07-17 17:06:33 +01:00
Gustavo Lopes
6939711766 Added unrar 5.5.5 2017-07-17 17:06:33 +01:00
Gustavo Lopes
c499b4d2d2 Added unrar 5.5.4 2017-07-17 17:06:33 +01:00
Gustavo Lopes
a191673249 Added unrar 5.5.3 2017-07-17 17:06:33 +01:00
Gustavo Lopes
c6f8765250 Added unrar 5.5.2 2017-07-17 17:06:33 +01:00
Gustavo Lopes
5402805db0 Added unrar 5.5.1 2017-07-17 17:06:33 +01:00
Gustavo Lopes
e6e481cfb2 Added unrar 5.4.5 2017-07-17 17:06:33 +01:00
Gustavo Lopes
a3c0236a7d Added unrar 5.4.4 2017-07-17 17:06:33 +01:00
Gustavo Lopes
f8ee7cc273 Added unrar 5.4.3 2017-07-17 17:06:33 +01:00
Gustavo Lopes
e699b159cf Added unrar 5.4.2 2017-07-17 17:06:33 +01:00
Gustavo Lopes
41875e7bd6 Added unrar 5.4.1 2017-07-17 17:06:33 +01:00
Gustavo Lopes
3a2688b3eb Added unrar 5.3.11 2017-07-17 17:06:33 +01:00
Gustavo Lopes
524d195253 Added unrar 5.3.10 2017-07-17 17:06:33 +01:00
Gustavo Lopes
e1609b9dfd Added unrar 5.3.9 2017-07-17 17:06:33 +01:00
Gustavo Lopes
4f804014ca Added unrar 5.3.8 2017-07-17 17:06:33 +01:00
Gustavo Lopes
abe9816391 Added unrar 5.3.7 2017-07-17 17:06:33 +01:00
Gustavo Lopes
5876366b26 Added unrar 5.3.6 2017-07-17 17:06:33 +01:00
Gustavo Lopes
c1e389af0d Added unrar 5.3.5 2017-07-17 17:06:33 +01:00
Gustavo Lopes
73972e070d Added unrar 5.3.4 2017-07-17 17:06:33 +01:00
Gustavo Lopes
74aed951bb Added unrar 5.3.3 2017-07-17 17:06:33 +01:00
Gustavo Lopes
26929db6a9 Added unrar 5.3.2 2017-07-17 17:06:33 +01:00
Gustavo Lopes
4fb28f3858 Added unrar 5.3.1 2017-07-17 17:06:32 +01:00
Gustavo Lopes
4e04320979 Added unrar 5.2.7 2017-07-17 17:06:32 +01:00
Gustavo Lopes
b72aaff789 Added unrar 5.2.6 2017-07-17 17:06:32 +01:00
Gustavo Lopes
3b2d2eb296 Added unrar 5.2.5 2017-07-17 17:06:32 +01:00
Gustavo Lopes
166fe908ad Added unrar 5.2.4 2017-07-17 17:06:32 +01:00
Gustavo Lopes
0265686bbd Added unrar 5.2.3 2017-07-17 17:06:32 +01:00
Gustavo Lopes
f650a6e340 Added unrar 5.2.2 2017-07-17 17:06:07 +01:00
Gustavo Lopes
a20ca1559c Ensure RAR archive is always closed 2017-07-17 15:41:19 +01:00
Gustavo Lopes
2ab141deed Add test for RAR5 archive 2017-07-17 15:13:11 +01:00
Gustavo Lopes
498cad468e Merge pull request #1 from weltling/master
missing file in config.w32
2017-07-17 06:39:34 +01:00
Gustavo Lopes
65d5132550 Merge branch 'unrar'
Conflicts:
	unrar/UnRAR.vcproj
	unrar/UnRARDll.vcproj
	unrar/arccmt.cpp
	unrar/arcread.cpp
	unrar/cmddata.cpp
	unrar/dll.cpp
	unrar/dll.hpp
	unrar/dll.rc
	unrar/errhnd.hpp
	unrar/extract.cpp
	unrar/extract.hpp
	unrar/filefn.cpp
	unrar/headers.hpp
	unrar/makefile
	unrar/os.hpp
	unrar/rdwrfn.hpp
	unrar/unpack.cpp
	unrar/unpack.hpp
	unrar/unpack15.cpp
	unrar/version.hpp
	unrar/volume.cpp
2017-07-17 06:30:09 +01:00
Gustavo Lopes
358432a7eb Added unrar 5.2.1 2014-10-22 23:42:31 +02:00
Gustavo Lopes
bbeab2dc4e Added unrar 5.1.7 2014-10-22 23:42:12 +02:00
Gustavo Lopes
5f81d8688f Added unrar 5.1.6 2014-10-22 23:42:04 +02:00
Gustavo Lopes
d6dfd5054c Added unrar 5.1.5 2014-10-22 23:41:54 +02:00
Gustavo Lopes
5d1e369c38 Added unrar 5.1.4 2014-10-22 23:41:44 +02:00
Gustavo Lopes
2f36bd7cac Added unrar 5.1.3 2014-10-22 23:41:36 +02:00
Gustavo Lopes
34859cf5b4 Added unrar 5.1.2 2014-10-22 23:41:26 +02:00
Gustavo Lopes
99cb19e838 Added unrar 5.1.1 2014-10-22 23:41:16 +02:00
Gustavo Lopes
f19f569f44 Added unrar 5.0.14 2014-10-22 23:40:13 +02:00
Gustavo Lopes
762b1ae3b0 Added unrar 5.0.13 2014-10-22 23:40:04 +02:00
Gustavo Lopes
fe2d2f46e4 Added unrar 5.0.12 2014-10-22 23:39:57 +02:00
Gustavo Lopes
6391dc21ca Added unrar 5.0.11 2014-10-22 23:39:48 +02:00
Gustavo Lopes
98bcf3697a Added unrar 5.0.10 2014-10-22 23:39:02 +02:00
Gustavo Lopes
4cda46d212 Added unrar 5.0.8 2014-10-22 23:37:27 +02:00
Gustavo Lopes
b2bc8dc586 Added unrar 5.0.7 2014-10-22 23:37:18 +02:00
Gustavo Lopes
96eec2b31c Added unrar 5.0.6 2014-10-22 23:37:10 +02:00
Gustavo Lopes
d5f04a3a88 Added unrar 5.0.5 2014-10-22 23:36:59 +02:00
Gustavo Lopes
13cb064031 Added unrar 5.0.4 2014-10-22 23:36:47 +02:00
Gustavo Lopes
a238d20430 Added unrar 5.0.3 2014-10-22 23:36:30 +02:00
Gustavo Lopes
66e2666696 Added unrar 5.0.2 2014-10-22 23:36:01 +02:00
Gustavo Lopes
55a328ff22 Added unrar 5.0.1 2014-10-22 23:35:46 +02:00
Gustavo Lopes
e632e338ef Added unrar 5.0.0 2014-10-22 23:32:03 +02:00
Anatol Belski
2ea5d74e6d missing file in config.w32 2014-10-22 23:25:15 +02:00
Anatol Belski
5840034b59 Merge branch 'master' of https://github.com/cataphract/php-rar 2014-02-05 12:26:26 +01:00
Gustavo Lopes
d72ef1dbce Merge pull request #3 from tony2001/master
added PHP license to the package
2013-10-11 06:23:30 -07:00
Antony Dovgal
e2db202b89 reflect the fact that UnRar has its own license 2013-10-11 15:31:41 +04:00
Antony Dovgal
1cf4e2c02c add license to package.xml 2013-10-11 15:29:49 +04:00
Antony Dovgal
ee28abf175 add LICENSE fail 2013-10-11 15:29:34 +04:00
Gustavo Lopes
ece47716ab Merge pull request #2 from tony2001/master
v3.0.2 update
2013-10-11 01:53:56 -07:00
Antony Dovgal
388707153c version 3.0.2 is coming 2013-10-11 12:19:49 +04:00
Antony Dovgal
60cf649b85 allow rb mode for dirs, it won't hurt 2013-10-11 12:18:24 +04:00
Anatol Belski
113935cbc5 missing file in config.w32 2013-10-01 16:02:30 +02:00
Gustavo Lopes
881989bbac Allow 'rb' mode for opening rar entries 2013-04-28 21:13:34 +02:00
Gustavo Lopes
b1c3582301 Convert rar_navigation.c to unix line endings 2013-04-28 20:32:45 +02:00
Gustavo Lopes
1cfe9592c0 Remove trailing space 2013-04-28 20:32:45 +02:00
Antony Dovgal
c92f03f1e2 Use zend_read_property() to read object properties 2013-04-28 13:19:12 +02:00
Gustavo Lopes
430a8ba763 Merge branch 'unrar', with unrar 4.2.4.
Conflicts:
	unrar/dll.rc
	unrar/version.hpp
2012-12-16 18:11:42 +01:00
Gustavo Lopes
e2c046d88d Added unrar 4.2.4. 2012-12-16 17:39:34 +01:00
Gustavo Lopes
63d3b18405 Prepare for 3.0.1 release 2012-07-29 02:48:36 +00:00
Gustavo Lopes
6963ed8f43 Add .gitignore 2012-07-29 02:03:44 +00:00
Gustavo Lopes
0a57b9b313 Remove revision information 2012-07-29 02:02:35 +00:00
Gustavo Lopes
3b9dd4dd6e Added test for bug #59939 (can't reproduce) 2012-07-29 00:44:38 +00:00
Gustavo Lopes
28e2572026 Fix bad pointer in error message 2012-07-29 00:42:45 +00:00
Gustavo Lopes
21cba90843 Fix some tests for when TZ != 'Europe/Lisbon' 2012-07-29 00:28:32 +00:00
Gustavo Lopes
0473c464e1 Fix problem in PHP >= 5.3.11, 5.4.1
And not compiling in master.
2012-07-29 02:15:57 +02:00
Gustavo Lopes
9cd367de03 Use <> in standard includes 2012-07-28 23:13:30 +00:00
Gustavo Lopes
0ef63a5fbb Merge branch 'unrar', with unrar 4.2.2
Conflicts:
	unrar/UnRAR.vcproj
	unrar/UnRARDll.vcproj
	unrar/arcread.cpp
	unrar/cmddata.cpp
	unrar/dll.cpp
	unrar/dll.rc
	unrar/errhnd.hpp
	unrar/extract.cpp
	unrar/makefile.bcc
	unrar/makefile.dj
	unrar/makefile.dmc
	unrar/makefile.unix
	unrar/os.hpp
	unrar/unpack.hpp
	unrar/version.hpp
	unrar/volume.cpp
2012-07-29 00:53:30 +02:00
Gustavo Lopes
75486ffa92 Merge with strategy ours 1e542a4db.
This will allow to merge in new changes int he unrar lib without using
a temporary branch.
2012-07-28 16:26:51 +02:00
Gustavo Lopes
7d8ada6e1e Added unrar 4.2.2. 2012-07-28 01:40:45 +02:00
Gustavo Lopes
02e98e3188 Added unrar 4.2.2. 2012-07-28 01:40:10 +02:00
Gustavo Lopes
18a025c38d Added unrar 4.2.1. 2012-07-28 01:06:28 +02:00
Gustavo Lopes
3bd27b4b36 Added unrar 4.1.4. 2012-07-28 00:58:41 +02:00
Gustavo Lopes
5bb815b5db Added unrar 4.1.3. 2012-07-28 00:58:06 +02:00
Gustavo Lopes
e06c6250d0 Merged in changes in unrar 4.1.1 and 4.1.2. 2011-11-02 11:48:33 +00:00
Gustavo Lopes
1e542a4db3 Added unrar 4.1.2 2011-11-02 11:14:35 +00:00
Gustavo Lopes
6907905144 Added unrar 4.1.1 2011-11-02 11:14:22 +00:00
Gustavo Lopes
f8cb60259d Added unrar 4.0.7 2011-06-12 02:09:21 +01:00
Gustavo Lopes
1e2e912de2 Added unrar 4.0.6. 2011-02-17 19:07:06 +00:00
Gustavo Lopes
479c373f4d Added unrar 4.0.5 2011-01-24 04:22:35 +00:00
Gustavo Lopes
6c1dd8a81f Added unrar 4.0.4 2011-01-13 18:50:03 +00:00
Gustavo Lopes
b451c7c79b Added unrar 4.0.3 2011-01-13 18:49:58 +00:00
Gustavo Lopes
c915d361f4 Added unrar 4.0.2 2011-01-13 18:49:54 +00:00
Gustavo Lopes
15aa6f20d6 Added unrar 4.0.1 2011-01-13 18:49:44 +00:00
Gustavo Lopes
561966f23b Added unrar 3.9.10 2011-01-13 18:49:25 +00:00
Gustavo Lopes
80986445f5 Added unrar 3.9.9 2011-01-13 18:49:13 +00:00
Gustavo Lopes
446a2e8492 Added unrar 3.9.8 2011-01-13 18:49:00 +00:00
Gustavo Lopes
12719dce2c Added unrar 3.9.7 2011-01-13 18:48:55 +00:00
Gustavo Lopes
75c4bbc240 Added unrar 3.9.6 2011-01-13 18:48:50 +00:00
Gustavo Lopes
951ccf9767 Added unrar 3.9.5 2011-01-13 18:48:45 +00:00
Gustavo Lopes
2538d242ee Added unrar 3.9.4 2011-01-13 18:48:41 +00:00
Gustavo Lopes
e91808a5eb Added unrar 3.9.3 2011-01-13 18:48:36 +00:00
Gustavo Lopes
a9631cfddd Added unrar 3.9.2 2011-01-13 18:48:32 +00:00
Gustavo Lopes
89c4cbe487 Added unrar 3.9.1 2011-01-13 18:48:26 +00:00
Gustavo Lopes
876cb51c4c Added unrar 3.8.5 2011-01-13 18:47:51 +00:00
Gustavo Lopes
ad8e1e2a2b Added unrar 3.8.4 2011-01-13 18:47:45 +00:00
Gustavo Lopes
825de01ac1 Added unrar 3.8.3 2011-01-13 18:47:39 +00:00
Gustavo Lopes
7a8b0a7f59 Added unrar 3.8.2 2011-01-13 18:47:31 +00:00
Gustavo Lopes
35f7e43f2f Added unrar 3.8.1 2011-01-13 18:47:24 +00:00
Gustavo Lopes
3a535eba4e Added unrar 3.7.8 2011-01-13 18:47:06 +00:00
Gustavo Lopes
a16b24d665 Added unrar 3.7.7 2011-01-13 18:47:00 +00:00
Gustavo Lopes
9bd14a69e8 Added unrar 3.7.6 2011-01-13 18:46:54 +00:00
Gustavo Lopes
c093245020 Added unrar 3.7.5 2011-01-13 18:46:49 +00:00
Gustavo Lopes
f5ca2159f0 Added unrar 3.7.4 2011-01-13 18:46:44 +00:00
Gustavo Lopes
b8102334c6 Added unrar 3.7.3 2011-01-13 18:46:33 +00:00
Gustavo Lopes
eaffae90c0 Added unrar 3.7.2 2011-01-13 18:46:27 +00:00
Gustavo Lopes
2e18f53535 Added unrar 3.7.1 2011-01-13 18:46:22 +00:00
Gustavo Lopes
fff0c56e2e Added unrar 3.6.8 2011-01-13 18:46:12 +00:00
Gustavo Lopes
59a53d18ed Added unrar 3.6.7 2011-01-13 18:46:05 +00:00
Gustavo Lopes
e1490118df Added unrar 3.6.6 2011-01-13 18:46:00 +00:00
Gustavo Lopes
7bacdf6736 Added unrar 3.6.5 2011-01-13 18:45:55 +00:00
Gustavo Lopes
00a58e1934 Added unrar 3.6.4 2011-01-13 18:45:40 +00:00
Gustavo Lopes
55dd7388ab Added unrar 3.6.3 2011-01-13 18:44:53 +00:00
Gustavo Lopes
a18c3b7fdc Added unrar 3.6.2 2011-01-13 18:44:41 +00:00
Gustavo Lopes
c3cf0e0dd4 Added unrar 3.6.1 2011-01-13 18:44:23 +00:00
204 changed files with 22925 additions and 12586 deletions

43
.gitignore vendored Normal file
View File

@@ -0,0 +1,43 @@
*.o
*.lo
/tests/*.sh
/tests/*.exp
/tests/*.diff
/tests/*.log
/tests/*.php
/tests/*.out
/tests/*.mem
/run-tests.php
/modules
/missing
/.deps
/.libs
/Makefile
/Makefile.fragments
/Makefile.global
/Makefile.objects
/acinclude.m4
/aclocal.m4
/autom4te.cache
/build
/config.guess
/config.h
/config.h.in
/config.log
/config.nice
/config.status
/config.sub
/configure
/configure.in
/install-sh
/intl.la
/libtool
/mkinstalldirs
/ltmain.sh
/.cproject
/.project
/.settings
/pecl-rar.*
/rar.la
*.autosave
/unrar/.libs

33
.travis.yml Normal file
View File

@@ -0,0 +1,33 @@
language: c
dist: trusty
addons:
apt:
packages:
- valgrind
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 RUN_TESTS_FLAGS=-m
- PHP_VERSION=5.6.30 ZTS=no
- PHP_VERSION=7.0.21 ZTS=yes COVERAGE=yes
- PHP_VERSION=7.1.7 ZTS=yes RUN_TESTS_FLAGS=-m
cache:
directories:
- $HOME/php_builds
before_install:
- source travis.sh
- maybe_install_php $PHP_VERSION $ZTS
install:
- build $PHP_VERSION $ZTS "$COVERAGE"
script:
- run_tests $PHP_VERSION $ZTS
after_success:
- 'test "$COVERAGE" != "yes" || bash <(curl -s https://codecov.io/bash)'

68
LICENSE Normal file
View File

@@ -0,0 +1,68 @@
--------------------------------------------------------------------
The PHP License, version 3.01
Copyright (c) 1999 - 2010 The PHP Group. All rights reserved.
--------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
modification, is permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
3. The name "PHP" must not be used to endorse or promote products
derived from this software without prior written permission. For
written permission, please contact group@php.net.
4. Products derived from this software may not be called "PHP", nor
may "PHP" appear in their name, without prior written permission
from group@php.net. You may indicate that your software works in
conjunction with PHP by saying "Foo for PHP" instead of calling
it "PHP Foo" or "phpfoo"
5. The PHP Group may publish revised and/or new versions of the
license from time to time. Each version will be given a
distinguishing version number.
Once covered code has been published under a particular version
of the license, you may always continue to use it under the terms
of that version. You may also choose to use such covered code
under the terms of any subsequent version of the license
published by the PHP Group. No one other than the PHP Group has
the right to modify the terms applicable to covered code created
under this License.
6. Redistributions of any form whatsoever must retain the following
acknowledgment:
"This product includes PHP software, freely available from
<http://www.php.net/software/>".
THIS SOFTWARE IS PROVIDED BY THE PHP DEVELOPMENT TEAM ``AS IS'' AND
ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PHP
DEVELOPMENT TEAM OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------
This software consists of voluntary contributions made by many
individuals on behalf of the PHP Group.
The PHP Group can be contacted via Email at group@php.net.
For more information on the PHP Group and the PHP project,
please see <http://www.php.net>.
PHP includes the Zend Engine, freely available at
<http://www.zend.com>.

View File

@@ -10,3 +10,6 @@ unrar/LICENSE.txt for details.
Some modifications have been applied to the UnRAR library, mainly to allow
streaming extraction of files without using threads.
[![Build Status Appveyor](https://ci.appveyor.com/api/projects/status/cbgpepx6kyax2198/branch/master?svg=true)](https://ci.appveyor.com/project/cataphract/php-rar/branch/master)
[![Build Status Travis](https://travis-ci.org/cataphract/php-rar.svg?branch=master)](https://travis-ci.org/cataphract/php-rar)
[![codecov](https://codecov.io/gh/cataphract/php-rar/branch/master/graph/badge.svg)](https://codecov.io/gh/cataphract/php-rar)

29
appveyor.bat Normal file
View File

@@ -0,0 +1,29 @@
echo Running appveyor.bat
echo on
CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\vcvars32.bat"
IF NOT EXIST "C:\projects\php-sdk" (
wget -nv http://windows.php.net/downloads/php-sdk/php-sdk-binary-tools-20110915.zip
7z x -y php-sdk-binary-tools-20110915.zip -oC:\projects\php-sdk
)
IF NOT EXIST "C:\projects\php-src\Release_TS\php7ts.lib" (
git clone --depth=1 --branch=PHP-7.1 https://github.com/php/php-src C:\projects\php-src
wget -nv http://windows.php.net/downloads/php-sdk/deps-7.1-vc14-x86.7z
7z x -y deps-7.1-vc14-x86.7z -oC:\projects\php-src
CALL C:\projects\php-sdk\bin\phpsdk_setvars.bat
cd C:\projects\php-src
CALL buildconf.bat
CALL configure.bat --disable-all --enable-cli --with-config-file-scan-dir=C:\projects\extension\bin\modules.d --with-prefix=%APPVEYOR_BUILD_FOLDER%\bin --with-php-build=deps
nmake
) ELSE (
echo php7ts.lib already exists
cd C:\projects\php-src
CALL C:\projects\php-sdk\bin\phpsdk_setvars.bat
)
CALL buildconf.bat --force --add-modules-dir=%APPVEYOR_BUILD_FOLDER%\..
CALL configure.bat --disable-all --enable-cli --enable-rar=shared --with-config-file-scan-dir=C:\projects\extension\bin\modules.d --with-prefix=%APPVEYOR_BUILD_FOLDER%\bin --with-php-build=deps
nmake || exit /b
rmdir Release_TS\php-rar /S /Q
del /S /Q "Release_TS\*.sbr"

26
appveyor.yml Normal file
View File

@@ -0,0 +1,26 @@
# Based on igbinary's appveyor config.
version: '{branch}.{build}'
install:
- cmd: choco feature enable -n=allowGlobalConfirmation
- cmd: cinst wget
- cmd: mkdir %APPVEYOR_BUILD_FOLDER%\bin
build_script:
- cmd: "%APPVEYOR_BUILD_FOLDER%\\appveyor.bat"
test_script:
- cmd: cd C:\projects\php-src
- cmd: set NO_INTERACTION=1
- cmd: set REPORT_EXIT_STATUS=1
- cmd: set TZ=UTC
- cmd: 'nmake test TESTS="--show-diff --set-timeout 30 -d extension=C:\projects\php-src\Release_TS\php_rar.dll %APPVEYOR_BUILD_FOLDER%\tests"'
after_test:
# - cmd: dir /S C:\projects\php-src\Release_TS
- cmd: 'del C:\projects\php-src\Release_TS\php_rar.*'
cache:
- C:\ProgramData\chocolatey\lib -> appveyor.yml
- C:\projects\php-src
- C:\projects\php-sdk

18
composer.json Normal file
View File

@@ -0,0 +1,18 @@
{
"name": "rar",
"type": "extension",
"license": [
"PHP License"
],
"authors": [
{
"name": "Gustavo Lopes",
"email": "cataphract@php.net"
},
{
"name": "Antony Dovgal",
"email": "tony@daylessday.org"
}
],
"description": "rar extension"
}

View File

@@ -4,28 +4,39 @@ dnl config.m4 for extension rar
PHP_ARG_ENABLE(rar, whether to enable rar support,
[ --enable-rar Enable rar support])
unrar_sources="unrar/rar.cpp unrar/strlist.cpp unrar/strfn.cpp \
unrar/pathfn.cpp unrar/smallfn.cpp unrar/savepos.cpp \
unrar/global.cpp unrar/file.cpp unrar/filefn.cpp \
unrar/filcreat.cpp unrar/archive.cpp unrar/arcread.cpp \
unrar/unicode.cpp unrar/system.cpp unrar/isnt.cpp \
unrar/crypt.cpp unrar/crc.cpp unrar/rawread.cpp \
unrar/encname.cpp unrar/resource.cpp unrar/match.cpp \
unrar/timefn.cpp unrar/rdwrfn.cpp unrar/consio.cpp \
unrar/options.cpp unrar/ulinks.cpp unrar/errhnd.cpp \
unrar/rarvm.cpp unrar/rijndael.cpp unrar/getbits.cpp \
unrar/sha1.cpp unrar/extinfo.cpp unrar/extract.cpp \
unrar/volume.cpp unrar/find.cpp \
unrar/unpack.cpp unrar/cmddata.cpp unrar/dll.cpp \
unrar/filestr.cpp unrar/recvol.cpp unrar/rs.cpp \
unrar/scantree.cpp unrar/log.cpp unrar/extractchunk.cpp"
unrar_sources="unrar/sha256.cpp unrar/qopen.cpp \
unrar/blake2s.cpp unrar/recvol.cpp \
unrar/headers.cpp unrar/match.cpp \
unrar/find.cpp \
unrar/resource.cpp \
unrar/pathfn.cpp \
unrar/dll.cpp unrar/threadpool.cpp unrar/volume.cpp \
unrar/unpack.cpp \
unrar/extract.cpp unrar/errhnd.cpp \
unrar/crc.cpp unrar/rijndael.cpp unrar/crypt.cpp \
unrar/rawread.cpp \
unrar/rs.cpp unrar/smallfn.cpp \
unrar/isnt.cpp unrar/rar.cpp unrar/consio.cpp \
unrar/scantree.cpp unrar/archive.cpp unrar/strfn.cpp \
unrar/strlist.cpp \
unrar/getbits.cpp unrar/hash.cpp \
unrar/filestr.cpp \
unrar/extinfo.cpp unrar/ui.cpp unrar/rarvm.cpp \
unrar/timefn.cpp unrar/sha1.cpp \
unrar/rdwrfn.cpp unrar/rs16.cpp unrar/cmddata.cpp \
unrar/extractchunk.cpp unrar/system.cpp \
unrar/unicode.cpp unrar/filcreat.cpp \
unrar/arcread.cpp unrar/filefn.cpp \
unrar/global.cpp unrar/list.cpp \
unrar/encname.cpp unrar/file.cpp \
unrar/secpassword.cpp unrar/options.cpp"
if test "$PHP_RAR" != "no"; then
PHP_REQUIRE_CXX
AC_DEFINE(HAVE_RAR, 1, [Whether you have rar support])
PHP_SUBST(RAR_SHARED_LIBADD)
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 -DGUI -DSILENT -Wno-write-strings -I@ext_srcdir@/unrar)
PHP_ADD_BUILD_DIR($ext_builddir/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 -I@ext_srcdir@/unrar)
PHP_ADD_BUILD_DIR($ext_builddir/unrar)
fi

View File

@@ -4,25 +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", "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");
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>2011-06-12</date>
<time>05:00:00</time>
<date>2017-07-22</date>
<time>03:00:00</time>
<version>
<release>3.0.0</release>
<api>3.0.0</api>
<release>4.0.0</release>
<api>4.0.0</api>
</version>
<stability>
@@ -36,24 +36,11 @@ http://pear.php.net/dtd/package-2.0.xsd">
</stability>
<license uri="http://www.php.net/license">PHP License</license>
<notes>Changes in this version:
- Updated to unrar 4.0.7 (corresponds to WinRAR 4.0.0 stable).
- Support for PHP 5.4.
- Added url wrapper rar://.
- Added volume find callback to RarArchive::open/rar_open.
- Added support for stat, both static and to opened streams.
- Added rar_allow_broken_set/RarArchive::setAllowBroken and rar_broken_is/
RarArchive::isBroken, which control/query the behavior with archives with
missing volumes.
- Added option to RarEntry::extract() to allow from extraction of ACL (windows)
/owner (unix)/extended attributes (os/2).
- Added support for RAR archives that have several entries with the same name.
- Implemented count elements handler for RarArchive.
- Implemented dimensions handlers for RarArchive.
- Fixed packed sizes which were using high bits from unpacked sizes.
- Fixed PECL bug #20498 (RarEntry::extract not really accepting a password).
- Fixed PECL bug #18449 (Extraction of uncompressed and encrypted files fails).
- Many more tests.
<notes>- Merge changes made to unrar up to version 5.5.6.
- Support PHP 7.0 and PHP 7.1.
- 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>
<contents>
<dir name="/">
@@ -157,11 +144,27 @@ http://pear.php.net/dtd/package-2.0.xsd">
<file role="test" name="096.phpt"/>
<file role="test" name="097.phpt"/>
<file role="test" name="098.phpt"/>
<file role="test" name="099.phpt"/>
<file role="test" name="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="commented.rar"/>
<file role="test" name="corrupted.rar"/>
<file role="test" name="directories.rar"/>
<file role="test" name="dirlink_unix.rar"/>
<file role="test" name="dirs_and_extra_headers.rar"/>
<file role="test" name="empty_file.rar"/>
<file role="test" name="encrypted_headers.rar"/>
<file role="test" name="encrypted_only_files.rar"/>
<file role="test" name="garbage.part03.rar"/>
@@ -179,14 +182,21 @@ 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" />
<file name="arccmt.cpp" role="src" />
<file name="archive.cpp" role="src" />
<file name="archive.hpp" role="src" />
<file name="arcread.cpp" role="src" />
<file name="array.hpp" role="src" />
<file name="beosea.cpp" role="src" />
<file name="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="coder.cpp" role="src" />
@@ -198,6 +208,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" />
@@ -223,7 +237,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" />
@@ -239,9 +258,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" />
@@ -251,10 +271,31 @@ http://pear.php.net/dtd/package-2.0.xsd">
<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" />
@@ -264,10 +305,11 @@ 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" />
<file name="secpassword.cpp" role="src" />
<file name="secpassword.hpp" role="src" />
<file name="sha1.cpp" role="src" />
<file name="sha1.hpp" role="src" />
<file name="smallfn.cpp" role="src" />
@@ -286,7 +328,6 @@ http://pear.php.net/dtd/package-2.0.xsd">
<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" />
@@ -301,7 +342,8 @@ http://pear.php.net/dtd/package-2.0.xsd">
<file name="config.m4" role="src" />
<file name="config.w32" role="src" />
<file name="CREDITS" role="doc" />
<file name="README" role="doc" />
<file name="LICENSE" role="doc" />
<file name="README.md" role="doc" />
<file name="example.php" role="doc" />
<file name="php_rar.h" role="src" />
<file name="rar.c" role="src" />
@@ -309,6 +351,7 @@ http://pear.php.net/dtd/package-2.0.xsd">
<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 role="src" name="rar_navigation.c"/>
</dir> <!-- / -->
</contents>
@@ -316,7 +359,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>
@@ -329,6 +372,40 @@ http://pear.php.net/dtd/package-2.0.xsd">
<extsrcrelease />
<changelog>
<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>
<api>3.0.0</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<date>2012-07-29</date>
<notes>Changes in this version:
- Merge changes made to unrar up to version 4.2.2.
- Fix leak in PHP >= 5.3.11, = 5.4.0 and compile error in master.
- Fix some tests failing if TZ != Europe/Lisbon.
- Fix bad pointer in an error message.
- Added test for bug #59939 (can't reproduce).
</notes>
</release>
<release>
<version>
<release>2.0.0</release>
@@ -361,7 +438,7 @@ For the other changes, see the changelog for version 2.0.0RC1.
<api>beta</api>
</stability>
<date>2010-01-17</date>
<license uri="http://www.php.net/license">PHP License</license>
<license>PHP License and UnRar license</license>
<notes>Changes in respect to release 1.0.0:
PHP SUPPORT:
- Support for PHP 4.3 dropped. PHP 5.2.x or 5.3.x is required.
@@ -398,7 +475,7 @@ Other changes:
- A lot of refactoring and compilation as C, not C++.
</notes>
</release>
<release>
<version>
<release>1.0.0</release>

View File

@@ -46,11 +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 "3.0.0"
#define PHP_RAR_REVISION "$Revision$"
#define PHP_RAR_VERSION "4.0.0"
#ifdef PHP_WIN32
#define PHP_RAR_API __declspec(dllexport)
@@ -67,6 +68,7 @@ extern zend_module_entry rar_module_entry;
/* #include "unrar/rar.hpp */
/* only these includes are necessary anyway: */
#include "unrar/raros.hpp"
#include "unrar/rartypes.hpp"
/* no need to reinclude windows.h or new.h */
#define LEAN_RAR_INCLUDES
#include "unrar/os.hpp"
@@ -77,19 +79,78 @@ enum HOST_SYSTEM {
HOST_MSDOS=0,HOST_OS2=1,HOST_WIN32=2,HOST_UNIX=3,HOST_MACOS=4,
HOST_BEOS=5,HOST_MAX
};
#define LHD_WINDOWMASK 0x00e0U
#define LHD_DIRECTORY 0x00e0U
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
/* PHP 7+ abstraction */
#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
typedef struct _rar_cb_user_data {
char *password; /* can be NULL */
zval *callable; /* can be NULL */
} rar_cb_user_data;
typedef struct rar {
zend_object_handle id;
rar_obj_ref obj_ref;
struct _rar_entries *entries;
struct RAROpenArchiveDataEx *list_open_data;
struct RAROpenArchiveDataEx *extract_open_data;
@@ -101,7 +162,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
@@ -136,7 +197,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 */
@@ -171,6 +232,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
@@ -288,10 +358,16 @@ void _rar_entry_to_zval(zval *parent,
/* rar_stream.c */
php_stream *php_stream_rar_open(char *arc_name,
size_t position,
rar_cb_user_data *cb_udata_ptr, /* will be copied */
char *mode STREAMS_DC TSRMLS_DC);
rar_cb_user_data *cb_udata_ptr /* will be copied */
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 */

101
rar.c
View File

@@ -155,13 +155,19 @@ void _rar_utf_to_wide(const char *src, wchar_t *dest, size_t dest_size) /* {{{ *
void _rar_destroy_userdata(rar_cb_user_data *udata) /* {{{ */
{
assert(udata != NULL);
if (udata->password != NULL) {
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;
@@ -180,7 +186,7 @@ int _rar_find_file(struct RAROpenArchiveDataEx *open_data, /* IN */
size_t utf_file_name_len = strlen(utf_file_name);
int ret;
file_name = ecalloc(utf_file_name_len + 1, sizeof *file_name);
file_name = ecalloc(utf_file_name_len + 1, sizeof *file_name);
_rar_utf_to_wide(utf_file_name, file_name, utf_file_name_len + 1);
ret = _rar_find_file_w(open_data, file_name, cb_udata, arc_handle, found,
header_data);
@@ -231,7 +237,7 @@ int _rar_find_file_w(struct RAROpenArchiveDataEx *open_data, /* IN */
goto cleanup;
}
RARSetCallback(*arc_handle, _rar_unrar_callback, (LPARAM) cb_udata);
while ((result = RARReadHeaderEx(*arc_handle, used_header_data)) == 0) {
#if WCHAR_MAX > 0xffff
_rar_fix_wide(used_header_data->FileNameW, NM);
@@ -292,10 +298,11 @@ int _rar_find_file_p(struct RAROpenArchiveDataEx *open_data, /* IN */
goto cleanup;
}
RARSetCallback(*arc_handle, _rar_unrar_callback, (LPARAM) cb_udata);
while ((result = RARReadHeaderEx(*arc_handle, used_header_data)) == 0) {
/* skip entries that were split before with incrementing current pos */
if ((used_header_data->Flags & 0x01U) || (curpos++ != position)) {
if ((used_header_data->Flags & RHDF_SPLITBEFORE) ||
(curpos++ != position)) {
process_result = RARProcessFile(*arc_handle, RAR_SKIP, NULL, NULL);
} else {
*found = TRUE;
@@ -321,7 +328,7 @@ cleanup:
}
/* An unRAR callback.
* Processes requests for passwords and missing volumes
* Processes requests for passwords and missing volumes
* If there is (userland) volume find callback specified, try to use that
* callback to retrieve the name of the missing volume. Otherwise, or if
* the volume find callback returns null, cancel the operation. */
@@ -329,7 +336,7 @@ int CALLBACK _rar_unrar_callback(UINT msg, LPARAM UserData, LPARAM P1, LPARAM P2
{
rar_cb_user_data *userdata = (rar_cb_user_data*) UserData;
TSRMLS_FETCH();
if (msg == UCM_NEEDPASSWORD) {
/* user data is the password or null if none */
char *password = userdata->password;
@@ -403,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);
}
/* }}} */
/* }}} */
@@ -440,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 */
}
@@ -499,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;
}
/* }}} */
@@ -615,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)
@@ -633,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++;
@@ -698,7 +754,7 @@ ZEND_MODULE_STARTUP_D(rar)
ZEND_MODULE_GLOBALS_DTOR_N(rar)); */
php_register_url_stream_wrapper("rar", &php_stream_rar_wrapper TSRMLS_CC);
REGISTER_LONG_CONSTANT("RAR_HOST_MSDOS", HOST_MSDOS, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("RAR_HOST_OS2", HOST_OS2, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("RAR_HOST_WIN32", HOST_WIN32, CONST_CS | CONST_PERSISTENT);
@@ -732,7 +788,6 @@ ZEND_MODULE_INFO_D(rar)
php_info_print_table_start();
php_info_print_table_header(2, "RAR support", "enabled");
php_info_print_table_row(2, "RAR EXT version", PHP_RAR_VERSION);
php_info_print_table_row(2, "Revision", PHP_RAR_REVISION);
#if RARVER_BETA != 0
sprintf(version,"%d.%02d beta%d patch%d %d-%02d-%02d", RARVER_MAJOR,

View File

@@ -52,11 +52,11 @@ int _rar_handle_error_ex(const char *preamble, int errcode TSRMLS_DC) /* {{{ */
if (err == NULL) {
return SUCCESS;
}
if (_rar_using_exceptions(TSRMLS_C)) {
zend_throw_exception_ex(rarexception_ce_ptr, errcode TSRMLS_CC,
"unRAR internal error: %s%s", preamble, err);
}
}
else {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s%s", preamble, err);
}
@@ -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);
assert(Z_TYPE_P(pval) == IS_BOOL);
#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,25 +186,39 @@ 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;
}
/* or zend_read_static_property, which calls zend_std_get... after chg scope */
#if PHP_VERSION_ID < 50399
pval = zend_std_get_static_property(rarexception_ce_ptr, "usingExceptions",
sizeof("usingExceptions") -1, (zend_bool) 0 TSRMLS_CC);
#else
#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);
assert(Z_TYPE_PP(pval) == IS_BOOL);
#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,8 +242,13 @@ 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_exception_get_default(TSRMLS_C));
#endif
rarexception_ce_ptr->ce_flags |= ZEND_ACC_FINAL;
zend_declare_property_bool(rarexception_ce_ptr, "usingExceptions",
sizeof("usingExceptions") -1, 0L /* FALSE */,

File diff suppressed because it is too large Load Diff

View File

@@ -34,18 +34,18 @@
extern "C" {
#endif
#include "php.h"
#include <php.h>
#if HAVE_RAR
#include <wchar.h>
#include "php_rar.h"
#include "unrar/rartypes.hpp"
#include "php_streams.h"
#include "ext/standard/url.h"
#include "ext/standard/php_string.h"
#include <php_streams.h>
#include <ext/standard/url.h>
#include <ext/standard/php_string.h>
#include <ext/standard/file.h>
typedef struct php_rar_stream_data_t {
struct RAROpenArchiveDataEx open_data;
@@ -63,7 +63,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;
@@ -79,7 +79,7 @@ typedef struct php_rar_dir_stream_data_t {
#define STREAM_DIR_DATA_FROM_STREAM \
php_rar_dir_stream_data_P self = (php_rar_dir_stream_data_P) stream->abstract;
/* len can be -1 (calculate) */
/* len can be -1 (calculate) */
static char *_rar_wide_to_utf_with_alloc(const wchar_t *wide, int len)
{
size_t size;
@@ -263,52 +263,22 @@ static mode_t _rar_convert_file_attrs(unsigned os_attrs,
/* leave as is */
ret = (mode_t) (os_attrs & 0xffff);
break;
default:
if ((flags & LHD_WINDOWMASK) == LHD_DIRECTORY)
if (flags & RHDF_DIRECTORY)
ret = S_IFDIR;
else
ret = S_IFREG;
ret |= 0777;
ret &= ~mask;
break;
}
break;
}
return ret;
}
/* }}} */
/* If from is not set, sets to to default and returns SUCCESS.
* If from is set, converts it to a time_t. In case of failure returns FAILURE.
* In case of success, copies the result to to and returns SUCCESS. */
static int _rar_time_convert(RARTime *from, time_t *to) /* {{{ */
{
time_t default_ = (time_t) 0;
time_t retval;
struct tm time_s = {0};
if (from->Year == 0U) {
*to = default_;
return SUCCESS;
}
time_s.tm_sec = from->Second;
time_s.tm_min = from->Minute;
time_s.tm_hour = from->Hour;
time_s.tm_mday = from->Day;
time_s.tm_mon = from->Month - 1; /* starts at 0 in time_t */
time_s.tm_year = from->Year - 1900;
if ((retval = mktime(&time_s)) == -1)
return FAILURE;
else {
*to = retval;
return SUCCESS;
}
}
/* }}} */
static int _rar_stat_from_header(struct RARHeaderDataEx *header,
php_stream_statbuf *ssb) /* {{{ */
{
@@ -338,27 +308,21 @@ 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->atime, &ssb->sb.st_atime);
_rar_time_convert(&header->ctime, &ssb->sb.st_ctime);
if (header->mtime.Year == 0) { /* high precision mod time undefined */
struct tm time_s = {0};
if (header->MtimeLow == 0 && header->MtimeHigh == 0) {
/* high precision mod time undefined */
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->mtime, &ssb->sb.st_mtime);
else {
rar_time_convert(header->MtimeLow, header->MtimeHigh,
&ssb->sb.st_mtime);
}
#ifdef HAVE_ST_BLKSIZE
ssb->sb.st_blksize = 0;
@@ -423,14 +387,21 @@ 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
}
self->cur_offset++;
@@ -443,15 +414,19 @@ static size_t php_rar_dir_ops_read(php_stream *stream, char *buf, size_t count T
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);
stream->abstract = NULL;
/* 0 because that's what php_plain_files_dirstream_close returns... */
return 0;
return 0;
}
/* }}} */
@@ -503,19 +478,14 @@ static php_stream_ops php_stream_rar_dirio_ops = {
* was already done in RarArchive::open */
php_stream *php_stream_rar_open(char *arc_name,
size_t position,
rar_cb_user_data *cb_udata_ptr, /* will be copied */
char *mode STREAMS_DC TSRMLS_DC)
rar_cb_user_data *cb_udata_ptr /* will be copied */
STREAMS_DC TSRMLS_DC)
{
php_stream *stream = NULL;
php_rar_stream_data_P self = NULL;
int result,
found;
/* mode must be exactly "r" */
if (strncmp(mode, "r", sizeof("r")) != 0) {
goto cleanup;
}
self = ecalloc(1, sizeof *self);
self->open_data.ArcName = estrdup(arc_name);
self->open_data.OpenMode = RAR_OM_EXTRACT;
@@ -523,10 +493,9 @@ 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,
&self->rar_handle, &found, &self->header_data);
@@ -551,7 +520,7 @@ php_stream *php_stream_rar_open(char *arc_name,
self->buffer = emalloc(buffer_size);
self->buffer_size = buffer_size;
stream = php_stream_alloc(&php_stream_rario_ops, self, NULL, mode);
stream = php_stream_alloc(&php_stream_rario_ops, self, NULL, "rb");
stream->flags |= PHP_STREAM_FLAG_NO_BUFFER;
}
@@ -591,7 +560,7 @@ static char *zend_resolve_path(const char *filename,
}
/* do not use the include path in these circumstances */
if ((*filename == '.' && (IS_SLASH(filename[1]) ||
if ((*filename == '.' && (IS_SLASH(filename[1]) ||
((filename[1] == '.') && IS_SLASH(filename[2])))) ||
IS_ABSOLUTE_PATH(filename, filename_length) ||
path == NULL || path[0] == '\0') {
@@ -645,7 +614,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);
@@ -655,32 +627,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,
@@ -728,7 +718,7 @@ static int _rar_get_archive_and_fragment(php_stream_wrapper *wrapper,
"<urlencoded entry name>]]\"");
goto cleanup;
}
tmp_arch_len = (tmp_fragment != NULL)?
(tmp_fragment - filename) : (strlen(filename));
tmp_archive = emalloc(tmp_arch_len + 1);
@@ -748,13 +738,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
zend_string *arc_str = zend_resolve_path(tmp_archive, tmp_arch_len);
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))
== NULL) {
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC,
"Could not expand the path %s", archive);
"Could not expand the path %s", tmp_archive);
goto cleanup;
}
}
@@ -802,7 +802,7 @@ static int _rar_get_archive_and_fragment(php_stream_wrapper *wrapper,
wchar_t *ptr;
for (ptr = *fragment; *ptr != L'\0'; ptr++) {
if (*ptr == L'\\' || *ptr == L'/')
*ptr = PATHDIVIDERW[0];
*ptr = SPATHDIVIDER[0];
}
}
@@ -816,10 +816,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)
{
@@ -842,10 +849,10 @@ static php_stream *php_stream_rar_opener(php_stream_wrapper *wrapper,
return NULL;
}
/* mode must be exactly "r" */
if (strncmp(mode, "r", sizeof("r")) != 0) {
/* mode must be "r" or "rb", which, for BC reasons, are treated identically */
if (mode[0] != 'r' || (mode[1] != '\0' && mode[1] != 'b') || strlen(mode) > 2) {
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC,
"Only the \"r\" open mode is permitted, given %s", mode);
"Only the \"r\" and \"rb\" open modes are permitted, given %s", mode);
return NULL;
}
@@ -866,11 +873,9 @@ 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,
&self->cb_userdata, &self->rar_handle, &file_found,
&self->header_data);
@@ -888,7 +893,7 @@ static php_stream *php_stream_rar_opener(php_stream_wrapper *wrapper,
efree(mb_fragment);
goto cleanup;
}
/* once found, the password that matters is the file level password.
* we will NOT default on the open password if no file level password is
* given, but an open password is. This behaviour is differs from that of
@@ -930,10 +935,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);
@@ -976,25 +987,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,
@@ -1011,7 +1027,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_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");
@@ -1027,15 +1043,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_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;
@@ -1047,16 +1063,23 @@ 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;
}
/* }}} */
/* {{{ _rar_stream_tidy_wrapper_error_log */
/* {{{ _rar_stream_tidy_wrapper_error_log
* These two different versions are because of PHP commit 7166298 */
#if PHP_VERSION_ID <= 50310 || PHP_VERSION_ID == 50400
/* copied from main/streams/streams.c because it's an internal function */
static void _rar_stream_tidy_wrapper_error_log(php_stream_wrapper *wrapper TSRMLS_DC)
{
@@ -1074,11 +1097,23 @@ static void _rar_stream_tidy_wrapper_error_log(php_stream_wrapper *wrapper TSRML
wrapper->err_count = 0;
}
}
#else
static void _rar_stream_tidy_wrapper_error_log(php_stream_wrapper *wrapper TSRMLS_DC)
{
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)
@@ -1092,11 +1127,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;
@@ -1107,7 +1148,7 @@ static int php_stream_rar_stater(php_stream_wrapper *wrapper,
NULL, &volume_cb TSRMLS_CC);
}
/* end preliminaries }}} */
if (_rar_get_cachable_rararch(wrapper, options, open_path, open_passwd,
volume_cb, &rararch, &rar TSRMLS_CC) == FAILURE)
goto cleanup;
@@ -1137,16 +1178,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
@@ -1155,19 +1204,27 @@ 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;
}
/* }}} */
/* {{{ 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)
{
@@ -1189,10 +1246,10 @@ static php_stream *php_stream_rar_dir_opener(php_stream_wrapper *wrapper,
return NULL;
}
/* mode must be exactly "r" */
if (strncmp(mode, "r", sizeof("r")) != 0) {
/* mode must be "r" or "rb", which, for BC reasons, are treated identically */
if (mode[0] != 'r' || (mode[1] != '\0' && mode[1] != 'b') || strlen(mode) > 2) {
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC,
"Only the \"r\" open mode is permitted, given %s", mode);
"Only the \"r\" and \"rb\" open modes are permitted, given %s", mode);
return NULL;
}
@@ -1216,16 +1273,16 @@ static php_stream *php_stream_rar_dir_opener(php_stream_wrapper *wrapper,
fragment_len = wcslen(fragment);
self->directory = ecalloc(fragment_len + 1, sizeof *self->directory);
wmemcpy(self->directory, fragment, fragment_len + 1);
/* Remove the ending in the path separator */
if (fragment_len > 0 &&
self->directory[fragment_len - 1] == PATHDIVIDERW[0]) {
self->directory[fragment_len - 1] == SPATHDIVIDER[0]) {
self->directory[fragment_len - 1] = L'\0';
self->dir_size = fragment_len;
}
else
self->dir_size = fragment_len + 1;
_rar_entry_search_start(rar, RAR_SEARCH_DIRECTORY | RAR_SEARCH_NAME,
&self->state TSRMLS_CC);
if (self->dir_size != 1) { /* skip if asked for root */
@@ -1233,10 +1290,10 @@ static php_stream *php_stream_rar_dir_opener(php_stream_wrapper *wrapper,
* to the archive, which I'll assume occurs in all good archives */
_rar_entry_search_advance(
self->state, self->directory, self->dir_size, 0);
if (!self->state->found || ((self->state->header->Flags &
LHD_WINDOWMASK) != LHD_DIRECTORY)) {
if (!self->state->found || !(self->state->header->Flags &
RHDF_DIRECTORY)) {
const char *message;
char *mb_entry = _rar_wide_to_utf_with_alloc(self->directory,
char *mb_entry = _rar_wide_to_utf_with_alloc(self->directory,
(size_t) self->dir_size - 1);
if (!self->state->found)
@@ -1265,22 +1322,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

326
rararch.c
View File

@@ -41,14 +41,23 @@ extern "C" {
/* {{{ 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,17 +81,30 @@ 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 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
static zend_object_value rararch_ce_create_object(zend_class_entry *class_type TSRMLS_DC);
static void rararch_ce_destroy_object(ze_rararch_object *object,
zend_object_handle handle 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_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);
#if PHP_MAJOR_VERSION < 7
static zval *rararch_read_dimension(zval *object, zval *offset, int type TSRMLS_DC);
#else
static zval *rararch_read_dimension(zval *object, zval *offset, int type, zval *rv);
#endif
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);
/* }}} */
@@ -126,23 +148,21 @@ 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);
return SUCCESS;
} else {
*err_code = rar->list_open_data->OpenResult;
efree(rar->list_open_data->ArcName);
efree(rar->list_open_data->CmtBuf);
efree(rar->list_open_data);
@@ -157,7 +177,7 @@ int _rar_create_rararch_obj(const char* resolved_path,
void _rar_close_file_resource(rar_file_t *rar) /* {{{ */
{
assert(rar->arch_handle != NULL);
/* When changed from resource to custom object, instead of fiddling
* with the refcount to force object destruction, an indication that
* the file is already closed is given by setting rar->arch_handle
@@ -174,7 +194,7 @@ void _rar_close_file_resource(rar_file_t *rar) /* {{{ */
int _rar_get_file_resource_ex(zval *zval_file, rar_file_t **rar_file, int silent TSRMLS_DC) /* {{{ */
{
ze_rararch_object *zobj;
zobj = zend_object_store_get_object(zval_file TSRMLS_CC);
zobj = rararch_object_from_zv(zval_file TSRMLS_CC);
if (zobj == NULL) {
php_error_docref(NULL TSRMLS_CC, E_WARNING,
"Could not find object in the store. This is a bug, please report it.");
@@ -198,16 +218,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 {
@@ -216,22 +230,70 @@ 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));
}
#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;
@@ -249,38 +311,44 @@ static zend_object_value rararch_ce_create_object(zend_class_entry *class_type T
object_properties_init((zend_object*)zobj, class_type);
#endif
zov.handle = zend_objects_store_put(zobj,
(zend_objects_store_dtor_t) rararch_ce_destroy_object,
(zend_objects_store_dtor_t) zend_objects_destroy_object,
(zend_objects_free_object_storage_t) rararch_ce_free_object_storage,
NULL TSRMLS_CC);
zov.handlers = &rararch_object_handlers;
return zov;
}
/* }}} */
static void rararch_ce_destroy_object(ze_rararch_object *object,
zend_object_handle handle TSRMLS_DC) /* {{{ */
#else
static zend_object *rararch_ce_create_object(zend_class_entry *ce)
{
rar_file_t *rar = object->rar_file;
ze_rararch_object *zobj =
emalloc(sizeof(*zobj) + zend_object_properties_size(ce));
/* can safely assume rar != NULL here. This function is not called
* if object construction fails */
assert(rar != NULL);
zobj->rar_file = NULL;
zend_object_std_init(&zobj->parent, ce);
zobj->parent.handlers = &rararch_object_handlers;
/* not really relevant, calls destr. zend func. ce->destructor if it exists */
zend_objects_destroy_object((zend_object*) object, handle TSRMLS_CC);
if (rar->arch_handle != NULL) {
RARCloseArchive(rar->arch_handle);
}
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() */
if (rar != NULL) {
if (rar->arch_handle != NULL) {
RARCloseArchive(rar->arch_handle);
}
_rar_destroy_userdata(&rar->cb_userdata);
_rar_delete_entries(rar TSRMLS_CC);
@@ -292,11 +360,13 @@ static void rararch_ce_free_object_storage(ze_rararch_object *object TSRMLS_DC)
efree(rar->extract_open_data);
efree(rar);
}
/* could call zend_objects_free_object_storage here (not before!), but
* instead I'll mimic its behaviour */
zend_object_std_dtor((zend_object*) object TSRMLS_CC);
zend_object_std_dtor(&object->parent TSRMLS_CC);
#if PHP_MAJOR_VERSION < 7
efree(object);
#endif
}
/* }}} */
@@ -310,7 +380,7 @@ static int rararch_handlers_preamble(zval *object, rar_file_t **rar TSRMLS_DC) /
if (_rar_get_file_resource(object, rar TSRMLS_CC) == FAILURE) {
return FAILURE;
}
return _rar_handle_error(_rar_list_files(*rar TSRMLS_CC) TSRMLS_CC);
}
/* }}} */
@@ -364,20 +434,32 @@ static int rararch_dimensions_preamble(rar_file_t *rar,
}
else if (Z_TYPE_P(offset) == IS_OBJECT) {
if (Z_OBJ_HT_P(offset)->get) {
/* get handler cannot return NULL */
zval *newoffset = Z_OBJ_HT_P(offset)->get(offset TSRMLS_CC);
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 "
"an integer (get handler returned another object)");
return FAILURE;
}
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 {
@@ -411,11 +493,11 @@ 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(zval *object, long *count TSRMLS_DC)
{
rar_file_t *rar = NULL;
size_t entry_count;
if (rararch_handlers_preamble(object, &rar TSRMLS_CC) == FAILURE) {
*count = 0L;
return SUCCESS; /* intentional */
@@ -432,7 +514,11 @@ static int rararch_count_elements(zval *object, long *count TSRMLS_DC)
/* }}} */
/* {{{ 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(zval *object, zval *offset, int type, zval *rv)
#endif
{
long index;
rar_file_t *rar = NULL;
@@ -455,11 +541,17 @@ 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
_rar_entry_to_zval(object, out->header, out->packed_size, out->position,
ret TSRMLS_CC);
_rar_entry_search_end(out);
#if PHP_MAJOR_VERSION < 7
Z_DELREF_P(ret); /* set refcount to 0 */
#endif
return ret;
}
/* }}} */
@@ -508,8 +600,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;
@@ -540,7 +632,7 @@ PHP_FUNCTION(rar_open)
RETURN_FALSE;
}
}
if (_rar_create_rararch_obj(resolved_path, password, callable,
return_value, &err_code TSRMLS_CC) == FAILURE) {
const char *err_str = _rar_error_to_string(err_code);
@@ -575,9 +667,9 @@ PHP_FUNCTION(rar_list)
if (_rar_handle_error(_rar_list_files(rar TSRMLS_CC) TSRMLS_CC) == FAILURE)
RETURN_FALSE;
array_init(return_value);
_rar_raw_entries_to_array(rar, return_value TSRMLS_CC);
}
/* }}} */
@@ -589,7 +681,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;
@@ -611,7 +703,7 @@ PHP_FUNCTION(rar_entry_get)
if (_rar_handle_error(_rar_list_files(rar TSRMLS_CC) TSRMLS_CC) == FAILURE)
RETURN_FALSE;
filename_c = ecalloc(filename_len + 1, sizeof *filename_c);
filename_c = ecalloc(filename_len + 1, sizeof *filename_c);
_rar_utf_to_wide(filename, filename_c, filename_len + 1);
_rar_entry_search_start(rar, RAR_SEARCH_NAME, &sstate TSRMLS_CC);
@@ -624,7 +716,7 @@ PHP_FUNCTION(rar_entry_get)
_rar_handle_ext_error(
"cannot find file \"%s\" in Rar archive \"%s\""
TSRMLS_CC, filename, rar->list_open_data->ArcName);
RETVAL_FALSE;
RETVAL_FALSE;
}
_rar_entry_search_end(sstate);
@@ -662,7 +754,7 @@ PHP_FUNCTION(rar_comment_get)
if (_rar_get_file_resource(file, &rar TSRMLS_CC) == FAILURE) {
RETURN_FALSE;
}
cmt_state = rar->list_open_data->CmtState;
if (_rar_handle_error(cmt_state TSRMLS_CC) == FAILURE)
@@ -673,7 +765,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);
}
}
@@ -699,7 +791,7 @@ PHP_FUNCTION(rar_broken_is)
result = _rar_list_files(rar TSRMLS_CC);
rar->allow_broken = orig_allow_broken;
RETURN_BOOL(_rar_error_to_string(result) != NULL);
RETURN_BOOL(_rar_error_to_string(result) != NULL);
}
/* {{{ proto bool rar_allow_broken_set(RarArchive rarfile, bool allow_broken)
@@ -760,7 +852,7 @@ PHP_METHOD(rararch, __toString)
char *restring;
size_t restring_size;
int is_closed;
RAR_RETNULL_ON_ARGS();
if (_rar_get_file_resource_ex(arch_obj, &rar, TRUE TSRMLS_CC) == FAILURE) {
@@ -779,8 +871,8 @@ PHP_METHOD(rararch, __toString)
snprintf(restring, restring_size, format, rar->list_open_data->ArcName,
is_closed?closed:"");
restring[restring_size - 1] = '\0'; /* just to be safe */
RETURN_STRINGL(restring, (int) restring_size - 1, 0);
RAR_RETURN_STRINGL(restring, (int) restring_size - 1, 0);
}
/* }}} */
@@ -830,8 +922,12 @@ 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);
/* }}} */
@@ -852,6 +948,19 @@ static zend_object_iterator *rararch_it_get_iterator(zend_class_entry *ce,
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
it->parent.funcs = ce->iterator_funcs.funcs;
it->state = NULL;
res = _rar_get_file_resource_ex(object, &rar, 1 TSRMLS_CC);
if (res == FAILURE)
php_error_docref(NULL TSRMLS_CC, E_ERROR,
@@ -859,7 +968,7 @@ static zend_object_iterator *rararch_it_get_iterator(zend_class_entry *ce,
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);
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;
@@ -867,11 +976,7 @@ static zend_object_iterator *rararch_it_get_iterator(zend_class_entry *ce,
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;
}
/* }}} */
@@ -880,10 +985,15 @@ static zend_object_iterator *rararch_it_get_iterator(zend_class_entry *ce,
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
}
/* }}} */
@@ -891,13 +1001,19 @@ static void rararch_it_invalidate_current(zend_object_iterator *iter TSRMLS_DC)
static void rararch_it_dtor(zend_object_iterator *iter TSRMLS_DC)
{
rararch_iterator *it = (rararch_iterator *) iter;
rararch_it_invalidate_current((zend_object_iterator *) it TSRMLS_CC);
#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
}
/* }}} */
@@ -906,40 +1022,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_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)
{
@@ -947,6 +1095,20 @@ 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;
#if PHP_MAJOR_VERSION < 7
ret = ((rararch_iterator *) iter)->value;
assert(ret != NULL);
#else
ret = &((rararch_iterator *) iter)->value;
assert(Z_TYPE_P(ret) != IS_UNDEF);
#endif
return ret;
}
#endif
/* }}} */
/* {{{ rararch_it_move_forward */
@@ -954,7 +1116,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);
}
/* }}} */
@@ -965,7 +1131,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);
}
/* }}} */
@@ -993,6 +1158,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);

View File

@@ -34,30 +34,27 @@ extern "C" {
#define _GNU_SOURCE
#include <string.h>
#include "php.h"
#include <php.h>
#include "php_rar.h"
/* {{{ Globals with external linkage */
zend_class_entry *rar_class_entry_ptr;
/* }}} */
/* {{{ Globals with internal linkage */
static zend_object_handlers rarentry_object_handlers;
/* }}} */
/* {{{ Function prototypes for functions with internal linkage */
static int _rar_decl_priv_prop_null(zend_class_entry *ce, const char *name,
int name_length, char *doc_comment,
int doc_comment_len TSRMLS_DC);
static zval **_rar_entry_get_property(zval *entry_obj, char *name, int namelen TSRMLS_DC);
static void _rar_dos_date_to_text(int dos_time, char *date_string);
static zend_object_value rarentry_ce_create_object(zend_class_entry *class_type TSRMLS_DC);
static zval *_rar_entry_get_property(zval *entry_obj, char *name, int namelen 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,
@@ -66,12 +63,21 @@ void _rar_entry_to_zval(zval *parent, /* zval to RarArchive object, will have it
char tmp_s [MAX_LENGTH_OF_LONG + 1];
char time[50];
char *filename;
int filename_size, filename_len;
int filename_size,
filename_len;
long unp_size; /* zval stores PHP ints as long, so use that here */
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);
sizeof("rararch") - 1, parent_copy TSRMLS_CC);
#if ULONG_MAX > 0xffffffffUL
unp_size = ((long) entry->UnpSize) + (((long) entry->UnpSizeHigh) << 32);
@@ -84,7 +90,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)
@@ -106,15 +112,15 @@ void _rar_entry_to_zval(zval *parent, /* zval to RarArchive object, will have it
sizeof("packed_size") - 1, packed_size TSRMLS_CC);
zend_update_property_long(rar_class_entry_ptr, object, "host_os",
sizeof("host_os") - 1, entry->HostOS TSRMLS_CC);
_rar_dos_date_to_text(entry->FileTime, time);
zend_update_property_string(rar_class_entry_ptr, object, "file_time",
sizeof("file_time") - 1, time TSRMLS_CC);
sprintf(tmp_s, "%x", entry->FileCRC);
zend_update_property_string(rar_class_entry_ptr, object, "crc",
sizeof("crc") - 1, tmp_s TSRMLS_CC);
zend_update_property_long(rar_class_entry_ptr, object, "attr",
sizeof("attr") - 1, entry->FileAttr TSRMLS_CC);
zend_update_property_long(rar_class_entry_ptr, object, "version",
@@ -124,6 +130,28 @@ void _rar_entry_to_zval(zval *parent, /* zval to RarArchive object, will have it
zend_update_property_long(rar_class_entry_ptr, object, "flags",
sizeof("flags") - 1, entry->Flags TSRMLS_CC);
zend_update_property_long(rar_class_entry_ptr, object, "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, object,
"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, object, "redir_target",
sizeof("redir_target") - 1, redir_target TSRMLS_CC);
efree(redir_target);
}
efree(filename);
}
/* }}} */
@@ -152,81 +180,76 @@ 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);
ret = zend_declare_property_ex(ce, name_str, &property, ZEND_ACC_PRIVATE,
doc_str);
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) /* {{{ */
static zval *_rar_entry_get_property(zval *entry_obj, char *name, int namelen TSRMLS_DC) /* {{{ */
{
zval **tmp;
zval member;
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
INIT_ZVAL(member);
Z_TYPE(member) = IS_STRING;
Z_STRVAL(member) = name;
Z_STRLEN(member) = namelen;
/* probably should be replaced by zend_read_property */
#if PHP_VERSION_ID < 50399
tmp = Z_OBJ_HANDLER_P(entry_obj, get_property_ptr_ptr)(entry_obj, &member
TSRMLS_CC);
#if PHP_MAJOR_VERSION < 7
tmp = zend_read_property(Z_OBJCE_P(entry_obj), entry_obj, name, namelen, 1 TSRMLS_CC);
#else
tmp = Z_OBJ_HANDLER_P(entry_obj, get_property_ptr_ptr)(entry_obj, &member,
NULL TSRMLS_CC);
tmp = zend_read_property(Z_OBJCE_P(entry_obj), entry_obj, name, namelen, 1, &zv);
#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);
}
/* }}} */
/* }}} */
@@ -240,7 +263,7 @@ PHP_METHOD(rarentry, extract)
char *dir,
*filepath = NULL,
*password = NULL;
int dir_len,
zpp_s_size_t dir_len,
filepath_len = 0,
password_len = 0;
char *considered_path;
@@ -248,8 +271,8 @@ PHP_METHOD(rarentry, extract)
int with_second_arg;
zend_bool process_ed = 0;
zval **tmp,
**tmp_position;
zval *tmp,
*tmp_position;
rar_file_t *rar = NULL;
zval *entry_obj = getThis();
struct RARHeaderDataEx entry;
@@ -259,7 +282,7 @@ PHP_METHOD(rarentry, extract)
/* gotta have a new copy (shallow is enough) because we may want to use a
* password that's different from the one stored in the rar_file_t object*/
rar_cb_user_data cb_udata = {NULL};
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ss!b", &dir,
&dir_len, &filepath, &filepath_len, &password, &password_len,
&process_ed) == FAILURE ) {
@@ -267,7 +290,7 @@ PHP_METHOD(rarentry, extract)
}
RAR_GET_PROPERTY(tmp, "rarfile");
if (_rar_get_file_resource(*tmp, &rar TSRMLS_CC) == FAILURE) {
if (_rar_get_file_resource(tmp, &rar TSRMLS_CC) == FAILURE) {
RETURN_FALSE;
}
@@ -284,14 +307,14 @@ PHP_METHOD(rarentry, extract)
else {
considered_path = filepath;
}
if (OPENBASEDIR_CHECKPATH(considered_path)) {
RETURN_FALSE;
}
if (!expand_filepath(considered_path, considered_path_res TSRMLS_CC)) {
RETURN_FALSE;
}
/* Find file inside archive */
RAR_GET_PROPERTY(tmp_position, "position");
@@ -304,7 +327,7 @@ PHP_METHOD(rarentry, extract)
memcpy(&cb_udata, &rar->cb_userdata, sizeof cb_udata);
result = _rar_find_file_p(rar->extract_open_data,
(size_t) Z_LVAL_PP(tmp_position), &cb_udata, &extract_handle, &found,
(size_t) Z_LVAL_P(tmp_position), &cb_udata, &extract_handle, &found,
&entry);
if (_rar_handle_error(result TSRMLS_CC) == FAILURE) {
@@ -314,7 +337,7 @@ PHP_METHOD(rarentry, extract)
if (!found) {
_rar_handle_ext_error("Can't find file with index %d in archive %s"
TSRMLS_CC, Z_LVAL_PP(tmp_position),
TSRMLS_CC, Z_LVAL_P(tmp_position),
rar->extract_open_data->ArcName);
RETVAL_FALSE;
goto cleanup;
@@ -341,7 +364,7 @@ PHP_METHOD(rarentry, extract)
else {
RETVAL_TRUE;
}
cleanup:
if (extract_handle != NULL)
RARCloseArchive(extract_handle);
@@ -352,14 +375,14 @@ cleanup:
Return position for the entry */
PHP_METHOD(rarentry, getPosition)
{
zval **tmp;
zval *tmp;
zval *entry_obj = getThis();
RAR_RETNULL_ON_ARGS();
RAR_GET_PROPERTY(tmp, "position");
RETURN_LONG(Z_LVAL_PP(tmp));
RETURN_LONG(Z_LVAL_P(tmp));
}
/* }}} */
@@ -367,14 +390,14 @@ PHP_METHOD(rarentry, getPosition)
Return entry name */
PHP_METHOD(rarentry, getName)
{
zval **tmp;
zval *tmp;
zval *entry_obj = getThis();
RAR_RETNULL_ON_ARGS();
RAR_GET_PROPERTY(tmp, "name");
RETURN_STRINGL(Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp), 1);
RAR_RETURN_STRINGL(Z_STRVAL_P(tmp), Z_STRLEN_P(tmp), 1);
}
/* }}} */
@@ -382,14 +405,14 @@ PHP_METHOD(rarentry, getName)
Return unpacked size of the entry */
PHP_METHOD(rarentry, getUnpackedSize)
{
zval **tmp;
zval *tmp;
zval *entry_obj = getThis();
RAR_RETNULL_ON_ARGS();
RAR_GET_PROPERTY(tmp, "unpacked_size");
RETURN_LONG(Z_LVAL_PP(tmp));
RETURN_LONG(Z_LVAL_P(tmp));
}
/* }}} */
@@ -397,14 +420,14 @@ PHP_METHOD(rarentry, getUnpackedSize)
Return packed size of the entry */
PHP_METHOD(rarentry, getPackedSize)
{
zval **tmp;
zval *tmp;
zval *entry_obj = getThis();
RAR_RETNULL_ON_ARGS();
RAR_GET_PROPERTY(tmp, "packed_size");
RETURN_LONG(Z_LVAL_PP(tmp));
RETURN_LONG(Z_LVAL_P(tmp));
}
/* }}} */
@@ -412,29 +435,31 @@ PHP_METHOD(rarentry, getPackedSize)
Return host OS of the entry */
PHP_METHOD(rarentry, getHostOs)
{
zval **tmp;
zval *tmp;
zval *entry_obj = getThis();
RAR_RETNULL_ON_ARGS();
RAR_GET_PROPERTY(tmp, "host_os");
RETURN_LONG(Z_LVAL_PP(tmp));
RETURN_LONG(Z_LVAL_P(tmp));
}
/* }}} */
/* {{{ proto string RarEntry::getFileTime()
Return modification time of the entry */
Return modification time of the entry.
Due to the way the unrar library returns this time, this is in the
system's timezone. */
PHP_METHOD(rarentry, getFileTime)
{
zval **tmp;
zval *tmp;
zval *entry_obj = getThis();
RAR_RETNULL_ON_ARGS();
RAR_GET_PROPERTY(tmp, "file_time");
RETURN_STRINGL(Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp), 1);
RAR_RETURN_STRINGL(Z_STRVAL_P(tmp), Z_STRLEN_P(tmp), 1);
}
/* }}} */
@@ -442,14 +467,14 @@ PHP_METHOD(rarentry, getFileTime)
Return CRC of the entry */
PHP_METHOD(rarentry, getCrc)
{
zval **tmp;
zval *tmp;
zval *entry_obj = getThis();
RAR_RETNULL_ON_ARGS();
RAR_GET_PROPERTY(tmp, "crc");
RETURN_STRINGL(Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp), 1);
RAR_RETURN_STRINGL(Z_STRVAL_P(tmp), Z_STRLEN_P(tmp), 1);
}
/* }}} */
@@ -457,14 +482,14 @@ PHP_METHOD(rarentry, getCrc)
Return attributes of the entry */
PHP_METHOD(rarentry, getAttr)
{
zval **tmp;
zval *tmp;
zval *entry_obj = getThis();
RAR_RETNULL_ON_ARGS();
RAR_GET_PROPERTY(tmp, "attr");
RETURN_LONG(Z_LVAL_PP(tmp));
RETURN_LONG(Z_LVAL_P(tmp));
}
/* }}} */
@@ -472,14 +497,14 @@ PHP_METHOD(rarentry, getAttr)
Return version of the archiver, used to create this entry */
PHP_METHOD(rarentry, getVersion)
{
zval **tmp;
zval *tmp;
zval *entry_obj = getThis();
RAR_RETNULL_ON_ARGS();
RAR_GET_PROPERTY(tmp, "version");
RETURN_LONG(Z_LVAL_PP(tmp));
RETURN_LONG(Z_LVAL_P(tmp));
}
/* }}} */
@@ -487,14 +512,14 @@ PHP_METHOD(rarentry, getVersion)
Return packing method */
PHP_METHOD(rarentry, getMethod)
{
zval **tmp;
zval *tmp;
zval *entry_obj = getThis();
RAR_RETNULL_ON_ARGS();
RAR_GET_PROPERTY(tmp, "method");
RETURN_LONG(Z_LVAL_PP(tmp));
RETURN_LONG(Z_LVAL_P(tmp));
}
/* }}} */
@@ -502,16 +527,16 @@ PHP_METHOD(rarentry, getMethod)
Return stream for current entry */
PHP_METHOD(rarentry, getStream)
{
zval **tmp,
**position;
zval *tmp,
*position;
rar_file_t *rar = NULL;
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};
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!",
&password, &password_len) == FAILURE ) {
return;
@@ -519,7 +544,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(tmp, &rar TSRMLS_CC) == FAILURE) {
RETURN_FALSE;
}
@@ -530,8 +555,8 @@ PHP_METHOD(rarentry, getStream)
/* doesn't matter that cb_udata is stack allocated, it will be copied */
stream = php_stream_rar_open(rar->extract_open_data->ArcName,
Z_LVAL_PP(position), &cb_udata, "r" STREAMS_CC TSRMLS_CC);
Z_LVAL_P(position), &cb_udata STREAMS_CC TSRMLS_CC);
if (stream != NULL) {
php_stream_to_zval(stream, return_value);
}
@@ -544,17 +569,17 @@ PHP_METHOD(rarentry, getStream)
Return whether the entry represents a directory */
PHP_METHOD(rarentry, isDirectory)
{
zval **tmp;
zval *tmp;
zval *entry_obj = getThis();
long flags;
int is_dir;
RAR_RETNULL_ON_ARGS();
RAR_GET_PROPERTY(tmp, "flags");
flags = Z_LVAL_PP(tmp);
is_dir = ((flags & LHD_WINDOWMASK) == LHD_DIRECTORY);
flags = Z_LVAL_P(tmp);
is_dir = (flags & RHDF_DIRECTORY) != 0;
RETURN_BOOL(is_dir);
}
/* }}} */
@@ -563,58 +588,112 @@ PHP_METHOD(rarentry, isDirectory)
Return whether the entry is encrypted and needs a password */
PHP_METHOD(rarentry, isEncrypted)
{
zval **tmp;
zval *tmp;
zval *entry_obj = getThis();
long flags;
int is_encrypted;
RAR_RETNULL_ON_ARGS();
RAR_GET_PROPERTY(tmp, "flags");
flags = Z_LVAL_PP(tmp);
is_encrypted = (flags & 0x04);
flags = Z_LVAL_P(tmp);
is_encrypted = (flags & RHDF_ENCRYPTED) != 0;
RETURN_BOOL(is_encrypted);
}
/* }}} */
/* {{{ 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)
{
zval **flags_zval,
**name_zval,
**crc_zval;
zval *flags_zval,
*name_zval,
*crc_zval;
zval *entry_obj = getThis();
long flags;
int is_dir;
char *name,
*crc;
char *restring;
int restring_len;
int restring_size;
const char format[] = "RarEntry for %s \"%s\" (%s)";
RAR_RETNULL_ON_ARGS();
RAR_GET_PROPERTY(flags_zval, "flags");
flags = Z_LVAL_PP(flags_zval);
is_dir = ((flags & 0xE0) == 0xE0);
flags = Z_LVAL_P(flags_zval);
is_dir = flags & RHDF_DIRECTORY;
RAR_GET_PROPERTY(name_zval, "name");
name = Z_STRVAL_PP(name_zval);
name = Z_STRVAL_P(name_zval);
RAR_GET_PROPERTY(crc_zval, "crc");
crc = Z_STRVAL_PP(crc_zval);
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 */
RETURN_STRING(restring, 0);
restring[restring_size - 1] = '\0'; /* just to be safe */
RAR_RETURN_STRINGL(restring, strlen(restring), 0);
}
/* }}} */
/* }}} */
@@ -650,6 +729,9 @@ 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, 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_void, ZEND_ACC_PUBLIC)
PHP_ME_MAPPING(__construct, rar_bogus_ctor, arginfo_rar_void, ZEND_ACC_PRIVATE | ZEND_ACC_CTOR)
{NULL, NULL, NULL}
@@ -659,15 +741,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");
@@ -681,7 +758,10 @@ 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);
REG_RAR_CLASS_CONST_LONG("HOST_WIN32", HOST_WIN32);
@@ -689,6 +769,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);

View File

@@ -24,7 +24,7 @@ array(2) {
[0]=>
object(RarEntry)#%d (%d) {
["rarfile%sprivate%s=>
object(RarArchive)#%s (%s) {
object(RarArchive)#%d (%d) {
}
["position%sprivate%s=>
int(0)
@@ -47,12 +47,18 @@ array(2) {
["method%sprivate%s=>
int(51)
["flags%sprivate%s=>
int(32800)
int(0)
["redir_type%sprivate]=>
int(0)
["redir_to_directory%sprivate]=>
NULL
["redir_target%sprivate]=>
NULL
}
[1]=>
object(RarEntry)#%d (%d) {
["rarfile%sprivate%s=>
object(RarArchive)#%d (0) {
object(RarArchive)#%d (%d) {
}
["position%sprivate%s=>
int(1)
@@ -75,7 +81,13 @@ array(2) {
["method%sprivate%s=>
int(51)
["flags%sprivate%s=>
int(32800)
int(0)
["redir_type%sprivate]=>
int(0)
["redir_to_directory%sprivate]=>
NULL
["redir_target%sprivate]=>
NULL
}
}
array(2) {
@@ -105,7 +117,13 @@ array(2) {
["method%sprivate%s=>
int(53)
["flags%sprivate%s=>
int(36992)
int(0)
["redir_type%sprivate]=>
int(0)
["redir_to_directory%sprivate]=>
NULL
["redir_target%sprivate]=>
NULL
}
[1]=>
object(RarEntry)#%d (%d) {
@@ -133,7 +151,13 @@ array(2) {
["method%sprivate%s=>
int(53)
["flags%sprivate%s=>
int(37008)
int(16)
["redir_type%sprivate]=>
int(0)
["redir_to_directory%sprivate]=>
NULL
["redir_target%sprivate]=>
NULL
}
}

View File

@@ -45,7 +45,13 @@ object(RarEntry)#%d (%d) {
["method%sprivate%s=>
int(51)
["flags%sprivate%s=>
int(32800)
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=>
@@ -72,7 +78,13 @@ object(RarEntry)#%d (%d) {
["method%sprivate%s=>
int(53)
["flags%sprivate%s=>
int(37008)
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

View File

@@ -55,7 +55,7 @@ blah-blah-blah
string(5) "22222"
object(RarEntry)#%d (%d) {
["rarfile%sprivate%s=>
object(RarArchive)#3 (0) {
object(RarArchive)#%d (%d) {
}
["position%sprivate%s=>
int(1)
@@ -78,7 +78,13 @@ object(RarEntry)#%d (%d) {
["method%sprivate%s=>
int(53)
["flags%sprivate%s=>
int(37008)
int(16)
["redir_type%sprivate%s=>
int(0)
["redir_to_directory%sprivate%s=>
NULL
["redir_target%sprivate%s=>
NULL
}
bool(true)
Done

View File

@@ -33,9 +33,9 @@ echo "Done\n";
--EXPECTF--
51 files (will test only the first 4):
: The great battle of Gunprex versus Optiter!!!!!1
test%s: The great battle of Gunprex versus Optiter!!!!!1
Gunprex, Fire!
So long, Optiter!
:
test%s
Done

View File

@@ -29,11 +29,11 @@ $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 = RarArchive::open($fn, null, 'strpos');
$rar->getEntries();
echo "\nGiven callback that takes another kind of arguments:\n";
$rar = RarArchive::open($fn, null, 'ksort');
$rar = RarArchive::open($fn, null, 'array_keys');
$rar->getEntries();
echo "\nGiven callback that returns another kind of arguments:\n";
@@ -64,15 +64,13 @@ bool(false)
Given callback that takes more arguments:
Warning: array_walk() expects at least %d parameters, 1 given in %s on line %d
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
Given callback that takes another kind of arguments:
Warning: ksort() expects parameter 1 to be array, string given in %s on line %d
Warning: RarArchive::getEntries(): Wrong type returned by volume find callback, expected string or NULL in %s on line %d
Warning: 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

View File

@@ -5,9 +5,9 @@ RarArchive::open() volume callback long return (case MAXPATHLEN > NM)
if(!extension_loaded("rar")) die("skip");
if (!defined("PHP_MAXPATHLEN"))
define("PHP_MAXPATHLEN", RAR_MAXPATHLEN);
if (!(PHP_MAXPATHLEN > 1024))
die("skip test is for systems where MAXPATHLEN > 1024");
$rp = dirname(__FILE__) . "/" . str_repeat("a", 1024);
if (!(PHP_MAXPATHLEN > 2048))
die("skip test is for systems where MAXPATHLEN > 2048");
$rp = dirname(__FILE__) . "/" . str_repeat("a", 2048);
if (strlen(dirname(__FILE__) > PHP_MAXPATHLEN - 1))
die("skip current directory is too deep.");
--FILE--
@@ -17,8 +17,8 @@ if (!defined("PHP_MAXPATHLEN"))
chdir(dirname(__FILE__));
$fn = dirname(__FILE__) . '/multi_broken.part1.rar';
function testA($vol) { if ($vol[0] != 'a') return str_repeat("a", 1024); }
function testA($vol) { if ($vol[0] != 'a') return str_repeat("a", 2048); }
$rar = RarArchive::open($fn, null, 'testA');
$rar->getEntries();

View File

@@ -3,13 +3,21 @@ RAR file stream stat
--SKIPIF--
<?php
if(!extension_loaded("rar")) die("skip");
--ENV--
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--

View File

@@ -3,6 +3,8 @@ url stat test
--SKIPIF--
<?php
if(!extension_loaded("rar")) die("skip");
--ENV--
TZ=Europe/Lisbon
--FILE--
<?php
umask(0);

View File

@@ -3,6 +3,8 @@ RAR directory stream stat
--SKIPIF--
<?php
if(!extension_loaded("rar")) die("skip");
--ENV--
TZ=Europe/Lisbon
--FILE--
<?php
umask(0);
@@ -19,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--

View File

@@ -1,7 +1,9 @@
--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");
--FILE--
<?php

View File

@@ -1,7 +1,8 @@
--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");
--FILE--
<?php

View File

@@ -37,7 +37,6 @@ echo "Done.\n";
--EXPECTF--
RAR support => enabled
RAR EXT version => %d.%d.%s
Revision => %s
UnRAR version => %d.%d%spatch%d %d-%d-%d
UnRAR API version => %d extension %d

29
tests/099.phpt Normal file
View File

@@ -0,0 +1,29 @@
--TEST--
Bug #59939: Streaming empty file from archive issues a warning
--SKIPIF--
<?php if(!extension_loaded("rar")) print "skip"; ?>
--FILE--
<?php
$rar = RarArchive::open(dirname(__FILE__) . '/empty_file.rar');
if ($rar === false) die("could not open RAR file");
$rar_file = $rar->getEntry('empty_file');
if ($rar_file === false) die("could not find entry");
$stream = $rar_file->getStream();
if ($stream === false) die("could not open stream");
var_dump(feof($stream),
fread($stream, 1024*1024),
feof($stream));
echo "\n";
echo "Done.\n";
?>
--EXPECT--
bool(false)
string(0) ""
bool(true)
Done.

37
tests/100.phpt Normal file
View File

@@ -0,0 +1,37 @@
--TEST--
fopen modes 'r' and 'rb' are the only allowed
--SKIPIF--
<?php if(!extension_loaded("rar")) print "skip"; ?>
--FILE--
<?php
$file = 'rar://' . rawurlencode(dirname(__FILE__) . '/linux_rar.rar')
. '#/plain.txt';
echo "Testing 'r'\n";
$fd = fopen($file, 'r');
if ($fd) echo "opened\n\n";
echo "Testing 'rb'\n";
$fd = fopen($file, 'rb');
if ($fd) echo "opened\n\n";
echo "Testing 'r+'\n";
$fd = fopen($file, 'r+');
if ($fd) echo "opened\n\n";
echo "\n";
echo "Done.\n";
?>
--EXPECTF--
Testing 'r'
opened
Testing 'rb'
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
Done.

54
tests/101.phpt Normal file
View File

@@ -0,0 +1,54 @@
--TEST--
Supports version 5 RAR files
--SKIPIF--
<?php if(!extension_loaded("rar")) die("skip");
if (isset($_ENV['APPVEYOR'])) die("skip failing on appveyor");
--FILE--
<?php
RarException::setUsingExceptions(true);
$file = dirname(__FILE__) . '/rar5_multi.part1.rar';
$rar = RarArchive::open($file);
$entry = $rar->getEntry('usr' . DIRECTORY_SEPARATOR . 'bin' .
DIRECTORY_SEPARATOR . 'text2image');
var_dump($entry);
$stream = $entry->getStream('passw0rd');
$contents = stream_get_contents($stream);
echo "(unpacked) MD5: ", md5($contents), "\n";
echo "Done.\n";
?>
--EXPECTF--
object(RarEntry)#%d (%d) {
["rarfile%sprivate%s=>
object(RarArchive)#%d (%d) {
}
["position%sprivate%s=>
int(0)
["name%sprivate%s=>
string(18) "usr%sbin%stext2image"
["unpacked_size%sprivate%s=>
int(147528)
["packed_size%sprivate%s=>
int(57104)
["host_os%sprivate%s=>
int(3)
["file_time%sprivate%s=>
string(19) "%s"
["crc%sprivate%s=>
string(8) "83c9a6b7"
["attr%sprivate%s=>
int(33261)
["version%sprivate%s=>
int(200)
["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 invalid context 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 invalid context 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(200)
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.

BIN
tests/empty_file.rar Normal file

Binary file not shown.

BIN
tests/rar5-links.rar Normal file

Binary file not shown.

BIN
tests/rar5_multi.part1.rar Normal file

Binary file not shown.

BIN
tests/rar5_multi.part2.rar Normal file

Binary file not shown.

86
travis.sh Executable file
View File

@@ -0,0 +1,86 @@
#!/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 coverage=$2
"$prefix"/bin/phpize
if [[ $coverage = 'yes' ]]; then
export CPPFLAGS="$CPPFLAGS --coverage"
fi
./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)"
echo "--suppressions=$dir/valgrind.supp" | tee ~/.valgrindrc
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
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 {} \;
return 1
fi
}
# 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)" "$3"
fi
}
function run_tests {
set -e
set -o pipefail
do_tests "$(prefix $1 $2)"
}

View File

@@ -10,13 +10,15 @@
1. All copyrights to RAR and the utility UnRAR are exclusively
owned by the author - Alexander Roshal.
2. The UnRAR sources may be used in any software to handle RAR
archives without limitations free of charge, but cannot be used
to re-create the RAR compression algorithm, which is proprietary.
Distribution of modified UnRAR sources in separate form or as a
part of other software is permitted, provided that it is clearly
stated in the documentation and source comments that the code may
not be used to develop a RAR (WinRAR) compatible archiver.
2. UnRAR source code may be used in any software to handle
RAR archives without limitations free of charge, but cannot be
used to develop RAR (WinRAR) compatible archiver and to
re-create RAR compression algorithm, which is proprietary.
Distribution of modified UnRAR source code in separate form
or as a part of other software is permitted, provided that
full text of this paragraph, starting from "UnRAR source code"
words, is included in license, or in documentation if license
is not available, and in source code comments of resulting package.
3. The UnRAR utility may be freely distributed. It is allowed
to distribute UnRAR inside of other software packages.
@@ -37,4 +39,4 @@
Thank you for your interest in RAR and UnRAR.
Alexander L. Roshal
Alexander L. Roshal

View File

@@ -4,12 +4,13 @@
1. General
This package includes freeware Unrar C++ source and a few makefiles
(makefile.bcc, makefile.msc+msc.dep, makefile.unix). Unrar source
is subset of RAR and generated from RAR source automatically,
This package includes freeware Unrar C++ source and makefile for
several Unix compilers.
Unrar source is subset of RAR and generated from RAR source automatically,
by a small program removing blocks like '#ifndef UNRAR ... #endif'.
Such method is not perfect and you may find some RAR related
stuff unnecessary in Unrar, especially in header files.
Such method is not perfect and you may find some RAR related stuff
unnecessary in Unrar, especially in header files.
If you wish to port Unrar to a new platform, you may need to edit
'#define LITTLE_ENDIAN' in os.hpp and data type definitions
@@ -17,16 +18,7 @@
if computer architecture does not allow not aligned data access,
you need to undefine ALLOW_NOT_ALIGNED_INT and define
STRICT_ALIGNMENT_REQUIRED in os.h. Note that it will increase memory
requirements.
If you use Borland C++ makefile (makefile.bcc), you need to define
BASEPATHCC environment (or makefile) variable containing
the path to Borland C++ installation.
Makefile.unix contains numerous compiler option sets.
GCC Linux is selected by default. If you need to compile Unrar
for other platforms, uncomment corresponding lines.
STRICT_ALIGNMENT_REQUIRED in os.h.
2. Unrar binaries
@@ -38,16 +30,8 @@
3. Acknowledgements
This source includes parts of code written by the following authors:
Dmitry Shkarin PPMII v.H text compression
Dmitry Subbotin Carryless rangecoder
Szymon Stefanek AES encryption
Brian Gladman AES encryption
Steve Reid SHA-1 hash function
Marcus Herbert makefile.unix file
Tomasz Klim fixes for libunrar.so
Robert Riebisch makefile.dj and patches for DJGPP
This source includes parts of code written by other authors.
Please see acknow.txt file for details.
4. Legal stuff

279
unrar/UnRAR.vcxproj Normal file
View File

@@ -0,0 +1,279 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{95CC809B-03FC-4EDB-BB20-FD07A698C05F}</ProjectGuid>
<RootNamespace>UnRAR</RootNamespace>
<Keyword>Win32Proj</Keyword>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v140_xp</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
<WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v140_xp</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v140_xp</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
<WholeProgramOptimization>false</WholeProgramOptimization>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v140_xp</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_ProjectFileVersion>14.0.24720.0</_ProjectFileVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<OutDir>build\unrar32\$(Configuration)\</OutDir>
<IntDir>build\unrar32\$(Configuration)\obj\</IntDir>
<LinkIncremental>true</LinkIncremental>
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<OutDir>build\unrar64\$(Configuration)\</OutDir>
<IntDir>build\unrar64\$(Configuration)\obj\</IntDir>
<LinkIncremental>true</LinkIncremental>
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<OutDir>build\unrar32\$(Configuration)\</OutDir>
<IntDir>build\unrar32\$(Configuration)\obj\</IntDir>
<LinkIncremental>false</LinkIncremental>
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<OutDir>build\unrar64\$(Configuration)\</OutDir>
<IntDir>build\unrar64\$(Configuration)\obj\</IntDir>
<LinkIncremental>false</LinkIncremental>
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<AdditionalOptions>/MP %(AdditionalOptions)</AdditionalOptions>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>UNRAR;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>false</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>rar.hpp</PrecompiledHeaderFile>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<CallingConvention>StdCall</CallingConvention>
<DisableSpecificWarnings>4007;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<TargetMachine>MachineX86</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
</Midl>
<ClCompile>
<AdditionalOptions>/MP %(AdditionalOptions)</AdditionalOptions>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>UNRAR;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>false</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>rar.hpp</PrecompiledHeaderFile>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<CallingConvention>StdCall</CallingConvention>
<DisableSpecificWarnings>4007;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<EnableEnhancedInstructionSet>NotSet</EnableEnhancedInstructionSet>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<TargetMachine>MachineX64</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<AdditionalOptions>/MP %(AdditionalOptions)</AdditionalOptions>
<Optimization>MaxSpeed</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions>
<FavorSizeOrSpeed>Neither</FavorSizeOrSpeed>
<OmitFramePointers>true</OmitFramePointers>
<WholeProgramOptimization>false</WholeProgramOptimization>
<PreprocessorDefinitions>UNRAR;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>false</MinimalRebuild>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<StructMemberAlignment>Default</StructMemberAlignment>
<BufferSecurityCheck>true</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
<EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
<FloatingPointModel>Precise</FloatingPointModel>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>rar.hpp</PrecompiledHeaderFile>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<CallingConvention>StdCall</CallingConvention>
<DisableSpecificWarnings>4007;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<LinkTimeCodeGeneration />
<TargetMachine>MachineX86</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
</Midl>
<ClCompile>
<AdditionalOptions>/MP %(AdditionalOptions)</AdditionalOptions>
<Optimization>MinSpace</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions>
<FavorSizeOrSpeed>Neither</FavorSizeOrSpeed>
<OmitFramePointers>true</OmitFramePointers>
<WholeProgramOptimization>false</WholeProgramOptimization>
<PreprocessorDefinitions>UNRAR;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>false</StringPooling>
<MinimalRebuild>false</MinimalRebuild>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<BufferSecurityCheck>true</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>rar.hpp</PrecompiledHeaderFile>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<CallingConvention>StdCall</CallingConvention>
<DisableSpecificWarnings>4007;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<EnableEnhancedInstructionSet>NotSet</EnableEnhancedInstructionSet>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<LinkTimeCodeGeneration />
<TargetMachine>MachineX64</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="archive.cpp" />
<ClCompile Include="arcread.cpp" />
<ClCompile Include="blake2s.cpp" />
<ClCompile Include="cmddata.cpp" />
<ClCompile Include="consio.cpp" />
<ClCompile Include="crc.cpp" />
<ClCompile Include="crypt.cpp" />
<ClCompile Include="encname.cpp" />
<ClCompile Include="errhnd.cpp" />
<ClCompile Include="extinfo.cpp" />
<ClCompile Include="extract.cpp" />
<ClCompile Include="filcreat.cpp" />
<ClCompile Include="file.cpp" />
<ClCompile Include="filefn.cpp" />
<ClCompile Include="filestr.cpp" />
<ClCompile Include="find.cpp" />
<ClCompile Include="getbits.cpp" />
<ClCompile Include="global.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
</PrecompiledHeader>
</ClCompile>
<ClCompile Include="hash.cpp" />
<ClCompile Include="headers.cpp" />
<ClCompile Include="isnt.cpp" />
<ClCompile Include="list.cpp" />
<ClCompile Include="match.cpp" />
<ClCompile Include="options.cpp" />
<ClCompile Include="pathfn.cpp" />
<ClCompile Include="qopen.cpp" />
<ClCompile Include="rar.cpp" />
<ClCompile Include="rarpch.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="rarvm.cpp" />
<ClCompile Include="rawread.cpp" />
<ClCompile Include="rdwrfn.cpp" />
<ClCompile Include="recvol.cpp" />
<ClCompile Include="resource.cpp" />
<ClCompile Include="rijndael.cpp" />
<ClCompile Include="rs.cpp" />
<ClCompile Include="rs16.cpp" />
<ClCompile Include="scantree.cpp" />
<ClCompile Include="secpassword.cpp" />
<ClCompile Include="sha1.cpp" />
<ClCompile Include="sha256.cpp" />
<ClCompile Include="smallfn.cpp" />
<ClCompile Include="strfn.cpp" />
<ClCompile Include="strlist.cpp" />
<ClCompile Include="system.cpp" />
<ClCompile Include="threadpool.cpp" />
<ClCompile Include="timefn.cpp" />
<ClCompile Include="ui.cpp" />
<ClCompile Include="unicode.cpp" />
<ClCompile Include="unpack.cpp" />
<ClCompile Include="volume.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

876
unrar/UnRARDll.vcproj Normal file
View File

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

420
unrar/UnRARDll.vcxproj Normal file
View File

@@ -0,0 +1,420 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="release_nocrypt|Win32">
<Configuration>release_nocrypt</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="release_nocrypt|x64">
<Configuration>release_nocrypt</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectName>UnRAR</ProjectName>
<ProjectGuid>{E815C46C-36C4-499F-BBC2-E772C6B17971}</ProjectGuid>
<RootNamespace>UnRAR</RootNamespace>
<Keyword>Win32Proj</Keyword>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='release_nocrypt|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v140_xp</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
<WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v140_xp</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
<WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v140_xp</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='release_nocrypt|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v140_xp</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
<WholeProgramOptimization>false</WholeProgramOptimization>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v140_xp</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
<WholeProgramOptimization>false</WholeProgramOptimization>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v140_xp</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='release_nocrypt|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='release_nocrypt|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_ProjectFileVersion>14.0.24720.0</_ProjectFileVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<OutDir>build\unrardll32\$(Configuration)\</OutDir>
<IntDir>build\unrardll32\$(Configuration)\obj\</IntDir>
<LinkIncremental>true</LinkIncremental>
<GenerateManifest>true</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<OutDir>build\unrardll64\$(Configuration)\</OutDir>
<IntDir>build\unrardll64\$(Configuration)\obj\</IntDir>
<LinkIncremental>true</LinkIncremental>
<GenerateManifest>true</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<OutDir>build\unrardll32\$(Configuration)\</OutDir>
<IntDir>build\unrardll32\$(Configuration)\obj\</IntDir>
<LinkIncremental>false</LinkIncremental>
<GenerateManifest>true</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<OutDir>build\unrardll64\$(Configuration)\</OutDir>
<IntDir>build\unrardll64\$(Configuration)\obj\</IntDir>
<LinkIncremental>false</LinkIncremental>
<GenerateManifest>true</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='release_nocrypt|Win32'">
<OutDir>build\unrardll32\$(Configuration)\</OutDir>
<IntDir>build\unrardll32\$(Configuration)\obj\</IntDir>
<LinkIncremental>false</LinkIncremental>
<GenerateManifest>true</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='release_nocrypt|x64'">
<OutDir>build\unrardll64\$(Configuration)\</OutDir>
<IntDir>build\unrardll64\$(Configuration)\obj\</IntDir>
<LinkIncremental>false</LinkIncremental>
<GenerateManifest>true</GenerateManifest>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<AdditionalOptions>/MP %(AdditionalOptions)</AdditionalOptions>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>RARDLL;UNRAR;SILENT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>false</MinimalRebuild>
<ExceptionHandling>Sync</ExceptionHandling>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<StructMemberAlignment>4Bytes</StructMemberAlignment>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>rar.hpp</PrecompiledHeaderFile>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<CallingConvention>Cdecl</CallingConvention>
<DisableSpecificWarnings>4007;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
</ClCompile>
<Link>
<OutputFile>$(OutDir)unrar.dll</OutputFile>
<ModuleDefinitionFile>dll.def</ModuleDefinitionFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<TargetMachine>MachineX86</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
</Midl>
<ClCompile>
<AdditionalOptions>/MP %(AdditionalOptions)</AdditionalOptions>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>RARDLL;UNRAR;SILENT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>false</MinimalRebuild>
<ExceptionHandling>Sync</ExceptionHandling>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<StructMemberAlignment>4Bytes</StructMemberAlignment>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>rar.hpp</PrecompiledHeaderFile>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<CallingConvention>Cdecl</CallingConvention>
<DisableSpecificWarnings>4007;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<EnableEnhancedInstructionSet>NotSet</EnableEnhancedInstructionSet>
</ClCompile>
<Link>
<OutputFile>$(OutDir)unrar.dll</OutputFile>
<ModuleDefinitionFile>dll.def</ModuleDefinitionFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<TargetMachine>MachineX64</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<AdditionalOptions>/MP %(AdditionalOptions)</AdditionalOptions>
<Optimization>MaxSpeed</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions>
<FavorSizeOrSpeed>Neither</FavorSizeOrSpeed>
<OmitFramePointers>true</OmitFramePointers>
<WholeProgramOptimization>false</WholeProgramOptimization>
<PreprocessorDefinitions>RARDLL;UNRAR;SILENT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>false</MinimalRebuild>
<ExceptionHandling>Sync</ExceptionHandling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<StructMemberAlignment>4Bytes</StructMemberAlignment>
<BufferSecurityCheck>true</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
<EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
<FloatingPointModel>Precise</FloatingPointModel>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>rar.hpp</PrecompiledHeaderFile>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<CallingConvention>Cdecl</CallingConvention>
<DisableSpecificWarnings>4007;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
</ClCompile>
<Link>
<AdditionalOptions>/SAFESEH %(AdditionalOptions)</AdditionalOptions>
<OutputFile>$(OutDir)unrar.dll</OutputFile>
<ModuleDefinitionFile>dll.def</ModuleDefinitionFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<LinkTimeCodeGeneration />
<TargetMachine>MachineX86</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
</Midl>
<ClCompile>
<AdditionalOptions>/MP %(AdditionalOptions)</AdditionalOptions>
<Optimization>MaxSpeed</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions>
<FavorSizeOrSpeed>Neither</FavorSizeOrSpeed>
<OmitFramePointers>true</OmitFramePointers>
<WholeProgramOptimization>false</WholeProgramOptimization>
<PreprocessorDefinitions>RARDLL;UNRAR;SILENT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>false</StringPooling>
<MinimalRebuild>false</MinimalRebuild>
<ExceptionHandling>Sync</ExceptionHandling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<StructMemberAlignment>4Bytes</StructMemberAlignment>
<BufferSecurityCheck>true</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>rar.hpp</PrecompiledHeaderFile>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<CallingConvention>Cdecl</CallingConvention>
<DisableSpecificWarnings>4007;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<EnableEnhancedInstructionSet>NotSet</EnableEnhancedInstructionSet>
</ClCompile>
<Link>
<OutputFile>$(OutDir)unrar.dll</OutputFile>
<ModuleDefinitionFile>dll.def</ModuleDefinitionFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<LinkTimeCodeGeneration />
<TargetMachine>MachineX64</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='release_nocrypt|Win32'">
<ClCompile>
<AdditionalOptions>/MP %(AdditionalOptions)</AdditionalOptions>
<Optimization>MaxSpeed</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions>
<FavorSizeOrSpeed>Neither</FavorSizeOrSpeed>
<OmitFramePointers>true</OmitFramePointers>
<WholeProgramOptimization>false</WholeProgramOptimization>
<PreprocessorDefinitions>RARDLL;UNRAR;SILENT;RAR_NOCRYPT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>false</MinimalRebuild>
<ExceptionHandling>Sync</ExceptionHandling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<StructMemberAlignment>4Bytes</StructMemberAlignment>
<BufferSecurityCheck>true</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
<EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
<FloatingPointModel>Precise</FloatingPointModel>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>rar.hpp</PrecompiledHeaderFile>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<CallingConvention>Cdecl</CallingConvention>
<DisableSpecificWarnings>4007;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
</ClCompile>
<Link>
<AdditionalOptions>/SAFESEH %(AdditionalOptions)</AdditionalOptions>
<OutputFile>$(OutDir)unrar.dll</OutputFile>
<ModuleDefinitionFile>dll_nocrypt.def</ModuleDefinitionFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<LinkTimeCodeGeneration />
<TargetMachine>MachineX86</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='release_nocrypt|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
</Midl>
<ClCompile>
<AdditionalOptions>/MP %(AdditionalOptions)</AdditionalOptions>
<Optimization>MaxSpeed</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions>
<FavorSizeOrSpeed>Neither</FavorSizeOrSpeed>
<OmitFramePointers>true</OmitFramePointers>
<WholeProgramOptimization>false</WholeProgramOptimization>
<PreprocessorDefinitions>RARDLL;UNRAR;SILENT;RAR_NOCRYPT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>false</StringPooling>
<MinimalRebuild>false</MinimalRebuild>
<ExceptionHandling>Sync</ExceptionHandling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<StructMemberAlignment>4Bytes</StructMemberAlignment>
<BufferSecurityCheck>true</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>rar.hpp</PrecompiledHeaderFile>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<CallingConvention>StdCall</CallingConvention>
<DisableSpecificWarnings>4007;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<EnableEnhancedInstructionSet>NotSet</EnableEnhancedInstructionSet>
</ClCompile>
<Link>
<OutputFile>$(OutDir)unrar.dll</OutputFile>
<ModuleDefinitionFile>dll_nocrypt.def</ModuleDefinitionFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<LinkTimeCodeGeneration />
<TargetMachine>MachineX64</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="archive.cpp" />
<ClCompile Include="arcread.cpp" />
<ClCompile Include="blake2s.cpp" />
<ClCompile Include="cmddata.cpp" />
<ClCompile Include="consio.cpp" />
<ClCompile Include="crc.cpp" />
<ClCompile Include="crypt.cpp" />
<ClCompile Include="dll.cpp" />
<ClCompile Include="encname.cpp" />
<ClCompile Include="errhnd.cpp" />
<ClCompile Include="extinfo.cpp" />
<ClCompile Include="extract.cpp" />
<ClCompile Include="filcreat.cpp" />
<ClCompile Include="file.cpp" />
<ClCompile Include="filefn.cpp" />
<ClCompile Include="filestr.cpp" />
<ClCompile Include="find.cpp" />
<ClCompile Include="getbits.cpp" />
<ClCompile Include="global.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='release_nocrypt|Win32'">
</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='release_nocrypt|x64'">
</PrecompiledHeader>
</ClCompile>
<ClCompile Include="hash.cpp" />
<ClCompile Include="headers.cpp" />
<ClCompile Include="isnt.cpp" />
<ClCompile Include="match.cpp" />
<ClCompile Include="options.cpp" />
<ClCompile Include="pathfn.cpp" />
<ClCompile Include="qopen.cpp" />
<ClCompile Include="rar.cpp" />
<ClCompile Include="rarpch.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='release_nocrypt|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='release_nocrypt|x64'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="rarvm.cpp" />
<ClCompile Include="rawread.cpp" />
<ClCompile Include="rdwrfn.cpp" />
<ClCompile Include="rijndael.cpp" />
<ClCompile Include="rs.cpp" />
<ClCompile Include="rs16.cpp" />
<ClCompile Include="scantree.cpp" />
<ClCompile Include="secpassword.cpp" />
<ClCompile Include="sha1.cpp" />
<ClCompile Include="sha256.cpp" />
<ClCompile Include="smallfn.cpp" />
<ClCompile Include="strfn.cpp" />
<ClCompile Include="strlist.cpp" />
<ClCompile Include="system.cpp" />
<ClCompile Include="threadpool.cpp" />
<ClCompile Include="timefn.cpp" />
<ClCompile Include="ui.cpp" />
<ClCompile Include="unicode.cpp" />
<ClCompile Include="unpack.cpp" />
<ClCompile Include="volume.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="rar.hpp" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="dll.rc" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

92
unrar/acknow.txt Normal file
View File

@@ -0,0 +1,92 @@
ACKNOWLEDGMENTS
* We used "Screaming Fast Galois Field Arithmetic Using Intel
SIMD Instructions" paper by James S. Plank, Kevin M. Greenan
and Ethan L. Miller to improve Reed-Solomon coding performance.
Also we are grateful to Artem Drobanov and Bulat Ziganshin
for samples and ideas allowed to make Reed-Solomon coding
more efficient.
* RAR text compression algorithm is based on Dmitry Shkarin PPMII
and Dmitry Subbotin carryless rangecoder public domain source code.
You may find it in ftp.elf.stuba.sk/pub/pc/pack.
* RAR encryption includes parts of code from Szymon Stefanek
and Brian Gladman AES implementations also as Steve Reid SHA-1 source.
---------------------------------------------------------------------------
Copyright (c) 2002, Dr Brian Gladman < >, Worcester, UK.
All rights reserved.
LICENSE TERMS
The free distribution and use of this software in both source and binary
form is allowed (with or without changes) provided that:
1. distributions of this source code include the above copyright
notice, this list of conditions and the following disclaimer;
2. distributions in binary form include the above copyright
notice, this list of conditions and the following disclaimer
in the documentation and/or other associated materials;
3. the copyright holder's name is not used to endorse products
built using this software without specific written permission.
ALTERNATIVELY, provided that this notice is retained in full, this product
may be distributed under the terms of the GNU General Public License (GPL),
in which case the provisions of the GPL apply INSTEAD OF those given above.
DISCLAIMER
This software is provided 'as is' with no explicit or implied warranties
in respect of its properties, including, but not limited to, correctness
and/or fitness for purpose.
---------------------------------------------------------------------------
Source code of this package also as other cryptographic technology
and computing project related links are available on Brian Gladman's
web site: http://www.gladman.me.uk
* RAR uses CRC32 function based on Intel Slicing-by-8 algorithm.
Original Intel Slicing-by-8 code is available here:
http://sourceforge.net/projects/slicing-by-8/
Original Intel Slicing-by-8 code is licensed under BSD License
available at http://www.opensource.org/licenses/bsd-license.html
Copyright (c) 2004-2006 Intel Corporation.
All Rights Reserved
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with
the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
* RAR archives may optionally include BLAKE2sp hash ( https://blake2.net ),
designed by Jean-Philippe Aumasson, Samuel Neves, Zooko Wilcox-O'Hearn
and Christian Winnerlein.
* Useful hints provided by Alexander Khoroshev and Bulat Ziganshin allowed
to significantly improve RAR compression and speed.

View File

@@ -1,66 +1,64 @@
bool IsAnsiComment(const char *Data,int Size);
static bool IsAnsiEscComment(const wchar *Data,size_t Size);
bool Archive::GetComment(Array<byte> *CmtData,Array<wchar> *CmtDataW)
bool Archive::GetComment(Array<wchar> *CmtData)
{
if (!MainComment)
return(false);
return false;
SaveFilePos SavePos(*this);
#ifndef SFX_MODULE
ushort CmtLength;
if (OldFormat)
if (Format==RARFMT14)
{
Seek(SFXSize+SIZEOF_OLDMHD,SEEK_SET);
Seek(SFXSize+SIZEOF_MAINHEAD14,SEEK_SET);
CmtLength=GetByte();
CmtLength+=(GetByte()<<8);
}
else
#endif
{
if (NewMhd.Flags & MHD_COMMENT)
if (MainHead.CommentInHeader)
{
// Old style (RAR 2.9) archive comment embedded into the main
// archive header.
Seek(SFXSize+SIZEOF_MARKHEAD+SIZEOF_NEWMHD,SEEK_SET);
Seek(SFXSize+SIZEOF_MARKHEAD3+SIZEOF_MAINHEAD3,SEEK_SET);
ReadHeader();
}
else
{
// Current (RAR 3.0+) version of archive comment.
Seek(SFXSize+SIZEOF_MARKHEAD+NewMhd.HeadSize,SEEK_SET);
return(SearchSubBlock(SUBHEAD_TYPE_CMT)!=0 && ReadCommentData(CmtData,CmtDataW)!=0);
Seek(GetStartPos(),SEEK_SET);
return SearchSubBlock(SUBHEAD_TYPE_CMT)!=0 && ReadCommentData(CmtData);
}
#ifndef SFX_MODULE
// Old style (RAR 2.9) comment header embedded into the main
// archive header.
if (CommHead.HeadCRC!=HeaderCRC)
if (BrokenHeader)
{
Log(FileName,St(MLogCommHead));
Alarm();
return(false);
uiMsg(UIERROR_CMTBROKEN,FileName);
return false;
}
CmtLength=CommHead.HeadSize-SIZEOF_COMMHEAD;
#endif
}
#ifndef SFX_MODULE
if (OldFormat && (OldMhd.Flags & MHD_PACK_COMMENT) || !OldFormat && CommHead.Method!=0x30)
if (Format==RARFMT14 && MainHead.PackComment || Format!=RARFMT14 && CommHead.Method!=0x30)
{
if (!OldFormat && (CommHead.UnpVer < 15 || CommHead.UnpVer > UNP_VER || CommHead.Method > 0x35))
return(false);
if (Format!=RARFMT14 && (CommHead.UnpVer < 15 || CommHead.UnpVer > VER_UNPACK || CommHead.Method > 0x35))
return false;
ComprDataIO DataIO;
Unpack Unpack(&DataIO);
Unpack.Init();
DataIO.SetTestMode(true);
uint UnpCmtLength;
if (OldFormat)
if (Format==RARFMT14)
{
#ifdef NOCRYPT
#ifdef RAR_NOCRYPT
return(false);
#else
UnpCmtLength=GetByte();
UnpCmtLength+=(GetByte()<<8);
CmtLength-=2;
DataIO.SetCmt13Encryption();
CommHead.UnpVer=15;
#endif
}
else
@@ -68,161 +66,99 @@ bool Archive::GetComment(Array<byte> *CmtData,Array<wchar> *CmtDataW)
DataIO.SetFiles(this,NULL);
DataIO.EnableShowProgress(false);
DataIO.SetPackedSizeToRead(CmtLength);
Unpack.SetDestSize(UnpCmtLength);
Unpack.DoUnpack(CommHead.UnpVer,false);
DataIO.UnpHash.Init(HASH_CRC32,1);
if (!OldFormat && ((~DataIO.UnpFileCRC)&0xffff)!=CommHead.CommCRC)
Unpack CmtUnpack(&DataIO);
CmtUnpack.Init(0x10000,false);
CmtUnpack.SetDestSize(UnpCmtLength);
CmtUnpack.DoUnpack(CommHead.UnpVer,false);
if (Format!=RARFMT14 && (DataIO.UnpHash.GetCRC32()&0xffff)!=CommHead.CommCRC)
{
Log(FileName,St(MLogCommBrk));
Alarm();
return(false);
uiMsg(UIERROR_CMTBROKEN,FileName);
return false;
}
else
{
byte *UnpData;
size_t UnpDataSize;
DataIO.GetUnpackedData(&UnpData,&UnpDataSize);
CmtData->Alloc(UnpDataSize);
memcpy(&((*CmtData)[0]),UnpData,UnpDataSize);
#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.
OemToCharBuffA((char *)UnpData,(char *)UnpData,(DWORD)UnpDataSize);
#endif
CmtData->Alloc(UnpDataSize+1);
memset(CmtData->Addr(0),0,CmtData->Size()*sizeof(wchar));
CharToWide((char *)UnpData,CmtData->Addr(0),CmtData->Size());
CmtData->Alloc(wcslen(CmtData->Addr(0)));
}
}
else
{
CmtData->Alloc(CmtLength);
Array<byte> CmtRaw(CmtLength);
Read(&CmtRaw[0],CmtLength);
Read(&((*CmtData)[0]),CmtLength);
if (!OldFormat && CommHead.CommCRC!=(~CRC(0xffffffff,&((*CmtData)[0]),CmtLength)&0xffff))
if (Format!=RARFMT14 && CommHead.CommCRC!=(~CRC32(0xffffffff,&CmtRaw[0],CmtLength)&0xffff))
{
Log(FileName,St(MLogCommBrk));
Alarm();
CmtData->Reset();
return(false);
uiMsg(UIERROR_CMTBROKEN,FileName);
return false;
}
}
CmtData->Alloc(CmtLength+1);
CmtRaw.Push(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.
OemToCharA((char *)&CmtRaw[0],(char *)&CmtRaw[0]);
#endif
#if defined(_WIN_ALL) && !defined(_WIN_CE)
if (CmtData->Size()>0)
{
size_t CmtSize=CmtData->Size();
char *DataA=(char *)CmtData->Addr();
OemToCharBuffA(DataA,DataA,(DWORD)CmtSize);
if (CmtDataW!=NULL)
{
CmtDataW->Alloc(CmtSize+1);
CmtData->Push(0);
CharToWide(DataA,CmtDataW->Addr(),CmtSize+1);
CmtData->Alloc(CmtSize);
CmtDataW->Alloc(wcslen(CmtDataW->Addr()));
CharToWide((char *)&CmtRaw[0],CmtData->Addr(0),CmtLength);
CmtData->Alloc(wcslen(CmtData->Addr(0)));
}
}
#endif
return(CmtData->Size()>0);
return CmtData->Size() > 0;
}
size_t Archive::ReadCommentData(Array<byte> *CmtData,Array<wchar> *CmtDataW)
bool Archive::ReadCommentData(Array<wchar> *CmtData)
{
bool Unicode=SubHead.SubFlags & SUBHEAD_FLAGS_CMT_UNICODE;
if (!ReadSubData(CmtData,NULL))
return(0);
size_t CmtSize=CmtData->Size();
if (Unicode)
{
CmtSize/=2;
Array<wchar> DataW(CmtSize+1);
RawToWide(CmtData->Addr(),DataW.Addr(),CmtSize);
DataW[CmtSize]=0;
size_t DestSize=CmtSize*4;
CmtData->Alloc(DestSize+1);
WideToChar(DataW.Addr(),(char *)CmtData->Addr(),DestSize);
(*CmtData)[DestSize]=0;
CmtSize=strlen((char *)CmtData->Addr());
CmtData->Alloc(CmtSize);
if (CmtDataW!=NULL)
{
*CmtDataW=DataW;
CmtDataW->Alloc(CmtSize);
}
}
Array<byte> CmtRaw;
if (!ReadSubData(&CmtRaw,NULL))
return false;
size_t CmtSize=CmtRaw.Size();
CmtRaw.Push(0);
CmtData->Alloc(CmtSize+1);
if (Format==RARFMT50)
UtfToWide((char *)&CmtRaw[0],CmtData->Addr(0),CmtData->Size());
else
if (CmtDataW!=NULL)
{
CmtData->Push(0);
CmtDataW->Alloc(CmtSize+1);
CharToWide((char *)CmtData->Addr(),CmtDataW->Addr(),CmtSize+1);
CmtData->Alloc(CmtSize);
CmtDataW->Alloc(wcslen(CmtDataW->Addr()));
if ((SubHead.SubFlags & SUBHEAD_FLAGS_CMT_UNICODE)!=0)
{
RawToWide(&CmtRaw[0],CmtData->Addr(0),CmtSize/2);
(*CmtData)[CmtSize/2]=0;
}
return(CmtSize);
else
{
CharToWide((char *)&CmtRaw[0],CmtData->Addr(0),CmtData->Size());
}
CmtData->Alloc(wcslen(CmtData->Addr(0))); // Set buffer size to actual comment length.
return true;
}
void Archive::ViewComment()
{
#ifndef GUI
if (Cmd->DisableComment)
return;
Array<byte> CmtBuf;
if (GetComment(&CmtBuf,NULL))
Array<wchar> CmtBuf;
if (GetComment(&CmtBuf)) // In GUI too, so "Test" command detects broken comments.
{
size_t CmtSize=CmtBuf.Size();
char *ChPtr=(char *)memchr(&CmtBuf[0],0x1A,CmtSize);
wchar *ChPtr=wcschr(&CmtBuf[0],0x1A);
if (ChPtr!=NULL)
CmtSize=ChPtr-(char *)&CmtBuf[0];
mprintf("\n");
OutComment((char *)&CmtBuf[0],CmtSize);
}
#endif
}
#ifndef SFX_MODULE
// Used for archives created by old RAR versions up to and including RAR 2.9.
// New RAR versions store file comments in separate headers and such comments
// are displayed in ListNewSubHeader function.
void Archive::ViewFileComment()
{
if (!(NewLhd.Flags & LHD_COMMENT) || Cmd->DisableComment || OldFormat)
return;
#ifndef GUI
mprintf(St(MFileComment));
#endif
const int MaxSize=0x8000;
Array<char> CmtBuf(MaxSize);
SaveFilePos SavePos(*this);
Seek(CurBlockPos+SIZEOF_NEWLHD+NewLhd.NameSize,SEEK_SET);
int64 SaveCurBlockPos=CurBlockPos;
int64 SaveNextBlockPos=NextBlockPos;
size_t Size=ReadHeader();
CurBlockPos=SaveCurBlockPos;
NextBlockPos=SaveNextBlockPos;
if (Size<7 || CommHead.HeadType!=COMM_HEAD)
return;
if (CommHead.HeadCRC!=HeaderCRC)
{
#ifndef GUI
Log(FileName,St(MLogCommHead));
#endif
return;
}
if (CommHead.UnpVer < 15 || CommHead.UnpVer > UNP_VER ||
CommHead.Method > 0x30 || CommHead.UnpSize > MaxSize)
return;
Read(&CmtBuf[0],CommHead.UnpSize);
if (CommHead.CommCRC!=((~CRC(0xffffffff,&CmtBuf[0],CommHead.UnpSize)&0xffff)))
{
Log(FileName,St(MLogBrokFCmt));
}
else
{
OutComment(&CmtBuf[0],CommHead.UnpSize);
#ifndef GUI
mprintf("\n");
#endif
CmtSize=ChPtr-&CmtBuf[0];
mprintf(L"\n");
OutComment(&CmtBuf[0],CmtSize);
}
}
#endif

View File

@@ -1,48 +1,47 @@
#include "rar.hpp"
#ifndef SHELL_EXT
#include "arccmt.cpp"
#endif
Archive::Archive(RAROptions *InitCmd)
{
Cmd=InitCmd==NULL ? &DummyCmd:InitCmd;
Cmd=NULL; // Just in case we'll have an exception in 'new' below.
DummyCmd=(InitCmd==NULL);
Cmd=DummyCmd ? (new RAROptions):InitCmd;
OpenShared=Cmd->OpenShared;
OldFormat=false;
Format=RARFMT15;
Solid=false;
Volume=false;
MainComment=false;
Locked=false;
Signed=false;
NotFirstVolume=false;
FirstVolume=false;
NewNumbering=false;
SFXSize=0;
LatestTime.Reset();
Protected=false;
Encrypted=false;
FailedHeaderDecryption=false;
BrokenFileHeader=false;
BrokenHeader=false;
LastReadBlock=0;
CurBlockPos=0;
NextBlockPos=0;
RecoveryPos=SIZEOF_MARKHEAD;
RecoverySectors=-1;
RecoverySize=-1;
RecoveryPercent=-1;
memset(&NewMhd,0,sizeof(NewMhd));
NewMhd.HeadType=MAIN_HEAD;
NewMhd.HeadSize=SIZEOF_NEWMHD;
HeaderCRC=0;
memset(&MainHead,0,sizeof(MainHead));
memset(&CryptHead,0,sizeof(CryptHead));
memset(&EndArcHead,0,sizeof(EndArcHead));
VolNumber=0;
VolWrite=0;
AddingFilesSize=0;
AddingHeadersSize=0;
#if !defined(SHELL_EXT) && !defined(NOCRYPT)
*HeadersSalt=0;
*SubDataSalt=0;
#endif
*FirstVolumeName=0;
*FirstVolumeNameW=0;
Splitting=false;
NewArchive=false;
@@ -52,83 +51,98 @@ Archive::Archive(RAROptions *InitCmd)
}
#ifndef SHELL_EXT
Archive::~Archive()
{
if (DummyCmd)
delete Cmd;
}
void Archive::CheckArc(bool EnableBroken)
{
if (!IsArchive(EnableBroken))
{
Log(FileName,St(MBadArc),FileName);
ErrHandler.Exit(FATAL_ERROR);
// If FailedHeaderDecryption is set, we already reported that archive
// password is incorrect.
if (!FailedHeaderDecryption)
uiMsg(UIERROR_BADARCHIVE,FileName);
ErrHandler.Exit(RARX_FATAL);
}
}
#endif
#if !defined(SHELL_EXT) && !defined(SFX_MODULE)
void Archive::CheckOpen(const char *Name,const wchar *NameW)
#if !defined(SFX_MODULE)
void Archive::CheckOpen(const wchar *Name)
{
TOpen(Name,NameW);
TOpen(Name);
CheckArc(false);
}
#endif
bool Archive::WCheckOpen(const char *Name,const wchar *NameW)
bool Archive::WCheckOpen(const wchar *Name)
{
if (!WOpen(Name,NameW))
return(false);
if (!WOpen(Name))
return false;
if (!IsArchive(false))
{
#ifndef SHELL_EXT
Log(FileName,St(MNotRAR),FileName);
#endif
uiMsg(UIERROR_BADARCHIVE,FileName);
Close();
return(false);
return false;
}
return(true);
return true;
}
bool Archive::IsSignature(byte *D)
RARFORMAT Archive::IsSignature(const byte *D,size_t Size)
{
bool Valid=false;
if (D[0]==0x52)
RARFORMAT Type=RARFMT_NONE;
if (Size>=1 && D[0]==0x52)
#ifndef SFX_MODULE
if (D[1]==0x45 && D[2]==0x7e && D[3]==0x5e)
{
OldFormat=true;
Valid=true;
}
if (Size>=4 && D[1]==0x45 && D[2]==0x7e && D[3]==0x5e)
Type=RARFMT14;
else
#endif
if (D[1]==0x61 && D[2]==0x72 && D[3]==0x21 && D[4]==0x1a && D[5]==0x07 && D[6]==0x00)
if (Size>=7 && D[1]==0x61 && D[2]==0x72 && D[3]==0x21 && D[4]==0x1a && D[5]==0x07)
{
OldFormat=false;
Valid=true;
// We check the last signature byte, so we can return a sensible
// warning in case we'll want to change the archive format
// sometimes in the future.
if (D[6]==0)
Type=RARFMT15;
else
if (D[6]==1)
Type=RARFMT50;
else
if (D[6]==2)
Type=RARFMT_FUTURE;
}
return(Valid);
return Type;
}
bool Archive::IsArchive(bool EnableBroken)
{
Encrypted=false;
BrokenHeader=false; // Might be left from previous volume.
#ifndef SFX_MODULE
if (IsDevice())
{
#ifndef SHELL_EXT
Log(FileName,St(MInvalidName),FileName);
#endif
return(false);
uiMsg(UIERROR_INVALIDNAME,FileName,FileName);
return false;
}
#endif
if (Read(MarkHead.Mark,SIZEOF_MARKHEAD)!=SIZEOF_MARKHEAD)
return(false);
if (Read(MarkHead.Mark,SIZEOF_MARKHEAD3)!=SIZEOF_MARKHEAD3)
return false;
SFXSize=0;
if (IsSignature(MarkHead.Mark))
RARFORMAT Type;
if ((Type=IsSignature(MarkHead.Mark,SIZEOF_MARKHEAD3))!=RARFMT_NONE)
{
if (OldFormat)
Seek(0,SEEK_SET);
Format=Type;
if (Format==RARFMT14)
Seek(Tell()-SIZEOF_MARKHEAD3,SEEK_SET);
}
else
{
@@ -136,9 +150,10 @@ bool Archive::IsArchive(bool EnableBroken)
long CurPos=(long)Tell();
int ReadSize=Read(&Buffer[0],Buffer.Size()-16);
for (int I=0;I<ReadSize;I++)
if (Buffer[I]==0x52 && IsSignature((byte *)&Buffer[I]))
if (Buffer[I]==0x52 && (Type=IsSignature((byte *)&Buffer[I],ReadSize-I))!=RARFMT_NONE)
{
if (OldFormat && I>0 && CurPos<28 && ReadSize>31)
Format=Type;
if (Format==RARFMT14 && I>0 && CurPos<28 && ReadSize>31)
{
char *D=&Buffer[28-CurPos];
if (D[0]!=0x52 || D[1]!=0x53 || D[2]!=0x46 || D[3]!=0x58)
@@ -146,55 +161,28 @@ bool Archive::IsArchive(bool EnableBroken)
}
SFXSize=CurPos+I;
Seek(SFXSize,SEEK_SET);
if (!OldFormat)
Read(MarkHead.Mark,SIZEOF_MARKHEAD);
if (Format==RARFMT15 || Format==RARFMT50)
Read(MarkHead.Mark,SIZEOF_MARKHEAD3);
break;
}
if (SFXSize==0)
return(false);
return false;
}
ReadHeader();
SeekToNext();
#ifndef SFX_MODULE
if (OldFormat)
if (Format==RARFMT_FUTURE)
{
NewMhd.Flags=OldMhd.Flags & 0x3f;
NewMhd.HeadSize=OldMhd.HeadSize;
uiMsg(UIERROR_NEWRARFORMAT,FileName);
return false;
}
if (Format==RARFMT50) // RAR 5.0 signature is by one byte longer.
{
Read(MarkHead.Mark+SIZEOF_MARKHEAD3,1);
if (MarkHead.Mark[SIZEOF_MARKHEAD3]!=0)
return false;
MarkHead.HeadSize=SIZEOF_MARKHEAD5;
}
else
#endif
{
if (HeaderCRC!=NewMhd.HeadCRC)
{
#ifndef SHELL_EXT
Log(FileName,St(MLogMainHead));
#endif
Alarm();
if (!EnableBroken)
return(false);
}
}
Volume=(NewMhd.Flags & MHD_VOLUME);
Solid=(NewMhd.Flags & MHD_SOLID)!=0;
MainComment=(NewMhd.Flags & MHD_COMMENT)!=0;
Locked=(NewMhd.Flags & MHD_LOCK)!=0;
Signed=(NewMhd.PosAV!=0);
Protected=(NewMhd.Flags & MHD_PROTECT)!=0;
Encrypted=(NewMhd.Flags & MHD_PASSWORD)!=0;
MarkHead.HeadSize=SIZEOF_MARKHEAD3;
if (NewMhd.EncryptVer>UNP_VER)
{
#ifdef RARDLL
Cmd->DllError=ERAR_UNKNOWN_FORMAT;
#else
ErrHandler.SetErrorCode(WARNING);
#if !defined(SILENT) && !defined(SFX_MODULE)
Log(FileName,St(MUnknownMeth),FileName);
Log(FileName,St(MVerRequired),NewMhd.EncryptVer/10,NewMhd.EncryptVer%10);
#endif
#endif
return(false);
}
#ifdef RARDLL
// If callback function is not set, we cannot get the password,
// so we skip the initial header processing for encrypted header archive.
@@ -204,45 +192,76 @@ bool Archive::IsArchive(bool EnableBroken)
SilentOpen=true;
#endif
// If not encrypted, we'll check it below.
NotFirstVolume=Encrypted && (NewMhd.Flags & MHD_FIRSTVOLUME)==0;
// Skip the archive encryption header if any and read the main header.
while (ReadHeader()!=0)
{
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)
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'
// messages when extracting encrypted archives with wrong password.
if (FailedHeaderDecryption && !EnableBroken)
return false;
SeekToNext();
if (BrokenHeader) // Main archive header is corrupt.
{
uiMsg(UIERROR_MHEADERBROKEN,FileName);
if (!EnableBroken)
return false;
}
MainComment=MainHead.CommentInHeader;
// If we process non-encrypted archive or can request a password,
// we set 'first volume' flag based on file attributes below.
// It is necessary for RAR 2.x archives, which did not have 'first volume'
// flag in main header. Also for all RAR formats we need to scan until
// 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)
{
SaveFilePos SavePos(*this);
int64 SaveCurBlockPos=CurBlockPos,SaveNextBlockPos=NextBlockPos;
HEADER_TYPE SaveCurHeaderType=CurHeaderType;
NotFirstVolume=false;
while (ReadHeader()!=0)
{
int HeaderType=GetHeaderType();
if (HeaderType==NEWSUB_HEAD)
HEADER_TYPE HeaderType=GetHeaderType();
if (HeaderType==HEAD_SERVICE)
{
if (SubHead.CmpName(SUBHEAD_TYPE_CMT))
MainComment=true;
if ((SubHead.Flags & LHD_SPLIT_BEFORE) ||
Volume && (NewMhd.Flags & MHD_FIRSTVOLUME)==0)
NotFirstVolume=true;
// If we have a split service headers, it surely indicates non-first
// volume. But not split service header does not guarantee the first
// volume, because we can have split file after non-split archive
// comment. So we do not quit from loop here.
FirstVolume=Volume && !SubHead.SplitBefore;
}
else
{
if (HeaderType==FILE_HEAD && ((NewLhd.Flags & LHD_SPLIT_BEFORE)!=0 ||
Volume && NewLhd.UnpVer>=29 && (NewMhd.Flags & MHD_FIRSTVOLUME)==0))
NotFirstVolume=true;
break;
}
if (HeaderType==HEAD_FILE)
{
FirstVolume=Volume && !FileHead.SplitBefore;
break;
}
else
if (HeaderType==HEAD_ENDARC) // Might happen if archive contains only a split service header.
break;
SeekToNext();
}
CurBlockPos=SaveCurBlockPos;
NextBlockPos=SaveNextBlockPos;
CurHeaderType=SaveCurHeaderType;
}
if (!Volume || !NotFirstVolume)
{
strcpy(FirstVolumeName,FileName);
wcscpy(FirstVolumeNameW,FileNameW);
}
if (!Volume || FirstVolume)
wcscpy(FirstVolumeName,FileName);
return(true);
return true;
}
@@ -254,20 +273,60 @@ void Archive::SeekToNext()
}
#ifndef SFX_MODULE
int Archive::GetRecoverySize(bool Required)
// Calculate the block size including encryption fields and padding if any.
uint Archive::FullHeaderSize(size_t Size)
{
if (!Protected)
return(0);
if (RecoverySectors!=-1 || !Required)
return(RecoverySectors);
SaveFilePos SavePos(*this);
Seek(SFXSize,SEEK_SET);
SearchSubBlock(SUBHEAD_TYPE_RR);
return(RecoverySectors);
if (Encrypted)
{
Size = ALIGN_VALUE(Size, CRYPT_BLOCK_SIZE); // Align to encryption block size.
if (Format == RARFMT50)
Size += SIZE_INITV;
else
Size += SIZE_SALT30;
}
return uint(Size);
}
#ifdef USE_QOPEN
bool Archive::Open(const wchar *Name,uint Mode)
{
// Important if we reuse Archive object and it has virtual QOpen
// file position not matching real. For example, for 'l -v volname'.
QOpen.Unload();
return File::Open(Name,Mode);
}
int Archive::Read(void *Data,size_t Size)
{
size_t Result;
if (QOpen.Read(Data,Size,Result))
return (int)Result;
return File::Read(Data,Size);
}
void Archive::Seek(int64 Offset,int Method)
{
if (!QOpen.Seek(Offset,Method))
File::Seek(Offset,Method);
}
int64 Archive::Tell()
{
int64 QPos;
if (QOpen.Tell(&QPos))
return QPos;
return File::Tell();
}
#endif

View File

@@ -1,79 +1,107 @@
#ifndef _RAR_ARCHIVE_
#define _RAR_ARCHIVE_
class Pack;
class PPack;
class RawRead;
class RawWrite;
enum {EN_LOCK=1,EN_VOL=2,EN_FIRSTVOL=4};
enum NOMODIFY_FLAGS
{
NMDF_ALLOWLOCK=1,NMDF_ALLOWANYVOLUME=2,NMDF_ALLOWFIRSTVOLUME=4
};
enum RARFORMAT {RARFMT_NONE,RARFMT14,RARFMT15,RARFMT50,RARFMT_FUTURE};
enum ADDSUBDATA_FLAGS
{
ASDF_SPLIT = 1, // Allow to split archive just before header if necessary.
ASDF_COMPRESS = 2, // Allow to compress data following subheader.
ASDF_CRYPT = 4, // Encrypt data after subheader if password is set.
ASDF_CRYPTIFHEADERS = 8 // Encrypt data after subheader only in -hp mode.
};
class Archive:public File
{
private:
bool IsSignature(byte *D);
void UpdateLatestTime(FileHeader *CurBlock);
void ConvertNameCase(char *Name);
void ConvertNameCase(wchar *Name);
void ConvertUnknownHeader();
size_t ReadOldHeader();
void ConvertFileHeader(FileHeader *hd);
void WriteBlock50(HEADER_TYPE HeaderType,BaseBlock *wb,bool OnlySetSize,bool NonFinalWrite);
size_t ReadHeader14();
size_t ReadHeader15();
size_t ReadHeader50();
void ProcessExtra50(RawRead *Raw,size_t ExtraSize,BaseBlock *bb);
void RequestArcPassword();
void UnexpEndArcMsg();
void BrokenHeaderMsg();
void UnkEncVerMsg(const wchar *Name);
void UnkEncVerMsg();
bool ReadCommentData(Array<wchar> *CmtData);
#if !defined(SHELL_EXT) && !defined(NOCRYPT)
#if !defined(RAR_NOCRYPT)
CryptData HeadersCrypt;
byte HeadersSalt[SALT_SIZE];
#endif
#ifndef SHELL_EXT
ComprDataIO SubDataIO;
byte SubDataSalt[SALT_SIZE];
#endif
RAROptions *Cmd,DummyCmd;
bool DummyCmd;
RAROptions *Cmd;
MarkHeader MarkHead;
OldMainHeader OldMhd;
int RecoverySectors;
int64 RecoveryPos;
bool FailedHeaderDecryption;
int64 RecoverySize;
int RecoveryPercent;
RarTime LatestTime;
int LastReadBlock;
int CurHeaderType;
HEADER_TYPE CurHeaderType;
bool SilentOpen;
#ifdef USE_QOPEN
QuickOpen QOpen;
#endif
public:
Archive(RAROptions *InitCmd=NULL);
~Archive();
static RARFORMAT IsSignature(const byte *D,size_t Size);
bool IsArchive(bool EnableBroken);
size_t SearchBlock(int BlockType);
size_t SearchSubBlock(const char *Type);
int ReadBlock(int BlockType);
void WriteBlock(int BlockType,BaseBlock *wb=NULL);
int PrepareNamesToWrite(char *Name,wchar *NameW,char *DestName,byte *DestNameW);
void SetLhdSize();
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 char *Name,const wchar *NameW=NULL);
bool WCheckOpen(const char *Name,const wchar *NameW=NULL);
bool GetComment(Array<byte> *CmtData,Array<wchar> *CmtDataW);
void CheckOpen(const wchar *Name);
bool WCheckOpen(const wchar *Name);
bool GetComment(Array<wchar> *CmtData);
void ViewComment();
void ViewFileComment();
void SetLatestTime(RarTime *NewTime);
void SeekToNext();
bool CheckAccess();
bool IsArcDir();
bool IsArcLabel();
void ConvertAttributes();
int GetRecoverySize(bool Required);
void VolSubtractHeaderSize(size_t SubSize);
void AddSubData(byte *SrcData,size_t DataSize,File *SrcFile,const char *Name,bool AllowSplit);
uint FullHeaderSize(size_t Size);
int64 GetStartPos();
void AddSubData(byte *SrcData,uint64 DataSize,File *SrcFile,
const wchar *Name,uint Flags);
bool ReadSubData(Array<byte> *UnpData,File *DestFile);
int GetHeaderType() {return(CurHeaderType);};
size_t ReadCommentData(Array<byte> *CmtData,Array<wchar> *CmtDataW);
void WriteCommentData(byte *Data,size_t DataSize,bool FileComment);
RAROptions* GetRAROptions() {return(Cmd);}
HEADER_TYPE GetHeaderType() {return CurHeaderType;};
RAROptions* GetRAROptions() {return Cmd;}
void SetSilentOpen(bool Mode) {SilentOpen=Mode;}
#if 0
void GetRecoveryInfo(bool Required,int64 *Size,int *Percent);
#endif
#ifdef USE_QOPEN
bool Open(const wchar *Name,uint Mode=FMF_READ);
int Read(void *Data,size_t Size);
void Seek(int64 Offset,int Method);
int64 Tell();
void QOpenUnload() {QOpen.Unload();}
#endif
BaseBlock ShortBlock;
MainHeader NewMhd;
FileHeader NewLhd;
MarkHeader MarkHead;
MainHeader MainHead;
CryptHeader CryptHead;
FileHeader FileHead;
EndArcHeader EndArcHead;
SubBlockHeader SubBlockHead;
FileHeader SubHead;
@@ -89,30 +117,34 @@ class Archive:public File
int64 CurBlockPos;
int64 NextBlockPos;
bool OldFormat;
RARFORMAT Format;
bool Solid;
bool Volume;
bool MainComment;
bool Locked;
bool Signed;
bool NotFirstVolume;
bool FirstVolume;
bool NewNumbering;
bool Protected;
bool Encrypted;
size_t SFXSize;
bool BrokenFileHeader;
bool BrokenHeader;
bool FailedHeaderDecryption;
#if !defined(RAR_NOCRYPT)
byte ArcSalt[SIZE_SALT50];
#endif
bool Splitting;
ushort HeaderCRC;
uint VolNumber;
int64 VolWrite;
int64 AddingFilesSize;
size_t AddingHeadersSize;
uint64 AddingFilesSize;
uint64 AddingHeadersSize;
bool NewArchive;
char FirstVolumeName[NM];
wchar FirstVolumeNameW[NM];
wchar FirstVolumeName[NM];
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -9,26 +9,39 @@ template <class T> class Array
T *Buffer;
size_t BufSize;
size_t AllocSize;
size_t MaxSize;
bool Secure; // Clean memory if true.
public:
Array();
Array(size_t Size);
Array(const Array &Src); // Copy constructor.
~Array();
inline void CleanData();
inline T& operator [](size_t Item);
inline T& operator [](size_t Item) const;
inline T* operator + (size_t Pos);
inline size_t Size(); // Returns the size in items, not in bytes.
void Add(size_t Items);
void Alloc(size_t Items);
void Reset();
void SoftReset();
void operator = (Array<T> &Src);
void Push(T Item);
T* Addr() {return(Buffer);}
void Append(T *Item,size_t Count);
T* Addr(size_t Item) {return Buffer+Item;}
void SetMaxSize(size_t Size) {MaxSize=Size;}
T* Begin() {return Buffer;}
T* End() {return Buffer==NULL ? NULL:Buffer+BufSize;}
void SetSecure() {Secure=true;}
};
template <class T> void Array<T>::CleanData()
{
Buffer=NULL;
BufSize=0;
AllocSize=0;
MaxSize=0;
Secure=false;
}
@@ -40,30 +53,47 @@ template <class T> Array<T>::Array()
template <class T> Array<T>::Array(size_t Size)
{
Buffer=(T *)malloc(sizeof(T)*Size);
if (Buffer==NULL && Size!=0)
ErrHandler.MemoryError();
CleanData();
Add(Size);
}
AllocSize=BufSize=Size;
// Copy constructor in case we need to pass an object as value.
template <class T> Array<T>::Array(const Array &Src)
{
CleanData();
Alloc(Src.BufSize);
if (Src.BufSize!=0)
memcpy((void *)Buffer,(void *)Src.Buffer,Src.BufSize*sizeof(T));
}
template <class T> Array<T>::~Array()
{
if (Buffer!=NULL)
{
if (Secure)
cleandata(Buffer,AllocSize*sizeof(T));
free(Buffer);
}
}
template <class T> inline T& Array<T>::operator [](size_t Item)
template <class T> inline T& Array<T>::operator [](size_t Item) const
{
return(Buffer[Item]);
return Buffer[Item];
}
template <class T> inline T* Array<T>::operator +(size_t Pos)
{
return Buffer+Pos;
}
template <class T> inline size_t Array<T>::Size()
{
return(BufSize);
return BufSize;
}
@@ -72,12 +102,35 @@ template <class T> void Array<T>::Add(size_t Items)
BufSize+=Items;
if (BufSize>AllocSize)
{
if (MaxSize!=0 && BufSize>MaxSize)
{
ErrHandler.GeneralErrMsg(L"Maximum allowed array size (%u) is exceeded",MaxSize);
ErrHandler.MemoryError();
}
size_t Suggested=AllocSize+AllocSize/4+32;
size_t NewSize=Max(BufSize,Suggested);
Buffer=(T *)realloc(Buffer,NewSize*sizeof(T));
if (Buffer==NULL)
ErrHandler.MemoryError();
T *NewBuffer;
if (Secure)
{
NewBuffer=(T *)malloc(NewSize*sizeof(T));
if (NewBuffer==NULL)
ErrHandler.MemoryError();
if (Buffer!=NULL)
{
memcpy(NewBuffer,Buffer,AllocSize*sizeof(T));
cleandata(Buffer,AllocSize*sizeof(T));
free(Buffer);
}
}
else
{
NewBuffer=(T *)realloc(Buffer,NewSize*sizeof(T));
if (NewBuffer==NULL)
ErrHandler.MemoryError();
}
Buffer=NewBuffer;
AllocSize=NewSize;
}
}
@@ -104,6 +157,14 @@ template <class T> void Array<T>::Reset()
}
// Reset buffer size, but preserve already allocated memory if any,
// so we can reuse it without wasting time to allocation.
template <class T> void Array<T>::SoftReset()
{
BufSize=0;
}
template <class T> void Array<T>::operator =(Array<T> &Src)
{
Reset();
@@ -119,4 +180,12 @@ template <class T> void Array<T>::Push(T Item)
(*this)[Size()-1]=Item;
}
template <class T> void Array<T>::Append(T *Items,size_t Count)
{
size_t CurSize=Size();
Add(Count);
memcpy(Buffer+CurSize,Items,Count*sizeof(T));
}
#endif

View File

@@ -1,113 +0,0 @@
void ExtractBeEA(Archive &Arc,char *FileName)
{
if (Arc.HeaderCRC!=Arc.EAHead.HeadCRC)
{
Log(Arc.FileName,St(MEABroken),FileName);
ErrHandler.SetErrorCode(CRC_ERROR);
return;
}
if (Arc.EAHead.Method<0x31 || Arc.EAHead.Method>0x35 || Arc.EAHead.UnpVer>PACK_VER)
{
Log(Arc.FileName,St(MEAUnknHeader),FileName);
return;
}
ComprDataIO DataIO;
Unpack Unpack(&DataIO);
Unpack.Init();
Array<byte> UnpData(Arc.EAHead.UnpSize);
DataIO.SetUnpackToMemory(&UnpData[0],Arc.EAHead.UnpSize);
DataIO.SetPackedSizeToRead(Arc.EAHead.DataSize);
DataIO.EnableShowProgress(false);
DataIO.SetFiles(&Arc,NULL);
Unpack.SetDestSize(Arc.EAHead.UnpSize);
Unpack.DoUnpack(Arc.EAHead.UnpVer,false);
if (Arc.EAHead.EACRC!=~DataIO.UnpFileCRC)
{
Log(Arc.FileName,St(MEABroken),FileName);
ErrHandler.SetErrorCode(CRC_ERROR);
return;
}
int fd = open(FileName,O_WRONLY);
if (fd==-1)
{
Log(Arc.FileName,St(MCannotSetEA),FileName);
ErrHandler.SetErrorCode(WARNING);
return;
}
int AttrPos=0;
while (AttrPos<Arc.EAHead.UnpSize)
{
unsigned char *CurItem=&UnpData[AttrPos];
int NameSize=CurItem[0]+((int)CurItem[1]<<8);
int Type=CurItem[2]+((int)CurItem[3]<<8)+((int)CurItem[4]<<16)+((int)CurItem[5]<<24);
int Size=CurItem[6]+((int)CurItem[7]<<8)+((int)CurItem[8]<<16)+((int)CurItem[9]<<24);
char Name[1024];
if (NameSize>=sizeof(Name))
{
Log(Arc.FileName,St(MCannotSetEA),FileName);
ErrHandler.SetErrorCode(WARNING);
break;
}
memcpy(Name,CurItem+10,NameSize);
Name[NameSize]=0;
if (fs_write_attr(fd,Name,Type,0,CurItem+10+NameSize,Size)==-1)
{
Log(Arc.FileName,St(MCannotSetEA),FileName);
ErrHandler.SetErrorCode(WARNING);
break;
}
AttrPos+=10+NameSize+Size;
}
close(fd);
mprintf(St(MShowEA));
}
void ExtractBeEANew(Archive &Arc,char *FileName)
{
Array<byte> SubData;
if (!Arc.ReadSubData(&SubData,NULL))
return;
int fd = open(FileName,O_WRONLY);
if (fd==-1)
{
Log(Arc.FileName,St(MCannotSetEA),FileName);
ErrHandler.SetErrorCode(WARNING);
return;
}
int AttrPos=0;
while (AttrPos<Arc.EAHead.UnpSize)
{
unsigned char *CurItem=&SubData[AttrPos];
int NameSize=CurItem[0]+((int)CurItem[1]<<8);
int Type=CurItem[2]+((int)CurItem[3]<<8)+((int)CurItem[4]<<16)+((int)CurItem[5]<<24);
int Size=CurItem[6]+((int)CurItem[7]<<8)+((int)CurItem[8]<<16)+((int)CurItem[9]<<24);
char Name[1024];
if (NameSize>=sizeof(Name))
{
Log(Arc.FileName,St(MCannotSetEA),FileName);
ErrHandler.SetErrorCode(WARNING);
break;
}
memcpy(Name,CurItem+10,NameSize);
Name[NameSize]=0;
if (fs_write_attr(fd,Name,Type,0,CurItem+10+NameSize,Size)==-1)
{
Log(Arc.FileName,St(MCannotSetEA),FileName);
ErrHandler.SetErrorCode(WARNING);
break;
}
AttrPos+=10+NameSize+Size;
}
close(fd);
mprintf(St(MShowEA));
}

183
unrar/blake2s.cpp Normal file
View File

@@ -0,0 +1,183 @@
// Based on public domain code written in 2012 by Samuel Neves
#include "rar.hpp"
#ifdef USE_SSE
#include "blake2s_sse.cpp"
#endif
static void blake2s_init_param( blake2s_state *S, uint32 node_offset, uint32 node_depth);
static void blake2s_update( blake2s_state *S, const byte *in, size_t inlen );
static void blake2s_final( blake2s_state *S, byte *digest );
#include "blake2sp.cpp"
static const uint32 blake2s_IV[8] =
{
0x6A09E667UL, 0xBB67AE85UL, 0x3C6EF372UL, 0xA54FF53AUL,
0x510E527FUL, 0x9B05688CUL, 0x1F83D9ABUL, 0x5BE0CD19UL
};
static const byte blake2s_sigma[10][16] =
{
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } ,
{ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } ,
{ 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } ,
{ 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } ,
{ 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } ,
{ 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } ,
{ 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } ,
{ 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } ,
{ 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } ,
{ 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } ,
};
static inline void blake2s_set_lastnode( blake2s_state *S )
{
S->f[1] = ~0U;
}
/* Some helper functions, not necessarily useful */
static inline void blake2s_set_lastblock( blake2s_state *S )
{
if( S->last_node ) blake2s_set_lastnode( S );
S->f[0] = ~0U;
}
static inline void blake2s_increment_counter( blake2s_state *S, const uint32 inc )
{
S->t[0] += inc;
S->t[1] += ( S->t[0] < inc );
}
/* init2 xors IV with input parameter block */
void blake2s_init_param( blake2s_state *S, uint32 node_offset, uint32 node_depth)
{
#ifdef USE_SSE
if (_SSE_Version>=SSE_SSE2)
blake2s_init_sse();
#endif
S->init(); // Clean data.
for( int i = 0; i < 8; ++i )
S->h[i] = blake2s_IV[i];
S->h[0] ^= 0x02080020; // We use BLAKE2sp parameters block.
S->h[2] ^= node_offset;
S->h[3] ^= (node_depth<<16)|0x20000000;
}
#define G(r,i,m,a,b,c,d) \
a = a + b + m[blake2s_sigma[r][2*i+0]]; \
d = rotr32(d ^ a, 16); \
c = c + d; \
b = rotr32(b ^ c, 12); \
a = a + b + m[blake2s_sigma[r][2*i+1]]; \
d = rotr32(d ^ a, 8); \
c = c + d; \
b = rotr32(b ^ c, 7);
static void blake2s_compress( blake2s_state *S, const byte block[BLAKE2S_BLOCKBYTES] )
{
uint32 m[16];
uint32 v[16];
for( size_t i = 0; i < 16; ++i )
m[i] = RawGet4( block + i * 4 );
for( size_t i = 0; i < 8; ++i )
v[i] = S->h[i];
v[ 8] = blake2s_IV[0];
v[ 9] = blake2s_IV[1];
v[10] = blake2s_IV[2];
v[11] = blake2s_IV[3];
v[12] = S->t[0] ^ blake2s_IV[4];
v[13] = S->t[1] ^ blake2s_IV[5];
v[14] = S->f[0] ^ blake2s_IV[6];
v[15] = S->f[1] ^ blake2s_IV[7];
for ( uint r = 0; r <= 9; ++r ) // No gain on i7 if unrolled, but exe size grows.
{
G(r,0,m,v[ 0],v[ 4],v[ 8],v[12]);
G(r,1,m,v[ 1],v[ 5],v[ 9],v[13]);
G(r,2,m,v[ 2],v[ 6],v[10],v[14]);
G(r,3,m,v[ 3],v[ 7],v[11],v[15]);
G(r,4,m,v[ 0],v[ 5],v[10],v[15]);
G(r,5,m,v[ 1],v[ 6],v[11],v[12]);
G(r,6,m,v[ 2],v[ 7],v[ 8],v[13]);
G(r,7,m,v[ 3],v[ 4],v[ 9],v[14]);
}
for( size_t i = 0; i < 8; ++i )
S->h[i] = S->h[i] ^ v[i] ^ v[i + 8];
}
void blake2s_update( blake2s_state *S, const byte *in, size_t inlen )
{
while( inlen > 0 )
{
size_t left = S->buflen;
size_t fill = 2 * BLAKE2S_BLOCKBYTES - left;
if( inlen > fill )
{
memcpy( S->buf + left, in, fill ); // Fill buffer
S->buflen += fill;
blake2s_increment_counter( S, BLAKE2S_BLOCKBYTES );
#ifdef USE_SSE
#ifdef _WIN_32 // We use SSSE3 _mm_shuffle_epi8 only in x64 mode.
if (_SSE_Version>=SSE_SSE2)
#else
if (_SSE_Version>=SSE_SSSE3)
#endif
blake2s_compress_sse( S, S->buf );
else
blake2s_compress( S, S->buf ); // Compress
#else
blake2s_compress( S, S->buf ); // Compress
#endif
memcpy( S->buf, S->buf + BLAKE2S_BLOCKBYTES, BLAKE2S_BLOCKBYTES ); // Shift buffer left
S->buflen -= BLAKE2S_BLOCKBYTES;
in += fill;
inlen -= fill;
}
else // inlen <= fill
{
memcpy( S->buf + left, in, (size_t)inlen );
S->buflen += (size_t)inlen; // Be lazy, do not compress
in += inlen;
inlen = 0;
}
}
}
void blake2s_final( blake2s_state *S, byte *digest )
{
if( S->buflen > BLAKE2S_BLOCKBYTES )
{
blake2s_increment_counter( S, BLAKE2S_BLOCKBYTES );
blake2s_compress( S, S->buf );
S->buflen -= BLAKE2S_BLOCKBYTES;
memcpy( S->buf, S->buf + BLAKE2S_BLOCKBYTES, S->buflen );
}
blake2s_increment_counter( S, ( uint32 )S->buflen );
blake2s_set_lastblock( S );
memset( S->buf + S->buflen, 0, 2 * BLAKE2S_BLOCKBYTES - S->buflen ); /* Padding */
blake2s_compress( S, S->buf );
for( int i = 0; i < 8; ++i ) /* Output full hash */
RawPut4( S->h[i], digest + 4 * i );
}

101
unrar/blake2s.hpp Normal file
View File

@@ -0,0 +1,101 @@
// Based on public domain code written in 2012 by Samuel Neves
#ifndef _RAR_BLAKE2_
#define _RAR_BLAKE2_
#define BLAKE2_DIGEST_SIZE 32
enum blake2s_constant
{
BLAKE2S_BLOCKBYTES = 64,
BLAKE2S_OUTBYTES = 32
};
// Alignment to 64 improves performance of both SSE and non-SSE versions.
// Alignment to n*16 is required for SSE version, so we selected 64.
// We use the custom alignment scheme instead of __declspec(align(x)),
// because it is less compiler dependent. Also the compiler directive
// does not help if structure is a member of class allocated through
// 'new' operator.
struct blake2s_state
{
enum { BLAKE_ALIGNMENT = 64 };
// buffer and uint32 h[8], t[2], f[2];
enum { BLAKE_DATA_SIZE = 48 + 2 * BLAKE2S_BLOCKBYTES };
byte ubuf[BLAKE_DATA_SIZE + BLAKE_ALIGNMENT];
byte *buf; // byte buf[2 * BLAKE2S_BLOCKBYTES].
uint32 *h, *t, *f; // uint32 h[8], t[2], f[2].
size_t buflen;
byte last_node;
blake2s_state()
{
set_pointers();
}
// Required when we declare and assign in the same command.
blake2s_state(blake2s_state &st)
{
set_pointers();
*this=st;
}
void set_pointers()
{
// Set aligned pointers. Must be done in constructor, not in Init(),
// so assignments like 'blake2sp_state res=blake2ctx' work correctly
// even if blake2sp_init is not called for 'res'.
buf = (byte *) ALIGN_VALUE(ubuf, BLAKE_ALIGNMENT);
h = (uint32 *) (buf + 2 * BLAKE2S_BLOCKBYTES);
t = h + 8;
f = t + 2;
}
void init()
{
memset( ubuf, 0, sizeof( ubuf ) );
buflen = 0;
last_node = 0;
}
// Since we use pointers, the default = would work incorrectly.
blake2s_state& operator = (blake2s_state &st)
{
if (this != &st)
{
memcpy(buf, st.buf, BLAKE_DATA_SIZE);
buflen = st.buflen;
last_node = st.last_node;
}
return *this;
}
};
#ifdef RAR_SMP
class ThreadPool;
#endif
struct blake2sp_state
{
blake2s_state S[8];
blake2s_state R;
byte buf[8 * BLAKE2S_BLOCKBYTES];
size_t buflen;
#ifdef RAR_SMP
ThreadPool *ThPool;
uint MaxThreads;
#endif
};
void blake2sp_init( blake2sp_state *S );
void blake2sp_update( blake2sp_state *S, const byte *in, size_t inlen );
void blake2sp_final( blake2sp_state *S, byte *digest );
#endif

129
unrar/blake2s_sse.cpp Normal file
View File

@@ -0,0 +1,129 @@
// Based on public domain code written in 2012 by Samuel Neves
extern const byte blake2s_sigma[10][16];
// Initialization vector.
static __m128i blake2s_IV_0_3, blake2s_IV_4_7;
#ifdef _WIN_64
// Constants for cyclic rotation. Used in 64-bit mode in mm_rotr_epi32 macro.
static __m128i crotr8, crotr16;
#endif
static void blake2s_init_sse()
{
// We cannot initialize these 128 bit variables in place when declaring
// them globally, because global scope initialization is performed before
// our SSE check and it would make code incompatible with older non-SSE2
// CPUs. Also we cannot initialize them as static inside of function
// using these variables, because SSE static initialization is not thread
// safe: first thread starts initialization and sets "init done" flag even
// if it is not done yet, second thread can attempt to access half-init
// SSE data. So we moved init code here.
blake2s_IV_0_3 = _mm_setr_epi32( 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A );
blake2s_IV_4_7 = _mm_setr_epi32( 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19 );
#ifdef _WIN_64
crotr8 = _mm_set_epi8( 12, 15, 14, 13, 8, 11, 10, 9, 4, 7, 6, 5, 0, 3, 2, 1 );
crotr16 = _mm_set_epi8( 13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2 );
#endif
}
#define LOAD(p) _mm_load_si128( (__m128i *)(p) )
#define STORE(p,r) _mm_store_si128((__m128i *)(p), r)
#ifdef _WIN_32
// 32-bit mode has less SSE2 registers and in MSVC2008 it is more efficient
// to not use _mm_shuffle_epi8 here.
#define mm_rotr_epi32(r, c) ( \
_mm_xor_si128(_mm_srli_epi32( (r), c ),_mm_slli_epi32( (r), 32-c )) )
#else
#define mm_rotr_epi32(r, c) ( \
c==8 ? _mm_shuffle_epi8(r,crotr8) \
: c==16 ? _mm_shuffle_epi8(r,crotr16) \
: _mm_xor_si128(_mm_srli_epi32( (r), c ),_mm_slli_epi32( (r), 32-c )) )
#endif
#define G1(row1,row2,row3,row4,buf) \
row1 = _mm_add_epi32( _mm_add_epi32( row1, buf), row2 ); \
row4 = _mm_xor_si128( row4, row1 ); \
row4 = mm_rotr_epi32(row4, 16); \
row3 = _mm_add_epi32( row3, row4 ); \
row2 = _mm_xor_si128( row2, row3 ); \
row2 = mm_rotr_epi32(row2, 12);
#define G2(row1,row2,row3,row4,buf) \
row1 = _mm_add_epi32( _mm_add_epi32( row1, buf), row2 ); \
row4 = _mm_xor_si128( row4, row1 ); \
row4 = mm_rotr_epi32(row4, 8); \
row3 = _mm_add_epi32( row3, row4 ); \
row2 = _mm_xor_si128( row2, row3 ); \
row2 = mm_rotr_epi32(row2, 7);
#define DIAGONALIZE(row1,row2,row3,row4) \
row4 = _mm_shuffle_epi32( row4, _MM_SHUFFLE(2,1,0,3) ); \
row3 = _mm_shuffle_epi32( row3, _MM_SHUFFLE(1,0,3,2) ); \
row2 = _mm_shuffle_epi32( row2, _MM_SHUFFLE(0,3,2,1) );
#define UNDIAGONALIZE(row1,row2,row3,row4) \
row4 = _mm_shuffle_epi32( row4, _MM_SHUFFLE(0,3,2,1) ); \
row3 = _mm_shuffle_epi32( row3, _MM_SHUFFLE(1,0,3,2) ); \
row2 = _mm_shuffle_epi32( row2, _MM_SHUFFLE(2,1,0,3) );
#ifdef _WIN_64
// MSVC 2008 in x64 mode expands _mm_set_epi32 to store to stack and load
// from stack operations, which are slower than this code.
#define _mm_set_epi32(i3,i2,i1,i0) \
_mm_unpacklo_epi32(_mm_unpacklo_epi32(_mm_cvtsi32_si128(i0),_mm_cvtsi32_si128(i2)), \
_mm_unpacklo_epi32(_mm_cvtsi32_si128(i1),_mm_cvtsi32_si128(i3)))
#endif
// Original BLAKE2 SSE4.1 message loading code was a little slower in x86 mode
// and about the same in x64 mode in our test. Perhaps depends on compiler.
// We also tried _mm_i32gather_epi32 and _mm256_i32gather_epi32 AVX2 gather
// instructions here, but they did not show any speed gain on i7-6700K.
#define SSE_ROUND(m,row,r) \
{ \
__m128i buf; \
buf=_mm_set_epi32(m[blake2s_sigma[r][6]],m[blake2s_sigma[r][4]],m[blake2s_sigma[r][2]],m[blake2s_sigma[r][0]]); \
G1(row[0],row[1],row[2],row[3],buf); \
buf=_mm_set_epi32(m[blake2s_sigma[r][7]],m[blake2s_sigma[r][5]],m[blake2s_sigma[r][3]],m[blake2s_sigma[r][1]]); \
G2(row[0],row[1],row[2],row[3],buf); \
DIAGONALIZE(row[0],row[1],row[2],row[3]); \
buf=_mm_set_epi32(m[blake2s_sigma[r][14]],m[blake2s_sigma[r][12]],m[blake2s_sigma[r][10]],m[blake2s_sigma[r][8]]); \
G1(row[0],row[1],row[2],row[3],buf); \
buf=_mm_set_epi32(m[blake2s_sigma[r][15]],m[blake2s_sigma[r][13]],m[blake2s_sigma[r][11]],m[blake2s_sigma[r][9]]); \
G2(row[0],row[1],row[2],row[3],buf); \
UNDIAGONALIZE(row[0],row[1],row[2],row[3]); \
}
static int blake2s_compress_sse( blake2s_state *S, const byte block[BLAKE2S_BLOCKBYTES] )
{
__m128i row[4];
__m128i ff0, ff1;
const uint32 *m = ( uint32 * )block;
row[0] = ff0 = LOAD( &S->h[0] );
row[1] = ff1 = LOAD( &S->h[4] );
row[2] = blake2s_IV_0_3;
row[3] = _mm_xor_si128( blake2s_IV_4_7, LOAD( &S->t[0] ) );
SSE_ROUND( m, row, 0 );
SSE_ROUND( m, row, 1 );
SSE_ROUND( m, row, 2 );
SSE_ROUND( m, row, 3 );
SSE_ROUND( m, row, 4 );
SSE_ROUND( m, row, 5 );
SSE_ROUND( m, row, 6 );
SSE_ROUND( m, row, 7 );
SSE_ROUND( m, row, 8 );
SSE_ROUND( m, row, 9 );
STORE( &S->h[0], _mm_xor_si128( ff0, _mm_xor_si128( row[0], row[2] ) ) );
STORE( &S->h[4], _mm_xor_si128( ff1, _mm_xor_si128( row[1], row[3] ) ) );
return 0;
}

153
unrar/blake2sp.cpp Normal file
View File

@@ -0,0 +1,153 @@
/*
BLAKE2 reference source code package - reference C implementations
Written in 2012 by Samuel Neves <sneves@dei.uc.pt>
To the extent possible under law, the author(s) have dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
You should have received a copy of the CC0 Public Domain Dedication along with
this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#define PARALLELISM_DEGREE 8
void blake2sp_init( blake2sp_state *S )
{
memset( S->buf, 0, sizeof( S->buf ) );
S->buflen = 0;
blake2s_init_param( &S->R, 0, 1 ); // Init root.
for( uint i = 0; i < PARALLELISM_DEGREE; ++i )
blake2s_init_param( &S->S[i], i, 0 ); // Init leaf.
S->R.last_node = 1;
S->S[PARALLELISM_DEGREE - 1].last_node = 1;
}
struct Blake2ThreadData
{
void Update();
blake2s_state *S;
const byte *in;
size_t inlen;
};
void Blake2ThreadData::Update()
{
size_t inlen__ = inlen;
const byte *in__ = ( const byte * )in;
while( inlen__ >= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES )
{
#ifdef USE_SSE
// We gain 5% in i7 SSE mode by prefetching next data block.
if (_SSE_Version>=SSE_SSE && inlen__ >= 2 * PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES)
_mm_prefetch((char*)(in__ + PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES), _MM_HINT_T0);
#endif
blake2s_update( S, in__, BLAKE2S_BLOCKBYTES );
in__ += PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES;
inlen__ -= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES;
}
}
#ifdef RAR_SMP
THREAD_PROC(Blake2Thread)
{
Blake2ThreadData *td=(Blake2ThreadData *)Data;
td->Update();
}
#endif
void blake2sp_update( blake2sp_state *S, const byte *in, size_t inlen )
{
size_t left = S->buflen;
size_t fill = sizeof( S->buf ) - left;
if( left && inlen >= fill )
{
memcpy( S->buf + left, in, fill );
for( size_t i = 0; i < PARALLELISM_DEGREE; ++i )
blake2s_update( &S->S[i], S->buf + i * BLAKE2S_BLOCKBYTES, BLAKE2S_BLOCKBYTES );
in += fill;
inlen -= fill;
left = 0;
}
Blake2ThreadData btd_array[PARALLELISM_DEGREE];
#ifdef RAR_SMP
uint ThreadNumber = inlen < 0x1000 ? 1 : S->MaxThreads;
if (ThreadNumber==6 || ThreadNumber==7) // 6 and 7 threads work slower than 4 here.
ThreadNumber=4;
#else
uint ThreadNumber=1;
#endif
for (size_t id__=0;id__<PARALLELISM_DEGREE;)
{
for (uint Thread=0;Thread<ThreadNumber && id__<PARALLELISM_DEGREE;Thread++)
{
Blake2ThreadData *btd=btd_array+Thread;
btd->inlen = inlen;
btd->in = in + id__ * BLAKE2S_BLOCKBYTES;
btd->S = &S->S[id__];
#ifdef RAR_SMP
if (ThreadNumber>1)
S->ThPool->AddTask(Blake2Thread,(void*)btd);
else
btd->Update();
#else
btd->Update();
#endif
id__++;
}
#ifdef RAR_SMP
if (S->ThPool!=NULL) // Can be NULL in -mt1 mode.
S->ThPool->WaitDone();
#endif // RAR_SMP
}
in += inlen - inlen % ( PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES );
inlen %= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES;
if( inlen > 0 )
memcpy( S->buf + left, in, (size_t)inlen );
S->buflen = left + (size_t)inlen;
}
void blake2sp_final( blake2sp_state *S, byte *digest )
{
byte hash[PARALLELISM_DEGREE][BLAKE2S_OUTBYTES];
for( size_t i = 0; i < PARALLELISM_DEGREE; ++i )
{
if( S->buflen > i * BLAKE2S_BLOCKBYTES )
{
size_t left = S->buflen - i * BLAKE2S_BLOCKBYTES;
if( left > BLAKE2S_BLOCKBYTES ) left = BLAKE2S_BLOCKBYTES;
blake2s_update( &S->S[i], S->buf + i * BLAKE2S_BLOCKBYTES, left );
}
blake2s_final( &S->S[i], hash[i] );
}
for( size_t i = 0; i < PARALLELISM_DEGREE; ++i )
blake2s_update( &S->R, hash[i], BLAKE2S_OUTBYTES );
blake2s_final( &S->R, digest );
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,57 +1,64 @@
#ifndef _RAR_CMDDATA_
#define _RAR_CMDDATA_
#define DefaultStoreList "7z;ace;arj;bz2;cab;gz;jpeg;jpg;lha;lzh;mp3;rar;taz;tgz;z;zip"
#define DefaultStoreList L"7z;ace;arj;bz2;cab;gz;jpeg;jpg;lha;lz;lzh;mp3;rar;taz;tgz;xz;z;zip;zipx"
enum RAR_CMD_LIST_MODE {RCLM_AUTO,RCLM_REJECT_LISTS,RCLM_ACCEPT_LISTS};
class CommandData:public RAROptions
{
private:
void ProcessSwitchesString(char *Str);
void ProcessSwitch(char *Switch,wchar *SwitchW=NULL);
void BadSwitch(char *Switch);
bool ExclCheckArgs(StringList *Args,bool Dir,char *CheckName,bool CheckFullPath,int MatchMode);
uint GetExclAttr(char *Str);
void ProcessSwitchesString(const wchar *Str);
void ProcessSwitch(const wchar *Switch);
void BadSwitch(const wchar *Switch);
uint GetExclAttr(const wchar *Str);
bool FileLists;
bool NoMoreSwitches;
RAR_CMD_LIST_MODE ListMode;
bool BareOutput;
public:
CommandData();
~CommandData();
void Init();
void Close();
void ParseArg(char *Arg,wchar *ArgW);
void ParseCommandLine(bool Preprocess,int argc, char *argv[]);
void ParseArg(wchar *ArgW);
void ParseDone();
void ParseEnvVar();
void ReadConfig(int argc,char *argv[]);
bool IsConfigEnabled(int argc,char *argv[]);
void ReadConfig();
void PreprocessArg(const wchar *Arg);
void OutTitle();
void OutHelp();
void OutHelp(RAR_EXIT ExitCode);
bool IsSwitch(int Ch);
bool ExclCheck(char *CheckName,bool Dir,bool CheckFullPath,bool CheckInclList);
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 SizeCheck(int64 Size);
bool AnyFiltersActive();
int IsProcessFile(FileHeader &NewLhd,bool *ExactMatch=NULL,int MatchType=MATCH_WILDSUBPATH);
int IsProcessFile(FileHeader &FileHead,bool *ExactMatch=NULL,int MatchType=MATCH_WILDSUBPATH,
wchar *MatchedArg=NULL,uint MatchedArgSize=0);
void ProcessCommand();
void AddArcName(const char *Name,const wchar *NameW);
bool GetArcName(char *Name,wchar *NameW,int MaxSize);
void AddArcName(const wchar *Name);
bool GetArcName(wchar *Name,int MaxSize);
bool CheckWinSize();
int GetRecoverySize(char *Str,int DefSize);
int GetRecoverySize(const wchar *Str,int DefSize);
char Command[NM+16];
wchar CommandW[NM+16];
#ifndef SFX_MODULE
void ReportWrongSwitches(RARFORMAT Format);
#endif
char ArcName[NM];
wchar ArcNameW[NM];
wchar Command[NM+16];
StringList *FileArgs;
StringList *ExclArgs;
StringList *InclArgs;
StringList *ArcNames;
StringList *StoreArgs;
wchar ArcName[NM];
StringList FileArgs;
StringList ExclArgs;
StringList InclArgs;
StringList ArcNames;
StringList StoreArgs;
};
#endif

View File

@@ -2,7 +2,6 @@
* Contents: 'Carryless rangecoder' by Dmitry Subbotin *
****************************************************************************/
const uint TOP=1 << 24, BOT=1 << 15;
class RangeCoder
{

View File

@@ -1,41 +1,50 @@
#ifndef _RAR_COMPRESS_
#define _RAR_COMPRESS_
class ComprDataIO;
class PackingFileTable;
// Combine pack and unpack constants to class to avoid polluting global
// namespace with numerous short names.
class PackDef
{
public:
static const uint MAX_LZ_MATCH = 0x1001;
static const uint MAX3_LZ_MATCH = 0x101; // Maximum match length for RAR v3.
static const uint LOW_DIST_REP_COUNT = 16;
#define MAX_LZ_MATCH 0x101
static const uint NC = 306; /* alphabet = {0, 1, 2, ..., NC - 1} */
static const uint DC = 64;
static const uint LDC = 16;
static const uint RC = 44;
static const uint HUFF_TABLE_SIZE = NC + DC + RC + LDC;
static const uint BC = 20;
#define CODEBUFSIZE 0x4000
#define MAXWINSIZE 0x400000
#define MAXWINMASK (MAXWINSIZE-1)
static const uint NC30 = 299; /* alphabet = {0, 1, 2, ..., NC - 1} */
static const uint DC30 = 60;
static const uint LDC30 = 17;
static const uint RC30 = 28;
static const uint BC30 = 20;
static const uint HUFF_TABLE_SIZE30 = NC30 + DC30 + RC30 + LDC30;
#define LOW_DIST_REP_COUNT 16
static const uint NC20 = 298; /* alphabet = {0, 1, 2, ..., NC - 1} */
static const uint DC20 = 48;
static const uint RC20 = 28;
static const uint BC20 = 19;
static const uint MC20 = 257;
#define NC 299 /* alphabet = {0, 1, 2, ..., NC - 1} */
#define DC 60
#define LDC 17
#define RC 28
#define HUFF_TABLE_SIZE (NC+DC+RC+LDC)
#define BC 20
// Largest alphabet size among all values listed above.
static const uint LARGEST_TABLE_SIZE = 306;
#define NC20 298 /* alphabet = {0, 1, 2, ..., NC - 1} */
#define DC20 48
#define RC20 28
#define BC20 19
#define MC20 257
// Largest alphabet size among all values listed above.
#define LARGEST_TABLE_SIZE 299
enum {CODE_HUFFMAN,CODE_LZ,CODE_LZ2,CODE_REPEATLZ,CODE_CACHELZ,
CODE_STARTFILE,CODE_ENDFILE,CODE_VM,CODE_VMDATA};
enum {
CODE_HUFFMAN, CODE_LZ, CODE_REPEATLZ, CODE_CACHELZ, CODE_STARTFILE,
CODE_ENDFILE, CODE_FILTER, CODE_FILTERDATA
};
};
enum FilterType {
FILTER_NONE, FILTER_PPM /*dummy*/, FILTER_E8, FILTER_E8E9,
FILTER_UPCASETOLOW, FILTER_AUDIO, FILTER_RGB, FILTER_DELTA,
FILTER_ITANIUM, FILTER_E8E9V2
// These values must not be changed, because we use them directly
// in RAR5 compression and decompression code.
FILTER_DELTA=0, FILTER_E8, FILTER_E8E9, FILTER_ARM,
FILTER_AUDIO, FILTER_RGB, FILTER_ITANIUM, FILTER_PPM, FILTER_NONE
};
#endif

View File

@@ -1,225 +1,286 @@
#include "rar.hpp"
#ifndef GUI
#include "log.cpp"
#endif
static int KbdAnsi(char *Addr,int Size);
#if !defined(GUI) && !defined(SILENT)
static void RawPrint(char *Msg,MESSAGE_TYPE MessageType);
static uint GetKey();
#endif
static MESSAGE_TYPE MsgStream=MSG_STDOUT;
static bool Sound=false;
static RAR_CHARSET RedirectCharset=RCH_DEFAULT;
const int MaxMsgSize=2*NM+2048;
void InitConsoleOptions(MESSAGE_TYPE MsgStream,bool Sound)
static bool StdoutRedirected=false,StderrRedirected=false,StdinRedirected=false;
#ifdef _WIN_ALL
static bool IsRedirected(DWORD nStdHandle)
{
::MsgStream=MsgStream;
::Sound=Sound;
HANDLE hStd=GetStdHandle(nStdHandle);
DWORD Mode;
return GetFileType(hStd)!=FILE_TYPE_CHAR || GetConsoleMode(hStd,&Mode)==0;
}
#endif
void InitConsole()
{
#ifdef _WIN_ALL
// We want messages like file names or progress percent to be printed
// immediately. Use only in Windows, in Unix they can cause wprintf %ls
// to fail with non-English strings.
setbuf(stdout,NULL);
setbuf(stderr,NULL);
// Detect if output is redirected and set output mode properly.
// We do not want to send Unicode output to files and especially to pipes
// like '|more', which cannot handle them correctly in Windows.
// In Unix console output is UTF-8 and it is handled correctly
// when redirecting, so no need to perform any adjustments.
StdoutRedirected=IsRedirected(STD_OUTPUT_HANDLE);
StderrRedirected=IsRedirected(STD_ERROR_HANDLE);
StdinRedirected=IsRedirected(STD_INPUT_HANDLE);
#ifdef _MSC_VER
if (!StdoutRedirected)
_setmode(_fileno(stdout), _O_U16TEXT);
if (!StderrRedirected)
_setmode(_fileno(stderr), _O_U16TEXT);
#endif
#elif defined(_UNIX)
StdoutRedirected=!isatty(fileno(stdout));
StderrRedirected=!isatty(fileno(stderr));
StdinRedirected=!isatty(fileno(stdin));
#endif
}
#if !defined(GUI) && !defined(SILENT)
void mprintf(const char *fmt,...)
void InitConsoleOptions(MESSAGE_TYPE MsgStream,RAR_CHARSET RedirectCharset)
{
::MsgStream=MsgStream;
::RedirectCharset=RedirectCharset;
}
#ifndef SILENT
static void cvt_wprintf(FILE *dest,const wchar *fmt,va_list arglist)
{
// This buffer is for format string only, not for entire output,
// so it can be short enough.
wchar fmtw[1024];
PrintfPrepareFmt(fmt,fmtw,ASIZE(fmtw));
#ifdef _WIN_ALL
safebuf wchar Msg[MaxMsgSize];
if (dest==stdout && StdoutRedirected || dest==stderr && StderrRedirected)
{
HANDLE hOut=GetStdHandle(dest==stdout ? STD_OUTPUT_HANDLE:STD_ERROR_HANDLE);
vswprintf(Msg,ASIZE(Msg),fmtw,arglist);
DWORD Written;
if (RedirectCharset==RCH_UNICODE)
WriteFile(hOut,Msg,(DWORD)wcslen(Msg)*sizeof(*Msg),&Written,NULL);
else
{
// Avoid Unicode for redirect in Windows, it does not work with pipes.
safebuf char MsgA[MaxMsgSize];
if (RedirectCharset==RCH_UTF8)
WideToUtf(Msg,MsgA,ASIZE(MsgA));
else
WideToChar(Msg,MsgA,ASIZE(MsgA));
if (RedirectCharset==RCH_DEFAULT || RedirectCharset==RCH_OEM)
CharToOemA(MsgA,MsgA); // Console tools like 'more' expect OEM encoding.
// We already converted \n to \r\n above, so we use WriteFile instead
// of C library to avoid unnecessary additional conversion.
WriteFile(hOut,MsgA,(DWORD)strlen(MsgA),&Written,NULL);
}
return;
}
// MSVC2008 vfwprintf writes every character to console separately
// and it is too slow. We use direct WriteConsole call instead.
vswprintf(Msg,ASIZE(Msg),fmtw,arglist);
HANDLE hOut=GetStdHandle(dest==stderr ? STD_ERROR_HANDLE:STD_OUTPUT_HANDLE);
DWORD Written;
WriteConsole(hOut,Msg,(DWORD)wcslen(Msg),&Written,NULL);
#else
vfwprintf(dest,fmtw,arglist);
// We do not use setbuf(NULL) in Unix (see comments in InitConsole).
fflush(dest);
#endif
}
void mprintf(const wchar *fmt,...)
{
if (MsgStream==MSG_NULL || MsgStream==MSG_ERRONLY)
return;
safebuf char Msg[MaxMsgSize];
va_list argptr;
va_start(argptr,fmt);
vsprintf(Msg,fmt,argptr);
RawPrint(Msg,MsgStream);
va_end(argptr);
fflush(stderr); // Ensure proper message order.
va_list arglist;
va_start(arglist,fmt);
FILE *dest=MsgStream==MSG_STDERR ? stderr:stdout;
cvt_wprintf(dest,fmt,arglist);
va_end(arglist);
}
#endif
#if !defined(GUI) && !defined(SILENT)
void eprintf(const char *fmt,...)
#ifndef SILENT
void eprintf(const wchar *fmt,...)
{
if (MsgStream==MSG_NULL)
return;
safebuf char Msg[MaxMsgSize];
va_list argptr;
va_start(argptr,fmt);
vsprintf(Msg,fmt,argptr);
RawPrint(Msg,MSG_STDERR);
va_end(argptr);
}
#endif
fflush(stdout); // Ensure proper message order.
#if !defined(GUI) && !defined(SILENT)
void RawPrint(char *Msg,MESSAGE_TYPE MessageType)
{
File OutFile;
switch(MessageType)
{
case MSG_STDOUT:
OutFile.SetHandleType(FILE_HANDLESTD);
break;
case MSG_STDERR:
case MSG_ERRONLY:
OutFile.SetHandleType(FILE_HANDLEERR);
break;
default:
return;
}
#ifdef _WIN_ALL
CharToOemA(Msg,Msg);
char OutMsg[MaxMsgSize],*OutPos=OutMsg;
for (int I=0;Msg[I]!=0;I++)
{
if (Msg[I]=='\n' && (I==0 || Msg[I-1]!='\r'))
*(OutPos++)='\r';
*(OutPos++)=Msg[I];
}
*OutPos=0;
strcpy(Msg,OutMsg);
#endif
#if defined(_UNIX) || defined(_EMX)
char OutMsg[MaxMsgSize],*OutPos=OutMsg;
for (int I=0;Msg[I]!=0;I++)
if (Msg[I]!='\r')
*(OutPos++)=Msg[I];
*OutPos=0;
strcpy(Msg,OutMsg);
#endif
OutFile.Write(Msg,strlen(Msg));
va_list arglist;
va_start(arglist,fmt);
cvt_wprintf(stderr,fmt,arglist);
va_end(arglist);
}
#endif
#ifndef SILENT
void Alarm()
{
#ifndef SFX_MODULE
if (Sound)
putchar('\007');
#endif
}
#endif
#ifndef SILENT
#ifndef GUI
void GetPasswordText(wchar *Str,uint MaxLength)
static void GetPasswordText(wchar *Str,uint MaxLength)
{
if (MaxLength==0)
return;
if (StdinRedirected)
getwstr(Str,MaxLength); // Read from pipe or redirected file.
else
{
#ifdef _WIN_ALL
HANDLE hConIn=GetStdHandle(STD_INPUT_HANDLE);
HANDLE hConOut=GetStdHandle(STD_OUTPUT_HANDLE);
DWORD ConInMode,ConOutMode;
DWORD Read=0;
GetConsoleMode(hConIn,&ConInMode);
GetConsoleMode(hConOut,&ConOutMode);
SetConsoleMode(hConIn,ENABLE_LINE_INPUT);
SetConsoleMode(hConOut,ENABLE_PROCESSED_OUTPUT|ENABLE_WRAP_AT_EOL_OUTPUT);
HANDLE hConIn=GetStdHandle(STD_INPUT_HANDLE);
HANDLE hConOut=GetStdHandle(STD_OUTPUT_HANDLE);
DWORD ConInMode,ConOutMode;
DWORD Read=0;
GetConsoleMode(hConIn,&ConInMode);
GetConsoleMode(hConOut,&ConOutMode);
SetConsoleMode(hConIn,ENABLE_LINE_INPUT);
SetConsoleMode(hConOut,ENABLE_PROCESSED_OUTPUT|ENABLE_WRAP_AT_EOL_OUTPUT);
ReadConsoleW(hConIn,Str,MaxLength-1,&Read,NULL);
Str[Read]=0;
SetConsoleMode(hConIn,ConInMode);
SetConsoleMode(hConOut,ConOutMode);
ReadConsole(hConIn,Str,MaxLength-1,&Read,NULL);
Str[Read]=0;
SetConsoleMode(hConIn,ConInMode);
SetConsoleMode(hConOut,ConOutMode);
#else
char StrA[MAXPASSWORD];
#if defined(_EMX) || defined(_BEOS) || defined(__sparc) || defined(sparc) || defined (__VMS)
fgets(StrA,ASIZE(StrA)-1,stdin);
char StrA[MAXPASSWORD];
#if defined(_EMX) || defined (__VMS)
fgets(StrA,ASIZE(StrA)-1,stdin);
#elif defined(__sun)
strncpyz(StrA,getpassphrase(""),ASIZE(StrA));
#else
strncpyz(StrA,getpass(""),ASIZE(StrA));
strncpyz(StrA,getpass(""),ASIZE(StrA));
#endif
CharToWide(StrA,Str,MaxLength);
CharToWide(StrA,Str,MaxLength);
cleandata(StrA,sizeof(StrA));
#endif
}
Str[MaxLength-1]=0;
RemoveLF(Str);
}
#endif
#endif
#ifndef SILENT
bool GetPassword(PASSWORD_TYPE Type,const char *FileName,const wchar *FileNameW,wchar *Password,uint MaxLength)
bool GetConsolePassword(UIPASSWORD_TYPE Type,const wchar *FileName,SecPassword *Password)
{
Alarm();
if (!StdinRedirected)
uiAlarm(UIALARM_QUESTION);
while (true)
{
char PromptStr[NM+256];
#if defined(_EMX) || defined(_BEOS)
strcpy(PromptStr,St(MAskPswEcho));
#else
strcpy(PromptStr,St(MAskPsw));
#endif
if (Type!=PASSWORD_GLOBAL)
{
strcat(PromptStr,St(MFor));
char *NameOnly=PointToName(FileName);
if (strlen(PromptStr)+strlen(NameOnly)<ASIZE(PromptStr))
strcat(PromptStr,NameOnly);
}
eprintf("\n%s: ",PromptStr);
GetPasswordText(Password,MaxLength);
if (*Password==0 && Type==PASSWORD_GLOBAL)
return(false);
if (Type==PASSWORD_GLOBAL)
if (!StdinRedirected)
if (Type==UIPASSWORD_GLOBAL)
eprintf(L"\n%s: ",St(MAskPsw));
else
eprintf(St(MAskPswFor),FileName);
wchar PlainPsw[MAXPASSWORD];
GetPasswordText(PlainPsw,ASIZE(PlainPsw));
if (*PlainPsw==0 && Type==UIPASSWORD_GLOBAL)
return false;
if (!StdinRedirected && Type==UIPASSWORD_GLOBAL)
{
eprintf(St(MReAskPsw));
wchar CmpStr[MAXPASSWORD];
GetPasswordText(CmpStr,ASIZE(CmpStr));
if (*CmpStr==0 || wcscmp(Password,CmpStr)!=0)
if (*CmpStr==0 || wcscmp(PlainPsw,CmpStr)!=0)
{
eprintf(St(MNotMatchPsw));
memset(Password,0,MaxLength*sizeof(*Password));
memset(CmpStr,0,sizeof(CmpStr));
cleandata(PlainPsw,sizeof(PlainPsw));
cleandata(CmpStr,sizeof(CmpStr));
continue;
}
memset(CmpStr,0,sizeof(CmpStr));
cleandata(CmpStr,sizeof(CmpStr));
}
Password->Set(PlainPsw);
cleandata(PlainPsw,sizeof(PlainPsw));
break;
}
return(true);
return true;
}
#endif
#if !defined(GUI) && !defined(SILENT)
uint GetKey()
#ifndef SILENT
bool getwstr(wchar *str,size_t n)
{
char Str[80];
bool EndOfFile;
#if defined(__GNUC__) || defined(sun)
EndOfFile=(fgets(Str,sizeof(Str),stdin)==NULL);
#else
File SrcFile;
SrcFile.SetHandleType(FILE_HANDLESTD);
EndOfFile=(SrcFile.Read(Str,sizeof(Str))==0);
#endif
if (EndOfFile)
// Print buffered prompt title function before waiting for input.
fflush(stderr);
*str=0;
#if defined(_WIN_ALL)
// fgetws does not work well with non-English text in Windows,
// so we do not use it.
if (StdinRedirected) // ReadConsole does not work if redirected.
{
// Looks like stdin is a null device. We can enter to infinite loop
// calling Ask(), so let's better exit.
ErrHandler.Exit(USER_BREAK);
// fgets does not work well with pipes in Windows in our test.
// Let's use files.
Array<char> StrA(n*4); // Up to 4 UTF-8 characters per wchar_t.
File SrcFile;
SrcFile.SetHandleType(FILE_HANDLESTD);
int ReadSize=SrcFile.Read(&StrA[0],StrA.Size()-1);
if (ReadSize<=0)
{
// Looks like stdin is a null device. We can enter to infinite loop
// calling Ask(), so let's better exit.
ErrHandler.Exit(RARX_USERBREAK);
}
StrA[ReadSize]=0;
CharToWide(&StrA[0],str,n);
cleandata(&StrA[0],StrA.Size()); // We can use this function to enter passwords.
}
return(Str[0]);
else
{
DWORD ReadSize=0;
if (ReadConsole(GetStdHandle(STD_INPUT_HANDLE),str,DWORD(n-1),&ReadSize,NULL)==0)
return false;
str[ReadSize]=0;
}
#else
if (fgetws(str,n,stdin)==NULL)
ErrHandler.Exit(RARX_USERBREAK); // Avoid infinite Ask() loop.
#endif
RemoveLF(str);
return true;
}
#endif
#if !defined(GUI) && !defined(SILENT)
int Ask(const char *AskStr)
#ifndef SILENT
// We allow this function to return 0 in case of invalid input,
// because it might be convenient to press Enter to some not dangerous
// prompts like "insert disk with next volume". We should call this function
// again in case of 0 in dangerous prompt such as overwriting file.
int Ask(const wchar *AskStr)
{
uiAlarm(UIALARM_QUESTION);
const int MaxItems=10;
char Item[MaxItems][40];
wchar Item[MaxItems][40];
int ItemKeyPos[MaxItems],NumItems=0;
for (const char *NextItem=AskStr;NextItem!=NULL;NextItem=strchr(NextItem+1,'_'))
for (const wchar *NextItem=AskStr;NextItem!=NULL;NextItem=wcschr(NextItem+1,'_'))
{
char *CurItem=Item[NumItems];
strncpyz(CurItem,NextItem+1,ASIZE(Item[0]));
char *EndItem=strchr(CurItem,'_');
wchar *CurItem=Item[NumItems];
wcsncpyz(CurItem,NextItem+1,ASIZE(Item[0]));
wchar *EndItem=wcschr(CurItem,'_');
if (EndItem!=NULL)
*EndItem=0;
int KeyPos=0,CurKey;
@@ -227,7 +288,7 @@ int Ask(const char *AskStr)
{
bool Found=false;
for (int I=0;I<NumItems && !Found;I++)
if (loctoupper(Item[I][ItemKeyPos[I]])==loctoupper(CurKey))
if (toupperw(Item[I][ItemKeyPos[I]])==toupperw(CurKey))
Found=true;
if (!Found && CurKey!=' ')
break;
@@ -239,61 +300,53 @@ int Ask(const char *AskStr)
for (int I=0;I<NumItems;I++)
{
eprintf(I==0 ? (NumItems>4 ? "\n":" "):", ");
eprintf(I==0 ? (NumItems>4 ? L"\n":L" "):L", ");
int KeyPos=ItemKeyPos[I];
for (int J=0;J<KeyPos;J++)
eprintf("%c",Item[I][J]);
eprintf("[%c]%s",Item[I][KeyPos],&Item[I][KeyPos+1]);
eprintf(L"%c",Item[I][J]);
eprintf(L"[%c]%ls",Item[I][KeyPos],&Item[I][KeyPos+1]);
}
eprintf(" ");
int Ch=GetKey();
#if defined(_WIN_ALL)
OemToCharBuff((LPCSTR)&Ch,(LPTSTR)&Ch,1);
#endif
Ch=loctoupper(Ch);
eprintf(L" ");
wchar Str[50];
getwstr(Str,ASIZE(Str));
wchar Ch=toupperw(Str[0]);
for (int I=0;I<NumItems;I++)
if (Ch==Item[I][ItemKeyPos[I]])
return(I+1);
return(0);
return I+1;
return 0;
}
#endif
int KbdAnsi(char *Addr,size_t Size)
static bool IsCommentUnsafe(const wchar *Data,size_t Size)
{
int RetCode=0;
#ifndef GUI
for (size_t I=0;I<Size;I++)
if (Addr[I]==27 && Addr[I+1]=='[')
{
if (Data[I]==27 && Data[I+1]=='[')
for (size_t J=I+2;J<Size;J++)
{
if (Addr[J]=='\"')
return(2);
if (!IsDigit(Addr[J]) && Addr[J]!=';')
// Return true for <ESC>[{key};"{string}"p used to redefine
// a keyboard key on some terminals.
if (Data[J]=='\"')
return true;
if (!IsDigit(Data[J]) && Data[J]!=';')
break;
}
RetCode=1;
}
#endif
return(RetCode);
return false;
}
void OutComment(char *Comment,size_t Size)
void OutComment(const wchar *Comment,size_t Size)
{
#ifndef GUI
if (KbdAnsi(Comment,Size)==2)
if (IsCommentUnsafe(Comment,Size))
return;
const size_t MaxOutSize=0x400;
for (size_t I=0;I<Size;I+=MaxOutSize)
{
char Msg[MaxOutSize+1];
wchar Msg[MaxOutSize+1];
size_t CopySize=Min(MaxOutSize,Size-I);
strncpy(Msg,Comment+I,CopySize);
wcsncpy(Msg,Comment+I,CopySize);
Msg[CopySize]=0;
mprintf("%s",Msg);
mprintf(L"%s",Msg);
}
mprintf("\n");
#endif
mprintf(L"\n");
}

View File

@@ -1,37 +1,26 @@
#ifndef _RAR_CONSIO_
#define _RAR_CONSIO_
#if !defined(SILENT) && !defined(SFX_MODULE)
enum {SOUND_OK,SOUND_ALARM,SOUND_ERROR,SOUND_QUESTION};
#endif
enum PASSWORD_TYPE {PASSWORD_GLOBAL,PASSWORD_FILE,PASSWORD_ARCHIVE};
void InitConsoleOptions(MESSAGE_TYPE MsgStream,bool Sound);
void InitConsole();
void InitConsoleOptions(MESSAGE_TYPE MsgStream,RAR_CHARSET RedirectCharset);
void OutComment(const wchar *Comment,size_t Size);
#ifndef SILENT
void mprintf(const char *fmt,...);
void eprintf(const char *fmt,...);
void Alarm();
void GetPasswordText(wchar *Str,uint MaxLength);
bool GetPassword(PASSWORD_TYPE Type,const char *FileName,const wchar *FileNameW,wchar *Password,uint MaxLength);
int Ask(const char *AskStr);
bool GetConsolePassword(UIPASSWORD_TYPE Type,const wchar *FileName,SecPassword *Password);
#endif
void OutComment(char *Comment,size_t Size);
#ifdef SILENT
#ifdef __GNUC__
#define mprintf(args...)
#define eprintf(args...)
#else
inline void mprintf(const char *fmt,...) {}
inline void eprintf(const char *fmt,...) {}
#endif
inline void mprintf(const wchar *fmt,...) {}
inline void eprintf(const wchar *fmt,...) {}
inline void Alarm() {}
inline void GetPasswordText(wchar *Str,uint MaxLength) {}
inline bool GetPassword(PASSWORD_TYPE Type,const char *FileName,const wchar *FileNameW,wchar *Password,uint MaxLength) {return(false);}
inline int Ask(const char *AskStr) {return(0);}
inline int Ask(const wchar *AskStr) {return 0;}
inline bool getwstr(wchar *str,size_t n) {return false;}
#else
void mprintf(const wchar *fmt,...);
void eprintf(const wchar *fmt,...);
void Alarm();
int Ask(const wchar *AskStr);
bool getwstr(wchar *str,size_t n);
#endif
#endif

View File

@@ -1,56 +1,93 @@
// This CRC function is based on Intel Slicing-by-8 algorithm.
//
// Original Intel Slicing-by-8 code is available here:
//
// http://sourceforge.net/projects/slicing-by-8/
//
// Original Intel Slicing-by-8 code is licensed as:
//
// Copyright (c) 2004-2006 Intel Corporation - All Rights Reserved
//
// This software program is licensed subject to the BSD License,
// available at http://www.opensource.org/licenses/bsd-license.html
#include "rar.hpp"
uint CRCTab[256];
static uint crc_tables[8][256]; // Tables for Slicing-by-8.
void InitCRC()
// Build the classic CRC32 lookup table.
// We also provide this function to legacy RAR and ZIP decryption code.
void InitCRC32(uint *CRCTab)
{
for (int I=0;I<256;I++)
if (CRCTab[1]!=0)
return;
for (uint I=0;I<256;I++)
{
uint C=I;
for (int J=0;J<8;J++)
C=(C & 1) ? (C>>1)^0xEDB88320L : (C>>1);
for (uint J=0;J<8;J++)
C=(C & 1) ? (C>>1)^0xEDB88320 : (C>>1);
CRCTab[I]=C;
}
}
uint CRC(uint StartCRC,const void *Addr,size_t Size)
static void InitTables()
{
if (CRCTab[1]==0)
InitCRC();
byte *Data=(byte *)Addr;
InitCRC32(crc_tables[0]);
#if defined(LITTLE_ENDIAN) && defined(PRESENT_INT32) && defined(ALLOW_NOT_ALIGNED_INT)
while (Size>0 && ((long)Data & 7))
for (uint I=0;I<256;I++) // Build additional lookup tables.
{
StartCRC=CRCTab[(byte)(StartCRC^Data[0])]^(StartCRC>>8);
Size--;
Data++;
uint C=crc_tables[0][I];
for (uint J=1;J<8;J++)
{
C=crc_tables[0][(byte)C]^(C>>8);
crc_tables[J][I]=C;
}
}
while (Size>=8)
{
StartCRC^=*(uint32 *)Data;
StartCRC=CRCTab[(byte)StartCRC]^(StartCRC>>8);
StartCRC=CRCTab[(byte)StartCRC]^(StartCRC>>8);
StartCRC=CRCTab[(byte)StartCRC]^(StartCRC>>8);
StartCRC=CRCTab[(byte)StartCRC]^(StartCRC>>8);
StartCRC^=*(uint32 *)(Data+4);
StartCRC=CRCTab[(byte)StartCRC]^(StartCRC>>8);
StartCRC=CRCTab[(byte)StartCRC]^(StartCRC>>8);
StartCRC=CRCTab[(byte)StartCRC]^(StartCRC>>8);
StartCRC=CRCTab[(byte)StartCRC]^(StartCRC>>8);
Data+=8;
Size-=8;
}
#endif
for (size_t I=0;I<Size;I++)
StartCRC=CRCTab[(byte)(StartCRC^Data[I])]^(StartCRC>>8);
return(StartCRC);
}
struct CallInitCRC {CallInitCRC() {InitTables();}} static CallInit32;
uint CRC32(uint StartCRC,const void *Addr,size_t Size)
{
byte *Data=(byte *)Addr;
// Align Data to 8 for better performance.
for (;Size>0 && ((size_t)Data & 7);Size--,Data++)
StartCRC=crc_tables[0][(byte)(StartCRC^Data[0])]^(StartCRC>>8);
for (;Size>=8;Size-=8,Data+=8)
{
#ifdef BIG_ENDIAN
StartCRC ^= Data[0]|(Data[1] << 8)|(Data[2] << 16)|(Data[3] << 24);
uint NextData = Data[4]|(Data[5] << 8)|(Data[6] << 16)|(Data[7] << 24);
#else
StartCRC ^= *(uint32 *) Data;
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[1][(byte)(NextData >> 16)] ^
crc_tables[0][(byte)(NextData >> 24)];
}
for (;Size>0;Size--,Data++) // Process left data.
StartCRC=crc_tables[0][(byte)(StartCRC^Data[0])]^(StartCRC>>8);
return StartCRC;
}
#ifndef SFX_MODULE
ushort OldCRC(ushort StartCRC,const void *Addr,size_t Size)
// For RAR 1.4 archives in case somebody still has them.
ushort Checksum14(ushort StartCRC,const void *Addr,size_t Size)
{
byte *Data=(byte *)Addr;
for (size_t I=0;I<Size;I++)
@@ -58,6 +95,8 @@ ushort OldCRC(ushort StartCRC,const void *Addr,size_t Size)
StartCRC=(StartCRC+Data[I])&0xffff;
StartCRC=((StartCRC<<1)|(StartCRC>>15))&0xffff;
}
return(StartCRC);
return StartCRC;
}
#endif

View File

@@ -1,10 +1,15 @@
#ifndef _RAR_CRC_
#define _RAR_CRC_
extern uint CRCTab[256];
// This function is only to intialize external CRC tables. We do not need to
// call it before calculating CRC32.
void InitCRC32(uint *CRCTab);
uint CRC32(uint StartCRC,const void *Addr,size_t Size);
#ifndef SFX_MODULE
ushort Checksum14(ushort StartCRC,const void *Addr,size_t Size);
#endif
void InitCRC();
uint CRC(uint StartCRC,const void *Addr,size_t Size);
ushort OldCRC(ushort StartCRC,const void *Addr,size_t Size);
#endif

View File

@@ -1,380 +1,134 @@
#include "rar.hpp"
#ifndef SFX_MODULE
extern uint CRCTab[256];
#include "crypt1.cpp"
#include "crypt2.cpp"
#endif
#define NROUNDS 32
#define rol(x,n,xsize) (((x)<<(n)) | ((x)>>(xsize-(n))))
#define ror(x,n,xsize) (((x)>>(n)) | ((x)<<(xsize-(n))))
#define substLong(t) ( (uint)SubstTable[(uint)t&255] | \
((uint)SubstTable[(int)(t>> 8)&255]<< 8) | \
((uint)SubstTable[(int)(t>>16)&255]<<16) | \
((uint)SubstTable[(int)(t>>24)&255]<<24) )
CryptKeyCacheItem CryptData::Cache[4];
int CryptData::CachePos=0;
#include "crypt3.cpp"
#include "crypt5.cpp"
#ifndef SFX_MODULE
static byte InitSubstTable[256]={
215, 19,149, 35, 73,197,192,205,249, 28, 16,119, 48,221, 2, 42,
232, 1,177,233, 14, 88,219, 25,223,195,244, 90, 87,239,153,137,
255,199,147, 70, 92, 66,246, 13,216, 40, 62, 29,217,230, 86, 6,
71, 24,171,196,101,113,218,123, 93, 91,163,178,202, 67, 44,235,
107,250, 75,234, 49,167,125,211, 83,114,157,144, 32,193,143, 36,
158,124,247,187, 89,214,141, 47,121,228, 61,130,213,194,174,251,
97,110, 54,229,115, 57,152, 94,105,243,212, 55,209,245, 63, 11,
164,200, 31,156, 81,176,227, 21, 76, 99,139,188,127, 17,248, 51,
207,120,189,210, 8,226, 41, 72,183,203,135,165,166, 60, 98, 7,
122, 38,155,170, 69,172,252,238, 39,134, 59,128,236, 27,240, 80,
131, 3, 85,206,145, 79,154,142,159,220,201,133, 74, 64, 20,129,
224,185,138,103,173,182, 43, 34,254, 82,198,151,231,180, 58, 10,
118, 26,102, 12, 50,132, 22,191,136,111,162,179, 45, 4,148,108,
161, 56, 78,126,242,222, 15,175,146, 23, 33,241,181,190, 77,225,
0, 46,169,186, 68, 95,237, 65, 53,208,253,168, 9, 18,100, 52,
116,184,160, 96,109, 37, 30,106,140,104,150, 5,204,117,112, 84
};
#endif
CryptData::CryptData()
{
Method=CRYPT_NONE;
memset(KDF3Cache,0,sizeof(KDF3Cache));
memset(KDF5Cache,0,sizeof(KDF5Cache));
KDF3CachePos=0;
KDF5CachePos=0;
memset(CRCTab,0,sizeof(CRCTab));
}
CryptData::~CryptData()
{
cleandata(KDF3Cache,sizeof(KDF3Cache));
cleandata(KDF5Cache,sizeof(KDF5Cache));
}
void CryptData::DecryptBlock(byte *Buf,size_t Size)
{
rin.blockDecrypt(Buf,Size,Buf);
}
#ifndef SFX_MODULE
void CryptData::EncryptBlock20(byte *Buf)
{
uint A,B,C,D,T,TA,TB;
#if defined(BIG_ENDIAN) || !defined(PRESENT_INT32) || !defined(ALLOW_NOT_ALIGNED_INT)
A=((uint)Buf[0]|((uint)Buf[1]<<8)|((uint)Buf[2]<<16)|((uint)Buf[3]<<24))^Key[0];
B=((uint)Buf[4]|((uint)Buf[5]<<8)|((uint)Buf[6]<<16)|((uint)Buf[7]<<24))^Key[1];
C=((uint)Buf[8]|((uint)Buf[9]<<8)|((uint)Buf[10]<<16)|((uint)Buf[11]<<24))^Key[2];
D=((uint)Buf[12]|((uint)Buf[13]<<8)|((uint)Buf[14]<<16)|((uint)Buf[15]<<24))^Key[3];
#else
uint32 *BufPtr=(uint32 *)Buf;
A=BufPtr[0]^Key[0];
B=BufPtr[1]^Key[1];
C=BufPtr[2]^Key[2];
D=BufPtr[3]^Key[3];
#endif
for(int I=0;I<NROUNDS;I++)
{
T=((C+rol(D,11,32))^Key[I&3]);
TA=A^substLong(T);
T=((D^rol(C,17,32))+Key[I&3]);
TB=B^substLong(T);
A=C;
B=D;
C=TA;
D=TB;
}
#if defined(BIG_ENDIAN) || !defined(PRESENT_INT32) || !defined(ALLOW_NOT_ALIGNED_INT)
C^=Key[0];
Buf[0]=(byte)C;
Buf[1]=(byte)(C>>8);
Buf[2]=(byte)(C>>16);
Buf[3]=(byte)(C>>24);
D^=Key[1];
Buf[4]=(byte)D;
Buf[5]=(byte)(D>>8);
Buf[6]=(byte)(D>>16);
Buf[7]=(byte)(D>>24);
A^=Key[2];
Buf[8]=(byte)A;
Buf[9]=(byte)(A>>8);
Buf[10]=(byte)(A>>16);
Buf[11]=(byte)(A>>24);
B^=Key[3];
Buf[12]=(byte)B;
Buf[13]=(byte)(B>>8);
Buf[14]=(byte)(B>>16);
Buf[15]=(byte)(B>>24);
#else
BufPtr[0]=C^Key[0];
BufPtr[1]=D^Key[1];
BufPtr[2]=A^Key[2];
BufPtr[3]=B^Key[3];
#endif
UpdKeys(Buf);
}
void CryptData::DecryptBlock20(byte *Buf)
{
byte InBuf[16];
uint A,B,C,D,T,TA,TB;
#if defined(BIG_ENDIAN) || !defined(PRESENT_INT32) || !defined(ALLOW_NOT_ALIGNED_INT)
A=((uint)Buf[0]|((uint)Buf[1]<<8)|((uint)Buf[2]<<16)|((uint)Buf[3]<<24))^Key[0];
B=((uint)Buf[4]|((uint)Buf[5]<<8)|((uint)Buf[6]<<16)|((uint)Buf[7]<<24))^Key[1];
C=((uint)Buf[8]|((uint)Buf[9]<<8)|((uint)Buf[10]<<16)|((uint)Buf[11]<<24))^Key[2];
D=((uint)Buf[12]|((uint)Buf[13]<<8)|((uint)Buf[14]<<16)|((uint)Buf[15]<<24))^Key[3];
#else
uint32 *BufPtr=(uint32 *)Buf;
A=BufPtr[0]^Key[0];
B=BufPtr[1]^Key[1];
C=BufPtr[2]^Key[2];
D=BufPtr[3]^Key[3];
#endif
memcpy(InBuf,Buf,sizeof(InBuf));
for(int I=NROUNDS-1;I>=0;I--)
{
T=((C+rol(D,11,32))^Key[I&3]);
TA=A^substLong(T);
T=((D^rol(C,17,32))+Key[I&3]);
TB=B^substLong(T);
A=C;
B=D;
C=TA;
D=TB;
}
#if defined(BIG_ENDIAN) || !defined(PRESENT_INT32) || !defined(ALLOW_NOT_ALIGNED_INT)
C^=Key[0];
Buf[0]=(byte)C;
Buf[1]=(byte)(C>>8);
Buf[2]=(byte)(C>>16);
Buf[3]=(byte)(C>>24);
D^=Key[1];
Buf[4]=(byte)D;
Buf[5]=(byte)(D>>8);
Buf[6]=(byte)(D>>16);
Buf[7]=(byte)(D>>24);
A^=Key[2];
Buf[8]=(byte)A;
Buf[9]=(byte)(A>>8);
Buf[10]=(byte)(A>>16);
Buf[11]=(byte)(A>>24);
B^=Key[3];
Buf[12]=(byte)B;
Buf[13]=(byte)(B>>8);
Buf[14]=(byte)(B>>16);
Buf[15]=(byte)(B>>24);
#else
BufPtr[0]=C^Key[0];
BufPtr[1]=D^Key[1];
BufPtr[2]=A^Key[2];
BufPtr[3]=B^Key[3];
#endif
UpdKeys(InBuf);
}
void CryptData::UpdKeys(byte *Buf)
{
for (int I=0;I<16;I+=4)
{
Key[0]^=CRCTab[Buf[I]];
Key[1]^=CRCTab[Buf[I+1]];
Key[2]^=CRCTab[Buf[I+2]];
Key[3]^=CRCTab[Buf[I+3]];
}
}
void CryptData::Swap(byte *Ch1,byte *Ch2)
{
byte Ch=*Ch1;
*Ch1=*Ch2;
*Ch2=Ch;
}
#endif
void CryptData::SetCryptKeys(const wchar *Password,const byte *Salt,bool Encrypt,bool OldOnly,bool HandsOffHash)
{
if (*Password==0)
return;
if (OldOnly)
switch(Method)
{
#ifndef SFX_MODULE
if (CRCTab[1]==0)
InitCRC();
char Psw[MAXPASSWORD];
memset(Psw,0,sizeof(Psw));
// We need to use ASCII password for older encryption algorithms.
WideToChar(Password,Psw,ASIZE(Psw));
Psw[ASIZE(Psw)-1]=0;
size_t PswLength=strlen(Psw);
SetOldKeys(Psw);
Key[0]=0xD3A3B879L;
Key[1]=0x3F6D12F7L;
Key[2]=0x7515A235L;
Key[3]=0xA4E7F123L;
memcpy(SubstTable,InitSubstTable,sizeof(SubstTable));
for (int J=0;J<256;J++)
for (size_t I=0;I<PswLength;I+=2)
{
uint N1=(byte)CRCTab [ (byte(Psw[I]) - J) &0xff];
uint N2=(byte)CRCTab [ (byte(Psw[I+1]) + J) &0xff];
for (int K=1;N1!=N2;N1=(N1+1)&0xff,K++)
Swap(&SubstTable[N1],&SubstTable[(N1+I+K)&0xff]);
}
for (size_t I=0;I<PswLength;I+=16)
EncryptBlock20((byte *)&Psw[I]);
#endif
return;
}
bool Cached=false;
for (uint I=0;I<ASIZE(Cache);I++)
if (wcscmp(Cache[I].Password,Password)==0 &&
(Salt==NULL && !Cache[I].SaltPresent || Salt!=NULL &&
Cache[I].SaltPresent && memcmp(Cache[I].Salt,Salt,SALT_SIZE)==0) &&
Cache[I].HandsOffHash==HandsOffHash)
{
memcpy(AESKey,Cache[I].AESKey,sizeof(AESKey));
memcpy(AESInit,Cache[I].AESInit,sizeof(AESInit));
Cached=true;
case CRYPT_RAR13:
Decrypt13(Buf,Size);
break;
case CRYPT_RAR15:
Crypt15(Buf,Size);
break;
case CRYPT_RAR20:
for (size_t I=0;I<Size;I+=CRYPT_BLOCK_SIZE)
DecryptBlock20(Buf+I);
break;
}
if (!Cached)
{
byte RawPsw[2*MAXPASSWORD+SALT_SIZE];
WideToRaw(Password,RawPsw);
size_t RawLength=2*wcslen(Password);
if (Salt!=NULL)
{
memcpy(RawPsw+RawLength,Salt,SALT_SIZE);
RawLength+=SALT_SIZE;
}
hash_context c;
hash_initial(&c);
const int HashRounds=0x40000;
for (int I=0;I<HashRounds;I++)
{
hash_process( &c, RawPsw, RawLength, HandsOffHash);
byte PswNum[3];
PswNum[0]=(byte)I;
PswNum[1]=(byte)(I>>8);
PswNum[2]=(byte)(I>>16);
hash_process( &c, PswNum, 3, HandsOffHash);
if (I%(HashRounds/16)==0)
{
hash_context tempc=c;
uint32 digest[5];
hash_final( &tempc, digest, HandsOffHash);
AESInit[I/(HashRounds/16)]=(byte)digest[4];
}
}
uint32 digest[5];
hash_final( &c, digest, HandsOffHash);
for (int I=0;I<4;I++)
for (int J=0;J<4;J++)
AESKey[I*4+J]=(byte)(digest[I]>>(J*8));
wcscpy(Cache[CachePos].Password,Password);
if ((Cache[CachePos].SaltPresent=(Salt!=NULL))==true)
memcpy(Cache[CachePos].Salt,Salt,SALT_SIZE);
Cache[CachePos].HandsOffHash=HandsOffHash;
memcpy(Cache[CachePos].AESKey,AESKey,sizeof(AESKey));
memcpy(Cache[CachePos].AESInit,AESInit,sizeof(AESInit));
CachePos=(CachePos+1)%(sizeof(Cache)/sizeof(Cache[0]));
}
rin.init(Encrypt ? Rijndael::Encrypt : Rijndael::Decrypt,AESKey,AESInit);
}
#ifndef SFX_MODULE
void CryptData::SetOldKeys(const char *Password)
{
uint PswCRC=CRC(0xffffffff,Password,strlen(Password));
OldKey[0]=PswCRC&0xffff;
OldKey[1]=(PswCRC>>16)&0xffff;
OldKey[2]=OldKey[3]=0;
PN1=PN2=PN3=0;
byte Ch;
while ((Ch=*Password)!=0)
{
PN1+=Ch;
PN2^=Ch;
PN3+=Ch;
PN3=(byte)rol(PN3,1,8);
OldKey[2]^=Ch^CRCTab[Ch];
OldKey[3]+=Ch+(CRCTab[Ch]>>16);
Password++;
}
}
void CryptData::SetAV15Encryption()
{
OldKey[0]=0x4765;
OldKey[1]=0x9021;
OldKey[2]=0x7382;
OldKey[3]=0x5215;
}
void CryptData::SetCmt13Encryption()
{
PN1=0;
PN2=7;
PN3=77;
}
void CryptData::Crypt(byte *Data,uint Count,int Method)
{
if (Method==OLD_DECODE)
Decode13(Data,Count);
else
if (Method==OLD_ENCODE)
Encode13(Data,Count);
else
Crypt15(Data,Count);
}
void CryptData::Encode13(byte *Data,uint Count)
{
while (Count--)
{
PN2+=PN3;
PN1+=PN2;
*Data+=PN1;
Data++;
}
}
void CryptData::Decode13(byte *Data,uint Count)
{
while (Count--)
{
PN2+=PN3;
PN1+=PN2;
*Data-=PN1;
Data++;
}
}
void CryptData::Crypt15(byte *Data,uint Count)
{
while (Count--)
{
OldKey[0]+=0x1234;
OldKey[1]^=CRCTab[(OldKey[0] & 0x1fe)>>1];
OldKey[2]-=CRCTab[(OldKey[0] & 0x1fe)>>1]>>16;
OldKey[0]^=OldKey[2];
OldKey[3]=ror(OldKey[3]&0xffff,1,16)^OldKey[1];
OldKey[3]=ror(OldKey[3]&0xffff,1,16);
OldKey[0]^=OldKey[3];
*Data^=(byte)(OldKey[0]>>8);
Data++;
}
}
#endif
case CRYPT_RAR30:
case CRYPT_RAR50:
rin.blockDecrypt(Buf,Size,Buf);
break;
}
}
bool CryptData::SetCryptKeys(bool Encrypt,CRYPT_METHOD Method,
SecPassword *Password,const byte *Salt,
const byte *InitV,uint Lg2Cnt,byte *HashKey,byte *PswCheck)
{
if (!Password->IsSet() || Method==CRYPT_NONE)
return false;
CryptData::Method=Method;
wchar PwdW[MAXPASSWORD];
Password->Get(PwdW,ASIZE(PwdW));
char PwdA[MAXPASSWORD];
WideToChar(PwdW,PwdA,ASIZE(PwdA));
switch(Method)
{
#ifndef SFX_MODULE
case CRYPT_RAR13:
SetKey13(PwdA);
break;
case CRYPT_RAR15:
SetKey15(PwdA);
break;
case CRYPT_RAR20:
SetKey20(PwdA);
break;
#endif
case CRYPT_RAR30:
SetKey30(Encrypt,Password,PwdW,Salt);
break;
case CRYPT_RAR50:
SetKey50(Encrypt,Password,PwdW,Salt,InitV,Lg2Cnt,HashKey,PswCheck);
break;
}
cleandata(PwdA,sizeof(PwdA));
cleandata(PwdW,sizeof(PwdW));
return true;
}
// Use the current system time to additionally randomize data.
static void TimeRandomize(byte *RndBuf,size_t BufSize)
{
static uint Count=0;
RarTime CurTime;
CurTime.SetCurrentTime();
uint64 Random=CurTime.GetWin()+clock();
for (size_t I=0;I<BufSize;I++)
{
byte RndByte = byte (Random >> ( (I & 7) * 8 ));
RndBuf[I]=byte( (RndByte ^ I) + Count++);
}
}
// Fill buffer with random data.
void GetRnd(byte *RndBuf,size_t BufSize)
{
bool Success=false;
#if defined(_WIN_ALL)
HCRYPTPROV hProvider = 0;
if (CryptAcquireContext(&hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
{
Success=CryptGenRandom(hProvider, (DWORD)BufSize, RndBuf) == TRUE;
CryptReleaseContext(hProvider, 0);
}
#elif defined(_UNIX)
FILE *rndf = fopen("/dev/urandom", "r");
if (rndf!=NULL)
{
Success=fread(RndBuf, BufSize, 1, rndf) == BufSize;
fclose(rndf);
}
#endif
// We use this code only as the last resort if code above failed.
if (!Success)
TimeRandomize(RndBuf,BufSize);
}

View File

@@ -1,62 +1,101 @@
#ifndef _RAR_CRYPT_
#define _RAR_CRYPT_
enum { OLD_DECODE=0,OLD_ENCODE=1,NEW_CRYPT=2 };
struct CryptKeyCacheItem
{
#ifndef _SFX_RTL_
CryptKeyCacheItem()
{
*Password=0;
}
~CryptKeyCacheItem()
{
memset(AESKey,0,sizeof(AESKey));
memset(AESInit,0,sizeof(AESInit));
memset(Password,0,sizeof(Password));
}
#endif
byte AESKey[16],AESInit[16];
wchar Password[MAXPASSWORD];
bool SaltPresent;
byte Salt[SALT_SIZE];
bool HandsOffHash;
enum CRYPT_METHOD {
CRYPT_NONE,CRYPT_RAR13,CRYPT_RAR15,CRYPT_RAR20,CRYPT_RAR30,CRYPT_RAR50
};
#define SIZE_SALT50 16
#define SIZE_SALT30 8
#define SIZE_INITV 16
#define SIZE_PSWCHECK 8
#define SIZE_PSWCHECK_CSUM 4
#define CRYPT_BLOCK_SIZE 16
#define CRYPT_BLOCK_MASK (CRYPT_BLOCK_SIZE-1) // 0xf
#define CRYPT5_KDF_LG2_COUNT 15 // LOG2 of PDKDF2 iteration count.
#define CRYPT5_KDF_LG2_COUNT_MAX 24 // LOG2 of maximum accepted iteration count.
#define CRYPT_VERSION 0 // Supported encryption version.
class CryptData
{
struct KDF5CacheItem
{
SecPassword Pwd;
byte Salt[SIZE_SALT50];
byte Key[32];
uint Lg2Count; // Log2 of PBKDF2 repetition count.
byte PswCheckValue[SHA256_DIGEST_SIZE];
byte HashKeyValue[SHA256_DIGEST_SIZE];
};
struct KDF3CacheItem
{
SecPassword Pwd;
byte Salt[SIZE_SALT30];
byte Key[16];
byte Init[16];
bool SaltPresent;
};
private:
void Encode13(byte *Data,uint Count);
void Decode13(byte *Data,uint Count);
void Crypt15(byte *Data,uint Count);
void UpdKeys(byte *Buf);
void Swap(byte *Ch1,byte *Ch2);
void SetOldKeys(const char *Password);
void SetKey13(const char *Password);
void Decrypt13(byte *Data,size_t Count);
Rijndael rin;
byte SubstTable[256];
uint Key[4];
ushort OldKey[4];
byte PN1,PN2,PN3;
void SetKey15(const char *Password);
void Crypt15(byte *Data,size_t Count);
byte AESKey[16],AESInit[16];
static CryptKeyCacheItem Cache[4];
static int CachePos;
public:
void SetCryptKeys(const wchar *Password,const byte *Salt,bool Encrypt,bool OldOnly,bool HandsOffHash);
void SetAV15Encryption();
void SetCmt13Encryption();
void SetKey20(const char *Password);
void Swap20(byte *Ch1,byte *Ch2);
void UpdKeys20(byte *Buf);
void EncryptBlock20(byte *Buf);
void DecryptBlock20(byte *Buf);
void SetKey30(bool Encrypt,SecPassword *Password,const wchar *PwdW,const byte *Salt);
void SetKey50(bool Encrypt,SecPassword *Password,const wchar *PwdW,const byte *Salt,const byte *InitV,uint Lg2Cnt,byte *HashKey,byte *PswCheck);
KDF3CacheItem KDF3Cache[4];
uint KDF3CachePos;
KDF5CacheItem KDF5Cache[4];
uint KDF5CachePos;
CRYPT_METHOD Method;
Rijndael rin;
uint CRCTab[256]; // For RAR 1.5 and RAR 2.0 encryption.
byte SubstTable20[256];
uint Key20[4];
byte Key13[3];
ushort Key15[4];
public:
CryptData();
~CryptData();
bool SetCryptKeys(bool Encrypt,CRYPT_METHOD Method,SecPassword *Password,
const byte *Salt,const byte *InitV,uint Lg2Cnt,
byte *HashKey,byte *PswCheck);
void SetAV15Encryption();
void SetCmt13Encryption();
void EncryptBlock(byte *Buf,size_t Size);
void DecryptBlock(byte *Buf,size_t Size);
void Crypt(byte *Data,uint Count,int Method);
static void SetSalt(byte *Salt,int SaltSize);
static void SetSalt(byte *Salt,size_t SaltSize);
};
void GetRnd(byte *RndBuf,size_t BufSize);
void hmac_sha256(const byte *Key,size_t KeyLength,const byte *Data,
size_t DataLength,byte *ResDigest);
void pbkdf2(const byte *pass, size_t pass_len, const byte *salt,
size_t salt_len,byte *key, byte *Value1, byte *Value2,
uint rounds);
void ConvertHashToMAC(HashValue *Value,byte *Key);
#endif

79
unrar/crypt1.cpp Normal file
View File

@@ -0,0 +1,79 @@
extern uint CRCTab[256];
void CryptData::SetKey13(const char *Password)
{
Key13[0]=Key13[1]=Key13[2]=0;
for (size_t I=0;Password[I]!=0;I++)
{
byte P=Password[I];
Key13[0]+=P;
Key13[1]^=P;
Key13[2]+=P;
Key13[2]=(byte)rotls(Key13[2],1,8);
}
}
void CryptData::SetKey15(const char *Password)
{
InitCRC32(CRCTab);
uint PswCRC=CRC32(0xffffffff,Password,strlen(Password));
Key15[0]=PswCRC&0xffff;
Key15[1]=(PswCRC>>16)&0xffff;
Key15[2]=Key15[3]=0;
for (size_t I=0;Password[I]!=0;I++)
{
byte P=Password[I];
Key15[2]^=P^CRCTab[P];
Key15[3]+=P+(CRCTab[P]>>16);
}
}
void CryptData::SetAV15Encryption()
{
InitCRC32(CRCTab);
Method=CRYPT_RAR15;
Key15[0]=0x4765;
Key15[1]=0x9021;
Key15[2]=0x7382;
Key15[3]=0x5215;
}
void CryptData::SetCmt13Encryption()
{
Method=CRYPT_RAR13;
Key13[0]=0;
Key13[1]=7;
Key13[2]=77;
}
void CryptData::Decrypt13(byte *Data,size_t Count)
{
while (Count--)
{
Key13[1]+=Key13[2];
Key13[0]+=Key13[1];
*Data-=Key13[0];
Data++;
}
}
void CryptData::Crypt15(byte *Data,size_t Count)
{
while (Count--)
{
Key15[0]+=0x1234;
Key15[1]^=CRCTab[(Key15[0] & 0x1fe)>>1];
Key15[2]-=CRCTab[(Key15[0] & 0x1fe)>>1]>>16;
Key15[0]^=Key15[2];
Key15[3]=rotrs(Key15[3]&0xffff,1,16)^Key15[1];
Key15[3]=rotrs(Key15[3]&0xffff,1,16);
Key15[0]^=Key15[3];
*Data^=(byte)(Key15[0]>>8);
Data++;
}
}

133
unrar/crypt2.cpp Normal file
View File

@@ -0,0 +1,133 @@
#define NROUNDS 32
#define substLong(t) ( (uint)SubstTable20[(uint)t&255] | \
((uint)SubstTable20[(int)(t>> 8)&255]<< 8) | \
((uint)SubstTable20[(int)(t>>16)&255]<<16) | \
((uint)SubstTable20[(int)(t>>24)&255]<<24) )
static byte InitSubstTable20[256]={
215, 19,149, 35, 73,197,192,205,249, 28, 16,119, 48,221, 2, 42,
232, 1,177,233, 14, 88,219, 25,223,195,244, 90, 87,239,153,137,
255,199,147, 70, 92, 66,246, 13,216, 40, 62, 29,217,230, 86, 6,
71, 24,171,196,101,113,218,123, 93, 91,163,178,202, 67, 44,235,
107,250, 75,234, 49,167,125,211, 83,114,157,144, 32,193,143, 36,
158,124,247,187, 89,214,141, 47,121,228, 61,130,213,194,174,251,
97,110, 54,229,115, 57,152, 94,105,243,212, 55,209,245, 63, 11,
164,200, 31,156, 81,176,227, 21, 76, 99,139,188,127, 17,248, 51,
207,120,189,210, 8,226, 41, 72,183,203,135,165,166, 60, 98, 7,
122, 38,155,170, 69,172,252,238, 39,134, 59,128,236, 27,240, 80,
131, 3, 85,206,145, 79,154,142,159,220,201,133, 74, 64, 20,129,
224,185,138,103,173,182, 43, 34,254, 82,198,151,231,180, 58, 10,
118, 26,102, 12, 50,132, 22,191,136,111,162,179, 45, 4,148,108,
161, 56, 78,126,242,222, 15,175,146, 23, 33,241,181,190, 77,225,
0, 46,169,186, 68, 95,237, 65, 53,208,253,168, 9, 18,100, 52,
116,184,160, 96,109, 37, 30,106,140,104,150, 5,204,117,112, 84
};
void CryptData::SetKey20(const char *Password)
{
InitCRC32(CRCTab);
char Psw[MAXPASSWORD];
strncpyz(Psw,Password,ASIZE(Psw)); // We'll need to modify it below.
size_t PswLength=strlen(Psw);
Key20[0]=0xD3A3B879L;
Key20[1]=0x3F6D12F7L;
Key20[2]=0x7515A235L;
Key20[3]=0xA4E7F123L;
memcpy(SubstTable20,InitSubstTable20,sizeof(SubstTable20));
for (uint J=0;J<256;J++)
for (size_t I=0;I<PswLength;I+=2)
{
uint N1=(byte)CRCTab [ (byte(Password[I]) - J) &0xff];
uint N2=(byte)CRCTab [ (byte(Password[I+1]) + J) &0xff];
for (int K=1;N1!=N2;N1=(N1+1)&0xff,K++)
Swap20(&SubstTable20[N1],&SubstTable20[(N1+I+K)&0xff]);
}
// Incomplete last block of password must be zero padded.
if ((PswLength & CRYPT_BLOCK_MASK)!=0)
for (size_t I=PswLength;I<=(PswLength|CRYPT_BLOCK_MASK);I++)
Psw[I]=0;
for (size_t I=0;I<PswLength;I+=CRYPT_BLOCK_SIZE)
EncryptBlock20((byte *)Psw+I);
}
void CryptData::EncryptBlock20(byte *Buf)
{
uint A,B,C,D,T,TA,TB;
A=RawGet4(Buf+0)^Key20[0];
B=RawGet4(Buf+4)^Key20[1];
C=RawGet4(Buf+8)^Key20[2];
D=RawGet4(Buf+12)^Key20[3];
for(int I=0;I<NROUNDS;I++)
{
T=((C+rotls(D,11,32))^Key20[I&3]);
TA=A^substLong(T);
T=((D^rotls(C,17,32))+Key20[I&3]);
TB=B^substLong(T);
A=C;
B=D;
C=TA;
D=TB;
}
RawPut4(C^Key20[0],Buf+0);
RawPut4(D^Key20[1],Buf+4);
RawPut4(A^Key20[2],Buf+8);
RawPut4(B^Key20[3],Buf+12);
UpdKeys20(Buf);
}
void CryptData::DecryptBlock20(byte *Buf)
{
byte InBuf[16];
uint A,B,C,D,T,TA,TB;
A=RawGet4(Buf+0)^Key20[0];
B=RawGet4(Buf+4)^Key20[1];
C=RawGet4(Buf+8)^Key20[2];
D=RawGet4(Buf+12)^Key20[3];
memcpy(InBuf,Buf,sizeof(InBuf));
for(int I=NROUNDS-1;I>=0;I--)
{
T=((C+rotls(D,11,32))^Key20[I&3]);
TA=A^substLong(T);
T=((D^rotls(C,17,32))+Key20[I&3]);
TB=B^substLong(T);
A=C;
B=D;
C=TA;
D=TB;
}
RawPut4(C^Key20[0],Buf+0);
RawPut4(D^Key20[1],Buf+4);
RawPut4(A^Key20[2],Buf+8);
RawPut4(B^Key20[3],Buf+12);
UpdKeys20(InBuf);
}
void CryptData::UpdKeys20(byte *Buf)
{
for (int I=0;I<16;I+=4)
{
Key20[0]^=CRCTab[Buf[I]];
Key20[1]^=CRCTab[Buf[I+1]];
Key20[2]^=CRCTab[Buf[I+2]];
Key20[3]^=CRCTab[Buf[I+3]];
}
}
void CryptData::Swap20(byte *Ch1,byte *Ch2)
{
byte Ch=*Ch1;
*Ch1=*Ch2;
*Ch2=Ch;
}

7
unrar/crypt2.loT Normal file
View File

@@ -0,0 +1,7 @@
# unrar/crypt2.lo - a libtool object file
# Generated by ltmain.sh - GNU libtool 1.5.26 (1.1220.2.492 2008/01/30 06:40:56)
#
# Please DO NOT delete this file!
# It is necessary for linking the library.
# Name of the PIC object.

68
unrar/crypt3.cpp Normal file
View File

@@ -0,0 +1,68 @@
void CryptData::SetKey30(bool Encrypt,SecPassword *Password,const wchar *PwdW,const byte *Salt)
{
byte AESKey[16],AESInit[16];
bool Cached=false;
for (uint I=0;I<ASIZE(KDF3Cache);I++)
if (KDF3Cache[I].Pwd==*Password &&
(Salt==NULL && !KDF3Cache[I].SaltPresent || Salt!=NULL &&
KDF3Cache[I].SaltPresent && memcmp(KDF3Cache[I].Salt,Salt,SIZE_SALT30)==0))
{
memcpy(AESKey,KDF3Cache[I].Key,sizeof(AESKey));
SecHideData(AESKey,sizeof(AESKey),false,false);
memcpy(AESInit,KDF3Cache[I].Init,sizeof(AESInit));
Cached=true;
break;
}
if (!Cached)
{
byte RawPsw[2*MAXPASSWORD+SIZE_SALT30];
WideToRaw(PwdW,RawPsw,ASIZE(RawPsw));
size_t RawLength=2*wcslen(PwdW);
if (Salt!=NULL)
{
memcpy(RawPsw+RawLength,Salt,SIZE_SALT30);
RawLength+=SIZE_SALT30;
}
sha1_context c;
sha1_init(&c);
const int HashRounds=0x40000;
for (int I=0;I<HashRounds;I++)
{
sha1_process_rar29( &c, RawPsw, RawLength );
byte PswNum[3];
PswNum[0]=(byte)I;
PswNum[1]=(byte)(I>>8);
PswNum[2]=(byte)(I>>16);
sha1_process(&c, PswNum, 3);
if (I%(HashRounds/16)==0)
{
sha1_context tempc=c;
uint32 digest[5];
sha1_done( &tempc, digest );
AESInit[I/(HashRounds/16)]=(byte)digest[4];
}
}
uint32 digest[5];
sha1_done( &c, digest );
for (int I=0;I<4;I++)
for (int J=0;J<4;J++)
AESKey[I*4+J]=(byte)(digest[I]>>(J*8));
KDF3Cache[KDF3CachePos].Pwd=*Password;
if ((KDF3Cache[KDF3CachePos].SaltPresent=(Salt!=NULL))==true)
memcpy(KDF3Cache[KDF3CachePos].Salt,Salt,SIZE_SALT30);
memcpy(KDF3Cache[KDF3CachePos].Key,AESKey,sizeof(AESKey));
SecHideData(KDF3Cache[KDF3CachePos].Key,sizeof(KDF3Cache[KDF3CachePos].Key),true,false);
memcpy(KDF3Cache[KDF3CachePos].Init,AESInit,sizeof(AESInit));
KDF3CachePos=(KDF3CachePos+1)%ASIZE(KDF3Cache);
cleandata(RawPsw,sizeof(RawPsw));
}
rin.Init(Encrypt, AESKey, 128, AESInit);
cleandata(AESKey,sizeof(AESKey));
cleandata(AESInit,sizeof(AESInit));
}

233
unrar/crypt5.cpp Normal file
View File

@@ -0,0 +1,233 @@
static void hmac_sha256(const byte *Key,size_t KeyLength,const byte *Data,
size_t DataLength,byte *ResDigest,
sha256_context *ICtxOpt,bool *SetIOpt,
sha256_context *RCtxOpt,bool *SetROpt)
{
const size_t Sha256BlockSize=64; // As defined in RFC 4868.
byte KeyHash[SHA256_DIGEST_SIZE];
if (KeyLength > Sha256BlockSize) // Convert longer keys to key hash.
{
sha256_context KCtx;
sha256_init(&KCtx);
sha256_process(&KCtx, Key, KeyLength);
sha256_done(&KCtx, KeyHash);
Key = KeyHash;
KeyLength = SHA256_DIGEST_SIZE;
}
byte KeyBuf[Sha256BlockSize]; // Store the padded key here.
sha256_context ICtx;
if (ICtxOpt!=NULL && *SetIOpt)
ICtx=*ICtxOpt; // Use already calculated first block context.
else
{
// This calculation is the same for all iterations with same password.
// So for PBKDF2 we can calculate it only for first block and then reuse
// to improve performance.
for (size_t I = 0; I < KeyLength; I++) // Use 0x36 padding for inner digest.
KeyBuf[I] = Key[I] ^ 0x36;
for (size_t I = KeyLength; I < Sha256BlockSize; I++)
KeyBuf[I] = 0x36;
sha256_init(&ICtx);
sha256_process(&ICtx, KeyBuf, Sha256BlockSize); // Hash padded key.
}
if (ICtxOpt!=NULL && !*SetIOpt) // Store constant context for further reuse.
{
*ICtxOpt=ICtx;
*SetIOpt=true;
}
sha256_process(&ICtx, Data, DataLength); // Hash data.
byte IDig[SHA256_DIGEST_SIZE]; // Internal digest for padded key and data.
sha256_done(&ICtx, IDig);
sha256_context RCtx;
if (RCtxOpt!=NULL && *SetROpt)
RCtx=*RCtxOpt; // Use already calculated first block context.
else
{
// This calculation is the same for all iterations with same password.
// So for PBKDF2 we can calculate it only for first block and then reuse
// to improve performance.
for (size_t I = 0; I < KeyLength; I++) // Use 0x5c for outer key padding.
KeyBuf[I] = Key[I] ^ 0x5c;
for (size_t I = KeyLength; I < Sha256BlockSize; I++)
KeyBuf[I] = 0x5c;
sha256_init(&RCtx);
sha256_process(&RCtx, KeyBuf, Sha256BlockSize); // Hash padded key.
}
if (RCtxOpt!=NULL && !*SetROpt) // Store constant context for further reuse.
{
*RCtxOpt=RCtx;
*SetROpt=true;
}
sha256_process(&RCtx, IDig, SHA256_DIGEST_SIZE); // Hash internal digest.
sha256_done(&RCtx, ResDigest);
}
// PBKDF2 for 32 byte key length. We generate the key for specified number
// of iteration count also as two supplementary values (key for checksums
// and password verification) for iterations+16 and iterations+32.
void pbkdf2(const byte *Pwd, size_t PwdLength,
const byte *Salt, size_t SaltLength,
byte *Key, byte *V1, byte *V2, uint Count)
{
const size_t MaxSalt=64;
byte SaltData[MaxSalt+4];
memcpy(SaltData, Salt, Min(SaltLength,MaxSalt));
SaltData[SaltLength + 0] = 0; // Salt concatenated to 1.
SaltData[SaltLength + 1] = 0;
SaltData[SaltLength + 2] = 0;
SaltData[SaltLength + 3] = 1;
// First iteration: HMAC of password, salt and block index (1).
byte U1[SHA256_DIGEST_SIZE];
hmac_sha256(Pwd, PwdLength, SaltData, SaltLength + 4, U1, NULL, NULL, NULL, NULL);
byte Fn[SHA256_DIGEST_SIZE]; // Current function value.
memcpy(Fn, U1, sizeof(Fn)); // Function at first iteration.
uint CurCount[] = { Count-1, 16, 16 };
byte *CurValue[] = { Key , V1, V2 };
sha256_context ICtxOpt,RCtxOpt;
bool SetIOpt=false,SetROpt=false;
byte U2[SHA256_DIGEST_SIZE];
for (uint I = 0; I < 3; I++) // For output key and 2 supplementary values.
{
for (uint J = 0; J < CurCount[I]; J++)
{
// U2 = PRF (P, U1).
hmac_sha256(Pwd, PwdLength, U1, sizeof(U1), U2, &ICtxOpt, &SetIOpt, &RCtxOpt, &SetROpt);
memcpy(U1, U2, sizeof(U1));
for (uint K = 0; K < sizeof(Fn); K++) // Function ^= U.
Fn[K] ^= U1[K];
}
memcpy(CurValue[I], Fn, SHA256_DIGEST_SIZE);
}
cleandata(SaltData, sizeof(SaltData));
cleandata(Fn, sizeof(Fn));
cleandata(U1, sizeof(U1));
cleandata(U2, sizeof(U2));
}
void CryptData::SetKey50(bool Encrypt,SecPassword *Password,const wchar *PwdW,
const byte *Salt,const byte *InitV,uint Lg2Cnt,byte *HashKey,
byte *PswCheck)
{
if (Lg2Cnt>CRYPT5_KDF_LG2_COUNT_MAX)
return;
byte Key[32],PswCheckValue[SHA256_DIGEST_SIZE],HashKeyValue[SHA256_DIGEST_SIZE];
bool Found=false;
for (uint I=0;I<ASIZE(KDF5Cache);I++)
{
KDF5CacheItem *Item=KDF5Cache+I;
if (Item->Lg2Count==Lg2Cnt && Item->Pwd==*Password &&
memcmp(Item->Salt,Salt,SIZE_SALT50)==0)
{
memcpy(Key,Item->Key,sizeof(Key));
SecHideData(Key,sizeof(Key),false,false);
memcpy(PswCheckValue,Item->PswCheckValue,sizeof(PswCheckValue));
memcpy(HashKeyValue,Item->HashKeyValue,sizeof(HashKeyValue));
Found=true;
break;
}
}
if (!Found)
{
char PwdUtf[MAXPASSWORD*4];
WideToUtf(PwdW,PwdUtf,ASIZE(PwdUtf));
pbkdf2((byte *)PwdUtf,strlen(PwdUtf),Salt,SIZE_SALT50,Key,HashKeyValue,PswCheckValue,(1<<Lg2Cnt));
cleandata(PwdUtf,sizeof(PwdUtf));
KDF5CacheItem *Item=KDF5Cache+(KDF5CachePos++ % ASIZE(KDF5Cache));
Item->Lg2Count=Lg2Cnt;
Item->Pwd=*Password;
memcpy(Item->Salt,Salt,SIZE_SALT50);
memcpy(Item->Key,Key,sizeof(Item->Key));
memcpy(Item->PswCheckValue,PswCheckValue,sizeof(PswCheckValue));
memcpy(Item->HashKeyValue,HashKeyValue,sizeof(HashKeyValue));
SecHideData(Item->Key,sizeof(Item->Key),true,false);
}
if (HashKey!=NULL)
memcpy(HashKey,HashKeyValue,SHA256_DIGEST_SIZE);
if (PswCheck!=NULL)
{
memset(PswCheck,0,SIZE_PSWCHECK);
for (uint I=0;I<SHA256_DIGEST_SIZE;I++)
PswCheck[I%SIZE_PSWCHECK]^=PswCheckValue[I];
cleandata(PswCheckValue,sizeof(PswCheckValue));
}
// NULL initialization vector is possible if we only need the password
// check value for archive encryption header.
if (InitV!=NULL)
rin.Init(Encrypt, Key, 256, InitV);
cleandata(Key,sizeof(Key));
}
void ConvertHashToMAC(HashValue *Value,byte *Key)
{
if (Value->Type==HASH_CRC32)
{
byte RawCRC[4];
RawPut4(Value->CRC32,RawCRC);
byte Digest[SHA256_DIGEST_SIZE];
hmac_sha256(Key,SHA256_DIGEST_SIZE,RawCRC,sizeof(RawCRC),Digest,NULL,NULL,NULL,NULL);
Value->CRC32=0;
for (uint I=0;I<ASIZE(Digest);I++)
Value->CRC32^=Digest[I] << ((I & 3) * 8);
}
if (Value->Type==HASH_BLAKE2)
{
byte Digest[BLAKE2_DIGEST_SIZE];
hmac_sha256(Key,BLAKE2_DIGEST_SIZE,Value->Digest,sizeof(Value->Digest),Digest,NULL,NULL,NULL,NULL);
memcpy(Value->Digest,Digest,sizeof(Value->Digest));
}
}
#if 0
static void TestPBKDF2();
struct TestKDF {TestKDF() {TestPBKDF2();exit(0);}} GlobalTestKDF;
void TestPBKDF2() // Test PBKDF2 HMAC-SHA256
{
byte Key[32],V1[32],V2[32];
pbkdf2((byte *)"password", 8, (byte *)"salt", 4, Key, V1, V2, 1);
byte Res1[32]={0x12, 0x0f, 0xb6, 0xcf, 0xfc, 0xf8, 0xb3, 0x2c, 0x43, 0xe7, 0x22, 0x52, 0x56, 0xc4, 0xf8, 0x37, 0xa8, 0x65, 0x48, 0xc9, 0x2c, 0xcc, 0x35, 0x48, 0x08, 0x05, 0x98, 0x7c, 0xb7, 0x0b, 0xe1, 0x7b };
mprintf(L"\nPBKDF2 test1: %s", memcmp(Key,Res1,32)==0 ? L"OK":L"Failed");
pbkdf2((byte *)"password", 8, (byte *)"salt", 4, Key, V1, V2, 4096);
byte Res2[32]={0xc5, 0xe4, 0x78, 0xd5, 0x92, 0x88, 0xc8, 0x41, 0xaa, 0x53, 0x0d, 0xb6, 0x84, 0x5c, 0x4c, 0x8d, 0x96, 0x28, 0x93, 0xa0, 0x01, 0xce, 0x4e, 0x11, 0xa4, 0x96, 0x38, 0x73, 0xaa, 0x98, 0x13, 0x4a };
mprintf(L"\nPBKDF2 test2: %s", memcmp(Key,Res2,32)==0 ? L"OK":L"Failed");
pbkdf2((byte *)"just some long string pretending to be a password", 49, (byte *)"salt, salt, salt, a lot of salt", 31, Key, V1, V2, 65536);
byte Res3[32]={0x08, 0x0f, 0xa3, 0x1d, 0x42, 0x2d, 0xb0, 0x47, 0x83, 0x9b, 0xce, 0x3a, 0x3b, 0xce, 0x49, 0x51, 0xe2, 0x62, 0xb9, 0xff, 0x76, 0x2f, 0x57, 0xe9, 0xc4, 0x71, 0x96, 0xce, 0x4b, 0x6b, 0x6e, 0xbf};
mprintf(L"\nPBKDF2 test3: %s", memcmp(Key,Res3,32)==0 ? L"OK":L"Failed");
}
#endif

View File

@@ -1,17 +1,16 @@
#include "rar.hpp"
#include "dll.hpp"
static int RarErrorToDll(int ErrCode);
static int RarErrorToDll(RAR_EXIT ErrCode);
struct DataSet
{
CommandData Cmd;
CmdExtract Extract;
Archive Arc;
CmdExtract Extract;
int OpenMode;
int HeaderSize;
DataSet():Arc(&Cmd) {};
DataSet():Arc(&Cmd),Extract(&Cmd) {};
};
@@ -27,52 +26,97 @@ HANDLE PASCAL RAROpenArchive(struct RAROpenArchiveData *r)
r->OpenResult=rx.OpenResult;
r->CmtSize=rx.CmtSize;
r->CmtState=rx.CmtState;
return(hArc);
return hArc;
}
HANDLE PASCAL RAROpenArchiveEx(struct RAROpenArchiveDataEx *r)
{
DataSet *Data=NULL;
try
{
r->OpenResult=0;
DataSet *Data=new DataSet;
Data=new DataSet;
Data->Cmd.DllError=0;
Data->OpenMode=r->OpenMode;
Data->Cmd.FileArgs->AddString("*");
Data->Cmd.FileArgs.AddString(L"*");
char an[NM];
if (r->ArcName==NULL && r->ArcNameW!=NULL)
char AnsiArcName[NM];
*AnsiArcName=0;
if (r->ArcName!=NULL)
{
WideToChar(r->ArcNameW,an,NM);
r->ArcName=an;
strncpyz(AnsiArcName,r->ArcName,ASIZE(AnsiArcName));
#ifdef _WIN_ALL
if (!AreFileApisANSI())
{
OemToCharBuffA(r->ArcName,AnsiArcName,ASIZE(AnsiArcName));
AnsiArcName[ASIZE(AnsiArcName)-1]=0;
}
#endif
}
Data->Cmd.AddArcName(r->ArcName,r->ArcNameW);
wchar ArcName[NM];
GetWideName(AnsiArcName,r->ArcNameW,ArcName,ASIZE(ArcName));
Data->Cmd.AddArcName(ArcName);
Data->Cmd.Overwrite=OVERWRITE_ALL;
Data->Cmd.VersionControl=1;
Data->Cmd.Callback=r->Callback;
Data->Cmd.UserData=r->UserData;
if (!Data->Arc.Open(r->ArcName,r->ArcNameW))
// Open shared mode is added by request of dll users, who need to
// browse and unpack archives while downloading.
Data->Cmd.OpenShared = true;
if (!Data->Arc.Open(ArcName,FMF_OPENSHARED))
{
r->OpenResult=ERAR_EOPEN;
delete Data;
return(NULL);
return NULL;
}
if (!Data->Arc.IsArchive(false))
if (!Data->Arc.IsArchive(true))
{
r->OpenResult=Data->Cmd.DllError!=0 ? Data->Cmd.DllError:ERAR_BAD_ARCHIVE;
if (Data->Cmd.DllError!=0)
r->OpenResult=Data->Cmd.DllError;
else
{
RAR_EXIT ErrCode=ErrHandler.GetErrorCode();
if (ErrCode!=RARX_SUCCESS && ErrCode!=RARX_WARNING)
r->OpenResult=RarErrorToDll(ErrCode);
else
r->OpenResult=ERAR_BAD_ARCHIVE;
}
delete Data;
return(NULL);
return NULL;
}
r->Flags=Data->Arc.NewMhd.Flags;
Array<byte> CmtData;
if (r->CmtBufSize!=0 && Data->Arc.GetComment(&CmtData,NULL))
r->Flags=0;
if (Data->Arc.Volume)
r->Flags|=0x01;
if (Data->Arc.Locked)
r->Flags|=0x04;
if (Data->Arc.Solid)
r->Flags|=0x08;
if (Data->Arc.NewNumbering)
r->Flags|=0x10;
if (Data->Arc.Signed)
r->Flags|=0x20;
if (Data->Arc.Protected)
r->Flags|=0x40;
if (Data->Arc.Encrypted)
r->Flags|=0x80;
if (Data->Arc.FirstVolume)
r->Flags|=0x100;
Array<wchar> CmtDataW;
if (r->CmtBufSize!=0 && Data->Arc.GetComment(&CmtDataW))
{
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;
size_t Size=CmtData.Size()+1;
r->CmtState=Size>r->CmtBufSize ? ERAR_SMALL_BUF:1;
r->CmtSize=(uint)Min(Size,r->CmtBufSize);
memcpy(r->CmtBuf,&CmtData[0],r->CmtSize-1);
@@ -81,16 +125,26 @@ HANDLE PASCAL RAROpenArchiveEx(struct RAROpenArchiveDataEx *r)
}
else
r->CmtState=r->CmtSize=0;
if (Data->Arc.Signed)
r->Flags|=0x20;
Data->Extract.ExtractArchiveInit(&Data->Cmd,Data->Arc);
return((HANDLE)Data);
Data->Extract.ExtractArchiveInit(Data->Arc);
return (HANDLE)Data;
}
catch (int ErrCode)
catch (RAR_EXIT ErrCode)
{
r->OpenResult=RarErrorToDll(ErrCode);
return(NULL);
if (Data!=NULL && Data->Cmd.DllError!=0)
r->OpenResult=Data->Cmd.DllError;
else
r->OpenResult=RarErrorToDll(ErrCode);
if (Data != NULL)
delete Data;
return NULL;
}
catch (std::bad_alloc&) // Catch 'new' exception.
{
r->OpenResult=ERAR_NO_MEMORY;
if (Data != NULL)
delete Data;
}
return NULL; // To make compilers happy.
}
@@ -99,130 +153,150 @@ int PASCAL RARCloseArchive(HANDLE hArcData)
DataSet *Data=(DataSet *)hArcData;
bool Success=Data==NULL ? false:Data->Arc.Close();
delete Data;
return(Success ? 0:ERAR_ECLOSE);
return Success ? ERAR_SUCCESS : ERAR_ECLOSE;
}
int PASCAL RARReadHeader(HANDLE hArcData,struct RARHeaderData *D)
{
DataSet *Data=(DataSet *)hArcData;
try
{
if ((Data->HeaderSize=(int)Data->Arc.SearchBlock(FILE_HEAD))<=0)
{
if (Data->Arc.Volume && Data->Arc.GetHeaderType()==ENDARC_HEAD &&
(Data->Arc.EndArcHead.Flags & EARC_NEXT_VOLUME))
if (MergeArchive(Data->Arc,NULL,false,'L'))
{
Data->Extract.SignatureFound=false;
Data->Arc.Seek(Data->Arc.CurBlockPos,SEEK_SET);
return(RARReadHeader(hArcData,D));
}
else
return(ERAR_EOPEN);
return(Data->Arc.BrokenFileHeader ? ERAR_BAD_DATA:ERAR_END_ARCHIVE);
}
if (Data->OpenMode==RAR_OM_LIST && (Data->Arc.NewLhd.Flags & LHD_SPLIT_BEFORE))
{
int Code=RARProcessFile(hArcData,RAR_SKIP,NULL,NULL);
if (Code==0)
return(RARReadHeader(hArcData,D));
else
return(Code);
}
strncpyz(D->ArcName,Data->Arc.FileName,ASIZE(D->ArcName));
strncpyz(D->FileName,Data->Arc.NewLhd.FileName,ASIZE(D->FileName));
D->Flags=Data->Arc.NewLhd.Flags;
D->PackSize=Data->Arc.NewLhd.PackSize;
D->UnpSize=Data->Arc.NewLhd.UnpSize;
D->HostOS=Data->Arc.NewLhd.HostOS;
D->FileCRC=Data->Arc.NewLhd.FileCRC;
D->FileTime=Data->Arc.NewLhd.FileTime;
D->UnpVer=Data->Arc.NewLhd.UnpVer;
D->Method=Data->Arc.NewLhd.Method;
D->FileAttr=Data->Arc.NewLhd.FileAttr;
D->CmtSize=0;
D->CmtState=0;
}
catch (int ErrCode)
{
return(RarErrorToDll(ErrCode));
}
return(0);
}
struct RARHeaderDataEx X;
memset(&X,0,sizeof(X));
int Code=RARReadHeaderEx(hArcData,&X);
strncpyz(D->ArcName,X.ArcName,ASIZE(D->ArcName));
strncpyz(D->FileName,X.FileName,ASIZE(D->FileName));
D->Flags=X.Flags;
D->PackSize=X.PackSize;
D->UnpSize=X.UnpSize;
D->HostOS=X.HostOS;
D->FileCRC=X.FileCRC;
D->FileTime=X.FileTime;
D->UnpVer=X.UnpVer;
D->Method=X.Method;
D->FileAttr=X.FileAttr;
D->CmtSize=0;
D->CmtState=0;
return Code;
}
int PASCAL RARReadHeaderEx(HANDLE hArcData,struct RARHeaderDataEx *D)
{
DataSet *Data=(DataSet *)hArcData;
try
{
if ((Data->HeaderSize=(int)Data->Arc.SearchBlock(FILE_HEAD))<=0)
if ((Data->HeaderSize=(int)Data->Arc.SearchBlock(HEAD_FILE))<=0)
{
if (Data->Arc.Volume && Data->Arc.GetHeaderType()==ENDARC_HEAD &&
(Data->Arc.EndArcHead.Flags & EARC_NEXT_VOLUME))
if (Data->Arc.Volume && Data->Arc.GetHeaderType()==HEAD_ENDARC &&
Data->Arc.EndArcHead.NextVolume)
if (MergeArchive(Data->Arc,NULL,false,'L'))
{
Data->Extract.SignatureFound=false;
Data->Arc.Seek(Data->Arc.CurBlockPos,SEEK_SET);
return(RARReadHeaderEx(hArcData,D));
return RARReadHeaderEx(hArcData,D);
}
else
return(ERAR_EOPEN);
return(Data->Arc.BrokenFileHeader ? ERAR_BAD_DATA:ERAR_END_ARCHIVE);
return ERAR_EOPEN;
if (Data->Arc.BrokenHeader)
return ERAR_BAD_DATA;
// Might be necessary if RARSetPassword is still called instead of
// open callback for RAR5 archives and if password is invalid.
if (Data->Arc.FailedHeaderDecryption)
return ERAR_BAD_PASSWORD;
return ERAR_END_ARCHIVE;
}
if (Data->OpenMode==RAR_OM_LIST && (Data->Arc.NewLhd.Flags & LHD_SPLIT_BEFORE))
FileHeader *hd=&Data->Arc.FileHead;
if (Data->OpenMode==RAR_OM_LIST && hd->SplitBefore)
{
int Code=RARProcessFile(hArcData,RAR_SKIP,NULL,NULL);
if (Code==0)
return(RARReadHeaderEx(hArcData,D));
return RARReadHeaderEx(hArcData,D);
else
return(Code);
return Code;
}
strncpyz(D->ArcName,Data->Arc.FileName,ASIZE(D->ArcName));
if (*Data->Arc.FileNameW)
wcsncpy(D->ArcNameW,Data->Arc.FileNameW,ASIZE(D->ArcNameW));
else
CharToWide(Data->Arc.FileName,D->ArcNameW);
strncpyz(D->FileName,Data->Arc.NewLhd.FileName,ASIZE(D->FileName));
if (*Data->Arc.NewLhd.FileNameW)
wcsncpy(D->FileNameW,Data->Arc.NewLhd.FileNameW,ASIZE(D->FileNameW));
else
{
wcsncpy(D->ArcNameW,Data->Arc.FileName,ASIZE(D->ArcNameW));
WideToChar(D->ArcNameW,D->ArcName,ASIZE(D->ArcName));
wcsncpy(D->FileNameW,hd->FileName,ASIZE(D->FileNameW));
WideToChar(D->FileNameW,D->FileName,ASIZE(D->FileName));
#ifdef _WIN_ALL
char AnsiName[NM];
OemToCharA(Data->Arc.NewLhd.FileName,AnsiName);
if (!CharToWide(AnsiName,D->FileNameW,ASIZE(D->FileNameW)))
*D->FileNameW=0;
#else
if (!CharToWide(Data->Arc.NewLhd.FileName,D->FileNameW,ASIZE(D->FileNameW)))
*D->FileNameW=0;
CharToOemA(D->FileName,D->FileName);
#endif
}
D->Flags=Data->Arc.NewLhd.Flags;
D->PackSize=Data->Arc.NewLhd.PackSize;
D->PackSizeHigh=Data->Arc.NewLhd.HighPackSize;
D->UnpSize=Data->Arc.NewLhd.UnpSize;
D->UnpSizeHigh=Data->Arc.NewLhd.HighUnpSize;
D->HostOS=Data->Arc.NewLhd.HostOS;
D->FileCRC=Data->Arc.NewLhd.FileCRC;
D->FileTime=Data->Arc.NewLhd.FileTime;
D->UnpVer=Data->Arc.NewLhd.UnpVer;
D->Method=Data->Arc.NewLhd.Method;
D->FileAttr=Data->Arc.NewLhd.FileAttr;
D->Flags=0;
if (hd->SplitBefore)
D->Flags|=RHDF_SPLITBEFORE;
if (hd->SplitAfter)
D->Flags|=RHDF_SPLITAFTER;
if (hd->Encrypted)
D->Flags|=RHDF_ENCRYPTED;
if (hd->Solid)
D->Flags|=RHDF_SOLID;
if (hd->Dir)
D->Flags|=RHDF_DIRECTORY;
D->PackSize=uint(hd->PackSize & 0xffffffff);
D->PackSizeHigh=uint(hd->PackSize>>32);
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();
uint64 MRaw=hd->mtime.GetWin();
D->MtimeLow=(uint)MRaw;
D->MtimeHigh=(uint)(MRaw>>32);
uint64 CRaw=hd->ctime.GetWin();
D->CtimeLow=(uint)CRaw;
D->CtimeHigh=(uint)(CRaw>>32);
uint64 ARaw=hd->atime.GetWin();
D->AtimeLow=(uint)ARaw;
D->AtimeHigh=(uint)(ARaw>>32);
D->Method=hd->Method+0x30;
D->FileAttr=hd->FileAttr;
D->CmtSize=0;
D->CmtState=0;
/* these four next lines were added by me */
Data->Arc.NewLhd.mtime.GetLocal((RarLocalTime *) &D->mtime);
Data->Arc.NewLhd.ctime.GetLocal((RarLocalTime *) &D->ctime);
Data->Arc.NewLhd.atime.GetLocal((RarLocalTime *) &D->atime);
Data->Arc.NewLhd.arctime.GetLocal((RarLocalTime *) &D->arctime);
D->DictSize=uint(hd->WinSize/1024);
switch (hd->FileHash.Type)
{
case HASH_RAR14:
case HASH_CRC32:
D->HashType=RAR_HASH_CRC32;
break;
case HASH_BLAKE2:
D->HashType=RAR_HASH_BLAKE2;
memcpy(D->Hash,hd->FileHash.Digest,BLAKE2_DIGEST_SIZE);
break;
default:
D->HashType=RAR_HASH_NONE;
break;
}
D->RedirType=hd->RedirType;
// RedirNameSize sanity check is useful in case some developer
// did not initialize Reserved area with 0 as required in docs.
// We have taken 'Redir*' fields from Reserved area. We may remove
// this RedirNameSize check sometimes later.
if (hd->RedirType!=FSREDIR_NONE && D->RedirName!=NULL &&
D->RedirNameSize>0 && D->RedirNameSize<100000)
wcsncpyz(D->RedirName,hd->RedirName,D->RedirNameSize);
D->DirTarget=hd->DirTarget;
}
catch (int ErrCode)
catch (RAR_EXIT ErrCode)
{
return(RarErrorToDll(ErrCode));
return Data->Cmd.DllError!=0 ? Data->Cmd.DllError : RarErrorToDll(ErrCode);
}
return(0);
return ERAR_SUCCESS;
}
@@ -252,59 +326,60 @@ int PASCAL ProcessFile(HANDLE hArcData, int Operation, char *DestPath,
if (Data->OpenMode==RAR_OM_LIST || Data->OpenMode==RAR_OM_LIST_INCSPLIT ||
Operation==RAR_SKIP && !Data->Arc.Solid)
{
if (Data->Arc.Volume &&
Data->Arc.GetHeaderType()==FILE_HEAD &&
(Data->Arc.NewLhd.Flags & LHD_SPLIT_AFTER)!=0)
if (Data->Arc.Volume && Data->Arc.GetHeaderType()==HEAD_FILE &&
Data->Arc.FileHead.SplitAfter)
if (MergeArchive(Data->Arc,NULL,false,'L'))
{
Data->Extract.SignatureFound=false;
Data->Arc.Seek(Data->Arc.CurBlockPos,SEEK_SET);
return(0);
return ERAR_SUCCESS;
}
else
return(ERAR_EOPEN);
return ERAR_EOPEN;
Data->Arc.SeekToNext();
}
else
{
Data->Cmd.DllOpMode=Operation;
if (DestPath!=NULL || DestName!=NULL)
*Data->Cmd.ExtrPath=0;
*Data->Cmd.DllDestName=0;
if (DestPath!=NULL)
{
char ExtrPathA[NM];
strncpyz(ExtrPathA,DestPath,ASIZE(ExtrPathA)-2);
#ifdef _WIN_ALL
OemToCharA(NullToEmpty(DestPath),Data->Cmd.ExtrPath);
#else
strcpy(Data->Cmd.ExtrPath,NullToEmpty(DestPath));
// We must not apply OemToCharBuffA directly to DestPath,
// because we do not know DestPath length and OemToCharBuffA
// does not stop at 0.
OemToCharA(ExtrPathA,ExtrPathA);
#endif
AddEndSlash(Data->Cmd.ExtrPath);
CharToWide(ExtrPathA,Data->Cmd.ExtrPath,ASIZE(Data->Cmd.ExtrPath));
AddEndSlash(Data->Cmd.ExtrPath,ASIZE(Data->Cmd.ExtrPath));
}
if (DestName!=NULL)
{
char DestNameA[NM];
strncpyz(DestNameA,DestName,ASIZE(DestNameA)-2);
#ifdef _WIN_ALL
OemToCharA(NullToEmpty(DestName),Data->Cmd.DllDestName);
#else
strcpy(Data->Cmd.DllDestName,NullToEmpty(DestName));
// We must not apply OemToCharBuffA directly to DestName,
// because we do not know DestName length and OemToCharBuffA
// does not stop at 0.
OemToCharA(DestNameA,DestNameA);
#endif
}
else
{
*Data->Cmd.ExtrPath=0;
*Data->Cmd.DllDestName=0;
CharToWide(DestNameA,Data->Cmd.DllDestName,ASIZE(Data->Cmd.DllDestName));
}
if (DestPathW!=NULL || DestNameW!=NULL)
if (DestPathW!=NULL)
{
wcsncpy(Data->Cmd.ExtrPathW,NullToEmpty(DestPathW),NM-2);
AddEndSlash(Data->Cmd.ExtrPathW);
wcsncpy(Data->Cmd.DllDestNameW,NullToEmpty(DestNameW),NM-1);
if (*Data->Cmd.DllDestNameW!=0 && *Data->Cmd.DllDestName==0)
WideToChar(Data->Cmd.DllDestNameW,Data->Cmd.DllDestName);
}
else
{
*Data->Cmd.ExtrPathW=0;
*Data->Cmd.DllDestNameW=0;
wcsncpy(Data->Cmd.ExtrPath,DestPathW,ASIZE(Data->Cmd.ExtrPath));
AddEndSlash(Data->Cmd.ExtrPath,ASIZE(Data->Cmd.ExtrPath));
}
strcpy(Data->Cmd.Command,Operation==RAR_EXTRACT ? "X":"T");
if (DestNameW!=NULL)
wcsncpyz(Data->Cmd.DllDestName,DestNameW,ASIZE(Data->Cmd.DllDestName));
wcscpy(Data->Cmd.Command,Operation==RAR_EXTRACT ? L"X":L"T");
Data->Cmd.Test=Operation!=RAR_EXTRACT;
if (Operation == RAR_EXTRACT_CHUNK)
{
@@ -318,14 +393,13 @@ int PASCAL ProcessFile(HANDLE hArcData, int Operation, char *DestPath,
bool Repeat=false;
if (Operation != RAR_EXTRACT_CHUNK)
Data->Extract.ExtractCurrentFile(&Data->Cmd,Data->Arc,
Data->HeaderSize,Repeat);
Data->Extract.ExtractCurrentFile(Data->Arc,Data->HeaderSize,Repeat);
else
{
if (InitDataIO) //chunk, init
{
bool res;
res = Data->Extract.ExtractCurrentFileChunkInit(&Data->Cmd, Data->Arc,
res = Data->Extract.ExtractCurrentFileChunkInit(Data->Arc,
Data->HeaderSize, Repeat);
if (!res && Data->Cmd.DllError == 0)
Data->Cmd.DllError = ERAR_UNKNOWN;
@@ -338,26 +412,37 @@ int PASCAL ProcessFile(HANDLE hArcData, int Operation, char *DestPath,
ReadSize, finished);
}
// Now we process extra file information if any.
//
// Archive can be closed if we process volumes, next volume is missing
// and current one is already removed or deleted. So we need to check
// if archive is still open to avoid calling file operations on
// the invalid file handle. Some of our file operations like Seek()
// process such invalid handle correctly, some not.
/* if extracting by chunks, do move to next block, not even if we've read
* the whole file. The only purpose of this code seems to be applying
* permissions and other metadata to files, so we're not interested if
* extracting chunks */
if (Operation != RAR_EXTRACT_CHUNK) {
while (Data->Arc.ReadHeader()!=0 && Data->Arc.GetHeaderType()==NEWSUB_HEAD)
{
Data->Extract.ExtractCurrentFile(&Data->Cmd,Data->Arc,Data->HeaderSize,Repeat);
Data->Arc.SeekToNext();
}
Data->Arc.Seek(Data->Arc.CurBlockPos,SEEK_SET);
while (Data->Arc.IsOpened() && Data->Arc.ReadHeader()!=0 &&
Data->Arc.GetHeaderType()==HEAD_SERVICE)
{
Data->Extract.ExtractCurrentFile(Data->Arc,Data->HeaderSize,Repeat);
Data->Arc.SeekToNext();
}
Data->Arc.Seek(Data->Arc.CurBlockPos,SEEK_SET);
}
}
}
catch (int ErrCode)
catch (std::bad_alloc&)
{
return(RarErrorToDll(ErrCode));
return ERAR_NO_MEMORY;
}
return(Data->Cmd.DllError);
catch (RAR_EXIT ErrCode)
{
return Data->Cmd.DllError!=0 ? Data->Cmd.DllError : RarErrorToDll(ErrCode);
}
return Data->Cmd.DllError;
}
@@ -419,42 +504,46 @@ void PASCAL RARSetProcessDataProc(HANDLE hArcData,PROCESSDATAPROC ProcessDataPro
Data->Cmd.ProcessDataProc=ProcessDataProc;
}
#ifndef NOCRYPT
#ifndef RAR_NOCRYPT
void PASCAL RARSetPassword(HANDLE hArcData,char *Password)
{
DataSet *Data=(DataSet *)hArcData;
GetWideName(Password,NULL,Data->Cmd.Password,ASIZE(Data->Cmd.Password));
wchar PasswordW[MAXPASSWORD];
GetWideName(Password,NULL,PasswordW,ASIZE(PasswordW));
Data->Cmd.Password.Set(PasswordW);
cleandata(PasswordW,sizeof(PasswordW));
}
#endif
int PASCAL RARGetDllVersion()
{
return(RAR_DLL_VERSION);
return RAR_DLL_VERSION;
}
static int RarErrorToDll(int ErrCode)
static int RarErrorToDll(RAR_EXIT ErrCode)
{
switch(ErrCode)
{
case FATAL_ERROR:
return(ERAR_EREAD);
case CRC_ERROR:
return(ERAR_BAD_DATA);
case WRITE_ERROR:
return(ERAR_EWRITE);
case OPEN_ERROR:
return(ERAR_EOPEN);
case CREATE_ERROR:
return(ERAR_ECREATE);
case MEMORY_ERROR:
return(ERAR_NO_MEMORY);
case NO_PASSWORD_ERROR: //not in original
return(ERAR_MISSING_PASSWORD);
case SUCCESS:
return(0);
case RARX_FATAL:
return ERAR_EREAD;
case RARX_CRC:
return ERAR_BAD_DATA;
case RARX_WRITE:
return ERAR_EWRITE;
case RARX_OPEN:
return ERAR_EOPEN;
case RARX_CREATE:
return ERAR_ECREATE;
case RARX_MEMORY:
return ERAR_NO_MEMORY;
case RARX_BADPWD:
return ERAR_BAD_PASSWORD;
case RARX_SUCCESS:
return ERAR_SUCCESS; // 0.
default:
return(ERAR_UNKNOWN);
return ERAR_UNKNOWN;
}
}

View File

@@ -3,6 +3,7 @@
#pragma pack(1)
#define ERAR_SUCCESS 0
#define ERAR_END_ARCHIVE 10
#define ERAR_NO_MEMORY 11
#define ERAR_BAD_DATA 12
@@ -16,6 +17,8 @@
#define ERAR_SMALL_BUF 20
#define ERAR_UNKNOWN 21
#define ERAR_MISSING_PASSWORD 22
#define ERAR_EREFERENCE 23
#define ERAR_BAD_PASSWORD 24
#define RAR_OM_LIST 0
#define RAR_OM_EXTRACT 1
@@ -29,9 +32,13 @@
#define RAR_VOL_ASK 0
#define RAR_VOL_NOTIFY 1
#define RAR_DLL_VERSION 5
#define RAR_DLL_VERSION 8
#define RAR_DLL_EXT_VERSION 1 //added by me
#define RAR_HASH_NONE 0
#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
@@ -60,6 +67,13 @@ typedef struct RARTime
unsigned int yDay;
} RARTime;
#define RHDF_SPLITBEFORE 0x01
#define RHDF_SPLITAFTER 0x02
#define RHDF_ENCRYPTED 0x04
#define RHDF_SOLID 0x10
#define RHDF_DIRECTORY 0x20
struct RARHeaderData
{
char ArcName[260];
@@ -101,15 +115,22 @@ struct RARHeaderDataEx
unsigned int CmtBufSize;
unsigned int CmtSize;
unsigned int CmtState;
/* these four were added by me and are optional (not all archives have them)
* check if year is 0 to decide if they are set */
RARTime mtime;
RARTime ctime;
RARTime atime;
RARTime arctime;
unsigned int DictSize;
unsigned int HashType;
char Hash[32];
unsigned int RedirType;
wchar_t *RedirName;
unsigned int RedirNameSize;
unsigned int DirTarget;
unsigned int MtimeLow;
unsigned int MtimeHigh;
unsigned int CtimeLow;
unsigned int CtimeHigh;
unsigned int AtimeLow;
unsigned int AtimeHigh;
/* 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[1024]; */
/* unsigned int Reserved[988]; */
};
@@ -126,6 +147,16 @@ struct RAROpenArchiveData
typedef int (CALLBACK *UNRARCALLBACK)(UINT msg,LPARAM UserData,LPARAM P1,LPARAM P2);
#define ROADF_VOLUME 0x0001
#define ROADF_COMMENT 0x0002
#define ROADF_LOCK 0x0004
#define ROADF_SOLID 0x0008
#define ROADF_NEWNUMBERING 0x0010
#define ROADF_SIGNED 0x0020
#define ROADF_RECOVERY 0x0040
#define ROADF_ENCHEADERS 0x0080
#define ROADF_FIRSTVOLUME 0x0100
struct RAROpenArchiveDataEx
{
char *ArcName;
@@ -144,7 +175,8 @@ struct RAROpenArchiveDataEx
};
enum UNRARCALLBACK_MESSAGES {
UCM_CHANGEVOLUME,UCM_PROCESSDATA,UCM_NEEDPASSWORD
UCM_CHANGEVOLUME,UCM_PROCESSDATA,UCM_NEEDPASSWORD,UCM_CHANGEVOLUMEW,
UCM_NEEDPASSWORDW
};
typedef int (PASCAL *CHANGEVOLPROC)(char *ArcName,int Mode);

28
unrar/dll.rc Normal file
View File

@@ -0,0 +1,28 @@
#include <windows.h>
#include <commctrl.h>
VS_VERSION_INFO VERSIONINFO
FILEVERSION 5, 50, 5, 2378
PRODUCTVERSION 5, 50, 5, 2378
FILEOS VOS__WINDOWS32
FILETYPE VFT_APP
{
BLOCK "StringFileInfo"
{
BLOCK "040904E4"
{
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 "OriginalFilename", "Unrar.dll\0"
}
}
BLOCK "VarFileInfo"
{
VALUE "Translation", 0x0409, 0x04E4
}
}

View File

@@ -1,8 +1,5 @@
#include "rar.hpp"
static bool UserBreak;
ErrorHandler::ErrorHandler()
{
Clean();
@@ -11,267 +8,239 @@ ErrorHandler::ErrorHandler()
void ErrorHandler::Clean()
{
ExitCode=SUCCESS;
ExitCode=RARX_SUCCESS;
ErrCount=0;
EnableBreak=true;
Silent=false;
DoShutdown=false;
UserBreak=false;
MainExit=false;
DisableShutdown=false;
}
void ErrorHandler::MemoryError()
{
MemoryErrorMsg();
Throw(MEMORY_ERROR);
Exit(RARX_MEMORY);
}
void ErrorHandler::OpenError(const char *FileName,const wchar *FileNameW)
void ErrorHandler::OpenError(const wchar *FileName)
{
#ifndef SILENT
OpenErrorMsg(FileName);
Throw(OPEN_ERROR);
Exit(RARX_OPEN);
#endif
}
void ErrorHandler::CloseError(const char *FileName,const wchar *FileNameW)
void ErrorHandler::CloseError(const wchar *FileName)
{
#ifndef SILENT
if (!UserBreak)
{
ErrMsg(NULL,St(MErrFClose),FileName);
uiMsg(UIERROR_FILECLOSE,FileName);
SysErrMsg();
}
#endif
#if !defined(SILENT) || defined(RARDLL)
Throw(FATAL_ERROR);
Exit(RARX_FATAL);
#endif
}
void ErrorHandler::ReadError(const char *FileName,const wchar *FileNameW)
void ErrorHandler::ReadError(const wchar *FileName)
{
#ifndef SILENT
ReadErrorMsg(NULL,NULL,FileName,FileNameW);
ReadErrorMsg(FileName);
#endif
#if !defined(SILENT) || defined(RARDLL)
Throw(FATAL_ERROR);
Exit(RARX_FATAL);
#endif
}
bool ErrorHandler::AskRepeatRead(const char *FileName,const wchar *FileNameW)
bool ErrorHandler::AskRepeatRead(const wchar *FileName)
{
#if !defined(SILENT) && !defined(SFX_MODULE) && !defined(_WIN_CE)
#if !defined(SILENT) && !defined(SFX_MODULE)
if (!Silent)
{
SysErrMsg();
mprintf("\n");
Log(NULL,St(MErrRead),FileName);
return(Ask(St(MRetryAbort))==1);
bool Repeat=uiAskRepeatRead(FileName);
if (!Repeat) // Disable shutdown if user pressed Cancel in error dialog.
DisableShutdown=true;
return Repeat;
}
#endif
return(false);
return false;
}
void ErrorHandler::WriteError(const char *ArcName,const wchar *ArcNameW,const char *FileName,const wchar *FileNameW)
void ErrorHandler::WriteError(const wchar *ArcName,const wchar *FileName)
{
#ifndef SILENT
WriteErrorMsg(ArcName,ArcNameW,FileName,FileNameW);
WriteErrorMsg(ArcName,FileName);
#endif
#if !defined(SILENT) || defined(RARDLL)
Throw(WRITE_ERROR);
Exit(RARX_WRITE);
#endif
}
#ifdef _WIN_ALL
void ErrorHandler::WriteErrorFAT(const char *FileName,const wchar *FileNameW)
void ErrorHandler::WriteErrorFAT(const wchar *FileName)
{
#if !defined(SILENT) && !defined(SFX_MODULE)
SysErrMsg();
ErrMsg(NULL,St(MNTFSRequired),FileName);
#endif
uiMsg(UIERROR_NTFSREQUIRED,FileName);
#if !defined(SILENT) && !defined(SFX_MODULE) || defined(RARDLL)
Throw(WRITE_ERROR);
Exit(RARX_WRITE);
#endif
}
#endif
bool ErrorHandler::AskRepeatWrite(const char *FileName,const wchar *FileNameW,bool DiskFull)
bool ErrorHandler::AskRepeatWrite(const wchar *FileName,bool DiskFull)
{
#if !defined(SILENT) && !defined(_WIN_CE)
#ifndef SILENT
if (!Silent)
{
// We do not display "repeat write" prompt in Android, so we do not
// need the matching system error message.
SysErrMsg();
mprintf("\n");
Log(NULL,St(DiskFull ? MNotEnoughDisk:MErrWrite),FileName);
return(Ask(St(MRetryAbort))==1);
bool Repeat=uiAskRepeatWrite(FileName,DiskFull);
if (!Repeat) // Disable shutdown if user pressed Cancel in error dialog.
DisableShutdown=true;
return Repeat;
}
#endif
return(false);
return false;
}
void ErrorHandler::SeekError(const char *FileName,const wchar *FileNameW)
void ErrorHandler::SeekError(const wchar *FileName)
{
#ifndef SILENT
if (!UserBreak)
{
ErrMsg(NULL,St(MErrSeek),FileName);
uiMsg(UIERROR_FILESEEK,FileName);
SysErrMsg();
}
#endif
#if !defined(SILENT) || defined(RARDLL)
Throw(FATAL_ERROR);
Exit(RARX_FATAL);
#endif
}
void ErrorHandler::GeneralErrMsg(const char *Msg)
void ErrorHandler::GeneralErrMsg(const wchar *fmt,...)
{
#ifndef SILENT
Log(NULL,"%s",Msg);
va_list arglist;
va_start(arglist,fmt);
wchar Msg[1024];
vswprintf(Msg,ASIZE(Msg),fmt,arglist);
uiMsg(UIERROR_GENERALERRMSG,Msg);
SysErrMsg();
#endif
va_end(arglist);
}
void ErrorHandler::MemoryErrorMsg()
{
#ifndef SILENT
ErrMsg(NULL,St(MErrOutMem));
#endif
uiMsg(UIERROR_MEMORY);
SetErrorCode(RARX_MEMORY);
}
void ErrorHandler::OpenErrorMsg(const char *FileName,const wchar *FileNameW)
void ErrorHandler::OpenErrorMsg(const wchar *FileName)
{
OpenErrorMsg(NULL,NULL,FileName,FileNameW);
OpenErrorMsg(NULL,FileName);
}
void ErrorHandler::OpenErrorMsg(const char *ArcName,const wchar *ArcNameW,const char *FileName,const wchar *FileNameW)
void ErrorHandler::OpenErrorMsg(const wchar *ArcName,const wchar *FileName)
{
#ifndef SILENT
if (FileName!=NULL)
Log(ArcName,St(MCannotOpen),FileName);
Alarm();
uiMsg(UIERROR_FILEOPEN,ArcName,FileName);
SysErrMsg();
#endif
SetErrorCode(RARX_OPEN);
}
void ErrorHandler::CreateErrorMsg(const char *FileName,const wchar *FileNameW)
void ErrorHandler::CreateErrorMsg(const wchar *FileName)
{
CreateErrorMsg(NULL,NULL,FileName,FileNameW);
CreateErrorMsg(NULL,FileName);
}
void ErrorHandler::CreateErrorMsg(const char *ArcName,const wchar *ArcNameW,const char *FileName,const wchar *FileNameW)
void ErrorHandler::CreateErrorMsg(const wchar *ArcName,const wchar *FileName)
{
#ifndef SILENT
if (FileName!=NULL)
Log(ArcName,St(MCannotCreate),FileName);
Alarm();
#if defined(_WIN_ALL) && !defined(_WIN_CE) && defined(MAX_PATH)
CheckLongPathErrMsg(FileName,FileNameW);
#endif
uiMsg(UIERROR_FILECREATE,ArcName,FileName);
SysErrMsg();
#endif
SetErrorCode(RARX_CREATE);
}
// Check the path length and display the error message if it is too long.
void ErrorHandler::CheckLongPathErrMsg(const char *FileName,const wchar *FileNameW)
void ErrorHandler::ReadErrorMsg(const wchar *FileName)
{
#if defined(_WIN_ALL) && !defined(_WIN_CE) && !defined (SILENT) && defined(MAX_PATH)
if (GetLastError()==ERROR_PATH_NOT_FOUND)
{
wchar WideFileName[NM];
GetWideName(FileName,FileNameW,WideFileName,ASIZE(WideFileName));
size_t NameLength=wcslen(WideFileName);
if (!IsFullPath(WideFileName))
{
wchar CurDir[NM];
GetCurrentDirectoryW(ASIZE(CurDir),CurDir);
NameLength+=wcslen(CurDir)+1;
}
if (NameLength>MAX_PATH)
{
Log(NULL,St(MMaxPathLimit),MAX_PATH);
}
}
#endif
ReadErrorMsg(NULL,FileName);
}
void ErrorHandler::ReadErrorMsg(const char *ArcName,const wchar *ArcNameW,const char *FileName,const wchar *FileNameW)
void ErrorHandler::ReadErrorMsg(const wchar *ArcName,const wchar *FileName)
{
#ifndef SILENT
ErrMsg(ArcName,St(MErrRead),FileName);
uiMsg(UIERROR_FILEREAD,ArcName,FileName);
SysErrMsg();
#endif
SetErrorCode(RARX_FATAL);
}
void ErrorHandler::WriteErrorMsg(const char *ArcName,const wchar *ArcNameW,const char *FileName,const wchar *FileNameW)
void ErrorHandler::WriteErrorMsg(const wchar *ArcName,const wchar *FileName)
{
#ifndef SILENT
ErrMsg(ArcName,St(MErrWrite),FileName);
uiMsg(UIERROR_FILEWRITE,ArcName,FileName);
SysErrMsg();
#endif
SetErrorCode(RARX_WRITE);
}
void ErrorHandler::Exit(int ExitCode)
void ErrorHandler::ArcBrokenMsg(const wchar *ArcName)
{
#ifndef SFX_MODULE
Alarm();
#endif
uiMsg(UIERROR_ARCBROKEN,ArcName);
SetErrorCode(RARX_CRC);
}
void ErrorHandler::ChecksumFailedMsg(const wchar *ArcName,const wchar *FileName)
{
uiMsg(UIERROR_CHECKSUM,ArcName,FileName);
SetErrorCode(RARX_CRC);
}
void ErrorHandler::UnknownMethodMsg(const wchar *ArcName,const wchar *FileName)
{
uiMsg(UIERROR_UNKNOWNMETHOD,ArcName,FileName);
ErrHandler.SetErrorCode(RARX_FATAL);
}
void ErrorHandler::Exit(RAR_EXIT ExitCode)
{
uiAlarm(UIALARM_ERROR);
Throw(ExitCode);
}
#ifndef GUI
void ErrorHandler::ErrMsg(const char *ArcName,const char *fmt,...)
{
safebuf char Msg[NM+1024];
va_list argptr;
va_start(argptr,fmt);
vsprintf(Msg,fmt,argptr);
va_end(argptr);
#ifdef _WIN_ALL
if (UserBreak)
Sleep(5000);
#endif
Alarm();
if (*Msg)
{
Log(ArcName,"\n%s",Msg);
mprintf("\n%s\n",St(MProgAborted));
}
}
#endif
void ErrorHandler::SetErrorCode(int Code)
void ErrorHandler::SetErrorCode(RAR_EXIT Code)
{
switch(Code)
{
case WARNING:
case USER_BREAK:
if (ExitCode==SUCCESS)
case RARX_WARNING:
case RARX_USERBREAK:
if (ExitCode==RARX_SUCCESS)
ExitCode=Code;
break;
case FATAL_ERROR:
if (ExitCode==SUCCESS || ExitCode==WARNING)
ExitCode=FATAL_ERROR;
case RARX_CRC:
if (ExitCode!=RARX_BADPWD)
ExitCode=Code;
break;
case RARX_FATAL:
if (ExitCode==RARX_SUCCESS || ExitCode==RARX_WARNING)
ExitCode=RARX_FATAL;
break;
default:
ExitCode=Code;
@@ -281,7 +250,6 @@ void ErrorHandler::SetErrorCode(int Code)
}
#if !defined(GUI) && !defined(_SFX_RTL_)
#ifdef _WIN_ALL
BOOL __stdcall ProcessSignal(DWORD SigType)
#else
@@ -295,54 +263,62 @@ void _stdfunction ProcessSignal(int SigType)
// When a console application is run as a service, this allows the service
// to continue running after the user logs off.
if (SigType==CTRL_LOGOFF_EVENT)
return(TRUE);
return TRUE;
#endif
UserBreak=true;
ErrHandler.UserBreak=true;
mprintf(St(MBreak));
for (int I=0;!File::RemoveCreated() && I<3;I++)
{
#ifdef _WIN_ALL
// Let the main thread to handle 'throw' and destroy file objects.
for (uint I=0;!ErrHandler.MainExit && I<50;I++)
Sleep(100);
#endif
}
#if defined(USE_RC) && !defined(SFX_MODULE) && !defined(_WIN_CE) && !defined(RARDLL)
#if defined(USE_RC) && !defined(SFX_MODULE) && !defined(RARDLL)
ExtRes.UnloadDLL();
#endif
exit(USER_BREAK);
exit(RARX_USERBREAK);
#endif
#ifdef _UNIX
static uint BreakCount=0;
// User continues to press Ctrl+C, exit immediately without cleanup.
if (++BreakCount>1)
exit(RARX_USERBREAK);
// Otherwise return from signal handler and let Wait() function to close
// files and quit. We cannot use the same approach as in Windows,
// because Unix signal handler can block execution of our main code.
#endif
#if defined(_WIN_ALL) && !defined(_MSC_VER)
// never reached, just to avoid a compiler warning
return(TRUE);
return TRUE;
#endif
}
#endif
void ErrorHandler::SetSignalHandlers(bool Enable)
{
EnableBreak=Enable;
#if !defined(GUI) && !defined(_SFX_RTL_)
#ifdef _WIN_ALL
SetConsoleCtrlHandler(Enable ? ProcessSignal:NULL,TRUE);
// signal(SIGBREAK,Enable ? ProcessSignal:SIG_IGN);
#else
signal(SIGINT,Enable ? ProcessSignal:SIG_IGN);
signal(SIGTERM,Enable ? ProcessSignal:SIG_IGN);
#endif
#endif
}
void ErrorHandler::Throw(int Code)
void ErrorHandler::Throw(RAR_EXIT Code)
{
if (Code==USER_BREAK && !EnableBreak)
if (Code==RARX_USERBREAK && !EnableBreak)
return;
ErrHandler.SetErrorCode(Code);
#ifdef ALLOW_EXCEPTIONS
throw Code;
#else
File::RemoveCreated();
exit(Code);
#if !defined(SILENT)
// Do not write "aborted" when just displaying online help.
if (Code!=RARX_SUCCESS && Code!=RARX_USERERROR)
mprintf(L"\n%s\n",St(MProgAborted));
#endif
SetErrorCode(Code);
throw Code;
}
@@ -371,17 +347,7 @@ void ErrorHandler::SysErrMsg()
*EndMsg=0;
EndMsg++;
}
// We use ASCII for output in Windows console, so let's convert Unicode
// message to single byte.
size_t Length=wcslen(CurMsg)*2; // Must be enough for DBCS characters.
char *MsgA=(char *)malloc(Length+2);
if (MsgA!=NULL)
{
WideToChar(CurMsg,MsgA,Length+1);
MsgA[Length]=0;
Log(NULL,"\n%s",MsgA);
free(MsgA);
}
uiMsg(UIERROR_SYSERRMSG,CurMsg);
CurMsg=EndMsg;
}
}
@@ -389,14 +355,37 @@ void ErrorHandler::SysErrMsg()
#endif
#if defined(_UNIX) || defined(_EMX)
char *err=strerror(errno);
if (err!=NULL)
Log(NULL,"\n%s",err);
if (errno!=0)
{
char *err=strerror(errno);
if (err!=NULL)
{
wchar Msg[1024];
CharToWide(err,Msg,ASIZE(Msg));
uiMsg(UIERROR_SYSERRMSG,Msg);
}
}
#endif
#endif
}
int ErrorHandler::GetSystemErrorCode()
{
#ifdef _WIN_ALL
return GetLastError();
#else
return errno;
#endif
}
void ErrorHandler::SetSystemErrorCode(int Code)
{
#ifdef _WIN_ALL
SetLastError(Code);
#else
errno=Code;
#endif
}

View File

@@ -1,57 +1,69 @@
#ifndef _RAR_ERRHANDLER_
#define _RAR_ERRHANDLER_
#if (defined(GUI) || !defined(_WIN_ALL)) && !defined(SFX_MODULE) && !defined(_WIN_CE) || defined(RARDLL)
#define ALLOW_EXCEPTIONS
#endif
//NO_PASSWORD_ERROR not in original. Maps to ERAR_MISSING_PASSWORD DLL error
enum { SUCCESS,WARNING,FATAL_ERROR,CRC_ERROR,LOCK_ERROR,WRITE_ERROR,
OPEN_ERROR,USER_ERROR,MEMORY_ERROR,CREATE_ERROR,NO_FILES_ERROR,
NO_PASSWORD_ERROR,
USER_BREAK=255};
enum RAR_EXIT // RAR exit code.
{
RARX_SUCCESS = 0,
RARX_WARNING = 1,
RARX_FATAL = 2,
RARX_CRC = 3,
RARX_LOCK = 4,
RARX_WRITE = 5,
RARX_OPEN = 6,
RARX_USERERROR = 7,
RARX_MEMORY = 8,
RARX_CREATE = 9,
RARX_NOFILES = 10,
RARX_BADPWD = 11,
RARX_USERBREAK = 255
};
class ErrorHandler
{
private:
void ErrMsg(const char *ArcName,const char *fmt,...);
int ExitCode;
int ErrCount;
RAR_EXIT ExitCode;
uint ErrCount;
bool EnableBreak;
bool Silent;
bool DoShutdown;
bool DisableShutdown; // Shutdown is not suitable after last error.
public:
ErrorHandler();
void Clean();
void MemoryError();
void OpenError(const char *FileName,const wchar *FileNameW);
void CloseError(const char *FileName,const wchar *FileNameW);
void ReadError(const char *FileName,const wchar *FileNameW);
bool AskRepeatRead(const char *FileName,const wchar *FileNameW);
void WriteError(const char *ArcName,const wchar *ArcNameW,const char *FileName,const wchar *FileNameW);
void WriteErrorFAT(const char *FileName,const wchar *FileNameW);
bool AskRepeatWrite(const char *FileName,const wchar *FileNameW,bool DiskFull);
void SeekError(const char *FileName,const wchar *FileNameW);
void GeneralErrMsg(const char *Msg);
void OpenError(const wchar *FileName);
void CloseError(const wchar *FileName);
void ReadError(const wchar *FileName);
bool AskRepeatRead(const wchar *FileName);
void WriteError(const wchar *ArcName,const wchar *FileName);
void WriteErrorFAT(const wchar *FileName);
bool AskRepeatWrite(const wchar *FileName,bool DiskFull);
void SeekError(const wchar *FileName);
void GeneralErrMsg(const wchar *fmt,...);
void MemoryErrorMsg();
void OpenErrorMsg(const char *FileName,const wchar *FileNameW=NULL);
void OpenErrorMsg(const char *ArcName,const wchar *ArcNameW,const char *FileName,const wchar *FileNameW);
void CreateErrorMsg(const char *FileName,const wchar *FileNameW=NULL);
void CreateErrorMsg(const char *ArcName,const wchar *ArcNameW,const char *FileName,const wchar *FileNameW);
void CheckLongPathErrMsg(const char *FileName,const wchar *FileNameW);
void ReadErrorMsg(const char *ArcName,const wchar *ArcNameW,const char *FileName,const wchar *FileNameW);
void WriteErrorMsg(const char *ArcName,const wchar *ArcNameW,const char *FileName,const wchar *FileNameW);
void Exit(int ExitCode);
void SetErrorCode(int Code);
int GetErrorCode() {return(ExitCode);}
int GetErrorCount() {return(ErrCount);}
void OpenErrorMsg(const wchar *FileName);
void OpenErrorMsg(const wchar *ArcName,const wchar *FileName);
void CreateErrorMsg(const wchar *FileName);
void CreateErrorMsg(const wchar *ArcName,const wchar *FileName);
void ReadErrorMsg(const wchar *FileName);
void ReadErrorMsg(const wchar *ArcName,const wchar *FileName);
void WriteErrorMsg(const wchar *ArcName,const wchar *FileName);
void ArcBrokenMsg(const wchar *ArcName);
void ChecksumFailedMsg(const wchar *ArcName,const wchar *FileName);
void UnknownMethodMsg(const wchar *ArcName,const wchar *FileName);
void Exit(RAR_EXIT ExitCode);
void SetErrorCode(RAR_EXIT Code);
RAR_EXIT GetErrorCode() {return ExitCode;}
uint GetErrorCount() {return ErrCount;}
void SetSignalHandlers(bool Enable);
void Throw(int Code);
void Throw(RAR_EXIT Code);
void SetSilent(bool Mode) {Silent=Mode;};
void SetShutdown(bool Mode) {DoShutdown=Mode;};
void SysErrMsg();
int GetSystemErrorCode();
void SetSystemErrorCode(int Code);
bool IsShutdownEnabled() {return !DisableShutdown;}
bool UserBreak; // Ctrl+Break is pressed.
bool MainExit; // main() is completed.
};

View File

@@ -1,51 +1,43 @@
#include "rar.hpp"
#include "hardlinks.cpp"
#include "win32stm.cpp"
#ifdef _WIN_ALL
#include "win32acl.cpp"
#include "win32stm.cpp"
#endif
#ifdef _BEOS
#include "beosea.cpp"
#endif
#if defined(_EMX) && !defined(_DJGPP)
#include "os2ea.cpp"
#include "win32lnk.cpp"
#endif
#ifdef _UNIX
#include "uowners.cpp"
#ifdef SAVE_LINKS
#include "ulinks.cpp"
#endif
#endif
// RAR2 service header extra records.
#ifndef SFX_MODULE
void SetExtraInfo(CommandData *Cmd,Archive &Arc,char *Name,wchar *NameW)
void SetExtraInfo20(CommandData *Cmd,Archive &Arc,wchar *Name)
{
if (Cmd->Test)
return;
switch(Arc.SubBlockHead.SubType)
{
#if defined(_EMX) && !defined(_DJGPP)
case EA_HEAD:
if (Cmd->ProcessEA)
ExtractOS2EA(Arc,Name);
break;
#endif
#ifdef _UNIX
case UO_HEAD:
if (Cmd->ProcessOwners)
ExtractUnixOwner(Arc,Name);
break;
#endif
#ifdef _BEOS
case BEEA_HEAD:
if (Cmd->ProcessEA)
ExtractBeEA(Arc,Name);
ExtractUnixOwner20(Arc,Name);
break;
#endif
#ifdef _WIN_ALL
case NTACL_HEAD:
if (Cmd->ProcessOwners)
ExtractACL(Arc,Name,NameW);
ExtractACL20(Arc,Name);
break;
case STREAM_HEAD:
ExtractStreams(Arc,Name,NameW);
ExtractStreams20(Arc,Name);
break;
#endif
}
@@ -53,24 +45,108 @@ void SetExtraInfo(CommandData *Cmd,Archive &Arc,char *Name,wchar *NameW)
#endif
void SetExtraInfoNew(CommandData *Cmd,Archive &Arc,char *Name,wchar *NameW)
// RAR3 and RAR5 service header extra records.
void SetExtraInfo(CommandData *Cmd,Archive &Arc,wchar *Name)
{
#if defined(_EMX) && !defined(_DJGPP)
if (Cmd->ProcessEA && Arc.SubHead.CmpName(SUBHEAD_TYPE_OS2EA))
ExtractOS2EANew(Arc,Name);
#endif
#ifdef _UNIX
if (Cmd->ProcessOwners && Arc.SubHead.CmpName(SUBHEAD_TYPE_UOWNER))
ExtractUnixOwnerNew(Arc,Name);
#endif
#ifdef _BEOS
if (Cmd->ProcessEA && Arc.SubHead.CmpName(SUBHEAD_TYPE_UOWNER))
ExtractUnixOwnerNew(Arc,Name);
if (!Cmd->Test && Cmd->ProcessOwners && Arc.Format==RARFMT15 &&
Arc.SubHead.CmpName(SUBHEAD_TYPE_UOWNER))
ExtractUnixOwner30(Arc,Name);
#endif
#ifdef _WIN_ALL
if (Cmd->ProcessOwners && Arc.SubHead.CmpName(SUBHEAD_TYPE_ACL))
ExtractACLNew(Arc,Name,NameW);
if (!Cmd->Test && Cmd->ProcessOwners && Arc.SubHead.CmpName(SUBHEAD_TYPE_ACL))
ExtractACL(Arc,Name);
if (Arc.SubHead.CmpName(SUBHEAD_TYPE_STREAM))
ExtractStreamsNew(Arc,Name,NameW);
ExtractStreams(Arc,Name,Cmd->Test);
#endif
}
// Extra data stored directly in file header.
void SetFileHeaderExtra(CommandData *Cmd,Archive &Arc,wchar *Name)
{
#ifdef _UNIX
if (Cmd->ProcessOwners && Arc.Format==RARFMT50 && Arc.FileHead.UnixOwnerSet)
SetUnixOwner(Arc,Name);
#endif
}
// Calculate a number of path components except \. and \..
static int CalcAllowedDepth(const wchar *Name)
{
int AllowedDepth=0;
while (*Name!=0)
{
if (IsPathDiv(Name[0]) && Name[1]!=0 && !IsPathDiv(Name[1]))
{
bool Dot=Name[1]=='.' && (IsPathDiv(Name[2]) || Name[2]==0);
bool Dot2=Name[1]=='.' && Name[2]=='.' && (IsPathDiv(Name[3]) || Name[3]==0);
if (!Dot && !Dot2)
AllowedDepth++;
}
Name++;
}
return AllowedDepth;
}
bool IsRelativeSymlinkSafe(CommandData *Cmd,const wchar *SrcName,const wchar *PrepSrcName,const wchar *TargetName)
{
// Catch root dir based /path/file paths also as stuff like \\?\.
// Do not check PrepSrcName here, it can be root based if destination path
// is a root based.
if (IsFullRootPath(SrcName) || IsFullRootPath(TargetName))
return false;
// We could check just prepared src name, but for extra safety
// we check both original (as from archive header) and prepared
// (after applying the destination path and -ep switches) names.
int AllowedDepth=CalcAllowedDepth(SrcName); // Original name depth.
// Remove the destination path from prepared name if any. We should not
// count the destination path depth, because the link target must point
// inside of this path, not outside of it.
size_t ExtrPathLength=wcslen(Cmd->ExtrPath);
if (ExtrPathLength>0 && wcsncmp(PrepSrcName,Cmd->ExtrPath,ExtrPathLength)==0)
{
PrepSrcName+=ExtrPathLength;
while (IsPathDiv(*PrepSrcName))
PrepSrcName++;
}
int PrepAllowedDepth=CalcAllowedDepth(PrepSrcName);
// Number of ".." in link target.
int UpLevels=0;
for (int Pos=0;*TargetName!=0;Pos++)
{
bool Dot2=TargetName[0]=='.' && TargetName[1]=='.' &&
(IsPathDiv(TargetName[2]) || TargetName[2]==0) &&
(Pos==0 || IsPathDiv(*(TargetName-1)));
if (Dot2)
UpLevels++;
TargetName++;
}
return AllowedDepth>=UpLevels && PrepAllowedDepth>=UpLevels;
}
bool ExtractSymlink(CommandData *Cmd,ComprDataIO &DataIO,Archive &Arc,const wchar *LinkName)
{
#if defined(SAVE_LINKS) && defined(_UNIX)
// For RAR 3.x archives we process links even in test mode to skip link data.
if (Arc.Format==RARFMT15)
return ExtractUnixLink30(Cmd,DataIO,Arc,LinkName);
if (Arc.Format==RARFMT50)
return ExtractUnixLink50(Cmd,LinkName,&Arc.FileHead);
#elif defined _WIN_ALL
// RAR 5.0 archives store link information in file header, so there is
// no need to additionally test it if we do not create a file.
if (Arc.Format==RARFMT50)
return CreateReparsePoint(Cmd,LinkName,&Arc.FileHead);
#endif
return false;
}

View File

@@ -1,8 +1,23 @@
#ifndef _RAR_EXTINFO_
#define _RAR_EXTINFO_
bool IsRelativeSymlinkSafe(CommandData *Cmd,const wchar *SrcName,const wchar *PrepSrcName,const wchar *TargetName);
bool ExtractSymlink(CommandData *Cmd,ComprDataIO &DataIO,Archive &Arc,const wchar *LinkName);
#ifdef _UNIX
void SetUnixOwner(Archive &Arc,const wchar *FileName);
#endif
bool ExtractHardlink(wchar *NameNew,wchar *NameExisting,size_t NameExistingSize);
void GetStreamNameNTFS(Archive &Arc,wchar *StreamName,size_t MaxSize);
#ifdef _WIN_ALL
bool SetPrivilege(LPCTSTR PrivName);
#endif
void SetExtraInfo20(CommandData *Cmd,Archive &Arc,wchar *Name);
void SetExtraInfo(CommandData *Cmd,Archive &Arc,wchar *Name);
void SetFileHeaderExtra(CommandData *Cmd,Archive &Arc,wchar *Name);
void SetExtraInfo(CommandData *Cmd,Archive &Arc,char *Name,wchar *NameW);
void SetExtraInfoNew(CommandData *Cmd,Archive &Arc,char *Name,wchar *NameW);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -6,9 +6,25 @@ enum EXTRACT_ARC_CODE {EXTRACT_ARC_NEXT,EXTRACT_ARC_REPEAT};
class CmdExtract
{
private:
EXTRACT_ARC_CODE ExtractArchive(CommandData *Cmd);
EXTRACT_ARC_CODE ExtractArchive();
bool ExtractFileCopy(File &New,wchar *ArcName,wchar *NameNew,wchar *NameExisting,size_t NameExistingSize);
void ExtrPrepareName(Archive &Arc,const wchar *ArcFileName,wchar *DestName,size_t DestSize);
#ifdef RARDLL
bool ExtrDllGetPassword();
#else
bool ExtrGetPassword(Archive &Arc,const wchar *ArcFileName);
#endif
#if defined(_WIN_ALL) && !defined(SFX_MODULE)
void ConvertDosPassword(Archive &Arc,SecPassword &DestPwd);
#endif
void ExtrCreateDir(Archive &Arc,const wchar *ArcFileName);
bool ExtrCreateFile(Archive &Arc,File &CurFile);
bool CheckUnpVer(Archive &Arc,const wchar *ArcFileName);
RarTime StartTime; // time when extraction started
CommandData *Cmd;
ComprDataIO DataIO;
Unpack *Unp;
unsigned long TotalFileCount;
@@ -25,29 +41,25 @@ class CmdExtract
// any wrong password hints.
bool AnySolidDataUnpackedWell;
char ArcName[NM];
wchar ArcNameW[NM];
wchar ArcName[NM];
wchar Password[MAXPASSWORD];
bool PasswordAll;
bool PrevExtracted;
char DestFileName[NM];
wchar DestFileNameW[NM];
bool PrevProcessed; // If previous file was successfully extracted or tested.
wchar DestFileName[NM];
bool PasswordCancelled;
#if defined(_WIN_ALL) && !defined(SFX_MODULE) && !defined(SILENT)
bool Fat32,NotFat32;
#endif
public:
CmdExtract();
CmdExtract(CommandData *Cmd);
~CmdExtract();
void DoExtract(CommandData *Cmd);
void ExtractArchiveInit(CommandData *Cmd,Archive &Arc);
bool ExtractCurrentFile(CommandData *Cmd,Archive &Arc,size_t HeaderSize,
bool &Repeat);
bool ExtractCurrentFileChunkInit(CommandData *Cmd, Archive &Arc,
size_t HeaderSize, bool &Repeat);
void DoExtract();
void ExtractArchiveInit(Archive &Arc);
bool ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat);
bool ExtractCurrentFileChunkInit(Archive &Arc, size_t HeaderSize, bool &Repeat);
bool ExtractCurrentFileChunk(CommandData *Cmd, Archive &Arc,
size_t *ReadSize, int *finished);
static void UnstoreFile(ComprDataIO &DataIO,int64 DestUnpSize);
bool SignatureFound;
//next two lines added by me
void *Buffer;
size_t BufferSize;

View File

@@ -1,39 +1,35 @@
#include "rar.hpp"
bool CmdExtract::ExtractCurrentFileChunkInit(CommandData *Cmd,
Archive &Arc,
bool CmdExtract::ExtractCurrentFileChunkInit(Archive &Arc,
size_t HeaderSize,
bool &Repeat)
{
char Command = 'T';
wchar Command = L'T';
Cmd->DllError=0;
Cmd->DllError = false;
Repeat = false;
//turn on checks reserved for the first files extracted from an archive?
FirstFile = true;
if (HeaderSize==0) {
if (HeaderSize==0)
if (DataIO.UnpVolume)
{
#ifdef NOVOLUME
return(false);
return false;
#else
if (!MergeArchive(Arc,&DataIO,false,Command)) //command irrelevant
if (!MergeArchive(Arc,&DataIO,false,Command))
{
ErrHandler.SetErrorCode(WARNING);
ErrHandler.SetErrorCode(RARX_WARNING);
return false;
}
SignatureFound=false;
#endif
}
else
return false;
}
int HeadType=Arc.GetHeaderType();
if (HeadType!=FILE_HEAD)
HEADER_TYPE HeaderType=Arc.GetHeaderType();
if (HeaderType!=HEAD_FILE)
{
return false;
}
DataIO.SetUnpackToMemory((byte*) this->Buffer, this->BufferSize);
DataIO.SetSkipUnpCRC(true);
@@ -42,71 +38,85 @@ bool CmdExtract::ExtractCurrentFileChunkInit(CommandData *Cmd,
//there'll be no operations in the filesystem
DataIO.SetTestMode(true);
if ((Arc.NewLhd.Flags & (LHD_SPLIT_BEFORE/*|LHD_SOLID*/)) && FirstFile)
if (Arc.FileHead.SplitBefore && FirstFile)
{
char CurVolName[NM];
strncpyz(ArcName, Arc.FileName, NM);
strncpyz(CurVolName, ArcName, sizeof CurVolName);
wchar CurVolName[NM];
wcsncpyz(CurVolName,ArcName,ASIZE(CurVolName));
VolNameToFirstName(ArcName,ArcName,ASIZE(ArcName),Arc.NewNumbering);
VolNameToFirstName(ArcName,ArcName,(Arc.NewMhd.Flags & MHD_NEWNUMBERING)!=0);
if (stricomp(ArcName,CurVolName)!=0 && FileExist(ArcName))
if (wcsicomp(ArcName,CurVolName)!=0 && FileExist(ArcName))
{
*ArcNameW=0;
// If first volume name does not match the current name and if such
// volume name really exists, let's unpack from this first volume.
*ArcName=0;
Repeat=true;
ErrHandler.SetErrorCode(WARNING);
ErrHandler.SetErrorCode(RARX_WARNING);
/* Actually known. The problem is that the file doesn't start on this volume. */
Cmd->DllError = ERAR_UNKNOWN;
return false;
}
strcpy(ArcName,CurVolName);
wcsncpyz(ArcName,CurVolName,ASIZE(ArcName));
}
DataIO.UnpVolume=(Arc.NewLhd.Flags & LHD_SPLIT_AFTER)!=0;
DataIO.UnpVolume=Arc.FileHead.SplitAfter;
DataIO.NextVolumeMissing=false;
Arc.Seek(Arc.NextBlockPos - Arc.NewLhd.FullPackSize, SEEK_SET);
Arc.Seek(Arc.NextBlockPos-Arc.FileHead.PackSize,SEEK_SET);
if ((Arc.NewLhd.Flags & LHD_PASSWORD)!=0)
if (Arc.FileHead.Encrypted)
{
if (*Cmd->Password==0)
if (!ExtrDllGetPassword())
{
char PasswordA[MAXPASSWORD];
if (Cmd->Callback==NULL ||
Cmd->Callback(UCM_NEEDPASSWORD,Cmd->UserData,(LPARAM)PasswordA,ASIZE(PasswordA))==-1)
{
ErrHandler.SetErrorCode(WARNING);
Cmd->DllError = ERAR_MISSING_PASSWORD;
return false;
}
GetWideName(PasswordA,NULL,Cmd->Password,ASIZE(Cmd->Password));
ErrHandler.SetErrorCode(RARX_WARNING);
Cmd->DllError=ERAR_MISSING_PASSWORD;
return false;
}
wcscpy(Password,Cmd->Password);
}
if (Arc.NewLhd.UnpVer<13 || Arc.NewLhd.UnpVer>UNP_VER)
if (*Cmd->DllDestName!=0)
{
ErrHandler.SetErrorCode(WARNING);
wcsncpyz(DestFileName,Cmd->DllDestName,ASIZE(DestFileName));
// Do we need this code?
// if (Cmd->DllOpMode!=RAR_EXTRACT)
// ExtrFile=false;
}
wchar ArcFileName[NM];
ConvertPath(Arc.FileHead.FileName,ArcFileName);
if (!CheckUnpVer(Arc,ArcFileName))
{
ErrHandler.SetErrorCode(RARX_FATAL);
Cmd->DllError=ERAR_UNKNOWN_FORMAT;
return false;
}
if (IsLink(Arc.NewLhd.FileAttr))
return true;
if (Arc.IsArcDir())
return true;
SecPassword FilePassword=Cmd->Password;
#if defined(_WIN_ALL) && !defined(SFX_MODULE)
ConvertDosPassword(Arc,FilePassword);
#endif
byte PswCheck[SIZE_PSWCHECK];
DataIO.SetEncryption(false,Arc.FileHead.CryptMethod,&FilePassword,
Arc.FileHead.SaltSet ? Arc.FileHead.Salt:NULL,
Arc.FileHead.InitV,Arc.FileHead.Lg2Count,
Arc.FileHead.HashKey,PswCheck);
// If header is damaged, we cannot rely on password check value,
// because it can be damaged too.
if (Arc.FileHead.Encrypted && Arc.FileHead.UsePswCheck &&
memcmp(Arc.FileHead.PswCheck,PswCheck,SIZE_PSWCHECK)!=0 &&
!Arc.BrokenHeader)
{
ErrHandler.SetErrorCode(RARX_BADPWD);
}
DataIO.CurUnpRead=0;
DataIO.CurUnpWrite=0;
DataIO.UnpFileCRC= Arc.OldFormat ? 0 : 0xffffffff;
DataIO.PackedCRC= 0xffffffff;
DataIO.SetEncryption(
(Arc.NewLhd.Flags & LHD_PASSWORD) ? Arc.NewLhd.UnpVer : 0, Password,
(Arc.NewLhd.Flags & LHD_SALT) ? Arc.NewLhd.Salt : NULL, false,
Arc.NewLhd.UnpVer >= 36);
DataIO.SetPackedSizeToRead(Arc.NewLhd.FullPackSize);
DataIO.UnpHash.Init(Arc.FileHead.FileHash.Type,Cmd->Threads);
DataIO.PackedDataHash.Init(Arc.FileHead.FileHash.Type,Cmd->Threads);
DataIO.SetPackedSizeToRead(Arc.FileHead.PackSize);
DataIO.SetFiles(&Arc,NULL);
DataIO.SetTestMode(true);
DataIO.SetSkipUnpCRC(true);
DataIO.SetFiles(&Arc, NULL);
return true;
}
@@ -115,7 +125,7 @@ bool CmdExtract::ExtractCurrentFileChunk(CommandData *Cmd, Archive &Arc,
size_t *ReadSize,
int *finished)
{
if (IsLink(Arc.NewLhd.FileAttr) || Arc.IsArcDir()) {
if (Arc.FileHead.RedirType!=FSREDIR_NONE|| Arc.IsArcDir()) {
*ReadSize = 0;
*finished = TRUE;
return true;
@@ -123,7 +133,7 @@ bool CmdExtract::ExtractCurrentFileChunk(CommandData *Cmd, Archive &Arc,
DataIO.SetUnpackToMemory((byte*) this->Buffer, this->BufferSize);
if (Arc.NewLhd.Method==0x30) {
if (Arc.FileHead.Method==0) {
UnstoreFile(DataIO, this->BufferSize);
/* not very sophisticated and may result in a subsequent
* unnecessary call to this function (and probably will if
@@ -133,12 +143,12 @@ bool CmdExtract::ExtractCurrentFileChunk(CommandData *Cmd, Archive &Arc,
}
else
{
Unp->SetDestSize(Arc.NewLhd.FullUnpSize);
if (Arc.NewLhd.UnpVer<=15)
Unp->Init(Arc.FileHead.WinSize,Arc.FileHead.Solid);
Unp->SetDestSize(Arc.FileHead.UnpSize);
if (Arc.Format!=RARFMT50 && Arc.FileHead.UnpVer<=15)
Unp->DoUnpack(15,FileCount>1 && Arc.Solid, this->Buffer != NULL);
else
Unp->DoUnpack(Arc.NewLhd.UnpVer,
(Arc.NewLhd.Flags & LHD_SOLID)!=0, this->Buffer != NULL);
Unp->DoUnpack(Arc.FileHead.UnpVer,Arc.FileHead.Solid, this->Buffer != NULL);
*finished = Unp->IsFileExtracted();
}
*ReadSize = this->BufferSize - DataIO.GetUnpackToMemorySizeLeft();

View File

@@ -1,17 +1,19 @@
#include "rar.hpp"
bool FileCreate(RAROptions *Cmd,File *NewFile,char *Name,wchar *NameW,
OVERWRITE_MODE Mode,bool *UserReject,int64 FileSize,
uint FileTime)
// If NewFile==NULL, we delete created file after user confirmation.
// It is useful we we need to overwrite an existing folder or file,
// but need user confirmation for that.
bool FileCreate(RAROptions *Cmd,File *NewFile,wchar *Name,size_t MaxNameSize,
bool *UserReject,int64 FileSize,RarTime *FileTime,bool WriteOnly)
{
if (UserReject!=NULL)
*UserReject=false;
#if defined(_WIN_ALL) && !defined(_WIN_CE)
#ifdef _WIN_ALL
bool ShortNameChanged=false;
#endif
while (FileExist(Name,NameW))
while (FileExist(Name))
{
#if defined(_WIN_ALL) && !defined(_WIN_CE)
#if defined(_WIN_ALL)
if (!ShortNameChanged)
{
// Avoid the infinite loop if UpdateExistingShortName returns
@@ -20,183 +22,85 @@ bool FileCreate(RAROptions *Cmd,File *NewFile,char *Name,wchar *NameW,
// Maybe our long name matches the short name of existing file.
// Let's check if we can change the short name.
wchar WideName[NM];
GetWideName(Name,NameW,WideName,ASIZE(WideName));
if (UpdateExistingShortName(WideName))
{
if (Name!=NULL && *Name!=0)
WideToChar(WideName,Name);
if (NameW!=NULL && *NameW!=0)
wcscpy(NameW,WideName);
if (UpdateExistingShortName(Name))
continue;
}
}
// Allow short name check again. It is necessary, because rename and
// autorename below can change the name, so we need to check it again.
ShortNameChanged=false;
#endif
if (Mode==OVERWRITE_NONE)
UIASKREP_RESULT Choice=uiAskReplaceEx(Cmd,Name,MaxNameSize,FileSize,FileTime,(NewFile==NULL ? UIASKREP_F_NORENAME:0));
if (Choice==UIASKREP_R_REPLACE)
break;
if (Choice==UIASKREP_R_SKIP)
{
if (UserReject!=NULL)
*UserReject=true;
return(false);
}
// Must be before Cmd->AllYes check or -y switch would override -or.
if (Mode==OVERWRITE_AUTORENAME)
{
if (!GetAutoRenamedName(Name,NameW))
Mode=OVERWRITE_DEFAULT;
continue;
}
#ifdef SILENT
Mode=OVERWRITE_ALL;
#endif
// This check must be after OVERWRITE_AUTORENAME processing or -y switch
// would override -or.
if (Cmd->AllYes || Mode==OVERWRITE_ALL)
break;
if (Mode==OVERWRITE_DEFAULT || Mode==OVERWRITE_FORCE_ASK)
{
char NewName[NM];
wchar NewNameW[NM];
*NewNameW=0;
eprintf(St(MFileExists),Name);
int Choice=Ask(St(MYesNoAllRenQ));
if (Choice==1)
break;
if (Choice==2)
{
if (UserReject!=NULL)
*UserReject=true;
return(false);
}
if (Choice==3)
{
Cmd->Overwrite=OVERWRITE_ALL;
break;
}
if (Choice==4)
{
if (UserReject!=NULL)
*UserReject=true;
Cmd->Overwrite=OVERWRITE_NONE;
return(false);
}
if (Choice==5)
{
#ifndef GUI
mprintf(St(MAskNewName));
#ifdef _WIN_ALL
File SrcFile;
SrcFile.SetHandleType(FILE_HANDLESTD);
int Size=SrcFile.Read(NewName,sizeof(NewName)-1);
NewName[Size]=0;
OemToCharA(NewName,NewName);
#else
if (fgets(NewName,sizeof(NewName),stdin)==NULL)
{
// Process fgets failure as if user answered 'No'.
if (UserReject!=NULL)
*UserReject=true;
return(false);
}
#endif
RemoveLF(NewName);
#endif
if (PointToName(NewName)==NewName)
strcpy(PointToName(Name),NewName);
else
strcpy(Name,NewName);
if (NameW!=NULL)
if (PointToName(NewNameW)==NewNameW)
wcscpy(PointToName(NameW),NewNameW);
else
wcscpy(NameW,NewNameW);
continue;
}
if (Choice==6)
ErrHandler.Exit(USER_BREAK);
return false;
}
if (Choice==UIASKREP_R_CANCEL)
ErrHandler.Exit(RARX_USERBREAK);
}
if (NewFile!=NULL && NewFile->Create(Name,NameW))
return(true);
PrepareToDelete(Name,NameW);
CreatePath(Name,NameW,true);
return(NewFile!=NULL ? NewFile->Create(Name,NameW):DelFile(Name,NameW));
// Try to truncate the existing file first instead of delete,
// so we preserve existing file permissions such as NTFS permissions.
uint FileMode=WriteOnly ? FMF_WRITE|FMF_SHAREREAD:FMF_UPDATE|FMF_SHAREREAD;
if (NewFile!=NULL && NewFile->Create(Name,FileMode))
return true;
CreatePath(Name,true);
return NewFile!=NULL ? NewFile->Create(Name,FileMode):DelFile(Name);
}
bool GetAutoRenamedName(char *Name,wchar *NameW)
bool GetAutoRenamedName(wchar *Name,size_t MaxNameSize)
{
char NewName[NM];
wchar NewNameW[NM];
if (Name!=NULL && strlen(Name)>ASIZE(NewName)-10 ||
NameW!=NULL && wcslen(NameW)>ASIZE(NewNameW)-10)
return(false);
char *Ext=NULL;
if (Name!=NULL && *Name!=0)
wchar NewName[NM];
size_t NameLength=wcslen(Name);
wchar *Ext=GetExt(Name);
if (Ext==NULL)
Ext=Name+NameLength;
for (uint FileVer=1;;FileVer++)
{
Ext=GetExt(Name);
if (Ext==NULL)
Ext=Name+strlen(Name);
}
wchar *ExtW=NULL;
if (NameW!=NULL && *NameW!=0)
{
ExtW=GetExt(NameW);
if (ExtW==NULL)
ExtW=NameW+wcslen(NameW);
}
*NewName=0;
*NewNameW=0;
for (int FileVer=1;;FileVer++)
{
if (Name!=NULL && *Name!=0)
sprintf(NewName,"%.*s(%d)%s",int(Ext-Name),Name,FileVer,Ext);
if (NameW!=NULL && *NameW!=0)
sprintfw(NewNameW,ASIZE(NewNameW),L"%.*s(%d)%s",int(ExtW-NameW),NameW,FileVer,ExtW);
if (!FileExist(NewName,NewNameW))
swprintf(NewName,ASIZE(NewName),L"%.*ls(%u)%ls",uint(Ext-Name),Name,FileVer,Ext);
if (!FileExist(NewName))
{
if (Name!=NULL && *Name!=0)
strcpy(Name,NewName);
if (NameW!=NULL && *NameW!=0)
wcscpy(NameW,NewNameW);
wcsncpyz(Name,NewName,MaxNameSize);
break;
}
if (FileVer>=1000000)
return(false);
return false;
}
return(true);
return true;
}
#if defined(_WIN_ALL) && !defined(_WIN_CE)
#if defined(_WIN_ALL)
// If we find a file, which short name is equal to 'Name', we try to change
// its short name, while preserving the long name. It helps when unpacking
// an archived file, which long name is equal to short name of already
// existing file. Otherwise we would overwrite the already existing file,
// even though its long name does not match the name of unpacking file.
bool UpdateExistingShortName(wchar *Name)
bool UpdateExistingShortName(const wchar *Name)
{
// 'Name' is the name of file which we want to create. Let's check
// if file with such name is exist. If it does not, we return.
FindData fd;
if (!FindFile::FastFind(NULL,Name,&fd))
return(false);
wchar LongPathName[NM];
DWORD Res=GetLongPathName(Name,LongPathName,ASIZE(LongPathName));
if (Res==0 || Res>=ASIZE(LongPathName))
return false;
wchar ShortPathName[NM];
Res=GetShortPathName(Name,ShortPathName,ASIZE(ShortPathName));
if (Res==0 || Res>=ASIZE(ShortPathName))
return false;
wchar *LongName=PointToName(LongPathName);
wchar *ShortName=PointToName(ShortPathName);
// We continue only if file has a short name, which does not match its
// long name, and this short name is equal to name of file which we need
// to create.
if (*fd.ShortName==0 || wcsicomp(PointToName(fd.NameW),fd.ShortName)==0 ||
wcsicomp(PointToName(Name),fd.ShortName)!=0)
return(false);
if (*ShortName==0 || wcsicomp(LongName,ShortName)==0 ||
wcsicomp(PointToName(Name),ShortName)!=0)
return false;
// Generate the temporary new name for existing file.
wchar NewName[NM];
@@ -208,28 +112,28 @@ bool UpdateExistingShortName(wchar *Name)
wcsncpyz(NewName,Name,ASIZE(NewName));
// Here we set the random name part.
sprintfw(PointToName(NewName),ASIZE(NewName),L"rtmp%d",I);
swprintf(PointToName(NewName),ASIZE(NewName),L"rtmp%d",I);
// If such file is already exist, try next random name.
if (FileExist(NULL,NewName))
if (FileExist(NewName))
*NewName=0;
}
// If we could not generate the name not used by any other file, we return.
if (*NewName==0)
return(false);
return false;
// FastFind returns the name without path, but we need the fully qualified
// name for renaming, so we use the path from file to create and long name
// from existing file.
wchar FullName[NM];
wcsncpyz(FullName,Name,ASIZE(FullName));
wcscpy(PointToName(FullName),PointToName(fd.NameW));
SetName(FullName,LongName,ASIZE(FullName));
// Rename the existing file to randomly generated name. Normally it changes
// the short name too.
if (!MoveFileW(FullName,NewName))
return(false);
if (!MoveFile(FullName,NewName))
return false;
// Now we need to create the temporary empty file with same name as
// short name of our already existing file. We do it to occupy its previous
@@ -237,13 +141,13 @@ bool UpdateExistingShortName(wchar *Name)
// its original long name.
File KeepShortFile;
bool Created=false;
if (!FileExist(NULL,Name))
Created=KeepShortFile.Create(NULL,Name);
if (!FileExist(Name))
Created=KeepShortFile.Create(Name,FMF_WRITE|FMF_SHAREREAD);
// Now we rename the existing file from temporary name to original long name.
// Since its previous short name is occupied by another file, it should
// get another short name.
MoveFileW(NewName,FullName);
MoveFile(NewName,FullName);
if (Created)
{
@@ -254,6 +158,6 @@ bool UpdateExistingShortName(wchar *Name)
// We successfully changed the short name. Maybe sometimes we'll simplify
// this function by use of SetFileShortName Windows API call.
// But SetFileShortName is not available in older Windows.
return(true);
return true;
}
#endif

View File

@@ -1,13 +1,14 @@
#ifndef _RAR_FILECREATE_
#define _RAR_FILECREATE_
bool FileCreate(RAROptions *Cmd,File *NewFile,char *Name,wchar *NameW,
OVERWRITE_MODE Mode,bool *UserReject,int64 FileSize=INT64NDF,
uint FileTime=0);
bool GetAutoRenamedName(char *Name,wchar *NameW);
bool FileCreate(RAROptions *Cmd,File *NewFile,wchar *Name,size_t MaxNameSize,
bool *UserReject,int64 FileSize=INT64NDF,
RarTime *FileTime=NULL,bool WriteOnly=false);
#if defined(_WIN_ALL) && !defined(_WIN_CE)
bool UpdateExistingShortName(wchar *Name);
bool GetAutoRenamedName(wchar *Name,size_t MaxNameSize);
#if defined(_WIN_ALL)
bool UpdateExistingShortName(const wchar *Name);
#endif
#endif

View File

@@ -1,13 +1,9 @@
#include "rar.hpp"
static File *CreatedFiles[256];
static int RemoveCreatedActive=0;
File::File()
{
hFile=BAD_HANDLE;
hFile=FILE_BAD_HANDLE;
*FileName=0;
*FileNameW=0;
NewFile=false;
LastWrite=false;
HandleType=FILE_HANDLENORMAL;
@@ -16,17 +12,17 @@ File::File()
ErrorType=FILE_SUCCESS;
OpenShared=false;
AllowDelete=true;
CloseCount=0;
AllowExceptions=true;
#ifdef _WIN_ALL
NoSequentialRead=false;
CreateMode=FMF_UNDEFINED;
#endif
}
File::~File()
{
if (hFile!=BAD_HANDLE && !SkipClose)
if (hFile!=FILE_BAD_HANDLE && !SkipClose)
if (NewFile)
Delete();
else
@@ -37,270 +33,274 @@ File::~File()
void File::operator = (File &SrcFile)
{
hFile=SrcFile.hFile;
strcpy(FileName,SrcFile.FileName);
NewFile=SrcFile.NewFile;
LastWrite=SrcFile.LastWrite;
HandleType=SrcFile.HandleType;
wcsncpyz(FileName,SrcFile.FileName,ASIZE(FileName));
SrcFile.SkipClose=true;
}
bool File::Open(const char *Name,const wchar *NameW,bool OpenShared,bool Update)
bool File::Open(const wchar *Name,uint Mode)
{
ErrorType=FILE_SUCCESS;
FileHandle hNewFile;
if (File::OpenShared)
OpenShared=true;
bool OpenShared=File::OpenShared || (Mode & FMF_OPENSHARED)!=0;
bool UpdateMode=(Mode & FMF_UPDATE)!=0;
bool WriteMode=(Mode & FMF_WRITE)!=0;
#ifdef _WIN_ALL
uint Access=GENERIC_READ;
if (Update)
uint Access=WriteMode ? GENERIC_WRITE:GENERIC_READ;
if (UpdateMode)
Access|=GENERIC_WRITE;
uint ShareMode=FILE_SHARE_READ;
uint ShareMode=(Mode & FMF_OPENEXCLUSIVE) ? 0 : FILE_SHARE_READ;
if (OpenShared)
ShareMode|=FILE_SHARE_WRITE;
uint Flags=NoSequentialRead ? 0:FILE_FLAG_SEQUENTIAL_SCAN;
if (WinNT() && NameW!=NULL && *NameW!=0)
hNewFile=CreateFileW(NameW,Access,ShareMode,NULL,OPEN_EXISTING,Flags,NULL);
else
hNewFile=CreateFileA(Name,Access,ShareMode,NULL,OPEN_EXISTING,Flags,NULL);
hNewFile=CreateFile(Name,Access,ShareMode,NULL,OPEN_EXISTING,Flags,NULL);
if (hNewFile==BAD_HANDLE && GetLastError()==ERROR_FILE_NOT_FOUND)
DWORD LastError;
if (hNewFile==FILE_BAD_HANDLE)
{
LastError=GetLastError();
wchar LongName[NM];
if (GetWinLongPath(Name,LongName,ASIZE(LongName)))
{
hNewFile=CreateFile(LongName,Access,ShareMode,NULL,OPEN_EXISTING,Flags,NULL);
// For archive names longer than 260 characters first CreateFile
// (without \\?\) fails and sets LastError to 3 (access denied).
// We need the correct "file not found" error code to decide
// if we create a new archive or quit with "cannot create" error.
// So we need to check the error code after \\?\ CreateFile again,
// otherwise we'll fail to create new archives with long names.
// But we cannot simply assign the new code to LastError,
// because it would break "..\arcname.rar" relative names processing.
// First CreateFile returns the correct "file not found" code for such
// names, but "\\?\" CreateFile returns ERROR_INVALID_NAME treating
// dots as a directory name. So we check only for "file not found"
// error here and for other errors use the first CreateFile result.
if (GetLastError()==ERROR_FILE_NOT_FOUND)
LastError=ERROR_FILE_NOT_FOUND;
}
}
if (hNewFile==FILE_BAD_HANDLE && LastError==ERROR_FILE_NOT_FOUND)
ErrorType=FILE_NOTFOUND;
#else
int flags=Update ? O_RDWR:O_RDONLY;
int flags=UpdateMode ? O_RDWR:(WriteMode ? O_WRONLY:O_RDONLY);
#ifdef O_BINARY
flags|=O_BINARY;
#if defined(_AIX) && defined(_LARGE_FILE_API)
flags|=O_LARGEFILE;
#endif
#endif
#if defined(_EMX) && !defined(_DJGPP)
int sflags=OpenShared ? SH_DENYNO:SH_DENYWR;
int handle=sopen(Name,flags,sflags);
#else
int handle=open(Name,flags);
char NameA[NM];
WideToChar(Name,NameA,ASIZE(NameA));
int handle=open(NameA,flags);
#ifdef LOCK_EX
#ifdef _OSF_SOURCE
extern "C" int flock(int, int);
#endif
if (!OpenShared && Update && handle>=0 && flock(handle,LOCK_EX|LOCK_NB)==-1)
if (!OpenShared && UpdateMode && handle>=0 && flock(handle,LOCK_EX|LOCK_NB)==-1)
{
close(handle);
return(false);
return false;
}
#endif
if (handle==-1)
hNewFile=FILE_BAD_HANDLE;
else
{
#ifdef FILE_USE_OPEN
hNewFile=handle;
#else
hNewFile=fdopen(handle,UpdateMode ? UPDATEBINARY:READBINARY);
#endif
hNewFile=handle==-1 ? BAD_HANDLE:fdopen(handle,Update ? UPDATEBINARY:READBINARY);
if (hNewFile==BAD_HANDLE && errno==ENOENT)
}
if (hNewFile==FILE_BAD_HANDLE && errno==ENOENT)
ErrorType=FILE_NOTFOUND;
#endif
NewFile=false;
HandleType=FILE_HANDLENORMAL;
SkipClose=false;
bool Success=hNewFile!=BAD_HANDLE;
bool Success=hNewFile!=FILE_BAD_HANDLE;
if (Success)
{
hFile=hNewFile;
// We use memove instead of strcpy and wcscpy to avoid problems
// with overlapped buffers. While we do not call this function with
// really overlapped buffers yet, we do call it with Name equal to
// FileName like Arc.Open(Arc.FileName,Arc.FileNameW).
if (NameW!=NULL)
memmove(FileNameW,NameW,(wcslen(NameW)+1)*sizeof(*NameW));
else
*FileNameW=0;
if (Name!=NULL)
memmove(FileName,Name,strlen(Name)+1);
else
WideToChar(NameW,FileName);
AddFileToList(hFile);
wcsncpyz(FileName,Name,ASIZE(FileName));
}
return(Success);
return Success;
}
#if !defined(SHELL_EXT) && !defined(SFX_MODULE)
void File::TOpen(const char *Name,const wchar *NameW)
#if !defined(SFX_MODULE)
void File::TOpen(const wchar *Name)
{
if (!WOpen(Name,NameW))
ErrHandler.Exit(OPEN_ERROR);
if (!WOpen(Name))
ErrHandler.Exit(RARX_OPEN);
}
#endif
bool File::WOpen(const char *Name,const wchar *NameW)
bool File::WOpen(const wchar *Name)
{
if (Open(Name,NameW))
return(true);
ErrHandler.OpenErrorMsg(Name,NameW);
return(false);
if (Open(Name))
return true;
ErrHandler.OpenErrorMsg(Name);
return false;
}
bool File::Create(const char *Name,const wchar *NameW,bool ShareRead)
bool File::Create(const wchar *Name,uint Mode)
{
// OpenIndiana based NAS and CIFS shares fail to set the file time if file
// was created in read+write mode and some data was written and not flushed
// before SetFileTime call. So we should use the write only mode if we plan
// SetFileTime call and do not need to read from file.
bool WriteMode=(Mode & FMF_WRITE)!=0;
bool ShareRead=(Mode & FMF_SHAREREAD)!=0 || File::OpenShared;
#ifdef _WIN_ALL
DWORD ShareMode=(ShareRead || File::OpenShared) ? FILE_SHARE_READ:0;
if (WinNT() && NameW!=NULL && *NameW!=0)
hFile=CreateFileW(NameW,GENERIC_READ|GENERIC_WRITE,ShareMode,NULL,
CREATE_ALWAYS,0,NULL);
CreateMode=Mode;
uint Access=WriteMode ? GENERIC_WRITE:GENERIC_READ|GENERIC_WRITE;
DWORD ShareMode=ShareRead ? FILE_SHARE_READ:0;
// Windows automatically removes dots and spaces in the end of file name,
// So we detect such names and process them with \\?\ prefix.
wchar *LastChar=PointToLastChar(Name);
bool Special=*LastChar=='.' || *LastChar==' ';
if (Special)
hFile=FILE_BAD_HANDLE;
else
hFile=CreateFileA(Name,GENERIC_READ|GENERIC_WRITE,ShareMode,NULL,
CREATE_ALWAYS,0,NULL);
hFile=CreateFile(Name,Access,ShareMode,NULL,CREATE_ALWAYS,0,NULL);
if (hFile==FILE_BAD_HANDLE)
{
wchar LongName[NM];
if (GetWinLongPath(Name,LongName,ASIZE(LongName)))
hFile=CreateFile(LongName,Access,ShareMode,NULL,CREATE_ALWAYS,0,NULL);
}
#else
hFile=fopen(Name,CREATEBINARY);
char NameA[NM];
WideToChar(Name,NameA,ASIZE(NameA));
#ifdef FILE_USE_OPEN
hFile=open(NameA,(O_CREAT|O_TRUNC) | (WriteMode ? O_WRONLY : O_RDWR),0666);
#else
hFile=fopen(NameA,WriteMode ? WRITEBINARY:CREATEBINARY);
#endif
#endif
NewFile=true;
HandleType=FILE_HANDLENORMAL;
SkipClose=false;
if (NameW!=NULL)
wcscpy(FileNameW,NameW);
else
*FileNameW=0;
if (Name!=NULL)
strcpy(FileName,Name);
else
WideToChar(NameW,FileName);
AddFileToList(hFile);
return(hFile!=BAD_HANDLE);
wcsncpyz(FileName,Name,ASIZE(FileName));
return hFile!=FILE_BAD_HANDLE;
}
void File::AddFileToList(FileHandle hFile)
#if !defined(SFX_MODULE)
void File::TCreate(const wchar *Name,uint Mode)
{
if (hFile!=BAD_HANDLE)
for (int I=0;I<sizeof(CreatedFiles)/sizeof(CreatedFiles[0]);I++)
if (CreatedFiles[I]==NULL)
{
CreatedFiles[I]=this;
break;
}
}
#if !defined(SHELL_EXT) && !defined(SFX_MODULE)
void File::TCreate(const char *Name,const wchar *NameW,bool ShareRead)
{
if (!WCreate(Name,NameW,ShareRead))
ErrHandler.Exit(FATAL_ERROR);
if (!WCreate(Name,Mode))
ErrHandler.Exit(RARX_FATAL);
}
#endif
bool File::WCreate(const char *Name,const wchar *NameW,bool ShareRead)
bool File::WCreate(const wchar *Name,uint Mode)
{
if (Create(Name,NameW,ShareRead))
return(true);
ErrHandler.SetErrorCode(CREATE_ERROR);
ErrHandler.CreateErrorMsg(Name,NameW);
return(false);
if (Create(Name,Mode))
return true;
ErrHandler.CreateErrorMsg(Name);
return false;
}
bool File::Close()
{
bool Success=true;
if (HandleType!=FILE_HANDLENORMAL)
HandleType=FILE_HANDLENORMAL;
else
if (hFile!=BAD_HANDLE)
if (hFile!=FILE_BAD_HANDLE)
{
if (!SkipClose)
{
if (!SkipClose)
{
#ifdef _WIN_ALL
// We use the standard system handle for stdout in Windows
// and it must not be closed here.
if (HandleType==FILE_HANDLENORMAL)
Success=CloseHandle(hFile)==TRUE;
#else
Success=fclose(hFile)!=EOF;
#endif
if (Success || !RemoveCreatedActive)
for (int I=0;I<sizeof(CreatedFiles)/sizeof(CreatedFiles[0]);I++)
if (CreatedFiles[I]==this)
{
CreatedFiles[I]=NULL;
break;
}
}
hFile=BAD_HANDLE;
if (!Success && AllowExceptions)
ErrHandler.CloseError(FileName,FileNameW);
}
CloseCount++;
return(Success);
}
void File::Flush()
{
#ifdef _WIN_ALL
FlushFileBuffers(hFile);
#ifdef FILE_USE_OPEN
Success=close(hFile)!=-1;
#else
fflush(hFile);
Success=fclose(hFile)!=EOF;
#endif
#endif
}
hFile=FILE_BAD_HANDLE;
}
HandleType=FILE_HANDLENORMAL;
if (!Success && AllowExceptions)
ErrHandler.CloseError(FileName);
return Success;
}
bool File::Delete()
{
if (HandleType!=FILE_HANDLENORMAL)
return(false);
if (hFile!=BAD_HANDLE)
return false;
if (hFile!=FILE_BAD_HANDLE)
Close();
if (!AllowDelete)
return(false);
return(DelFile(FileName,FileNameW));
return false;
return DelFile(FileName);
}
bool File::Rename(const char *NewName,const wchar *NewNameW)
bool File::Rename(const wchar *NewName)
{
// we do not need to rename if names are already same
bool Success=strcmp(FileName,NewName)==0;
if (Success && *FileNameW!=0 && *NullToEmpty(NewNameW)!=0)
Success=wcscmp(FileNameW,NewNameW)==0;
// No need to rename if names are already same.
bool Success=wcscmp(FileName,NewName)==0;
if (!Success)
Success=RenameFile(FileName,FileNameW,NewName,NewNameW);
Success=RenameFile(FileName,NewName);
if (Success)
{
// renamed successfully, storing the new name
strcpy(FileName,NewName);
wcscpy(FileNameW,NullToEmpty(NewNameW));
}
return(Success);
wcscpy(FileName,NewName);
return Success;
}
void File::Write(const void *Data,size_t Size)
bool File::Write(const void *Data,size_t Size)
{
if (Size==0)
return;
#ifndef _WIN_CE
if (HandleType!=FILE_HANDLENORMAL)
switch(HandleType)
return true;
if (HandleType==FILE_HANDLESTD)
{
#ifdef _WIN_ALL
hFile=GetStdHandle(STD_OUTPUT_HANDLE);
#else
// Cannot use the standard stdout here, because it already has wide orientation.
if (hFile==FILE_BAD_HANDLE)
{
case FILE_HANDLESTD:
#ifdef _WIN_ALL
hFile=GetStdHandle(STD_OUTPUT_HANDLE);
#ifdef FILE_USE_OPEN
hFile=dup(STDOUT_FILENO); // Open new stdout stream.
#else
hFile=stdout;
hFile=fdopen(dup(STDOUT_FILENO),"w"); // Open new stdout stream.
#endif
break;
case FILE_HANDLEERR:
#ifdef _WIN_ALL
hFile=GetStdHandle(STD_ERROR_HANDLE);
#else
hFile=stderr;
#endif
break;
}
#endif
}
bool Success;
while (1)
{
bool Success=false;
Success=false;
#ifdef _WIN_ALL
DWORD Written=0;
if (HandleType!=FILE_HANDLENORMAL)
@@ -316,9 +316,14 @@ void File::Write(const void *Data,size_t Size)
}
else
Success=WriteFile(hFile,Data,(DWORD)Size,&Written,NULL)==TRUE;
#else
#ifdef FILE_USE_OPEN
ssize_t Written=write(hFile,Data,Size);
Success=Written==Size;
#else
int Written=fwrite(Data,1,Size,hFile);
Success=Written==Size && !ferror(hFile);
#endif
#endif
if (!Success && AllowExceptions && HandleType==FILE_HANDLENORMAL)
{
@@ -328,22 +333,23 @@ void File::Write(const void *Data,size_t Size)
uint64 FreeSize=GetFreeDisk(FileName);
SetLastError(ErrCode);
if (FreeSize>Size && FilePos-Size<=0xffffffff && FilePos+Size>0xffffffff)
ErrHandler.WriteErrorFAT(FileName,FileNameW);
ErrHandler.WriteErrorFAT(FileName);
#endif
if (ErrHandler.AskRepeatWrite(FileName,FileNameW,false))
if (ErrHandler.AskRepeatWrite(FileName,false))
{
#ifndef _WIN_ALL
#if !defined(_WIN_ALL) && !defined(FILE_USE_OPEN)
clearerr(hFile);
#endif
if (Written<Size && Written>0)
Seek(Tell()-Written,SEEK_SET);
continue;
}
ErrHandler.WriteError(NULL,NULL,FileName,FileNameW);
ErrHandler.WriteError(NULL,FileName);
}
break;
}
LastWrite=true;
return Success; // It can return false only if AllowExceptions is disabled.
}
@@ -374,14 +380,14 @@ int File::Read(void *Data,size_t Size)
}
else
{
if (HandleType==FILE_HANDLENORMAL && ErrHandler.AskRepeatRead(FileName,FileNameW))
if (HandleType==FILE_HANDLENORMAL && ErrHandler.AskRepeatRead(FileName))
continue;
ErrHandler.ReadError(FileName,FileNameW);
ErrHandler.ReadError(FileName);
}
}
break;
}
return(ReadSize);
return ReadSize;
}
@@ -390,30 +396,52 @@ int File::DirectRead(void *Data,size_t Size)
{
#ifdef _WIN_ALL
const size_t MaxDeviceRead=20000;
const size_t MaxLockedRead=32768;
#endif
#ifndef _WIN_CE
if (HandleType==FILE_HANDLESTD)
{
#ifdef _WIN_ALL
if (Size>MaxDeviceRead)
Size=MaxDeviceRead;
// if (Size>MaxDeviceRead)
// Size=MaxDeviceRead;
hFile=GetStdHandle(STD_INPUT_HANDLE);
#else
#ifdef FILE_USE_OPEN
hFile=STDIN_FILENO;
#else
hFile=stdin;
#endif
}
#endif
}
#ifdef _WIN_ALL
// For pipes like 'type file.txt | rar -si arcname' ReadFile may return
// data in small ~4KB blocks. It may slightly reduce the compression ratio.
DWORD Read;
if (!ReadFile(hFile,Data,(DWORD)Size,&Read,NULL))
{
if (IsDevice() && Size>MaxDeviceRead)
return(DirectRead(Data,MaxDeviceRead));
return DirectRead(Data,MaxDeviceRead);
if (HandleType==FILE_HANDLESTD && GetLastError()==ERROR_BROKEN_PIPE)
return(0);
return(-1);
return 0;
// We had a bug report about failure to archive 1C database lock file
// 1Cv8tmp.1CL, which is a zero length file with a region above 200 KB
// permanently locked. If our first read request uses too large buffer
// and if we are in -dh mode, so we were able to open the file,
// we'll fail with "Read error". So now we use try a smaller buffer size
// in case of lock error.
if (HandleType==FILE_HANDLENORMAL && Size>MaxLockedRead &&
GetLastError()==ERROR_LOCK_VIOLATION)
return DirectRead(Data,MaxLockedRead);
return -1;
}
return(Read);
return Read;
#else
#ifdef FILE_USE_OPEN
ssize_t ReadSize=read(hFile,Data,Size);
if (ReadSize==-1)
return -1;
return (int)ReadSize;
#else
if (LastWrite)
{
@@ -423,8 +451,9 @@ int File::DirectRead(void *Data,size_t Size)
clearerr(hFile);
size_t ReadSize=fread(Data,1,Size,hFile);
if (ferror(hFile))
return(-1);
return((int)ReadSize);
return -1;
return (int)ReadSize;
#endif
#endif
}
@@ -432,14 +461,14 @@ int File::DirectRead(void *Data,size_t Size)
void File::Seek(int64 Offset,int Method)
{
if (!RawSeek(Offset,Method) && AllowExceptions)
ErrHandler.SeekError(FileName,FileNameW);
ErrHandler.SeekError(FileName);
}
bool File::RawSeek(int64 Offset,int Method)
{
if (hFile==BAD_HANDLE)
return(true);
if (hFile==FILE_BAD_HANDLE)
return true;
if (Offset<0 && Method!=SEEK_SET)
{
Offset=(Method==SEEK_CUR ? Tell():FileLength())+Offset;
@@ -449,41 +478,47 @@ bool File::RawSeek(int64 Offset,int Method)
LONG HighDist=(LONG)(Offset>>32);
if (SetFilePointer(hFile,(LONG)Offset,&HighDist,Method)==0xffffffff &&
GetLastError()!=NO_ERROR)
return(false);
return false;
#else
LastWrite=false;
#if defined(_LARGEFILE_SOURCE) && !defined(_OSF_SOURCE) && !defined(__VMS)
#ifdef FILE_USE_OPEN
if (lseek(hFile,(off_t)Offset,Method)==-1)
return false;
#elif defined(_LARGEFILE_SOURCE) && !defined(_OSF_SOURCE) && !defined(__VMS)
if (fseeko(hFile,Offset,Method)!=0)
return false;
#else
if (fseek(hFile,(long)Offset,Method)!=0)
return false;
#endif
return(false);
#endif
return(true);
return true;
}
int64 File::Tell()
{
if (hFile==BAD_HANDLE)
if (hFile==FILE_BAD_HANDLE)
if (AllowExceptions)
ErrHandler.SeekError(FileName,FileNameW);
ErrHandler.SeekError(FileName);
else
return(-1);
return -1;
#ifdef _WIN_ALL
LONG HighDist=0;
uint LowDist=SetFilePointer(hFile,0,&HighDist,FILE_CURRENT);
if (LowDist==0xffffffff && GetLastError()!=NO_ERROR)
if (AllowExceptions)
ErrHandler.SeekError(FileName,FileNameW);
ErrHandler.SeekError(FileName);
else
return(-1);
return(INT32TO64(HighDist,LowDist));
return -1;
return INT32TO64(HighDist,LowDist);
#else
#if defined(_LARGEFILE_SOURCE) && !defined(_OSF_SOURCE)
return(ftello(hFile));
#ifdef FILE_USE_OPEN
return lseek(hFile,0,SEEK_CUR);
#elif defined(_LARGEFILE_SOURCE) && !defined(_OSF_SOURCE)
return ftello(hFile);
#else
return(ftell(hFile));
return ftell(hFile);
#endif
#endif
}
@@ -498,6 +533,14 @@ void File::Prealloc(int64 Size)
Seek(0,SEEK_SET);
}
#endif
#if defined(_UNIX) && defined(USE_FALLOCATE)
// fallocate is rather new call. Only latest kernels support it.
// So we are not using it by default yet.
int fd = GetFD();
if (fd >= 0)
fallocate(fd, 0, 0, Size);
#endif
}
@@ -505,7 +548,7 @@ byte File::GetByte()
{
byte Byte=0;
Read(&Byte,1);
return(Byte);
return Byte;
}
@@ -518,9 +561,22 @@ void File::PutByte(byte Byte)
bool File::Truncate()
{
#ifdef _WIN_ALL
return(SetEndOfFile(hFile)==TRUE);
return SetEndOfFile(hFile)==TRUE;
#else
return(false);
return ftruncate(GetFD(),(off_t)Tell())==0;
#endif
}
void File::Flush()
{
#ifdef _WIN_ALL
FlushFileBuffers(hFile);
#else
#ifndef FILE_USE_OPEN
fflush(hFile);
#endif
fsync(GetFD());
#endif
}
@@ -528,16 +584,22 @@ bool File::Truncate()
void File::SetOpenFileTime(RarTime *ftm,RarTime *ftc,RarTime *fta)
{
#ifdef _WIN_ALL
// Workaround for OpenIndiana NAS time bug. If we cannot create a file
// in write only mode, we need to flush the write buffer before calling
// SetFileTime or file time will not be changed.
if (CreateMode!=FMF_UNDEFINED && (CreateMode & FMF_WRITE)==0)
FlushFileBuffers(hFile);
bool sm=ftm!=NULL && ftm->IsSet();
bool sc=ftc!=NULL && ftc->IsSet();
bool sa=fta!=NULL && fta->IsSet();
FILETIME fm,fc,fa;
if (sm)
ftm->GetWin32(&fm);
ftm->GetWinFT(&fm);
if (sc)
ftc->GetWin32(&fc);
ftc->GetWinFT(&fc);
if (sa)
fta->GetWin32(&fa);
fta->GetWinFT(&fa);
SetFileTime(hFile,sc ? &fc:NULL,sa ? &fa:NULL,sm ? &fm:NULL);
#endif
}
@@ -545,29 +607,47 @@ void File::SetOpenFileTime(RarTime *ftm,RarTime *ftc,RarTime *fta)
void File::SetCloseFileTime(RarTime *ftm,RarTime *fta)
{
#if defined(_UNIX) || defined(_EMX)
// Android APP_PLATFORM := android-14 does not support futimens and futimes.
// Newer platforms support futimens, but fail on Android 4.2.
// We have to use utime for Android.
// Also we noticed futimens fail to set timestamps on NTFS partition
// mounted to virtual Linux x86 machine, but utimensat worked correctly.
// So we set timestamps for already closed files in Unix.
#ifdef _UNIX
SetCloseFileTimeByName(FileName,ftm,fta);
#endif
}
void File::SetCloseFileTimeByName(const char *Name,RarTime *ftm,RarTime *fta)
void File::SetCloseFileTimeByName(const wchar *Name,RarTime *ftm,RarTime *fta)
{
#if defined(_UNIX) || defined(_EMX)
#ifdef _UNIX
bool setm=ftm!=NULL && ftm->IsSet();
bool seta=fta!=NULL && fta->IsSet();
if (setm || seta)
{
char NameA[NM];
WideToChar(Name,NameA,ASIZE(NameA));
#ifdef UNIX_TIME_NS
timespec times[2];
times[0].tv_sec=seta ? fta->GetUnix() : 0;
times[0].tv_nsec=seta ? long(fta->GetUnixNS()%1000000000) : UTIME_NOW;
times[1].tv_sec=setm ? ftm->GetUnix() : 0;
times[1].tv_nsec=setm ? long(ftm->GetUnixNS()%1000000000) : UTIME_NOW;
utimensat(AT_FDCWD,NameA,times,0);
#else
utimbuf ut;
if (setm)
ut.modtime=ftm->GetUnix();
else
ut.modtime=fta->GetUnix();
ut.modtime=fta->GetUnix(); // Need to set something, cannot left it 0.
if (seta)
ut.actime=fta->GetUnix();
else
ut.actime=ut.modtime;
utime(Name,&ut);
ut.actime=ut.modtime; // Need to set something, cannot left it 0.
utime(NameA,&ut);
#endif
}
#endif
}
@@ -578,12 +658,12 @@ void File::GetOpenFileTime(RarTime *ft)
#ifdef _WIN_ALL
FILETIME FileTime;
GetFileTime(hFile,NULL,NULL,&FileTime);
*ft=FileTime;
ft->SetWinFT(&FileTime);
#endif
#if defined(_UNIX) || defined(_EMX)
struct stat st;
fstat(fileno(hFile),&st);
*ft=st.st_mtime;
fstat(GetFD(),&st);
ft->SetUnix(st.st_mtime);
#endif
}
@@ -592,82 +672,27 @@ int64 File::FileLength()
{
SaveFilePos SavePos(*this);
Seek(0,SEEK_END);
return(Tell());
}
void File::SetHandleType(FILE_HANDLETYPE Type)
{
HandleType=Type;
return Tell();
}
bool File::IsDevice()
{
if (hFile==BAD_HANDLE)
return(false);
if (hFile==FILE_BAD_HANDLE)
return false;
#ifdef _WIN_ALL
uint Type=GetFileType(hFile);
return(Type==FILE_TYPE_CHAR || Type==FILE_TYPE_PIPE);
return Type==FILE_TYPE_CHAR || Type==FILE_TYPE_PIPE;
#else
return(isatty(fileno(hFile)));
return isatty(GetFD());
#endif
}
#ifndef SFX_MODULE
void File::fprintf(const char *fmt,...)
{
va_list argptr;
va_start(argptr,fmt);
safebuf char Msg[2*NM+1024],OutMsg[2*NM+1024];
vsprintf(Msg,fmt,argptr);
#ifdef _WIN_ALL
for (int Src=0,Dest=0;;Src++)
{
char CurChar=Msg[Src];
if (CurChar=='\n')
OutMsg[Dest++]='\r';
OutMsg[Dest++]=CurChar;
if (CurChar==0)
break;
}
#else
strcpy(OutMsg,Msg);
#endif
Write(OutMsg,strlen(OutMsg));
va_end(argptr);
}
#endif
bool File::RemoveCreated()
{
RemoveCreatedActive++;
bool RetCode=true;
for (int I=0;I<sizeof(CreatedFiles)/sizeof(CreatedFiles[0]);I++)
if (CreatedFiles[I]!=NULL)
{
CreatedFiles[I]->SetExceptions(false);
bool Success;
if (CreatedFiles[I]->NewFile)
Success=CreatedFiles[I]->Delete();
else
Success=CreatedFiles[I]->Close();
if (Success)
CreatedFiles[I]=NULL;
else
RetCode=false;
}
RemoveCreatedActive--;
return(RetCode);
}
#ifndef SFX_MODULE
int64 File::Copy(File &Dest,int64 Length)
{
Array<char> Buffer(0x10000);
Array<char> Buffer(0x40000);
int64 CopySize=0;
bool CopyAll=(Length==INT64NDF);
@@ -675,14 +700,30 @@ int64 File::Copy(File &Dest,int64 Length)
{
Wait();
size_t SizeToRead=(!CopyAll && Length<(int64)Buffer.Size()) ? (size_t)Length:Buffer.Size();
int ReadSize=Read(&Buffer[0],SizeToRead);
char *Buf=&Buffer[0];
int ReadSize=Read(Buf,SizeToRead);
if (ReadSize==0)
break;
Dest.Write(&Buffer[0],ReadSize);
size_t WriteSize=ReadSize;
#ifdef _WIN_ALL
// For FAT32 USB flash drives in Windows if first write is 4 KB or more,
// write caching is disabled and "write through" is enabled, resulting
// in bad performance, especially for many small files. It happens when
// we create SFX archive on USB drive, because SFX module is written first.
// So we split the first write to small 1 KB followed by rest of data.
if (CopySize==0 && WriteSize>=4096)
{
const size_t FirstWrite=1024;
Dest.Write(Buf,FirstWrite);
Buf+=FirstWrite;
WriteSize-=FirstWrite;
}
#endif
Dest.Write(Buf,WriteSize);
CopySize+=ReadSize;
if (!CopyAll)
Length-=ReadSize;
}
return(CopySize);
return CopySize;
}
#endif

View File

@@ -1,34 +1,52 @@
#ifndef _RAR_FILE_
#define _RAR_FILE_
#define FILE_USE_OPEN
#ifdef _WIN_ALL
typedef HANDLE FileHandle;
#define BAD_HANDLE INVALID_HANDLE_VALUE
typedef HANDLE FileHandle;
#define FILE_BAD_HANDLE INVALID_HANDLE_VALUE
#elif defined(FILE_USE_OPEN)
typedef off_t FileHandle;
#define FILE_BAD_HANDLE -1
#else
typedef FILE* FileHandle;
#define BAD_HANDLE NULL
typedef FILE* FileHandle;
#define FILE_BAD_HANDLE NULL
#endif
class RAROptions;
enum FILE_HANDLETYPE {FILE_HANDLENORMAL,FILE_HANDLESTD,FILE_HANDLEERR};
enum FILE_HANDLETYPE {FILE_HANDLENORMAL,FILE_HANDLESTD};
enum FILE_ERRORTYPE {FILE_SUCCESS,FILE_NOTFOUND,FILE_READERROR};
struct FileStat
{
uint FileAttr;
uint FileTime;
int64 FileSize;
bool IsDir;
enum FILE_MODE_FLAGS {
// Request read only access to file. Default for Open.
FMF_READ=0,
// Request both read and write access to file. Default for Create.
FMF_UPDATE=1,
// Request write only access to file.
FMF_WRITE=2,
// Open files which are already opened for write by other programs.
FMF_OPENSHARED=4,
// Open files only if no other program is opened it even in shared mode.
FMF_OPENEXCLUSIVE=8,
// Provide read access to created file for other programs.
FMF_SHAREREAD=16,
// Mode flags are not defined yet.
FMF_UNDEFINED=256
};
class File
{
private:
void AddFileToList(FileHandle hFile);
FileHandle hFile;
bool LastWrite;
FILE_HANDLETYPE HandleType;
@@ -39,60 +57,67 @@ class File
bool AllowExceptions;
#ifdef _WIN_ALL
bool NoSequentialRead;
uint CreateMode;
#endif
protected:
bool OpenShared;
bool OpenShared; // Set by 'Archive' class.
public:
char FileName[NM];
wchar FileNameW[NM];
wchar FileName[NM];
FILE_ERRORTYPE ErrorType;
uint CloseCount;
public:
File();
virtual ~File();
void operator = (File &SrcFile);
bool Open(const char *Name,const wchar *NameW=NULL,bool OpenShared=false,bool Update=false);
void TOpen(const char *Name,const wchar *NameW=NULL);
bool WOpen(const char *Name,const wchar *NameW=NULL);
bool Create(const char *Name,const wchar *NameW=NULL,bool ShareRead=true);
void TCreate(const char *Name,const wchar *NameW=NULL,bool ShareRead=true);
bool WCreate(const char *Name,const wchar *NameW=NULL,bool ShareRead=true);
virtual bool Open(const wchar *Name,uint Mode=FMF_READ);
void TOpen(const wchar *Name);
bool WOpen(const wchar *Name);
bool Create(const wchar *Name,uint Mode=FMF_UPDATE|FMF_SHAREREAD);
void TCreate(const wchar *Name,uint Mode=FMF_UPDATE|FMF_SHAREREAD);
bool WCreate(const wchar *Name,uint Mode=FMF_UPDATE|FMF_SHAREREAD);
bool Close();
void Flush();
bool Delete();
bool Rename(const char *NewName,const wchar *NewNameW=NULL);
void Write(const void *Data,size_t Size);
int Read(void *Data,size_t Size);
bool Rename(const wchar *NewName);
bool Write(const void *Data,size_t Size);
virtual int Read(void *Data,size_t Size);
int DirectRead(void *Data,size_t Size);
void Seek(int64 Offset,int Method);
virtual void Seek(int64 Offset,int Method);
bool RawSeek(int64 Offset,int Method);
int64 Tell();
virtual int64 Tell();
void Prealloc(int64 Size);
byte GetByte();
void PutByte(byte Byte);
bool Truncate();
void Flush();
void SetOpenFileTime(RarTime *ftm,RarTime *ftc=NULL,RarTime *fta=NULL);
void SetCloseFileTime(RarTime *ftm,RarTime *fta=NULL);
static void SetCloseFileTimeByName(const char *Name,RarTime *ftm,RarTime *fta);
static void SetCloseFileTimeByName(const wchar *Name,RarTime *ftm,RarTime *fta);
void GetOpenFileTime(RarTime *ft);
bool IsOpened() {return(hFile!=BAD_HANDLE);};
bool IsOpened() {return hFile!=FILE_BAD_HANDLE;};
int64 FileLength();
void SetHandleType(FILE_HANDLETYPE Type);
FILE_HANDLETYPE GetHandleType() {return(HandleType);};
void SetHandleType(FILE_HANDLETYPE Type) {HandleType=Type;}
FILE_HANDLETYPE GetHandleType() {return HandleType;}
bool IsDevice();
void fprintf(const char *fmt,...);
static bool RemoveCreated();
FileHandle GetHandle() {return(hFile);};
void SetIgnoreReadErrors(bool Mode) {IgnoreReadErrors=Mode;};
char *GetName() {return(FileName);}
FileHandle GetHandle() {return hFile;}
void SetHandle(FileHandle Handle) {Close();hFile=Handle;}
void SetIgnoreReadErrors(bool Mode) {IgnoreReadErrors=Mode;}
int64 Copy(File &Dest,int64 Length=INT64NDF);
void SetAllowDelete(bool Allow) {AllowDelete=Allow;}
void SetExceptions(bool Allow) {AllowExceptions=Allow;}
#ifdef _WIN_ALL
void RemoveSequentialFlag() {NoSequentialRead=true;}
#endif
#ifdef _UNIX
int GetFD()
{
#ifdef FILE_USE_OPEN
return hFile;
#else
return fileno(hFile);
#endif
}
#endif
};
#endif

View File

@@ -1,104 +1,47 @@
#include "rar.hpp"
MKDIR_CODE MakeDir(const char *Name,const wchar *NameW,bool SetAttr,uint Attr)
MKDIR_CODE MakeDir(const wchar *Name,bool SetAttr,uint Attr)
{
#ifdef _WIN_ALL
BOOL RetCode;
if (WinNT() && NameW!=NULL && *NameW!=0)
RetCode=CreateDirectoryW(NameW,NULL);
else
if (Name!=NULL)
RetCode=CreateDirectoryA(Name,NULL);
else
return(MKDIR_BADPATH);
// Windows automatically removes dots and spaces in the end of directory
// name. So we detect such names and process them with \\?\ prefix.
wchar *LastChar=PointToLastChar(Name);
bool Special=*LastChar=='.' || *LastChar==' ';
BOOL RetCode=Special ? FALSE : CreateDirectory(Name,NULL);
if (RetCode==0 && !FileExist(Name))
{
wchar LongName[NM];
if (GetWinLongPath(Name,LongName,ASIZE(LongName)))
RetCode=CreateDirectory(LongName,NULL);
}
if (RetCode!=0) // Non-zero return code means success for CreateDirectory.
{
if (SetAttr)
SetFileAttr(Name,NameW,Attr);
return(MKDIR_SUCCESS);
SetFileAttr(Name,Attr);
return MKDIR_SUCCESS;
}
int ErrCode=GetLastError();
if (ErrCode==ERROR_FILE_NOT_FOUND || ErrCode==ERROR_PATH_NOT_FOUND)
return(MKDIR_BADPATH);
return(MKDIR_ERROR);
#else
// No Unicode in the rest of function, so Name must be not NULL.
if (Name==NULL)
return(MKDIR_BADPATH);
#endif
#ifdef _EMX
#ifdef _DJGPP
if (mkdir(Name,(Attr & FA_RDONLY) ? 0:S_IWUSR)==0)
#else
if (__mkdir(Name)==0)
#endif
{
if (SetAttr)
SetFileAttr(Name,NameW,Attr);
return(MKDIR_SUCCESS);
}
return(errno==ENOENT ? MKDIR_BADPATH:MKDIR_ERROR);
#endif
#ifdef _UNIX
return MKDIR_BADPATH;
return MKDIR_ERROR;
#elif defined(_UNIX)
char NameA[NM];
WideToChar(Name,NameA,ASIZE(NameA));
mode_t uattr=SetAttr ? (mode_t)Attr:0777;
int ErrCode=mkdir(Name,uattr);
int ErrCode=mkdir(NameA,uattr);
if (ErrCode==-1)
return(errno==ENOENT ? MKDIR_BADPATH:MKDIR_ERROR);
return(MKDIR_SUCCESS);
#endif
}
bool CreatePath(const char *Path,bool SkipLastName)
{
if (Path==NULL || *Path==0)
return(false);
#if defined(_WIN_ALL) || defined(_EMX)
uint DirAttr=0;
return errno==ENOENT ? MKDIR_BADPATH:MKDIR_ERROR;
return MKDIR_SUCCESS;
#else
uint DirAttr=0777;
return MKDIR_ERROR;
#endif
bool Success=true;
for (const char *s=Path;*s!=0;s=charnext(s))
{
if (s-Path>=NM)
break;
if (*s==CPATHDIVIDER)
{
char DirName[NM];
strncpy(DirName,Path,s-Path);
DirName[s-Path]=0;
if (MakeDir(DirName,NULL,true,DirAttr)==MKDIR_SUCCESS)
{
#ifndef GUI
mprintf(St(MCreatDir),DirName);
mprintf(" %s",St(MOk));
#endif
}
else
Success=false;
}
}
if (!SkipLastName)
if (!IsPathDiv(*PointToLastChar(Path)))
if (MakeDir(Path,NULL,true,DirAttr)!=MKDIR_SUCCESS)
Success=false;
return(Success);
}
bool CreatePath(const wchar *Path,bool SkipLastName)
{
if (Path==NULL || *Path==0)
return(false);
return false;
#if defined(_WIN_ALL) || defined(_EMX)
uint DirAttr=0;
@@ -110,83 +53,74 @@ bool CreatePath(const wchar *Path,bool SkipLastName)
for (const wchar *s=Path;*s!=0;s++)
{
if (s-Path>=NM)
wchar DirName[NM];
if (s-Path>=ASIZE(DirName))
break;
if (*s==CPATHDIVIDER)
// Process all kinds of path separators, so user can enter Unix style
// path in Windows or Windows in Unix. s>Path check avoids attempting
// creating an empty directory for paths starting from path separator.
if (IsPathDiv(*s) && s>Path)
{
wchar DirName[NM];
#ifdef _WIN_ALL
// We must not attempt to create "D:" directory, because first
// CreateDirectory will fail, so we'll use \\?\D:, which forces Wine
// to create "D:" directory.
if (s==Path+2 && Path[1]==':')
continue;
#endif
wcsncpy(DirName,Path,s-Path);
DirName[s-Path]=0;
if (MakeDir(NULL,DirName,true,DirAttr)==MKDIR_SUCCESS)
Success=MakeDir(DirName,true,DirAttr)==MKDIR_SUCCESS;
if (Success)
{
#ifndef GUI
char DirNameA[NM];
WideToChar(DirName,DirNameA,ASIZE(DirNameA));
DirNameA[ASIZE(DirNameA)-1]=0;
mprintf(St(MCreatDir),DirNameA);
mprintf(" %s",St(MOk));
#endif
mprintf(St(MCreatDir),DirName);
mprintf(L" %s",St(MOk));
}
else
Success=false;
}
}
if (!SkipLastName)
if (!IsPathDiv(*PointToLastChar(Path)))
if (MakeDir(NULL,Path,true,DirAttr)!=MKDIR_SUCCESS)
Success=false;
return(Success);
if (!SkipLastName && !IsPathDiv(*PointToLastChar(Path)))
Success=MakeDir(Path,true,DirAttr)==MKDIR_SUCCESS;
return Success;
}
bool CreatePath(const char *Path,const wchar *PathW,bool SkipLastName)
void SetDirTime(const wchar *Name,RarTime *ftm,RarTime *ftc,RarTime *fta)
{
#ifdef _WIN_ALL
// If we are in Windows, let's try Unicode path first. In Unix we do not
// need it (Unix MakeDir will fails with Unicode only name).
if (PathW!=NULL && *PathW!=0)
return(CreatePath(PathW,SkipLastName));
#endif
if (Path!=NULL && *Path!=0)
return(CreatePath(Path,SkipLastName));
return(false);
}
void SetDirTime(const char *Name,const wchar *NameW,RarTime *ftm,RarTime *ftc,RarTime *fta)
{
#ifdef _WIN_ALL
if (!WinNT())
return;
#if defined(_WIN_ALL)
bool sm=ftm!=NULL && ftm->IsSet();
bool sc=ftc!=NULL && ftc->IsSet();
bool sa=fta!=NULL && fta->IsSet();
unsigned int DirAttr=GetFileAttr(Name,NameW);
bool ResetAttr=(DirAttr!=0xffffffff && (DirAttr & FA_RDONLY)!=0);
uint DirAttr=GetFileAttr(Name);
bool ResetAttr=(DirAttr!=0xffffffff && (DirAttr & FILE_ATTRIBUTE_READONLY)!=0);
if (ResetAttr)
SetFileAttr(Name,NameW,0);
SetFileAttr(Name,0);
wchar DirNameW[NM];
GetWideName(Name,NameW,DirNameW,ASIZE(DirNameW));
HANDLE hFile=CreateFileW(DirNameW,GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,
HANDLE hFile=CreateFile(Name,GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL,OPEN_EXISTING,FILE_FLAG_BACKUP_SEMANTICS,NULL);
if (hFile==INVALID_HANDLE_VALUE)
{
wchar LongName[NM];
if (GetWinLongPath(Name,LongName,ASIZE(LongName)))
hFile=CreateFile(LongName,GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL,OPEN_EXISTING,FILE_FLAG_BACKUP_SEMANTICS,NULL);
}
if (hFile==INVALID_HANDLE_VALUE)
return;
FILETIME fm,fc,fa;
if (sm)
ftm->GetWin32(&fm);
ftm->GetWinFT(&fm);
if (sc)
ftc->GetWin32(&fc);
ftc->GetWinFT(&fc);
if (sa)
fta->GetWin32(&fa);
fta->GetWinFT(&fa);
SetFileTime(hFile,sc ? &fc:NULL,sa ? &fa:NULL,sm ? &fm:NULL);
CloseHandle(hFile);
if (ResetAttr)
SetFileAttr(Name,NameW,DirAttr);
SetFileAttr(Name,DirAttr);
#endif
#if defined(_UNIX) || defined(_EMX)
File::SetCloseFileTimeByName(Name,ftm,fta);
@@ -194,157 +128,100 @@ void SetDirTime(const char *Name,const wchar *NameW,RarTime *ftm,RarTime *ftc,Ra
}
bool IsRemovable(const char *Name)
bool IsRemovable(const wchar *Name)
{
#ifdef _WIN_ALL
char Root[NM];
GetPathRoot(Name,Root);
int Type=GetDriveTypeA(*Root!=0 ? Root:NULL);
return(Type==DRIVE_REMOVABLE || Type==DRIVE_CDROM);
#elif defined(_EMX)
char Drive=etoupper(Name[0]);
return((Drive=='A' || Drive=='B') && Name[1]==':');
#if defined(_WIN_ALL)
wchar Root[NM];
GetPathRoot(Name,Root,ASIZE(Root));
int Type=GetDriveType(*Root!=0 ? Root:NULL);
return Type==DRIVE_REMOVABLE || Type==DRIVE_CDROM;
#else
return(false);
return false;
#endif
}
#ifndef SFX_MODULE
int64 GetFreeDisk(const char *Name)
int64 GetFreeDisk(const wchar *Name)
{
#ifdef _WIN_ALL
char Root[NM];
GetPathRoot(Name,Root);
typedef BOOL (WINAPI *GETDISKFREESPACEEX)(
LPCSTR,PULARGE_INTEGER,PULARGE_INTEGER,PULARGE_INTEGER
);
static GETDISKFREESPACEEX pGetDiskFreeSpaceEx=NULL;
if (pGetDiskFreeSpaceEx==NULL)
{
HMODULE hKernel=GetModuleHandleW(L"kernel32.dll");
if (hKernel!=NULL)
pGetDiskFreeSpaceEx=(GETDISKFREESPACEEX)GetProcAddress(hKernel,"GetDiskFreeSpaceExA");
}
if (pGetDiskFreeSpaceEx!=NULL)
{
GetFilePath(Name,Root,ASIZE(Root));
ULARGE_INTEGER uiTotalSize,uiTotalFree,uiUserFree;
uiUserFree.u.LowPart=uiUserFree.u.HighPart=0;
if (pGetDiskFreeSpaceEx(*Root ? Root:NULL,&uiUserFree,&uiTotalSize,&uiTotalFree) &&
uiUserFree.u.HighPart<=uiTotalFree.u.HighPart)
return(INT32TO64(uiUserFree.u.HighPart,uiUserFree.u.LowPart));
}
// We are here if we failed to load GetDiskFreeSpaceExA.
DWORD SectorsPerCluster,BytesPerSector,FreeClusters,TotalClusters;
if (!GetDiskFreeSpaceA(*Root ? Root:NULL,&SectorsPerCluster,&BytesPerSector,&FreeClusters,&TotalClusters))
return(1457664);
int64 FreeSize=SectorsPerCluster*BytesPerSector;
FreeSize=FreeSize*FreeClusters;
return(FreeSize);
#elif defined(_BEOS)
char Root[NM];
wchar Root[NM];
GetFilePath(Name,Root,ASIZE(Root));
dev_t Dev=dev_for_path(*Root ? Root:".");
if (Dev<0)
return(1457664);
fs_info Info;
if (fs_stat_dev(Dev,&Info)!=0)
return(1457664);
int64 FreeSize=Info.block_size;
FreeSize=FreeSize*Info.free_blocks;
return(FreeSize);
ULARGE_INTEGER uiTotalSize,uiTotalFree,uiUserFree;
uiUserFree.u.LowPart=uiUserFree.u.HighPart=0;
if (GetDiskFreeSpaceEx(*Root!=0 ? Root:NULL,&uiUserFree,&uiTotalSize,&uiTotalFree) &&
uiUserFree.u.HighPart<=uiTotalFree.u.HighPart)
return INT32TO64(uiUserFree.u.HighPart,uiUserFree.u.LowPart);
return 0;
#elif defined(_UNIX)
return(1457664);
#elif defined(_EMX)
int Drive=IsDiskLetter(Name) ? etoupper(Name[0])-'A'+1:0;
#ifndef _DJGPP
if (_osmode == OS2_MODE)
{
FSALLOCATE fsa;
if (DosQueryFSInfo(Drive,1,&fsa,sizeof(fsa))!=0)
return(1457664);
int64 FreeSize=fsa.cSectorUnit*fsa.cbSector;
FreeSize=FreeSize*fsa.cUnitAvail;
return(FreeSize);
}
else
#endif
{
union REGS regs,outregs;
memset(&regs,0,sizeof(regs));
regs.h.ah=0x36;
regs.h.dl=Drive;
#ifdef _DJGPP
int86 (0x21,&regs,&outregs);
wchar Root[NM];
GetFilePath(Name,Root,ASIZE(Root));
char RootA[NM];
WideToChar(Root,RootA,ASIZE(RootA));
struct statvfs sfs;
if (statvfs(*RootA!=0 ? RootA:".",&sfs)!=0)
return 0;
int64 FreeSize=sfs.f_bsize;
FreeSize=FreeSize*sfs.f_bavail;
return FreeSize;
#else
_int86 (0x21,&regs,&outregs);
#endif
if (outregs.x.ax==0xffff)
return(1457664);
int64 FreeSize=outregs.x.ax*outregs.x.cx;
FreeSize=FreeSize*outregs.x.bx;
return(FreeSize);
}
#else
#define DISABLEAUTODETECT
return(1457664);
return 0;
#endif
}
#endif
bool FileExist(const char *Name,const wchar *NameW)
#if defined(_WIN_ALL) && !defined(SFX_MODULE) && !defined(SILENT)
// Return 'true' for FAT and FAT32, so we can adjust the maximum supported
// file size to 4 GB for these file systems.
bool IsFAT(const wchar *Name)
{
#ifdef _WIN_ALL
if (WinNT() && NameW!=NULL && *NameW!=0)
return(GetFileAttributesW(NameW)!=0xffffffff);
else
return(Name!=NULL && GetFileAttributesA(Name)!=0xffffffff);
#elif defined(ENABLE_ACCESS)
return(access(Name,0)==0);
#else
FindData FD;
return(FindFile::FastFind(Name,NameW,&FD));
#endif
wchar Root[NM];
GetPathRoot(Name,Root,ASIZE(Root));
wchar FileSystem[MAX_PATH+1];
if (GetVolumeInformation(Root,NULL,0,NULL,NULL,NULL,FileSystem,ASIZE(FileSystem)))
return wcscmp(FileSystem,L"FAT")==0 || wcscmp(FileSystem,L"FAT32")==0;
return false;
}
#endif
bool FileExist(const wchar *Name)
{
return FileExist(NULL,Name);
#ifdef _WIN_ALL
return GetFileAttr(Name)!=0xffffffff;
#elif defined(ENABLE_ACCESS)
char NameA[NM];
WideToChar(Name,NameA,ASIZE(NameA));
return access(NameA,0)==0;
#else
FindData FD;
return FindFile::FastFind(Name,&FD);
#endif
}
bool WildFileExist(const char *Name,const wchar *NameW)
bool WildFileExist(const wchar *Name)
{
if (IsWildcard(Name,NameW))
if (IsWildcard(Name))
{
FindFile Find;
Find.SetMask(Name);
Find.SetMaskW(NameW);
FindData fd;
return(Find.Next(&fd));
return Find.Next(&fd);
}
return(FileExist(Name,NameW));
return FileExist(Name);
}
bool IsDir(uint Attr)
{
#if defined (_WIN_ALL) || defined(_EMX)
return(Attr!=0xffffffff && (Attr & 0x10)!=0);
#ifdef _WIN_ALL
return Attr!=0xffffffff && (Attr & FILE_ATTRIBUTE_DIRECTORY)!=0;
#endif
#if defined(_UNIX)
return((Attr & 0xF000)==0x4000);
return (Attr & 0xF000)==0x4000;
#endif
}
@@ -352,28 +229,20 @@ bool IsDir(uint Attr)
bool IsUnreadable(uint Attr)
{
#if defined(_UNIX) && defined(S_ISFIFO) && defined(S_ISSOCK) && defined(S_ISCHR)
return(S_ISFIFO(Attr) || S_ISSOCK(Attr) || S_ISCHR(Attr));
#endif
return(false);
}
bool IsLabel(uint Attr)
{
#if defined (_WIN_ALL) || defined(_EMX)
return((Attr & 8)!=0);
#else
return(false);
return S_ISFIFO(Attr) || S_ISSOCK(Attr) || S_ISCHR(Attr);
#endif
return false;
}
bool IsLink(uint Attr)
{
#ifdef _UNIX
return((Attr & 0xF000)==0xA000);
return (Attr & 0xF000)==0xA000;
#elif defined(_WIN_ALL)
return (Attr & FILE_ATTRIBUTE_REPARSE_POINT)!=0;
#else
return(false);
return false;
#endif
}
@@ -384,144 +253,134 @@ bool IsLink(uint Attr)
bool IsDeleteAllowed(uint FileAttr)
{
#if defined(_WIN_ALL) || defined(_EMX)
return((FileAttr & (FA_RDONLY|FA_SYSTEM|FA_HIDDEN))==0);
#ifdef _WIN_ALL
return (FileAttr & (FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_HIDDEN))==0;
#else
return((FileAttr & (S_IRUSR|S_IWUSR))==(S_IRUSR|S_IWUSR));
return (FileAttr & (S_IRUSR|S_IWUSR))==(S_IRUSR|S_IWUSR);
#endif
}
void PrepareToDelete(const char *Name,const wchar *NameW)
void PrepareToDelete(const wchar *Name)
{
#if defined(_WIN_ALL) || defined(_EMX)
SetFileAttr(Name,NameW,0);
SetFileAttr(Name,0);
#endif
#ifdef _UNIX
if (Name!=NULL)
chmod(Name,S_IRUSR|S_IWUSR|S_IXUSR);
#endif
}
uint GetFileAttr(const char *Name,const wchar *NameW)
{
#ifdef _WIN_ALL
if (WinNT() && NameW!=NULL && *NameW!=0)
return(GetFileAttributesW(NameW));
else
return(GetFileAttributesA(Name));
#elif defined(_DJGPP)
return(_chmod(Name,0));
#else
struct stat st;
if (stat(Name,&st)!=0)
return(0);
#ifdef _EMX
return(st.st_attr);
#else
return(st.st_mode);
#endif
#endif
}
bool SetFileAttr(const char *Name,const wchar *NameW,uint Attr)
{
bool Success;
#ifdef _WIN_ALL
if (WinNT() && NameW!=NULL && *NameW!=0)
Success=SetFileAttributesW(NameW,Attr)!=0;
else
if (Name!=NULL)
Success=SetFileAttributesA(Name,Attr)!=0;
else
Success=false;
#elif defined(_DJGPP)
Success=_chmod(Name,1,Attr)!=-1;
#elif defined(_EMX)
Success=__chmod(Name,1,Attr)!=-1;
#elif defined(_UNIX)
Success=chmod(Name,(mode_t)Attr)==0;
#else
Success=false;
#endif
return(Success);
}
#ifndef SFX_MODULE
char *MkTemp(char *Name)
{
size_t Length=strlen(Name);
if (Length<=6)
return(NULL);
// We need some kind of random start point for first temporary name.
RarTime CurTime;
CurTime.SetCurrentTime();
int Random=(int)CurTime.GetRaw();
for (int Attempt=0;;Attempt++)
{
sprintf(Name+Length-6,"%06u",(Random+Attempt)%1000000);
Name[Length-4]='.';
if (!FileExist(Name))
break;
if (Attempt==1000)
return(NULL);
char NameA[NM];
WideToChar(Name,NameA,ASIZE(NameA));
chmod(NameA,S_IRUSR|S_IWUSR|S_IXUSR);
}
return(Name);
}
#endif
}
#if defined(_WIN_ALL) && !defined(SFX_MODULE)
wchar *MkTemp(wchar *Name)
uint GetFileAttr(const wchar *Name)
{
#ifdef _WIN_ALL
DWORD Attr=GetFileAttributes(Name);
if (Attr==0xffffffff)
{
wchar LongName[NM];
if (GetWinLongPath(Name,LongName,ASIZE(LongName)))
Attr=GetFileAttributes(LongName);
}
return Attr;
#else
char NameA[NM];
WideToChar(Name,NameA,ASIZE(NameA));
struct stat st;
if (stat(NameA,&st)!=0)
return 0;
return st.st_mode;
#endif
}
bool SetFileAttr(const wchar *Name,uint Attr)
{
#ifdef _WIN_ALL
bool Success=SetFileAttributes(Name,Attr)!=0;
if (!Success)
{
wchar LongName[NM];
if (GetWinLongPath(Name,LongName,ASIZE(LongName)))
Success=SetFileAttributes(LongName,Attr)!=0;
}
return Success;
#elif defined(_UNIX)
char NameA[NM];
WideToChar(Name,NameA,ASIZE(NameA));
return chmod(NameA,(mode_t)Attr)==0;
#else
return false;
#endif
}
#if 0
wchar *MkTemp(wchar *Name,size_t MaxSize)
{
size_t Length=wcslen(Name);
if (Length<=6)
return(NULL);
// We need some kind of random start point for first temporary name.
RarTime CurTime;
CurTime.SetCurrentTime();
int Random=(int)CurTime.GetRaw();
// We cannot use CurTime.GetWin() as is, because its lowest bits can
// have low informational value, like being a zero or few fixed numbers.
uint Random=(uint)(CurTime.GetWin()/100000);
// Using PID we guarantee that different RAR copies use different temp names
// even if started in exactly the same time.
uint PID=0;
#ifdef _WIN_ALL
PID=(uint)GetCurrentProcessId();
#elif defined(_UNIX)
PID=(uint)getpid();
#endif
for (uint Attempt=0;;Attempt++)
{
sprintfw(Name+Length-6,7,L"%06u",(Random+Attempt)%1000000);
Name[Length-4]='.';
if (!FileExist(NULL,Name))
uint Ext=Random%50000+Attempt;
wchar RndText[50];
swprintf(RndText,ASIZE(RndText),L"%u.%03u",PID,Ext);
if (Length+wcslen(RndText)>=MaxSize || Attempt==1000)
return NULL;
wcscpy(Name+Length,RndText);
if (!FileExist(Name))
break;
if (Attempt==1000)
return(NULL);
}
return(Name);
return Name;
}
#endif
#ifndef SFX_MODULE
uint CalcFileCRC(File *SrcFile,int64 Size,CALCCRC_SHOWMODE ShowMode)
#if !defined(SFX_MODULE)
void CalcFileSum(File *SrcFile,uint *CRC32,byte *Blake2,uint Threads,int64 Size,uint Flags)
{
SaveFilePos SavePos(*SrcFile);
const size_t BufSize=0x10000;
Array<byte> Data(BufSize);
int64 BlockCount=0;
uint DataCRC=0xffffffff;
#if !defined(SILENT) && !defined(_WIN_CE)
int64 FileLength=SrcFile->FileLength();
if (ShowMode!=CALCCRC_SHOWNONE)
{
mprintf(St(MCalcCRC));
mprintf(" ");
}
#ifndef SILENT
int64 FileLength=Size==INT64NDF ? SrcFile->FileLength() : Size;
#endif
SrcFile->Seek(0,SEEK_SET);
if ((Flags & (CALCFSUM_SHOWTEXT|CALCFSUM_SHOWPERCENT))!=0)
uiMsg(UIEVENT_FILESUMSTART);
if ((Flags & CALCFSUM_CURPOS)==0)
SrcFile->Seek(0,SEEK_SET);
const size_t BufSize=0x100000;
Array<byte> Data(BufSize);
DataHash HashCRC,HashBlake2;
HashCRC.Init(HASH_CRC32,Threads);
HashBlake2.Init(HASH_BLAKE2,Threads);
int64 BlockCount=0;
int64 TotalRead=0;
while (true)
{
size_t SizeToRead;
@@ -532,69 +391,111 @@ uint CalcFileCRC(File *SrcFile,int64 Size,CALCCRC_SHOWMODE ShowMode)
int ReadSize=SrcFile->Read(&Data[0],SizeToRead);
if (ReadSize==0)
break;
TotalRead+=ReadSize;
++BlockCount;
if ((BlockCount & 15)==0)
if ((++BlockCount & 0xf)==0)
{
#if !defined(SILENT) && !defined(_WIN_CE)
if (ShowMode==CALCCRC_SHOWALL)
mprintf("\b\b\b\b%3d%%",ToPercent(BlockCount*int64(BufSize),FileLength));
#ifndef SILENT
if ((Flags & CALCFSUM_SHOWPROGRESS)!=0)
uiExtractProgress(TotalRead,FileLength,TotalRead,FileLength);
else
{
if ((Flags & CALCFSUM_SHOWPERCENT)!=0)
uiMsg(UIEVENT_FILESUMPROGRESS,ToPercent(TotalRead,FileLength));
}
#endif
Wait();
}
DataCRC=CRC(DataCRC,&Data[0],ReadSize);
if (CRC32!=NULL)
HashCRC.Update(&Data[0],ReadSize);
if (Blake2!=NULL)
HashBlake2.Update(&Data[0],ReadSize);
if (Size!=INT64NDF)
Size-=ReadSize;
}
#if !defined(SILENT) && !defined(_WIN_CE)
if (ShowMode==CALCCRC_SHOWALL)
mprintf("\b\b\b\b ");
#endif
return(DataCRC^0xffffffff);
if ((Flags & CALCFSUM_SHOWPERCENT)!=0)
uiMsg(UIEVENT_FILESUMEND);
if (CRC32!=NULL)
*CRC32=HashCRC.GetCRC32();
if (Blake2!=NULL)
{
HashValue Result;
HashBlake2.Result(&Result);
memcpy(Blake2,Result.Digest,sizeof(Result.Digest));
}
}
#endif
bool RenameFile(const char *SrcName,const wchar *SrcNameW,const char *DestName,const wchar *DestNameW)
bool RenameFile(const wchar *SrcName,const wchar *DestName)
{
return(rename(SrcName,DestName)==0);
#ifdef _WIN_ALL
bool Success=MoveFile(SrcName,DestName)!=0;
if (!Success)
{
wchar LongName1[NM],LongName2[NM];
if (GetWinLongPath(SrcName,LongName1,ASIZE(LongName1)) &&
GetWinLongPath(DestName,LongName2,ASIZE(LongName2)))
Success=MoveFile(LongName1,LongName2)!=0;
}
return Success;
#else
char SrcNameA[NM],DestNameA[NM];
WideToChar(SrcName,SrcNameA,ASIZE(SrcNameA));
WideToChar(DestName,DestNameA,ASIZE(DestNameA));
bool Success=rename(SrcNameA,DestNameA)==0;
return Success;
#endif
}
bool DelFile(const char *Name)
bool DelFile(const wchar *Name)
{
return(DelFile(Name,NULL));
#ifdef _WIN_ALL
bool Success=DeleteFile(Name)!=0;
if (!Success)
{
wchar LongName[NM];
if (GetWinLongPath(Name,LongName,ASIZE(LongName)))
Success=DeleteFile(LongName)!=0;
}
return Success;
#else
char NameA[NM];
WideToChar(Name,NameA,ASIZE(NameA));
bool Success=remove(NameA)==0;
return Success;
#endif
}
bool DelFile(const char *Name,const wchar *NameW)
#if defined(_WIN_ALL) && !defined(SFX_MODULE)
bool SetFileCompression(const wchar *Name,bool State)
{
return(Name!=NULL && remove(Name)==0);
}
#if defined(_WIN_ALL) && !defined(_WIN_CE) && !defined(SFX_MODULE)
bool SetFileCompression(char *Name,wchar *NameW,bool State)
{
wchar FileNameW[NM];
GetWideName(Name,NameW,FileNameW,ASIZE(FileNameW));
HANDLE hFile=CreateFileW(FileNameW,FILE_READ_DATA|FILE_WRITE_DATA,
HANDLE hFile=CreateFile(Name,FILE_READ_DATA|FILE_WRITE_DATA,
FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_SEQUENTIAL_SCAN,NULL);
if (hFile==INVALID_HANDLE_VALUE)
return(false);
{
wchar LongName[NM];
if (GetWinLongPath(Name,LongName,ASIZE(LongName)))
hFile=CreateFile(LongName,FILE_READ_DATA|FILE_WRITE_DATA,
FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_SEQUENTIAL_SCAN,NULL);
}
if (hFile==INVALID_HANDLE_VALUE)
return false;
SHORT NewState=State ? COMPRESSION_FORMAT_DEFAULT:COMPRESSION_FORMAT_NONE;
DWORD Result;
int RetCode=DeviceIoControl(hFile,FSCTL_SET_COMPRESSION,&NewState,
sizeof(NewState),NULL,0,&Result,NULL);
CloseHandle(hFile);
return(RetCode!=0);
return RetCode!=0;
}
#endif
@@ -605,3 +506,4 @@ bool SetFileCompression(char *Name,wchar *NameW,bool State)

View File

@@ -3,48 +3,48 @@
enum MKDIR_CODE {MKDIR_SUCCESS,MKDIR_ERROR,MKDIR_BADPATH};
MKDIR_CODE MakeDir(const char *Name,const wchar *NameW,bool SetAttr,uint Attr);
bool CreatePath(const char *Path,bool SkipLastName);
MKDIR_CODE MakeDir(const wchar *Name,bool SetAttr,uint Attr);
bool CreatePath(const wchar *Path,bool SkipLastName);
bool CreatePath(const char *Path,const wchar *PathW,bool SkipLastName);
void SetDirTime(const char *Name,const wchar *NameW,RarTime *ftm,RarTime *ftc,RarTime *fta);
bool IsRemovable(const char *Name);
void SetDirTime(const wchar *Name,RarTime *ftm,RarTime *ftc,RarTime *fta);
bool IsRemovable(const wchar *Name);
#ifndef SFX_MODULE
int64 GetFreeDisk(const char *Name);
int64 GetFreeDisk(const wchar *Name);
#endif
#if defined(_WIN_ALL) && !defined(SFX_MODULE) && !defined(SILENT)
bool IsFAT(const wchar *Root);
#endif
bool FileExist(const char *Name,const wchar *NameW=NULL);
bool FileExist(const wchar *Name);
bool WildFileExist(const char *Name,const wchar *NameW=NULL);
bool WildFileExist(const wchar *Name);
bool IsDir(uint Attr);
bool IsUnreadable(uint Attr);
bool IsLabel(uint Attr);
bool IsLink(uint Attr);
void SetSFXMode(const char *FileName);
void EraseDiskContents(const char *FileName);
void SetSFXMode(const wchar *FileName);
void EraseDiskContents(const wchar *FileName);
bool IsDeleteAllowed(uint FileAttr);
void PrepareToDelete(const char *Name,const wchar *NameW=NULL);
uint GetFileAttr(const char *Name,const wchar *NameW=NULL);
bool SetFileAttr(const char *Name,const wchar *NameW,uint Attr);
char* MkTemp(char *Name);
wchar* MkTemp(wchar *Name);
void PrepareToDelete(const wchar *Name);
uint GetFileAttr(const wchar *Name);
bool SetFileAttr(const wchar *Name,uint Attr);
#if 0
wchar* MkTemp(wchar *Name,size_t MaxSize);
#endif
enum CALCCRC_SHOWMODE {CALCCRC_SHOWNONE,CALCCRC_SHOWTEXT,CALCCRC_SHOWALL};
uint CalcFileCRC(File *SrcFile,int64 Size=INT64NDF,CALCCRC_SHOWMODE ShowMode=CALCCRC_SHOWNONE);
enum CALCFSUM_FLAGS {CALCFSUM_SHOWTEXT=1,CALCFSUM_SHOWPERCENT=2,CALCFSUM_SHOWPROGRESS=4,CALCFSUM_CURPOS=8};
bool RenameFile(const char *SrcName,const wchar *SrcNameW,const char *DestName,const wchar *DestNameW);
bool DelFile(const char *Name);
bool DelFile(const char *Name,const wchar *NameW);
bool DelDir(const char *Name);
bool DelDir(const char *Name,const wchar *NameW);
void CalcFileSum(File *SrcFile,uint *CRC32,byte *Blake2,uint Threads,int64 Size=INT64NDF,uint Flags=0);
#if defined(_WIN_ALL) && !defined(_WIN_CE)
bool SetFileCompression(char *Name,wchar *NameW,bool State);
bool RenameFile(const wchar *SrcName,const wchar *DestName);
bool DelFile(const wchar *Name);
bool DelDir(const wchar *Name);
#if defined(_WIN_ALL) && !defined(SFX_MODULE)
bool SetFileCompression(const wchar *Name,bool State);
#endif
#endif

View File

@@ -1,10 +1,7 @@
#include "rar.hpp"
static bool IsUnicode(byte *Data,int Size);
bool ReadTextFile(
const char *Name,
const wchar *NameW,
const wchar *Name,
StringList *List,
bool Config,
bool AbortOnError,
@@ -13,196 +10,153 @@ bool ReadTextFile(
bool SkipComments,
bool ExpandEnvStr)
{
char FileName[NM];
wchar FileName[NM];
*FileName=0;
if (Name!=NULL)
if (Config)
GetConfigName(Name,FileName,true);
GetConfigName(Name,FileName,ASIZE(FileName),true,false);
else
strcpy(FileName,Name);
wchar FileNameW[NM];
*FileNameW=0;
#ifdef _WIN_ALL
if (NameW!=NULL)
if (Config)
GetConfigName(NameW,FileNameW,true);
else
wcscpy(FileNameW,NameW);
#endif
wcsncpyz(FileName,Name,ASIZE(FileName));
File SrcFile;
if (FileName!=NULL && *FileName!=0 || FileNameW!=NULL && *FileNameW!=0)
if (*FileName!=0)
{
bool OpenCode=AbortOnError ? SrcFile.WOpen(FileName,FileNameW):SrcFile.Open(FileName,FileNameW);
bool OpenCode=AbortOnError ? SrcFile.WOpen(FileName):SrcFile.Open(FileName,0);
if (!OpenCode)
{
if (AbortOnError)
ErrHandler.Exit(OPEN_ERROR);
return(false);
ErrHandler.Exit(RARX_OPEN);
return false;
}
}
else
SrcFile.SetHandleType(FILE_HANDLESTD);
unsigned int DataSize=0,ReadSize;
const int ReadBlock=1024;
Array<char> Data(ReadBlock+5);
uint DataSize=0,ReadSize;
const int ReadBlock=4096;
Array<byte> Data(ReadBlock);
while ((ReadSize=SrcFile.Read(&Data[DataSize],ReadBlock))!=0)
{
DataSize+=ReadSize;
Data.Add(ReadSize);
Data.Add(ReadSize); // Always have ReadBlock available for next data.
}
// Set to really read size, so we can zero terminate it correctly.
Data.Alloc(DataSize);
memset(&Data[DataSize],0,5);
int LowEndian=DataSize>=2 && Data[0]==255 && Data[1]==254 ? 1:0;
int BigEndian=DataSize>=2 && Data[0]==254 && Data[1]==255 ? 1:0;
bool Utf8=DataSize>=3 && Data[0]==0xef && Data[1]==0xbb && Data[2]==0xbf;
if (SrcCharset==RCH_UNICODE ||
SrcCharset==RCH_DEFAULT && IsUnicode((byte *)&Data[0],DataSize))
if (SrcCharset==RCH_DEFAULT)
{
// Unicode in native system format, can be more than 2 bytes per character.
Array<wchar> DataW(Data.Size()/2+1);
for (size_t I=2;I<Data.Size()-1;I+=2)
{
// Need to convert Data to (byte) first to prevent the sign extension
// to higher bytes.
DataW[(I-2)/2]=(wchar)((byte)Data[I])+(wchar)((byte)Data[I+1])*256;
}
wchar *CurStr=&DataW[0];
Array<char> AnsiName;
while (*CurStr!=0)
{
wchar *NextStr=CurStr,*CmtPtr=NULL;
while (*NextStr!='\r' && *NextStr!='\n' && *NextStr!=0)
{
if (SkipComments && NextStr[0]=='/' && NextStr[1]=='/')
if (LowEndian || BigEndian)
for (size_t I=2;I<DataSize;I++)
if (Data[I]<32 && Data[I]!='\r' && Data[I]!='\n')
{
*NextStr=0;
CmtPtr=NextStr;
}
NextStr++;
}
*NextStr=0;
for (wchar *SpacePtr=(CmtPtr ? CmtPtr:NextStr)-1;SpacePtr>=CurStr;SpacePtr--)
{
if (*SpacePtr!=' ' && *SpacePtr!='\t')
SrcCharset=RCH_UNICODE; // High byte in UTF-16 char is found.
break;
*SpacePtr=0;
}
if (*CurStr)
{
// Length and AddSize must be defined as signed, because AddSize
// can be negative.
int Length=(int)wcslen(CurStr);
int AddSize=4*(Length-(int)AnsiName.Size()+1);
if (AddSize>0)
AnsiName.Add(AddSize);
if (Unquote && *CurStr=='\"' && CurStr[Length-1]=='\"')
{
CurStr[Length-1]=0;
CurStr++;
}
WideToChar(CurStr,&AnsiName[0],AnsiName.Size());
bool Expanded=false;
#if defined(_WIN_ALL) && !defined(_WIN_CE)
if (ExpandEnvStr && *CurStr=='%')
{
// Expanding environment variables in Windows version.
char ExpName[NM];
wchar ExpNameW[NM];
*ExpNameW=0;
int ret,retw=1;
ret=ExpandEnvironmentStringsA(&AnsiName[0],ExpName,ASIZE(ExpName));
if (ret!=0 && WinNT())
retw=ExpandEnvironmentStringsW(CurStr,ExpNameW,ASIZE(ExpNameW));
Expanded=ret!=0 && ret<ASIZE(ExpName) &&
retw!=0 && retw<ASIZE(ExpNameW);
if (Expanded)
List->AddString(ExpName,ExpNameW);
}
#endif
if (!Expanded)
List->AddString(&AnsiName[0],CurStr);
}
CurStr=NextStr+1;
while (*CurStr=='\r' || *CurStr=='\n')
CurStr++;
if (Utf8)
{
Data.Push(0); // Need a zero terminated string for UtfToWide.
if (IsTextUtf8((const char *)(Data+3)))
SrcCharset=RCH_UTF8;
}
}
else
Array<wchar> DataW;
if (SrcCharset==RCH_DEFAULT || SrcCharset==RCH_OEM || SrcCharset==RCH_ANSI)
{
char *CurStr=&Data[0];
while (*CurStr!=0)
{
char *NextStr=CurStr,*CmtPtr=NULL;
while (*NextStr!='\r' && *NextStr!='\n' && *NextStr!=0)
{
if (SkipComments && NextStr[0]=='/' && NextStr[1]=='/')
{
*NextStr=0;
CmtPtr=NextStr;
}
NextStr++;
}
*NextStr=0;
for (char *SpacePtr=(CmtPtr ? CmtPtr:NextStr)-1;SpacePtr>=CurStr;SpacePtr--)
{
if (*SpacePtr!=' ' && *SpacePtr!='\t')
break;
*SpacePtr=0;
}
if (*CurStr)
{
if (Unquote && *CurStr=='\"')
{
size_t Length=strlen(CurStr);
if (CurStr[Length-1]=='\"')
{
CurStr[Length-1]=0;
CurStr++;
}
}
Data.Push(0); // Zero terminate.
#if defined(_WIN_ALL)
if (SrcCharset==RCH_OEM)
OemToCharA(CurStr,CurStr);
if (SrcCharset==RCH_OEM)
OemToCharA((char *)&Data[0],(char *)&Data[0]);
#endif
bool Expanded=false;
#if defined(_WIN_ALL) && !defined(_WIN_CE)
if (ExpandEnvStr && *CurStr=='%')
{
// Expanding environment variables in Windows version.
char ExpName[NM];
int ret=ExpandEnvironmentStringsA(CurStr,ExpName,ASIZE(ExpName));
Expanded=ret!=0 && ret<ASIZE(ExpName);
if (Expanded)
List->AddString(ExpName);
}
#endif
if (!Expanded)
List->AddString(CurStr);
}
CurStr=NextStr+1;
while (*CurStr=='\r' || *CurStr=='\n')
CurStr++;
}
DataW.Alloc(Data.Size());
CharToWide((char *)&Data[0],&DataW[0],DataW.Size());
}
return(true);
}
if (SrcCharset==RCH_UNICODE)
{
size_t Start=2; // Skip byte order mark.
if (!LowEndian && !BigEndian) // No byte order mask.
{
Start=0;
LowEndian=1;
}
DataW.Alloc(Data.Size()/2+1);
size_t End=Data.Size() & ~1; // We need even bytes number for UTF-16.
for (size_t I=Start;I<End;I+=2)
DataW[(I-Start)/2]=Data[I+BigEndian]+Data[I+LowEndian]*256;
DataW[(End-Start)/2]=0;
}
bool IsUnicode(byte *Data,int Size)
{
if (Size<4 || Data[0]!=0xff || Data[1]!=0xfe)
return(false);
for (int I=2;I<Size;I++)
if (Data[I]<32 && Data[I]!='\r' && Data[I]!='\n')
return(true);
return(false);
if (SrcCharset==RCH_UTF8)
{
Data.Push(0); // Zero terminate data.
DataW.Alloc(Data.Size());
UtfToWide((const char *)(Data+(Utf8 ? 3:0)),&DataW[0],DataW.Size());
}
wchar *CurStr=&DataW[0];
while (*CurStr!=0)
{
wchar *NextStr=CurStr,*CmtPtr=NULL;
while (*NextStr!='\r' && *NextStr!='\n' && *NextStr!=0)
{
if (SkipComments && NextStr[0]=='/' && NextStr[1]=='/')
{
*NextStr=0;
CmtPtr=NextStr;
}
NextStr++;
}
bool Done=*NextStr==0;
*NextStr=0;
for (wchar *SpacePtr=(CmtPtr!=NULL ? CmtPtr:NextStr)-1;SpacePtr>=CurStr;SpacePtr--)
{
if (*SpacePtr!=' ' && *SpacePtr!='\t')
break;
*SpacePtr=0;
}
if (Unquote && *CurStr=='\"')
{
size_t Length=wcslen(CurStr);
if (CurStr[Length-1]=='\"')
{
CurStr[Length-1]=0;
CurStr++;
}
}
bool Expanded=false;
#if defined(_WIN_ALL)
if (ExpandEnvStr && *CurStr=='%') // Expand environment variables in Windows.
{
wchar ExpName[NM];
*ExpName=0;
DWORD Result=ExpandEnvironmentStrings(CurStr,ExpName,ASIZE(ExpName));
Expanded=Result!=0 && Result<ASIZE(ExpName);
if (Expanded && *ExpName!=0)
List->AddString(ExpName);
}
#endif
if (!Expanded && *CurStr!=0)
List->AddString(CurStr);
if (Done)
break;
CurStr=NextStr+1;
while (*CurStr=='\r' || *CurStr=='\n')
CurStr++;
}
return true;
}

View File

@@ -2,8 +2,7 @@
#define _RAR_FILESTR_
bool ReadTextFile(
const char *Name,
const wchar *NameW,
const wchar *Name,
StringList *List,
bool Config,
bool AbortOnError=false,

View File

@@ -3,7 +3,6 @@
FindFile::FindFile()
{
*FindMask=0;
*FindMaskW=0;
FirstCall=true;
#ifdef _WIN_ALL
hFind=INVALID_HANDLE_VALUE;
@@ -25,267 +24,195 @@ FindFile::~FindFile()
}
void FindFile::SetMask(const char *FindMask)
void FindFile::SetMask(const wchar *Mask)
{
strcpy(FindFile::FindMask,NullToEmpty(FindMask));
if (*FindMaskW==0)
CharToWide(FindMask,FindMaskW);
wcscpy(FindMask,Mask);
FirstCall=true;
}
void FindFile::SetMaskW(const wchar *FindMaskW)
{
if (FindMaskW==NULL)
return;
wcscpy(FindFile::FindMaskW,FindMaskW);
if (*FindMask==0)
WideToChar(FindMaskW,FindMask);
FirstCall=true;
}
bool FindFile::Next(struct FindData *fd,bool GetSymLink)
bool FindFile::Next(FindData *fd,bool GetSymLink)
{
fd->Error=false;
if (*FindMask==0)
return(false);
return false;
#ifdef _WIN_ALL
if (FirstCall)
{
if ((hFind=Win32Find(INVALID_HANDLE_VALUE,FindMask,FindMaskW,fd))==INVALID_HANDLE_VALUE)
return(false);
if ((hFind=Win32Find(INVALID_HANDLE_VALUE,FindMask,fd))==INVALID_HANDLE_VALUE)
return false;
}
else
if (Win32Find(hFind,FindMask,FindMaskW,fd)==INVALID_HANDLE_VALUE)
return(false);
if (Win32Find(hFind,FindMask,fd)==INVALID_HANDLE_VALUE)
return false;
#else
if (FirstCall)
{
char DirName[NM];
strcpy(DirName,FindMask);
wchar DirName[NM];
wcsncpyz(DirName,FindMask,ASIZE(DirName));
RemoveNameFromPath(DirName);
if (*DirName==0)
strcpy(DirName,".");
if ((dirp=opendir(DirName))==NULL)
wcscpy(DirName,L".");
char DirNameA[NM];
WideToChar(DirName,DirNameA,ASIZE(DirNameA));
if ((dirp=opendir(DirNameA))==NULL)
{
fd->Error=(errno!=ENOENT);
return(false);
return false;
}
}
while (1)
{
struct dirent *ent=readdir(dirp);
if (ent==NULL)
return(false);
return false;
if (strcmp(ent->d_name,".")==0 || strcmp(ent->d_name,"..")==0)
continue;
if (CmpName(FindMask,ent->d_name,MATCH_NAMES))
wchar Name[NM];
if (!CharToWide(ent->d_name,Name,ASIZE(Name)))
uiMsg(UIERROR_INVALIDNAME,UINULL,Name);
if (CmpName(FindMask,Name,MATCH_NAMES))
{
char FullName[NM];
strcpy(FullName,FindMask);
wchar FullName[NM];
wcscpy(FullName,FindMask);
*PointToName(FullName)=0;
if (strlen(FullName)+strlen(ent->d_name)>=ASIZE(FullName)-1)
if (wcslen(FullName)+wcslen(Name)>=ASIZE(FullName)-1)
{
#ifndef SILENT
Log(NULL,"\n%s%s",FullName,ent->d_name);
Log(NULL,St(MPathTooLong));
#endif
return(false);
uiMsg(UIERROR_PATHTOOLONG,FullName,L"",Name);
return false;
}
strcat(FullName,ent->d_name);
if (!FastFind(FullName,NULL,fd,GetSymLink))
wcscat(FullName,Name);
if (!FastFind(FullName,fd,GetSymLink))
{
ErrHandler.OpenErrorMsg(FullName);
continue;
}
strcpy(fd->Name,FullName);
wcscpy(fd->Name,FullName);
break;
}
}
*fd->NameW=0;
#ifdef _APPLE
if (!LowAscii(fd->Name))
UtfToWide(fd->Name,fd->NameW,sizeof(fd->NameW));
#elif defined(UNICODE_SUPPORTED)
if (!LowAscii(fd->Name) && UnicodeEnabled())
CharToWide(fd->Name,fd->NameW);
#endif
#endif
fd->Flags=0;
fd->IsDir=IsDir(fd->FileAttr);
fd->IsLink=IsLink(fd->FileAttr);
FirstCall=false;
char *Name=PointToName(fd->Name);
if (strcmp(Name,".")==0 || strcmp(Name,"..")==0)
return(Next(fd));
return(true);
wchar *NameOnly=PointToName(fd->Name);
if (wcscmp(NameOnly,L".")==0 || wcscmp(NameOnly,L"..")==0)
return Next(fd);
return true;
}
bool FindFile::FastFind(const char *FindMask,const wchar *FindMaskW,FindData *fd,bool GetSymLink)
bool FindFile::FastFind(const wchar *FindMask,FindData *fd,bool GetSymLink)
{
fd->Error=false;
#ifndef _UNIX
if (IsWildcard(FindMask,FindMaskW))
return(false);
if (IsWildcard(FindMask))
return false;
#endif
#ifdef _WIN_ALL
HANDLE hFind=Win32Find(INVALID_HANDLE_VALUE,FindMask,FindMaskW,fd);
HANDLE hFind=Win32Find(INVALID_HANDLE_VALUE,FindMask,fd);
if (hFind==INVALID_HANDLE_VALUE)
return(false);
return false;
FindClose(hFind);
#else
char FindMaskA[NM];
WideToChar(FindMask,FindMaskA,ASIZE(FindMaskA));
struct stat st;
if (GetSymLink)
{
#ifdef SAVE_LINKS
if (lstat(FindMask,&st)!=0)
if (lstat(FindMaskA,&st)!=0)
#else
if (stat(FindMask,&st)!=0)
if (stat(FindMaskA,&st)!=0)
#endif
{
fd->Error=(errno!=ENOENT);
return(false);
return false;
}
}
else
if (stat(FindMask,&st)!=0)
if (stat(FindMaskA,&st)!=0)
{
fd->Error=(errno!=ENOENT);
return(false);
return false;
}
#ifdef _DJGPP
fd->FileAttr=_chmod(FindMask,0);
#elif defined(_EMX)
fd->FileAttr=st.st_attr;
#else
fd->FileAttr=st.st_mode;
#endif
fd->IsDir=IsDir(st.st_mode);
fd->Size=st.st_size;
fd->mtime=st.st_mtime;
fd->atime=st.st_atime;
fd->ctime=st.st_ctime;
fd->FileTime=fd->mtime.GetDos();
strcpy(fd->Name,FindMask);
*fd->NameW=0;
#ifdef _APPLE
if (!LowAscii(fd->Name))
UtfToWide(fd->Name,fd->NameW,sizeof(fd->NameW));
#elif defined(UNICODE_SUPPORTED)
if (!LowAscii(fd->Name) && UnicodeEnabled())
CharToWide(fd->Name,fd->NameW);
#ifdef UNIX_TIME_NS
fd->mtime.SetUnixNS(st.st_mtim.tv_sec*(uint64)1000000000+st.st_mtim.tv_nsec);
fd->atime.SetUnixNS(st.st_atim.tv_sec*(uint64)1000000000+st.st_atim.tv_nsec);
fd->ctime.SetUnixNS(st.st_ctim.tv_sec*(uint64)1000000000+st.st_ctim.tv_nsec);
#else
fd->mtime.SetUnix(st.st_mtime);
fd->atime.SetUnix(st.st_atime);
fd->ctime.SetUnix(st.st_ctime);
#endif
wcsncpyz(fd->Name,FindMask,ASIZE(fd->Name));
#endif
fd->Flags=0;
fd->IsDir=IsDir(fd->FileAttr);
return(true);
fd->IsLink=IsLink(fd->FileAttr);
return true;
}
#ifdef _WIN_ALL
HANDLE FindFile::Win32Find(HANDLE hFind,const char *Mask,const wchar *MaskW,FindData *fd)
HANDLE FindFile::Win32Find(HANDLE hFind,const wchar *Mask,FindData *fd)
{
#ifndef _WIN_CE
if (WinNT())
#endif
WIN32_FIND_DATA FindData;
if (hFind==INVALID_HANDLE_VALUE)
{
wchar WideMask[NM];
if (MaskW!=NULL && *MaskW!=0)
wcscpy(WideMask,MaskW);
else
CharToWide(Mask,WideMask);
WIN32_FIND_DATAW FindData;
hFind=FindFirstFile(Mask,&FindData);
if (hFind==INVALID_HANDLE_VALUE)
{
hFind=FindFirstFileW(WideMask,&FindData);
if (hFind==INVALID_HANDLE_VALUE)
{
int SysErr=GetLastError();
fd->Error=(SysErr!=ERROR_FILE_NOT_FOUND &&
SysErr!=ERROR_PATH_NOT_FOUND &&
SysErr!=ERROR_NO_MORE_FILES);
}
wchar LongMask[NM];
if (GetWinLongPath(Mask,LongMask,ASIZE(LongMask)))
hFind=FindFirstFile(LongMask,&FindData);
}
else
if (!FindNextFileW(hFind,&FindData))
{
hFind=INVALID_HANDLE_VALUE;
fd->Error=GetLastError()!=ERROR_NO_MORE_FILES;
}
if (hFind!=INVALID_HANDLE_VALUE)
if (hFind==INVALID_HANDLE_VALUE)
{
wcscpy(fd->NameW,WideMask);
wcscpy(PointToName(fd->NameW),FindData.cFileName);
WideToChar(fd->NameW,fd->Name);
fd->Size=INT32TO64(FindData.nFileSizeHigh,FindData.nFileSizeLow);
fd->FileAttr=FindData.dwFileAttributes;
wcscpy(fd->ShortName,FindData.cAlternateFileName);
fd->ftCreationTime=FindData.ftCreationTime;
fd->ftLastAccessTime=FindData.ftLastAccessTime;
fd->ftLastWriteTime=FindData.ftLastWriteTime;
fd->mtime=FindData.ftLastWriteTime;
fd->ctime=FindData.ftCreationTime;
fd->atime=FindData.ftLastAccessTime;
fd->FileTime=fd->mtime.GetDos();
#ifndef _WIN_CE
// if (LowAscii(fd->NameW))
// *fd->NameW=0;
#endif
int SysErr=GetLastError();
// We must not issue an error for "file not found" and "path not found",
// because it is normal to not find anything for wildcard mask when
// archiving. Also searching for non-existent file is normal in some
// other modules, like WinRAR scanning for winrar_theme_description.txt
// to check if any themes are available.
fd->Error=SysErr!=ERROR_FILE_NOT_FOUND &&
SysErr!=ERROR_PATH_NOT_FOUND &&
SysErr!=ERROR_NO_MORE_FILES;
}
}
#ifndef _WIN_CE
else
if (!FindNextFile(hFind,&FindData))
{
hFind=INVALID_HANDLE_VALUE;
fd->Error=GetLastError()!=ERROR_NO_MORE_FILES;
}
if (hFind!=INVALID_HANDLE_VALUE)
{
char CharMask[NM];
if (Mask!=NULL && *Mask!=0)
strcpy(CharMask,Mask);
else
WideToChar(MaskW,CharMask);
wcsncpyz(fd->Name,Mask,ASIZE(fd->Name));
SetName(fd->Name,FindData.cFileName,ASIZE(fd->Name));
fd->Size=INT32TO64(FindData.nFileSizeHigh,FindData.nFileSizeLow);
fd->FileAttr=FindData.dwFileAttributes;
fd->ftCreationTime=FindData.ftCreationTime;
fd->ftLastAccessTime=FindData.ftLastAccessTime;
fd->ftLastWriteTime=FindData.ftLastWriteTime;
fd->mtime.SetWinFT(&FindData.ftLastWriteTime);
fd->ctime.SetWinFT(&FindData.ftCreationTime);
fd->atime.SetWinFT(&FindData.ftLastAccessTime);
WIN32_FIND_DATAA FindData;
if (hFind==INVALID_HANDLE_VALUE)
{
hFind=FindFirstFileA(CharMask,&FindData);
if (hFind==INVALID_HANDLE_VALUE)
{
int SysErr=GetLastError();
fd->Error=SysErr!=ERROR_FILE_NOT_FOUND && SysErr!=ERROR_PATH_NOT_FOUND;
}
}
else
if (!FindNextFileA(hFind,&FindData))
{
hFind=INVALID_HANDLE_VALUE;
fd->Error=GetLastError()!=ERROR_NO_MORE_FILES;
}
if (hFind!=INVALID_HANDLE_VALUE)
{
strcpy(fd->Name,CharMask);
strcpy(PointToName(fd->Name),FindData.cFileName);
CharToWide(fd->Name,fd->NameW);
fd->Size=INT32TO64(FindData.nFileSizeHigh,FindData.nFileSizeLow);
fd->FileAttr=FindData.dwFileAttributes;
CharToWide(FindData.cAlternateFileName,fd->ShortName);
fd->ftCreationTime=FindData.ftCreationTime;
fd->ftLastAccessTime=FindData.ftLastAccessTime;
fd->ftLastWriteTime=FindData.ftLastWriteTime;
fd->mtime=FindData.ftLastWriteTime;
fd->ctime=FindData.ftCreationTime;
fd->atime=FindData.ftLastAccessTime;
fd->FileTime=fd->mtime.GetDos();
// if (LowAscii(fd->Name))
// *fd->NameW=0;
}
}
#endif
fd->Flags=0;
return(hFind);
return hFind;
}
#endif

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