126 Commits

Author SHA1 Message Date
Gustavo Lopes
b4d66343e7 Do not build linux binaries on release 2026-03-09 10:59:06 +00:00
Gustavo Lopes
2ef087bd9e Version validation in CI 2026-03-09 10:34:59 +00:00
Gustavo Lopes
d9bc8cd4c5 Merge pull request #26 from remicollet/patch-1
Fix version
2026-03-09 09:59:38 +00:00
Remi Collet
60eaceb6ee Fix version 2026-03-09 07:21:40 +01:00
Gustavo Lopes
b6d9dc8eae Update README.md 2026-03-09 00:26:34 +00:00
Gustavo Lopes
d58737756c Fix release build on 32-bit windows 2026-03-09 00:19:32 +00:00
Gustavo Lopes
b79e6491b5 Prepare 4.3.0 release 2026-03-08 23:54:43 +00:00
Gustavo Lopes
1f1baf4fc1 Fix for 32-bit windows 2026-03-08 23:54:43 +00:00
Gustavo Lopes
4e914be013 .gitignore 2026-03-08 23:07:15 +00:00
Gustavo Lopes
05c8e5e675 Fix warning 2026-03-08 23:07:05 +00:00
Gustavo Lopes
b482f2f156 Add largepage.cpp and motw.cpp to Windows build config
These files implement LargePageAlloc and MarkOfTheWeb classes
respectively, which were causing 13 unresolved external symbols
during the Windows DLL link step.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-08 21:51:37 +00:00
Gustavo Lopes
4115c69fe2 Fix wrong printf format 2026-03-08 21:48:55 +00:00
Gustavo Lopes
ea74acb27b Remove NM definition. Size of P1 in actually MAXPATHSIZE 2026-03-08 21:48:41 +00:00
Gustavo Lopes
1b6a2a5aa4 Fix windows build 2026-03-08 21:15:48 +00:00
Gustavo Lopes
e5b9669359 Add but don't apply .clang-format 2026-03-08 21:12:54 +00:00
Gustavo Lopes
89ac57cd59 Fix dll.cpp: don't propagate non-fatal ErrHandler errors as failures
unrar 7.2.4 changed RARReadHeaderEx and ProcessFile to return
RarErrorToDll(ErrHandler.GetErrorCode()) on the success path instead of
ERAR_SUCCESS. This caused RARX_CRC errors set during header CRC
validation (which still allows the header to be read successfully) to
propagate as ERAR_BAD_DATA, breaking the entry listing loop for archives
with broken header checksums even when allow_broken is set.

Non-fatal error codes RARX_SUCCESS, RARX_WARNING, and RARX_CRC should
not cause RARReadHeaderEx or ProcessFile to return failure on the success
path; callers detect data integrity issues via BrokenHeader or the list
result separately.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-08 16:25:08 +00:00
Gustavo Lopes
440d2a14c8 Merge unrar 7.2.4 2026-03-08 15:55:36 +00:00
Gustavo Lopes
a169ed937e Fix build: add largepage.cpp, exclude motw.cpp (Windows-only) for unrar 7.1
unrar 7.1 added largepage.cpp and motw.cpp. Add largepage.cpp to the
build (its LargePageAlloc class is declared without platform guards and
compiled cleanly on Linux with the Windows-only code guarded out).

Exclude motw.cpp because MarkOfTheWeb is only declared when PROPAGATE_MOTW
is set (Windows-only), so motw.cpp cannot compile on Linux.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-08 15:55:01 +00:00
Gustavo Lopes
10e3e3222a Merge unrar 7.1.5 2026-03-08 15:52:13 +00:00
Gustavo Lopes
055906e455 Fix rarentry.c: zero-initialize RARHeaderDataEx to prevent segfault
The RARHeaderDataEx struct gained ArcNameEx and FileNameEx pointer fields
in unrar 7.0. In rarentry.c the struct was declared on the stack without
initialization, leaving these pointers with garbage values. RARReadHeaderEx
checks if these pointers are non-NULL before writing through them, so it
would follow the garbage pointer and cause a segfault (reproducible in
test 004.phpt).

Fix by zero-initializing the struct at declaration.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-08 15:51:10 +00:00
Gustavo Lopes
2d3b968d23 Update extractchunk.cpp for unrar 7.0 std::wstring API changes
unrar 7.0 converted all path/name variables from wchar arrays to
std::wstring. Update extractchunk.cpp to use the new API:
- ArcName, DestFileName, DllDestName are now std::wstring
- VolNameToFirstName and ConvertPath have new signatures

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-08 15:44:13 +00:00
Gustavo Lopes
371536d3a8 Fix arccmt.cpp: remove extra brace introduced during 6.2.9 conflict resolution
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-08 15:43:06 +00:00
Gustavo Lopes
3f536c9f9d Fix os.hpp: restore NM define removed in unrar 7.0
unrar 7.0 removed the NM path-size define from os.hpp, but the PHP
extension code in rar.c still uses it. Add NM back as a compatibility
define with the same value (2048).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-08 15:42:32 +00:00
Gustavo Lopes
ff2aa63dbf Merge unrar 7.0.9 2026-03-08 15:42:00 +00:00
Gustavo Lopes
0cace1db4b Fix extract.cpp: fix brace mismatch in password check block after 6.2.9 merge
The conflict resolution accidentally closed the while(true) password loop
prematurely. Fix the brace structure so our custom empty-password check
sits inside the loop before the SetEncryption/PswCheck code.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-08 15:37:38 +00:00
Gustavo Lopes
0c05fac324 Merge unrar 6.2.9 2026-03-08 15:36:33 +00:00
Gustavo Lopes
ae9a4623fe Fix isnt.cpp: wrap Windows-only code in #ifdef _WIN_ALL
isnt.cpp was added in unrar 6.1.5 without platform guards, causing
compilation failure on Linux due to Windows-only headers (comdef.h,
Wbemidl.h). Wrap entire implementation in #ifdef _WIN_ALL to match
the original pattern and rar.hpp include guard.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-08 15:32:39 +00:00
Gustavo Lopes
88773b47f1 Merge unrar 6.1.5 2026-03-08 15:31:20 +00:00
Gustavo Lopes
5e74ad9803 Update unrar_update.md 2026-03-08 15:21:45 +00:00
Gustavo Lopes
f6650b4abe Remove PHP 5 support 2026-03-08 15:11:27 +00:00
Gustavo Lopes
be202cc5b1 Add PHP 8.3 CI support; fix type-error wording in tests
Wire up PHP 8.3 Linux matrix jobs and Justfile targets. Fix three EXPECTF
patterns in tests/002, 003, 008: PHP 8.3 changed the type-error message
wording from "bool given" to "false given", so widen "boo%s" to "%s" to
match both old and new phrasing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-08 15:11:16 +00:00
Gustavo Lopes
6a2ec1ccfc Add PHP 8.2 CI support; fix __toString arginfo
Wire up PHP 8.2 Linux matrix jobs and Justfile targets. Update Windows CI
to PHP 8.2. Fix the __toString() methods on RarArchive and RarEntry to
declare IS_STRING return type under PHP_VERSION_ID >= 80200 — PHP 8.2
enforces that __toString() has a declared string return type and emits
warnings (breaking tests) without it.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-08 15:10:36 +00:00
Gustavo Lopes
eb1a919fb9 Document php upgrade procedure.
Both debug and release-zts variants pass 109/109 tests under PHP 8.1.
2026-03-08 15:09:46 +00:00
Gustavo Lopes
5e063a9626 Add PHP 8.1 CI support
Wire up PHP 8.1 Linux matrix jobs (debug + release-zts) via Docker image
SHA entries and Justfile targets. Update Windows CI job from PHP 8.0 to 8.1.
No C source changes required for 8.1 compatibility.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-02 01:14:35 +00:00
Gustavo Lopes
4a4e67ec33 Moderninze run-tests.php; use it on windows CI too 2026-03-02 01:14:35 +00:00
Gustavo Lopes
3dcba946ab Migrate CI from Azure Pipelines/Appveyor to GitHub Actions
Replace the old Azure Pipelines + Appveyor setup with GitHub Actions:
- Add .github/workflows/tests.yml with Linux (matrix) and Windows jobs
- Add .github/scripts/build-and-test.sh (shared build+test script)
- Add .github/scripts/update-docker-shas.sh (Docker image SHA lockfile updater)
- Add .github/docker-image-shas.yml (pinned OCI index digests for Linux jobs)
- Add Justfile for local test targets mirroring CI
- Add unrar_update.md documenting the unrar update process
- Remove azure-pipelines.yml, azure-template.yml, appveyor.yml, appveyor.bat,
  test_funcs.sh
2026-03-01 18:14:32 +00:00
Gustavo Lopes
77cc02a1db Fix RAR5 chunk extraction spurious warning on Windows with multi-core CPUs
On Windows, RAR_SMP is defined and Unpack5MT is used when MaxUserThreads > 1
(i.e. on any multi-core machine). Unlike Unpack5, Unpack5MT does not set
FileExtracted = true on completion, leaving it false after SetDestSize() clears
it. In chunk extraction mode (suspendAfterInit = true), this caused
RARProcessFileChunk to return *finished = false even after writing all data,
triggering a second unnecessary call that wrote 0 bytes and fired the spurious
"Extraction reported as unfinished but no data read" warning.

Fix by skipping Unpack5MT when suspendAfterInit is true, falling through to
Unpack5 which correctly implements the suspend/resume protocol. The existing
comment in DoUnpack already noted that Unpack5MT must not be used in suspended
mode; the condition just wasn't enforced.

Remove the now-stale Appveyor skip from test 101.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-01 17:33:13 +00:00
Gustavo Lopes
0131eef66c Use zend_long in lieu of long where appropriate 2026-03-01 17:33:13 +00:00
Gustavo Lopes
823315f6d6 Added unrar 7.2.4 2026-02-28 01:18:16 +00:00
Gustavo Lopes
40a7872954 Added unrar 7.2.3 2026-02-28 01:18:16 +00:00
Gustavo Lopes
9babd4f983 Added unrar 7.2.2 2026-02-28 01:18:15 +00:00
Gustavo Lopes
366007b41a Added unrar 7.2.1 2026-02-28 01:18:14 +00:00
Gustavo Lopes
320f84b6ae Added unrar 7.1.5 2026-02-28 01:18:14 +00:00
Gustavo Lopes
899eb2cedd Added unrar 7.1.4 2026-02-28 01:18:13 +00:00
Gustavo Lopes
d21e05b1f7 Added unrar 7.1.3 2026-02-28 01:18:12 +00:00
Gustavo Lopes
1c76380291 Added unrar 7.1.2 2026-02-28 01:18:12 +00:00
Gustavo Lopes
55a566364a Added unrar 7.1.1 2026-02-28 01:18:11 +00:00
Gustavo Lopes
5823bb16b5 Added unrar 7.0.9 2026-02-28 01:18:11 +00:00
Gustavo Lopes
9a5d712d99 Added unrar 7.0.8 2026-02-28 01:18:10 +00:00
Gustavo Lopes
95fe328cc2 Added unrar 7.0.7 2026-02-28 01:18:09 +00:00
Gustavo Lopes
0a08604b53 Added unrar 7.0.6 2026-02-28 01:18:09 +00:00
Gustavo Lopes
9f17788011 Added unrar 7.0.5 2026-02-28 01:18:08 +00:00
Gustavo Lopes
a657432560 Added unrar 7.0.4 2026-02-28 01:18:08 +00:00
Gustavo Lopes
abb9fa4632 Added unrar 7.0.3 2026-02-28 01:18:07 +00:00
Gustavo Lopes
b810988366 Added unrar 7.0.2 2026-02-28 01:18:07 +00:00
Gustavo Lopes
294d87a695 Added unrar 7.0.1 2026-02-28 01:18:06 +00:00
Gustavo Lopes
f57721dbb3 Added unrar 6.2.9 2026-02-28 01:18:05 +00:00
Gustavo Lopes
094a536987 Added unrar 6.2.8 2026-02-28 01:18:05 +00:00
Gustavo Lopes
340695bebb Added unrar 6.2.7 2026-02-28 01:18:04 +00:00
Gustavo Lopes
e63362d16a Added unrar 6.2.6 2026-02-28 01:18:03 +00:00
Gustavo Lopes
cc7d8e8c40 Added unrar 6.2.5 2026-02-28 01:18:03 +00:00
Gustavo Lopes
d2b82835c4 Added unrar 6.2.4 2026-02-28 01:18:02 +00:00
Gustavo Lopes
571deeda60 Added unrar 6.2.3 2026-02-28 01:18:02 +00:00
Gustavo Lopes
412c7bf024 Added unrar 6.2.2 2026-02-28 01:18:01 +00:00
Gustavo Lopes
4594bd1cd1 Added unrar 6.1.5 2026-02-28 01:18:00 +00:00
Gustavo Lopes
3fcd7f12fe Added unrar 6.2.1 2026-02-28 01:18:00 +00:00
Gustavo Lopes
efddae46a9 Added unrar 6.1.4 2026-02-28 01:17:59 +00:00
Gustavo Lopes
63a7b8bbbb Added unrar 6.1.3 2026-02-28 01:17:59 +00:00
Gustavo Lopes
d7a5b2c8f0 Added unrar 6.1.2 2026-02-28 01:17:58 +00:00
Gustavo Lopes
2f979b4b64 Added unrar 6.1.1 2026-02-28 01:17:58 +00:00
Gustavo Lopes
0922854405 Added unrar 6.0.7 2026-02-28 01:16:34 +00:00
Gustavo Lopes
b7ec361367 Added unrar 6.0.6 2026-02-28 01:16:33 +00:00
Gustavo Lopes
1502c092f0 Added unrar 6.0.5 2026-02-28 01:16:33 +00:00
Gustavo Lopes
c00e9c1493 Added unrar 6.0.4 2026-02-28 01:16:32 +00:00
Gustavo Lopes
f367a22fe3 Added unrar 6.0.3 2026-02-28 01:16:31 +00:00
Gustavo Lopes
ab26d28575 Fixes for PHP 8.1 2021-08-16 01:28:05 +01:00
Gustavo Lopes
488dd3caaa Release 4.2.0 2020-12-06 19:57:33 +00:00
Gustavo Lopes
1dc896be94 Merge branch 'unrar', with unrar 6.0.2 2020-12-06 19:46:49 +00:00
Gustavo Lopes
36345d004e Added unrar 6.0.2 2020-12-06 19:45:17 +00:00
Gustavo Lopes
8f070c282f Added unrar 6.0.1 2020-12-06 19:45:04 +00:00
Gustavo Lopes
91ed5b09a0 Publish coverage on codecov 2020-12-06 19:38:25 +00:00
Gustavo Lopes
d95cab037b Support PHP 8 2020-12-06 19:18:01 +00:00
Gustavo Lopes
7cff10aa2c Suppress warnings in PHP header files 2020-12-06 19:18:01 +00:00
Gustavo Lopes
5b94797037 Backport PHP8's run-tests.php 2020-12-06 19:18:01 +00:00
Gustavo Lopes
4ff664b2b0 Merge pull request #9 from Alexander1000/remove-never-used
remove never used piece of code
2020-11-25 14:31:21 +00:00
Aleksandr Dankovtsev
2e13165bdb remove never used piece of code 2020-11-23 22:01:33 +03:00
Gustavo Lopes
d0cd509090 Release 4.1.0 2020-10-11 19:18:11 +01:00
Gustavo Lopes
bd65eab735 Compile with -fvisibility=hidden 2020-10-11 19:01:59 +01:00
Gustavo Lopes
45742b94ab Update to unrar 5.9.4 2020-10-11 18:56:44 +01:00
Gustavo Lopes
6545fdd215 Added unrar 5.9.4 2020-10-11 18:54:32 +01:00
Gustavo Lopes
08f8190e49 Added unrar 5.9.3 2020-10-11 18:54:32 +01:00
Gustavo Lopes
095b4cdd58 Fix PHP 7.4 valgrind tests 2020-10-11 18:38:57 +01:00
Gustavo Lopes
da32228c34 The buffer must be at least as big as the window size 2020-10-11 17:30:15 +01:00
Gustavo Lopes
2788a30227 Warn when we read more data than the file's declared size
Last commit changed how data is read for solid files, but this had a
side effect in that the data returned by the unrar lib was no longer
limited to the size of the file, as declared in its header.

Still keep this new behavior, but add a warning when this happens.
2020-10-11 17:30:15 +01:00
Gustavo Lopes
e0c6c97ef0 Fix bug 76592: streaming unpacking of uncompressed files incomplete 2020-10-11 17:30:15 +01:00
Gustavo Lopes
2322542282 Fixup CI 2020-10-01 09:39:56 +01:00
Gustavo Lopes
2b12de7a8f 7.4 fixes 2020-09-28 09:44:36 +01:00
Gustavo Lopes
23430540f1 Travis to Azure 2020-09-28 09:43:30 +01:00
Gustavo Lopes
e3f3ecd1ab Update to unrar 5.9.2 2020-09-27 23:36:29 +01:00
Gustavo Lopes
544f55920a Add unrar 5.9.2 2020-04-29 20:12:36 +01:00
Gustavo Lopes
24b421e0e6 Add unrar 5.9.1 2020-04-29 20:12:36 +01:00
Gustavo Lopes
05a48cbbeb Added unrar 5.8.5 2020-04-29 20:12:36 +01:00
Gustavo Lopes
6d0e583ef9 Added unrar 5.8.4 2020-04-29 20:12:36 +01:00
Gustavo Lopes
714f15cb06 Added unrar 5.8.3 2020-04-29 20:12:36 +01:00
Gustavo Lopes
58bb195ae3 Added unrar 5.8.2 2020-04-29 20:12:36 +01:00
Gustavo Lopes
5293a8f07e Added unrar 5.8.1 2020-04-29 20:12:36 +01:00
Gustavo Lopes
61edb08973 Added unrar 5.7.5 2020-04-29 20:12:36 +01:00
Gustavo Lopes
adc9fe7d39 Added unrar 5.7.4 2020-04-29 20:12:36 +01:00
Gustavo Lopes
5eb1055447 Added unrar 5.7.3 2020-04-29 20:12:36 +01:00
Gustavo Lopes
7ca7561e09 Added unrar 5.7.2 2020-04-29 20:12:36 +01:00
Gustavo Lopes
61eca15136 Added unrar 5.7.1 2020-04-29 20:12:36 +01:00
Gustavo Lopes
dc8ee65999 Added unrar 5.6.8 2020-04-29 20:12:36 +01:00
Gustavo Lopes
656c3fa69d Added unrar 5.6.7 2020-04-29 20:12:36 +01:00
Gustavo Lopes
a6bea8fec8 Added unrar 5.6.6 2020-04-29 20:12:36 +01:00
Gustavo Lopes
3b405bea8e Added unrar 5.6.5 2020-04-29 20:12:36 +01:00
Gustavo Lopes
18cd0568aa Added unrar 5.6.4 2020-04-29 20:12:36 +01:00
Gustavo Lopes
dc298847c7 Added unrar 5.6.3 2020-04-29 20:12:36 +01:00
Gustavo Lopes
246a80fdeb Added unrar 5.6.2 2020-04-29 20:12:36 +01:00
Gustavo Lopes
4b6fd31d08 Added unrar 5.6.1 2020-04-29 20:12:36 +01:00
Gustavo Lopes
44e35b8f6a Added unrar 5.5.8 2020-04-29 20:12:36 +01:00
Gustavo Lopes
fe4a94305b Added unrar 5.5.7 2020-04-29 20:12:36 +01:00
Gustavo Lopes
0453380858 Suppress some warnings on unrar code 2020-04-29 19:40:03 +01:00
Gustavo Lopes
957fc7702d Merge pull request #4 from remicollet/issue-php73
Fix for PHP 7.3
2018-11-14 18:19:29 +00:00
Remi Collet
5a0cd32191 new constant names in 7.3 2018-08-16 14:52:03 +02:00
Remi Collet
5ca8d78562 fix for iterator changes in 7.3.0alpha4 2018-07-18 11:02:14 +02:00
Remi Collet
1225c9240e relax tests for 7.3 (bool/boolean, main/count) 2018-06-26 15:22:42 +02:00
227 changed files with 15341 additions and 7276 deletions

88
.clang-format Normal file
View File

@@ -0,0 +1,88 @@
---
# Formatting style for php-rar C source files.
# Does NOT apply to unrar/ (see unrar/.clang-format).
Language: Cpp
BasedOnStyle: LLVM
# Indentation: real tabs, width 4 (matches vim modeline: noet sw=4 ts=4)
UseTab: Always
TabWidth: 4
IndentWidth: 4
ContinuationIndentWidth: 4
# Disable line-length wrapping to preserve hand-formatted long lines
ColumnLimit: 0
# Brace style:
# - Functions: brace on its own line (Allman)
# - Structs/unions/enums/extern "C": brace attached (K&R)
# - Control statements: brace attached (K&R)
# - else/else if: on its own line (after closing })
BreakBeforeBraces: Custom
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: Never
AfterEnum: false
AfterFunction: true
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: true
BeforeLambdaBody: false
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: false
SplitEmptyRecord: false
SplitEmptyNamespace: false
# Preserve indentation of preprocessor directives (# include, # define inside #ifdef)
IndentPPDirectives: AfterHash
PPIndentWidth: 1
# Pointer star attached to variable name: char *ptr
PointerAlignment: Right
DerivePointerAlignment: false
# Spaces
SpaceBeforeParens: ControlStatements
SpaceAfterCStyleCast: true
SpacesInParentheses: false
SpaceInEmptyParentheses: false
SpaceBeforeAssignmentOperators: true
# Don't align backslashes in multi-line macros (just 1 space before \)
AlignEscapedNewlines: DontAlign
# ZEND_BEGIN/END_ARG_INFO_EX act as block delimiters so ZEND_ARG_INFO lines
# inside them keep their indentation.
MacroBlockBegin: "^ZEND_BEGIN_ARG_INFO"
MacroBlockEnd: "^ZEND_END_ARG_INFO"
# Align continuation arguments after opening paren; when ( is last on the line,
# fall back to a block indent (ContinuationIndentWidth).
AlignAfterOpenBracket: Align
# Preserve existing include order
SortIncludes: Never
# case labels are indented one level inside switch
IndentCaseLabels: true
# Don't collapse or expand short constructs
AllowShortBlocksOnASingleLine: Never
AllowShortFunctionsOnASingleLine: None
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
# Alignment: leave hand-aligned blocks alone
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignTrailingComments: false
# Blank lines
MaxEmptyLinesToKeep: 2
KeepEmptyLinesAtTheStartOfBlocks: true

27
.github/docker-image-shas.yml vendored Normal file
View File

@@ -0,0 +1,27 @@
# Docker image SHA lock file.
# Maps image tags to their multi-arch OCI index digests (amd64 + arm64).
# Regenerate with: .github/scripts/update-docker-shas.sh
datadog/dd-appsec-php-ci:
php-7.0-debug: "sha256:0a9aaeaf79bd4c578eac6dedabf6ac131537266f44562158ce67fdb37c794916"
php-7.0-release-zts: "sha256:4bb5fac6fbd3124234d062328c68f6c51027aa95f13e4e8b14afd7c8de518ec6"
php-7.1-debug: "sha256:500007ad057d9e71b2bb9079a2f8ba3f1ecfbb26d112db69e17d6007b4e857b5"
php-7.1-release-zts: "sha256:d997b9f99c28967872bd0949f8572b089daaadb6ceaa1e856ccc76e07e2ba6b7"
php-7.2-debug: "sha256:4c5f111f8e84fcb7dcc9e3cc13e1277d0702b04cd33286ce33db885485d1f025"
php-7.2-release-zts: "sha256:634b857d74c3d77b88986ceb088be2dd5bc30151bc08c2b536443984e6659d6e"
php-7.3-debug: "sha256:efa81f79783097478a434578226fe9a3b8fe84abda33168034aaea60c197c73b"
php-7.3-release-zts: "sha256:c713df299596a9615f88cfe73c29b0a1f9faf32e5e6fa62fa07ee839313cd57e"
php-7.4-debug: "sha256:b8a9e982179189122d73feb896c1a1e8578a92fc9a023dabc825f45db8299c22"
php-7.4-release-zts: "sha256:6492e3334e722b106352180ec9f0cbee8dd81f008e3537d03f4b8da3522f49e1"
php-8.0-debug: "sha256:900ceae7487db1e3652de2880c181e572fdf053673bcda8ff47abf664ff74d39"
php-8.0-release-zts: "sha256:b6243199f6aea0792a97583c9036f0b191ad9efb96ea337632fbaca76289a4da"
php-8.1-debug: "sha256:1a1e5b44cf043e59768c65fd7c94aaefdacde5fa96d83102d35db11ad86f24c6"
php-8.1-release-zts: "sha256:5b8a269b4228d9191420059daef820b660110be0aca6776557924172fd1ff0c8"
php-8.2-debug: "sha256:52ad14560672fc8c5130f5758bbee3fa401bc1d35b412f4a230c6258143291a5"
php-8.2-release-zts: "sha256:cb143d915b394f16a2d78018765705460f3d1b788fdd2a90ef50fad5f8f5918c"
php-8.3-debug: "sha256:bb6df08160126374d3d9247428928aa19a9c2b2429c98356650199b85ae20212"
php-8.3-release-zts: "sha256:e58e25a017f75df82691d408b8cb70453875ff36718e295ee8c6653a0f117331"
php-8.4-debug: "sha256:15045688f6986f4625b1507a7f4be6104e7bbb88caf877f1611463b929f2bca2"
php-8.4-release-zts: "sha256:8e0ac25a3306b4b9f692c593b8a509cc789c2e001ce52682928065a92c880136"
php-8.5-debug: "sha256:bd0170331b34fb469e29d00b19b20fb88b726160f76df274a1bdc3a27ac18d30"
php-8.5-release-zts: "sha256:e071b2095da55bd24686209422f43a01c65acfc6021f04156d9fb43fd3d4d426"

35
.github/scripts/build-and-test.sh vendored Executable file
View File

@@ -0,0 +1,35 @@
#!/usr/bin/env bash
# Build the extension and run the test suite.
# Expected to run inside a datadog/dd-appsec-php-ci container from the repo root.
set -euo pipefail
# Clean up artifacts from any previous build so stale objects don't survive a
# PHP-version switch (safe in CI where the workspace is always fresh).
if [ -f Makefile ]; then
make -f Makefile distclean
fi
phpize
./configure --with-php-config="$(which php-config)"
make -f Makefile -j"$(nproc)"
# The generated Makefile silences and ignores errors on the `if` commands;
# undo that so test failures surface properly.
sed -i 's/-@if/@if/' Makefile
ret=0
TEST_PHP_EXECUTABLE="$(which php)" \
TEST_PHP_JUNIT=report.xml \
REPORT_EXIT_STATUS=1 \
NO_INTERACTION=1 \
TESTS="--set-timeout 300 --show-diff" \
make -f Makefile test || ret=$?
found=$(find tests -name '*.mem' | wc -l)
if [ "$found" -gt 0 ]; then
echo "Found $found memory leak(s):"
find tests -name '*.mem' -print -exec cat {} \;
ret=1
fi
exit "$ret"

52
.github/scripts/update-docker-shas.sh vendored Executable file
View File

@@ -0,0 +1,52 @@
#!/usr/bin/env bash
# Refresh docker-image-shas.yml with current OCI index digests.
# The index digest covers all platforms (amd64 + arm64); Docker resolves the
# right platform image from it at pull time.
# Justfile and tests.yml read from docker-image-shas.yml directly — no patching needed.
set -euo pipefail
IMAGE="datadog/dd-appsec-php-ci"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
LOCK_FILE="$SCRIPT_DIR/../docker-image-shas.yml"
TAGS=(
php-7.0-debug php-7.0-release-zts
php-7.1-debug php-7.1-release-zts
php-7.2-debug php-7.2-release-zts
php-7.3-debug php-7.3-release-zts
php-7.4-debug php-7.4-release-zts
php-8.0-debug php-8.0-release-zts
php-8.1-debug php-8.1-release-zts
php-8.2-debug php-8.2-release-zts
php-8.3-debug php-8.3-release-zts
php-8.4-debug php-8.4-release-zts
php-8.5-debug php-8.5-release-zts
)
get_index_digest() {
# The top-level "digest" field in the Hub tags API is the manifest-list
# (OCI index) digest, not a per-platform image digest.
curl -fsSL "https://hub.docker.com/v2/repositories/${IMAGE}/tags/$1" \
| python3 -c "import sys,json; print(json.load(sys.stdin)['digest'])"
}
# Collect all digests first so we fail fast before touching any file.
declare -A DIGESTS
for tag in "${TAGS[@]}"; do
echo "Fetching $tag ..." >&2
DIGESTS[$tag]=$(get_index_digest "$tag")
done
# ── Update docker-image-shas.yml ─────────────────────────────────────────────
{
echo "# Docker image SHA lock file."
echo "# Maps image tags to their multi-arch OCI index digests (amd64 + arm64)."
echo "# Regenerate with: .github/scripts/update-docker-shas.sh"
echo ""
echo "${IMAGE}:"
for tag in "${TAGS[@]}"; do
printf " %-20s \"%s\"\n" "${tag}:" "${DIGESTS[$tag]}"
done
} > "$LOCK_FILE"
echo "Updated $LOCK_FILE" >&2

123
.github/workflows/release.yml vendored Normal file
View File

@@ -0,0 +1,123 @@
name: Release binaries
on:
push:
tags:
- 'v[0-9]*.[0-9]*.[0-9]*'
permissions:
contents: read
jobs:
check-version:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Check version consistency
run: |
TAG_VERSION="${GITHUB_REF_NAME#v}"
HEADER_VERSION=$(grep -oP '(?<=#define PHP_RAR_VERSION ")[^"]+' php_rar.h)
PACKAGE_VERSION=$(python3 -c "
import xml.etree.ElementTree as ET
t = ET.parse('package.xml')
ns = {'p': 'http://pear.php.net/dtd/package-2.0'}
print(t.find('p:version/p:release', ns).text)
")
echo "Tag version: $TAG_VERSION"
echo "Header version: $HEADER_VERSION"
echo "Package version: $PACKAGE_VERSION"
if [ "$TAG_VERSION" != "$HEADER_VERSION" ]; then
echo "ERROR: Tag version ($TAG_VERSION) does not match PHP_RAR_VERSION in php_rar.h ($HEADER_VERSION)"
exit 1
fi
if [ "$TAG_VERSION" != "$PACKAGE_VERSION" ]; then
echo "ERROR: Tag version ($TAG_VERSION) does not match version in package.xml ($PACKAGE_VERSION)"
exit 1
fi
echo "All versions match: $TAG_VERSION"
create-draft-release:
needs: [check-version]
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
with:
fetch-tags: 'true'
ref: ${{ github.ref }}
- name: Create draft release from tag
env:
GH_TOKEN: ${{ github.token }}
run: gh release create "${{ github.ref_name }}" --title "${{ github.ref_name }}" --draft --notes-from-tag
windows-extension-matrix:
needs: [create-draft-release]
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.extension-matrix.outputs.matrix }}
steps:
- uses: actions/checkout@v4
- name: Get the extension matrix
id: extension-matrix
uses: php/php-windows-builder/extension-matrix@v1
with:
php-version-list: '8.0, 8.1, 8.2, 8.3, 8.4, 8.5'
windows-build:
needs: [windows-extension-matrix]
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.windows-extension-matrix.outputs.matrix) }}
steps:
- uses: actions/checkout@v4
- name: Build the extension for Windows
uses: php/php-windows-builder/extension@v1
with:
php-version: ${{ matrix.php-version }}
arch: ${{ matrix.arch }}
ts: ${{ matrix.ts }}
args: --enable-rar=shared
test-runner: run-tests-rar.php
windows-release:
needs: [windows-build]
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Upload artifacts to the release
uses: php/php-windows-builder/release@v1
with:
release: ${{ github.ref_name }}
token: ${{ secrets.GITHUB_TOKEN }}
draft: 'true'
pecl-package:
needs: [create-draft-release]
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
tools: pecl
- name: Build PECL package
run: pecl package
- name: Upload PECL package to release
env:
GH_TOKEN: ${{ github.token }}
run: gh release upload "${{ github.ref_name }}" rar-*.tgz

92
.github/workflows/tests.yml vendored Normal file
View File

@@ -0,0 +1,92 @@
name: Tests
on:
push:
pull_request:
jobs:
check-dev-version:
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/master'
steps:
- uses: actions/checkout@v4
- name: Check PHP_RAR_VERSION ends in -dev
run: |
HEADER_VERSION=$(grep -oP '(?<=#define PHP_RAR_VERSION ")[^"]+' php_rar.h)
echo "Header version: $HEADER_VERSION"
if [[ "$HEADER_VERSION" != *-dev ]]; then
echo "ERROR: PHP_RAR_VERSION ($HEADER_VERSION) does not end in -dev on master"
exit 1
fi
generate-matrix:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
- uses: actions/checkout@v4
- id: set-matrix
run: |
python3 <<'EOF'
import yaml, json, os
with open('.github/docker-image-shas.yml') as f:
data = yaml.safe_load(f)
image = 'datadog/dd-appsec-php-ci'
includes = []
for tag, sha in data[image].items():
# tag: "php-7.0-debug" or "php-7.0-release-zts"
ver, variant = tag[len('php-'):].split('-', 1)
includes.append({'php': ver, 'variant': variant, 'image_sha': sha})
with open(os.environ['GITHUB_OUTPUT'], 'a') as f:
f.write('matrix=' + json.dumps({'include': includes}) + '\n')
EOF
linux:
name: PHP ${{ matrix.php }} (${{ matrix.variant }})
needs: generate-matrix
runs-on: ubuntu-latest
container:
image: datadog/dd-appsec-php-ci@${{ matrix.image_sha }}
options: --user root
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.generate-matrix.outputs.matrix) }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build and test
run: bash .github/scripts/build-and-test.sh
- name: Upload test results
uses: actions/upload-artifact@v4
if: always()
with:
name: test-results-php${{ matrix.php }}-${{ matrix.variant }}
path: report.xml
windows:
name: Windows PHP 8.1 TS
runs-on: windows-2022
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build and test
uses: php/php-windows-builder/extension@v1
with:
php-version: '8.1'
arch: x64
ts: ts
args: --enable-rar=shared
test-runner: ${{ github.workspace }}/run-tests-rar.php
test-workers: 1
- name: Upload test results
uses: actions/upload-artifact@v4
if: always()
with:
name: test-results-windows-php8.1-ts
path: '*.xml'

13
.gitignore vendored
View File

@@ -1,5 +1,6 @@
*.o
*.lo
/run-tests.php
/tests/*.sh
/tests/*.exp
/tests/*.diff
@@ -7,7 +8,6 @@
/tests/*.php
/tests/*.out
/tests/*.mem
/run-tests.php
/modules
/missing
/.deps
@@ -23,12 +23,14 @@
/config.guess
/config.h
/config.h.in
/config.h.in~
/config.log
/config.nice
/config.status
/config.sub
/configure
/configure.in
/configure.ac
/install-sh
/intl.la
/libtool
@@ -41,3 +43,12 @@
/rar.la
*.autosave
/unrar/.libs
/tmp-php.ini
/php-rar.creator.user
/compile_commands.json
/.clangd
/report.xml
/.worktrees
*.dep
/configure~
/.cache/

View File

@@ -1,33 +0,0 @@
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)'

113
Justfile Normal file
View File

@@ -0,0 +1,113 @@
# Build and test inside the matching CI Docker image.
# Image SHAs are read from .github/docker-image-shas.yml (multi-arch OCI index digests).
# To refresh SHAs: .github/scripts/update-docker-shas.sh
# ── Images ────────────────────────────────────────────────────────────────────
_base := "datadog/dd-appsec-php-ci@"
_shas := ".github/docker-image-shas.yml"
image_7_0_debug := _base + `grep 'php-7.0-debug:' .github/docker-image-shas.yml | cut -d'"' -f2`
image_7_0_release_zts := _base + `grep 'php-7.0-release-zts:' .github/docker-image-shas.yml | cut -d'"' -f2`
image_7_1_debug := _base + `grep 'php-7.1-debug:' .github/docker-image-shas.yml | cut -d'"' -f2`
image_7_1_release_zts := _base + `grep 'php-7.1-release-zts:' .github/docker-image-shas.yml | cut -d'"' -f2`
image_7_2_debug := _base + `grep 'php-7.2-debug:' .github/docker-image-shas.yml | cut -d'"' -f2`
image_7_2_release_zts := _base + `grep 'php-7.2-release-zts:' .github/docker-image-shas.yml | cut -d'"' -f2`
image_7_3_debug := _base + `grep 'php-7.3-debug:' .github/docker-image-shas.yml | cut -d'"' -f2`
image_7_3_release_zts := _base + `grep 'php-7.3-release-zts:' .github/docker-image-shas.yml | cut -d'"' -f2`
image_7_4_debug := _base + `grep 'php-7.4-debug:' .github/docker-image-shas.yml | cut -d'"' -f2`
image_7_4_release_zts := _base + `grep 'php-7.4-release-zts:' .github/docker-image-shas.yml | cut -d'"' -f2`
image_8_0_debug := _base + `grep 'php-8.0-debug:' .github/docker-image-shas.yml | cut -d'"' -f2`
image_8_0_release_zts := _base + `grep 'php-8.0-release-zts:' .github/docker-image-shas.yml | cut -d'"' -f2`
image_8_1_debug := _base + `grep 'php-8.1-debug:' .github/docker-image-shas.yml | cut -d'"' -f2`
image_8_1_release_zts := _base + `grep 'php-8.1-release-zts:' .github/docker-image-shas.yml | cut -d'"' -f2`
image_8_2_debug := _base + `grep 'php-8.2-debug:' .github/docker-image-shas.yml | cut -d'"' -f2`
image_8_2_release_zts := _base + `grep 'php-8.2-release-zts:' .github/docker-image-shas.yml | cut -d'"' -f2`
image_8_3_debug := _base + `grep 'php-8.3-debug:' .github/docker-image-shas.yml | cut -d'"' -f2`
image_8_3_release_zts := _base + `grep 'php-8.3-release-zts:' .github/docker-image-shas.yml | cut -d'"' -f2`
image_8_4_debug := _base + `grep 'php-8.4-debug:' .github/docker-image-shas.yml | cut -d'"' -f2`
image_8_4_release_zts := _base + `grep 'php-8.4-release-zts:' .github/docker-image-shas.yml | cut -d'"' -f2`
image_8_5_debug := _base + `grep 'php-8.5-debug:' .github/docker-image-shas.yml | cut -d'"' -f2`
image_8_5_release_zts := _base + `grep 'php-8.5-release-zts:' .github/docker-image-shas.yml | cut -d'"' -f2`
_run := "docker run --rm --entrypoint bash -v \"$PWD:/workspace\" -w /workspace --user root"
# ── Default ───────────────────────────────────────────────────────────────────
default:
@just --list
# ── Individual targets ────────────────────────────────────────────────────────
test-7_0-debug:
{{_run}} {{image_7_0_debug}} .github/scripts/build-and-test.sh
test-7_0-release-zts:
{{_run}} {{image_7_0_release_zts}} .github/scripts/build-and-test.sh
test-7_1-debug:
{{_run}} {{image_7_1_debug}} .github/scripts/build-and-test.sh
test-7_1-release-zts:
{{_run}} {{image_7_1_release_zts}} .github/scripts/build-and-test.sh
test-7_2-debug:
{{_run}} {{image_7_2_debug}} .github/scripts/build-and-test.sh
test-7_2-release-zts:
{{_run}} {{image_7_2_release_zts}} .github/scripts/build-and-test.sh
test-7_3-debug:
{{_run}} {{image_7_3_debug}} .github/scripts/build-and-test.sh
test-7_3-release-zts:
{{_run}} {{image_7_3_release_zts}} .github/scripts/build-and-test.sh
test-7_4-debug:
{{_run}} {{image_7_4_debug}} .github/scripts/build-and-test.sh
test-7_4-release-zts:
{{_run}} {{image_7_4_release_zts}} .github/scripts/build-and-test.sh
test-8_0-debug:
{{_run}} {{image_8_0_debug}} .github/scripts/build-and-test.sh
test-8_0-release-zts:
{{_run}} {{image_8_0_release_zts}} .github/scripts/build-and-test.sh
test-8_1-debug:
{{_run}} {{image_8_1_debug}} .github/scripts/build-and-test.sh
test-8_1-release-zts:
{{_run}} {{image_8_1_release_zts}} .github/scripts/build-and-test.sh
test-8_2-debug:
{{_run}} {{image_8_2_debug}} .github/scripts/build-and-test.sh
test-8_2-release-zts:
{{_run}} {{image_8_2_release_zts}} .github/scripts/build-and-test.sh
test-8_3-debug:
{{_run}} {{image_8_3_debug}} .github/scripts/build-and-test.sh
test-8_3-release-zts:
{{_run}} {{image_8_3_release_zts}} .github/scripts/build-and-test.sh
test-8_4-debug:
{{_run}} {{image_8_4_debug}} .github/scripts/build-and-test.sh
test-8_4-release-zts:
{{_run}} {{image_8_4_release_zts}} .github/scripts/build-and-test.sh
test-8_5-debug:
{{_run}} {{image_8_5_debug}} .github/scripts/build-and-test.sh
test-8_5-release-zts:
{{_run}} {{image_8_5_release_zts}} .github/scripts/build-and-test.sh
# ── Per-version aggregates (sequential to avoid workspace conflicts) ───────────
test-7_0: test-7_0-debug test-7_0-release-zts
test-7_1: test-7_1-debug test-7_1-release-zts
test-7_2: test-7_2-debug test-7_2-release-zts
test-7_3: test-7_3-debug test-7_3-release-zts
test-7_4: test-7_4-debug test-7_4-release-zts
test-8_0: test-8_0-debug test-8_0-release-zts
test-8_1: test-8_1-debug test-8_1-release-zts
test-8_2: test-8_2-debug test-8_2-release-zts
test-8_3: test-8_3-debug test-8_3-release-zts
test-8_4: test-8_4-debug test-8_4-release-zts
test-8_5: test-8_5-debug test-8_5-release-zts
# ── All Linux targets ─────────────────────────────────────────────────────────
test-linux: test-7_0 test-7_1 test-7_2 test-7_3 test-7_4 test-8_0 test-8_1 test-8_2 test-8_3 test-8_4 test-8_5

5
Makefile.frag Normal file
View File

@@ -0,0 +1,5 @@
.PHONY: replace-run-tests
replace-run-tests:
cp run-tests-rar.php run-tests.php
test: replace-run-tests

View File

@@ -10,6 +10,22 @@ 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)
## Installation
### With PECL
```sh
pecl install rar
```
Then add `extension=rar` to your `php.ini`.
### With PIE
[PIE](https://github.com/php/pie) is the modern replacement for PECL, available from PHP 8.1+.
```sh
pie install rar
```
PIE automatically adds the extension to your `php.ini`.

View File

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

View File

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

View File

@@ -1,18 +1,31 @@
{
"name": "rar",
"type": "extension",
"license": [
"PHP License"
],
"name": "cataphract/rar",
"type": "php-ext",
"description": "PHP extension for reading RAR archives using bundled unRAR library",
"license": "PHP-3.01",
"authors": [
{
"name": "Gustavo Lopes",
"email": "cataphract@php.net"
"email": "cataphract@php.net",
"role": "lead"
},
{
"name": "Antony Dovgal",
"email": "tony@daylessday.org"
"email": "tony@daylessday.org",
"role": "developer"
}
],
"description": "rar extension"
}
"require": {
"php": "^7.0 || ^8.0"
},
"replace": {
"ext-rar": "*"
},
"support": {
"source": "https://github.com/cataphract/php-rar"
},
"php-ext": {
"extension-name": "rar",
"download-url-method": ["pre-packaged-binary", "composer-default"]
}
}

View File

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

View File

@@ -18,7 +18,7 @@ if (PHP_RAR != "no") {
crc.cpp rijndael.cpp crypt.cpp \
rawread.cpp \
rs.cpp smallfn.cpp \
isnt.cpp rar.cpp consio.cpp \
isnt.cpp consio.cpp \
scantree.cpp archive.cpp strfn.cpp \
strlist.cpp \
getbits.cpp hash.cpp \
@@ -31,7 +31,8 @@ if (PHP_RAR != "no") {
arcread.cpp filefn.cpp \
global.cpp list.cpp \
encname.cpp file.cpp \
secpassword.cpp options.cpp", "rar");
secpassword.cpp options.cpp \
largepage.cpp motw.cpp", "rar");
AC_DEFINE("HAVE_RAR", 1, "Rar support");
}

View File

@@ -23,10 +23,10 @@ http://pear.php.net/dtd/package-2.0.xsd">
<active>no</active>
</developer>
<date>2017-07-22</date>
<time>03:00:00</time>
<date>2026-03-08</date>
<time>20:00:00</time>
<version>
<release>4.0.0</release>
<release>4.3.0</release>
<api>4.0.0</api>
</version>
@@ -36,11 +36,10 @@ http://pear.php.net/dtd/package-2.0.xsd">
</stability>
<license uri="http://www.php.net/license">PHP License</license>
<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>- Add PHP 8.1, 8.2, 8.3, 8.4, 8.5 support.
- Drop PHP 5 support; minimum PHP version is now 7.0.
- Update bundled unrar to 7.2.4.
- Fix Windows bug
</notes>
<contents>
<dir name="/">
@@ -113,8 +112,6 @@ http://pear.php.net/dtd/package-2.0.xsd">
<file role="test" name="065.phpt"/>
<file role="test" name="066.phpt"/>
<file role="test" name="067.phpt"/>
<file role="test" name="068.phpt"/>
<file role="test" name="069.phpt"/>
<file role="test" name="070.phpt"/>
<file role="test" name="071.phpt"/>
<file role="test" name="072.phpt"/>
@@ -150,7 +147,6 @@ http://pear.php.net/dtd/package-2.0.xsd">
<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"/>
@@ -159,6 +155,8 @@ http://pear.php.net/dtd/package-2.0.xsd">
<file role="test" name="111.phpt"/>
<file role="test" name="112.phpt"/>
<file role="test" name="113.phpt"/>
<file role="test" name="114.phpt"/>
<file role="test" name="115.phpt"/>
<file role="test" name="commented.rar"/>
<file role="test" name="corrupted.rar"/>
<file role="test" name="directories.rar"/>
@@ -174,6 +172,7 @@ http://pear.php.net/dtd/package-2.0.xsd">
<file role="test" name="multi.part2.rar"/>
<file role="test" name="multi.part3.rar"/>
<file role="test" name="multi_broken.part1.rar"/>
<file role="test" name="php8compat.php.inc"/>
<file role="test" name="rar_notrar.rar"/>
<file role="test" name="rar_unicode.rar"/>
<file role="test" name="repeated_name.rar"/>
@@ -192,13 +191,14 @@ http://pear.php.net/dtd/package-2.0.xsd">
<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="blake2s.cpp" role="src" />
<file name="blake2s.hpp" role="src" />
<file name="blake2s_sse.cpp" role="src" />
<file name="blake2sp.cpp" role="src" />
<file name="cmddata.cpp" role="src" />
<file name="cmddata.hpp" role="src" />
<file name="cmdfilter.cpp" role="src" />
<file name="cmdmix.cpp" role="src" />
<file name="coder.cpp" role="src" />
<file name="coder.hpp" role="src" />
<file name="compress.hpp" role="src" />
@@ -245,6 +245,8 @@ http://pear.php.net/dtd/package-2.0.xsd">
<file name="headers5.hpp" role="src" />
<file name="isnt.cpp" role="src" />
<file name="isnt.hpp" role="src" />
<file name="largepage.cpp" role="src" />
<file name="largepage.hpp" role="src" />
<file name="LICENSE.txt" role="doc" />
<file name="list.cpp" role="src" />
<file name="list.hpp" role="src" />
@@ -255,6 +257,8 @@ http://pear.php.net/dtd/package-2.0.xsd">
<file name="match.hpp" role="src" />
<file name="model.cpp" role="src" />
<file name="model.hpp" role="src" />
<file name="motw.cpp" role="src" />
<file name="motw.hpp" role="src" />
<file name="options.cpp" role="src" />
<file name="options.hpp" role="src" />
<file name="os.hpp" role="src" />
@@ -270,7 +274,6 @@ http://pear.php.net/dtd/package-2.0.xsd">
<file name="rartypes.hpp" role="src" />
<file name="rarvm.cpp" role="src" />
<file name="rarvm.hpp" role="src" />
<file name="rarvmtbl.cpp" role="src" />
<file name="rawint.hpp" role="src" />
<file name="rawread.cpp" role="src" />
<file name="rawread.hpp" role="src" />
@@ -305,7 +308,6 @@ http://pear.php.net/dtd/package-2.0.xsd">
<file name="rijndael.hpp" role="src" />
<file name="rs.cpp" role="src" />
<file name="rs.hpp" role="src" />
<file name="savepos.hpp" role="src" />
<file name="scantree.cpp" role="src" />
<file name="scantree.hpp" role="src" />
<file name="secpassword.cpp" role="src" />
@@ -325,7 +327,6 @@ http://pear.php.net/dtd/package-2.0.xsd">
<file name="timefn.cpp" role="src" />
<file name="timefn.hpp" role="src" />
<file name="ulinks.cpp" role="src" />
<file name="ulinks.hpp" role="src" />
<file name="unicode.cpp" role="src" />
<file name="unicode.hpp" role="src" />
<file name="unpack.cpp" role="src" />
@@ -343,8 +344,10 @@ http://pear.php.net/dtd/package-2.0.xsd">
<file name="config.w32" role="src" />
<file name="CREDITS" role="doc" />
<file name="LICENSE" role="doc" />
<file name="Makefile.frag" role="src" />
<file name="README.md" role="doc" />
<file name="example.php" role="doc" />
<file name="php_compat.h" role="src" />
<file name="php_rar.h" role="src" />
<file name="rar.c" role="src" />
<file name="rar_stream.c" role="src" />
@@ -352,6 +355,7 @@ http://pear.php.net/dtd/package-2.0.xsd">
<file name="rarentry.c" role="src" />
<file name="rar_error.c" role="src" />
<file name="rar_time.c" role="src" />
<file name="run-tests-rar.php" role="test" />
<file role="src" name="rar_navigation.c"/>
</dir> <!-- / -->
</contents>
@@ -359,7 +363,7 @@ http://pear.php.net/dtd/package-2.0.xsd">
<dependencies>
<required>
<php>
<min>5.3.0</min>
<min>7.0.0</min>
</php>
<pearinstaller>
<min>1.4.0</min>
@@ -370,8 +374,80 @@ http://pear.php.net/dtd/package-2.0.xsd">
<providesextension>rar</providesextension>
<extsrcrelease />
<changelog>
<release>
<version>
<release>4.3.0</release>
<api>4.0.0</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<date>2026-03-08</date>
<notes>Changes in this version:
- Add PHP 8.1, 8.2, 8.3 support.
- Drop PHP 5 support; minimum PHP version is now 7.0.
- Update bundled unrar to 7.2.4.
- Fix segfault caused by uninitialized RARHeaderDataEx.
- Fix dll.cpp: don't propagate non-fatal ErrHandler errors as failures.
- Fix RAR5 chunk extraction spurious warning on Windows with multi-core CPUs.
- Migrate CI from Azure Pipelines/Appveyor to GitHub Actions.
</notes>
</release>
<release>
<version>
<release>4.2.0</release>
<api>4.0.0</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<date>2020-12-06</date>
<notes>Changes in this version:
- Support PHP 8.
- Merge unrar 6.0.2.
- RarArchive implements IteratorAggregate (PHP 8 only).
</notes>
</release>
<release>
<version>
<release>4.1.0</release>
<api>4.0.0</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<date>2020-10-11</date>
<notes>Changes in this version:
- Merge changes made to unrar up to version 5.5.6.
- Support PHP 7.2, PHP 7.3 and PHP 7.4.
- Update to unrar 5.9.4.
- Fix bug #76592: streaming unpacking of uncompressed files incomplete.
</notes>
</release>
<release>
<version>
<release>4.0.0</release>
<api>4.0.0</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<date>2017-07-22</date>
<notes>Changes in this version:
- Added functions RarEntry::getRedirType(), RarEntry::isRedirectToDirectory() and RarEntry::getRedirTarget(), as well as the following constants on RarEntry: FSREDIR_UNIXSYMLINK, FSREDIR_WINSYMLINK, FSREDIR_JUNCTION, FSREDIR_HARDLINK and FSREDIR_FILECOPY.
- Changed stat handler to return UTC time for creation, modification and access time (does not work reliably on Windows).
- Fix cloning of RarArchive being allowed.
</notes>
</release>
<release>
<version>
<release>3.0.2</release>

11
php-rar.config Normal file
View File

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

1
php-rar.creator Normal file
View File

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

161
php-rar.files Normal file
View File

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

4
php-rar.includes Normal file
View File

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

54
php_compat.h Normal file
View File

@@ -0,0 +1,54 @@
#include <php.h>
#if PHP_MAJOR_VERSION >= 8
# define TSRMLS_DC
# define TSRMLS_D
# define TSRMLS_CC
# define TSRMLS_C
# define TSRMLS_FETCH()
# define IS_CALLABLE_STRICT 0
# define zend_qsort zend_sort
# define ZV_TO_THIS_FOR_HANDLER(zv) (Z_OBJ_P(zv))
typedef zend_object handler_this_t;
#else
# define ZV_TO_THIS_FOR_HANDLER(zv) (zv)
typedef zval handler_this_t;
#endif
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

114
php_rar.h
View File

@@ -51,7 +51,7 @@
extern zend_module_entry rar_module_entry;
#define phpext_rar_ptr &rar_module_entry
#define PHP_RAR_VERSION "4.0.0"
#define PHP_RAR_VERSION "4.3.1-dev"
#ifdef PHP_WIN32
#define PHP_RAR_API __declspec(dllexport)
@@ -63,6 +63,8 @@ extern zend_module_entry rar_module_entry;
#include "TSRM.h"
#endif
#include "php_compat.h"
/* causes linking errors (multiple definitions) in functions
that were requested inlining but were not inlined by the compiler */
/* #include "unrar/rar.hpp */
@@ -75,6 +77,7 @@ extern zend_module_entry rar_module_entry;
#include "unrar/dll.hpp"
#include "unrar/version.hpp"
/* These are in unrar/headers.hpp, but that header depends on several other */
/* clang-format off */
enum HOST_SYSTEM {
HOST_MSDOS=0,HOST_OS2=1,HOST_WIN32=2,HOST_UNIX=3,HOST_MACOS=4,
HOST_BEOS=5,HOST_MAX
@@ -83,67 +86,12 @@ enum FILE_SYSTEM_REDIRECT {
FSREDIR_NONE=0, FSREDIR_UNIXSYMLINK, FSREDIR_WINSYMLINK, FSREDIR_JUNCTION,
FSREDIR_HARDLINK, FSREDIR_FILECOPY
};
/* clang-format on */
/* 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
/* clang-format off */
typedef struct _rar_cb_user_data {
char *password; /* can be NULL */
zval *callable; /* can be NULL */
@@ -160,13 +108,19 @@ typedef struct rar {
rar_cb_user_data cb_userdata;
int allow_broken;
} rar_file_t;
/* clang-format on */
/* Misc */
#if defined(ZTS) && PHP_MAJOR_VERSION < 7
# define RAR_TSRMLS_TC , void ***
#else
# if defined(__GNUC__) || defined(__clang__)
# define ARR_SIZE(arr) \
(sizeof(arr) / sizeof((arr)[0]) + \
0 * sizeof(char[1 - 2 * __builtin_types_compatible_p( \
__typeof__(arr), __typeof__(&(arr)[0]))]))
# else
# define ARR_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
# endif
# define RAR_TSRMLS_TC
#endif
#define RAR_RETNULL_ON_ARGS() \
if (zend_parse_parameters_none() == FAILURE) { \
@@ -213,33 +167,6 @@ ZEND_EXTERN_MODULE_GLOBALS(rar);
# define RAR_G(v) (rar_globals.v)
#endif
/* PHP 5.2 compatibility */
#if PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION < 3
#define zend_parse_parameters_none() \
zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "")
#define Z_DELREF_P ZVAL_DELREF
# define STREAM_ASSUME_REALPATH 0
# define ALLOC_PERMANENT_ZVAL(z) \
(z) = (zval*) malloc(sizeof(zval));
# define OPENBASEDIR_CHECKPATH(filename) \
(PG(safe_mode) && \
(!php_checkuid(filename, NULL, CHECKUID_CHECK_FILE_AND_DIR))) \
|| php_check_open_basedir(filename TSRMLS_CC)
# undef ZEND_BEGIN_ARG_INFO_EX
# define ZEND_BEGIN_ARG_INFO_EX(name, pass_rest_by_reference, return_reference, required_num_args) \
static const zend_arg_info name[] = { \
{ NULL, 0, NULL, 0, 0, 0, pass_rest_by_reference, return_reference, required_num_args },
#endif
/* Other compatibility quirks */
/* 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);
@@ -303,7 +230,7 @@ typedef struct _rar_find_output {
int found;
size_t position;
struct RARHeaderDataEx * header;
unsigned long packed_size;
zend_ulong packed_size;
int eof;
} rar_find_output;
#define RAR_SEARCH_INDEX 0x01U
@@ -333,8 +260,9 @@ void _rar_close_file_resource(rar_file_t *rar);
/* Fetches the rar_file_t part of the RarArchive object in order to use the
* operations above and (discouraged) to have direct access to the fields
* RarEntry::extract/getStream access extract_open_dat and cb_userdata */
int _rar_get_file_resource(zval *zval_file, rar_file_t **rar_file TSRMLS_DC);
int _rar_get_file_resource_ex(zval *zval_file, rar_file_t **rar_file, int silent TSRMLS_DC);
int _rar_get_file_resource_zv(zval *zv_file, rar_file_t **rar_file TSRMLS_DC);
int _rar_get_file_resource_zv_ex(zval *zv_file, rar_file_t **rar_file, int silent TSRMLS_DC);
int _rar_get_file_resource_ex(rar_obj_ref objref_file, rar_file_t **rar_file, int silent TSRMLS_DC);
void minit_rararch(TSRMLS_D);
PHP_FUNCTION(rar_open);
@@ -351,7 +279,7 @@ extern zend_class_entry *rar_class_entry_ptr;
void minit_rarentry(TSRMLS_D);
void _rar_entry_to_zval(zval *parent,
struct RARHeaderDataEx *entry,
unsigned long packed_size,
zend_ulong packed_size,
size_t index,
zval *entry_object TSRMLS_DC);

189
php_upgrade.md Normal file
View File

@@ -0,0 +1,189 @@
# PHP 8.18.5 Upgrade Procedure for php-rar
This document describes the step-by-step procedure to extend php-rar support
from PHP 8.0 to PHP 8.5. Each minor version is handled independently: CI is
wired up, the extension is compiled and tested inside the matching Docker image,
code changes are applied to fix any failures, and only then is the next version
tackled.
---
## Overview of files touched per version
| File | Change |
|---|---|
| `.github/docker-image-shas.yml` | Add new tag → SHA entries |
| `.github/scripts/update-docker-shas.sh` | Add new tags to the `TAGS` array |
| `Justfile` | Add image variables and `test-X_Y-*` targets |
| `*.c` / `*.h` | C source changes for API compatibility |
| `.github/workflows/tests.yml` | Windows job — update `php-version` (once per bump) |
The Linux CI matrix is generated automatically from `docker-image-shas.yml`, so
no manual edit to `tests.yml` is needed for Linux jobs.
---
## Repeatable procedure for each version
Follow these numbered steps for **each** minor version in order. Example:
8.0 → 8.1 → 8.2 → 8.3 → 8.4 → 8.5.
### Step 1 — Read the upgrade guides in php-src
Clone or browse php-src on the target branch, e.g. `PHP-8.1`:
```
https://github.com/php/php-src/blob/PHP-8.X/UPGRADING
https://github.com/php/php-src/blob/PHP-8.X/UPGRADING.INTERNALS
```
Focus on sections relevant to C extensions:
- Removed or renamed macros / functions
- Changed return types (`int``zend_result`)
- Changed struct member types
- New mandatory includes
- Any other backwards-incompatible changes
The per-version notes below summarise the items relevant to php-rar.
### Step 2 — Add the Docker image SHA
Fetch the OCI index digest from Docker Hub for the two new tags:
```bash
# Quick one-liner — prints the index digest for a given tag
curl -fsSL "https://hub.docker.com/v2/repositories/datadog/dd-appsec-php-ci/tags/php-X.Y-debug" \
| python3 -c "import sys,json; print(json.load(sys.stdin)['digest'])"
```
Or regenerate everything at once with the provided script after adding the new
tags to it (see Step 3):
```bash
.github/scripts/update-docker-shas.sh
```
Append the two lines to `.github/docker-image-shas.yml`:
```yaml
php-X.Y-debug: "sha256:<INDEX-DIGEST>"
php-X.Y-release-zts: "sha256:<INDEX-DIGEST>"
```
Also add both tags to the `TAGS` array in `.github/scripts/update-docker-shas.sh`:
```bash
TAGS=(
...existing tags...
php-X.Y-debug php-X.Y-release-zts
)
```
### Step 3 — Add Justfile targets
Add image variables and `test-X_Y-*` targets following the existing pattern:
```just
image_X_Y_debug := _base + `grep 'php-X.Y-debug:' .github/docker-image-shas.yml | cut -d'"' -f2`
image_X_Y_release_zts := _base + `grep 'php-X.Y-release-zts:' .github/docker-image-shas.yml | cut -d'"' -f2`
test-X_Y-debug:
{{_run}} {{image_X_Y_debug}} .github/scripts/build-and-test.sh
test-X_Y-release-zts:
{{_run}} {{image_X_Y_release_zts}} .github/scripts/build-and-test.sh
test-X_Y: test-X_Y-debug test-X_Y-release-zts
```
Add `test-X_Y` to the `test-linux` aggregate at the bottom.
### Step 4 — Compile and test
Run both variants locally before pushing:
```bash
just test-X_Y-debug
just test-X_Y-release-zts
```
Or both together:
```bash
just test-X_Y
```
Examine the output for compiler warnings, errors, and test failures.
### Step 5 — Apply C source changes
Based on the compilation output and the per-version notes below, make the
minimum necessary changes to `.c`/`.h` files. Guard every change with `#if
PHP_VERSION_ID >= XXYY00` so that older PHP versions continue to work.
### Step 6 — Re-run tests until green
Repeat Step 4 after each change. When both `debug` and `release-zts` pass,
commit.
### Step 7 — Push and verify CI
Push the branch. The `linux` CI job matrix is auto-built from
`docker-image-shas.yml` — the new versions appear automatically. Verify the
GitHub Actions run is green for all new jobs.
### Step 8 — Update Windows CI (optional, once per bump)
The Windows job in `.github/workflows/tests.yml` pins a specific PHP version.
Update it when the Linux jobs for the matching version are confirmed green:
```yaml
- name: Build and test
uses: php/php-windows-builder/extension@v1
with:
php-version: 'X.Y' # ← change here
```
Also update the `name:` and artifact `name:` strings in the same Windows job
block.
---
## Current Docker image SHAs (as of 2026-03-01)
These are the OCI index digests (multi-arch: amd64 + arm64) to use in
`docker-image-shas.yml`.
```yaml
php-8.1-debug: "sha256:1a1e5b44cf043e59768c65fd7c94aaefdacde5fa96d83102d35db11ad86f24c6"
php-8.1-release-zts: "sha256:5b8a269b4228d9191420059daef820b660110be0aca6776557924172fd1ff0c8"
php-8.2-debug: "sha256:52ad14560672fc8c5130f5758bbee3fa401bc1d35b412f4a230c6258143291a5"
php-8.2-release-zts: "sha256:cb143d915b394f16a2d78018765705460f3d1b788fdd2a90ef50fad5f8f5918c"
php-8.3-debug: "sha256:bb6df08160126374d3d9247428928aa19a9c2b2429c98356650199b85ae20212"
php-8.3-release-zts: "sha256:e58e25a017f75df82691d408b8cb70453875ff36718e295ee8c6653a0f117331"
php-8.4-debug: "sha256:15045688f6986f4625b1507a7f4be6104e7bbb88caf877f1611463b929f2bca2"
php-8.4-release-zts: "sha256:8e0ac25a3306b4b9f692c593b8a509cc789c2e001ce52682928065a92c880136"
php-8.5-debug: "sha256:bd0170331b34fb469e29d00b19b20fb88b726160f76df274a1bdc3a27ac18d30"
php-8.5-release-zts: "sha256:e071b2095da55bd24686209422f43a01c65acfc6021f04156d9fb43fd3d4d426"
```
Refresh at any time with `.github/scripts/update-docker-shas.sh` after adding
the new tags.
---
## Summary checklist
For each version X.Y in order (8.1, 8.2, 8.3, 8.4, 8.5):
- [ ] Read `PHP-X.Y/UPGRADING.INTERNALS` on GitHub
- [ ] Add two SHA entries to `.github/docker-image-shas.yml`
- [ ] Add both tags to `TAGS` array in `.github/scripts/update-docker-shas.sh`
- [ ] Add `image_X_Y_*` variables and `test-X_Y-*` targets to `Justfile`
- [ ] Add `test-X_Y` to `test-linux` aggregate in `Justfile`
- [ ] Run `just test-X_Y` and fix all compilation errors
- [ ] Run `just test-X_Y` again; confirm all tests pass
- [ ] Commit infrastructure + code changes together
- [ ] Push; confirm GitHub Actions CI is green for the new matrix entries
- [ ] (Optional) Update Windows `php-version` in `.github/workflows/tests.yml` to X.Y
<!-- vim: set tw=80: -->

115
rar.c
View File

@@ -28,14 +28,12 @@
/* $Id$ */
#ifdef HAVE_CONFIG_H
#include "config.h"
# include "config.h"
#endif
#ifdef __cplusplus
extern "C" {
#ifndef _GNU_SOURCE
# define _GNU_SOURCE
#endif
#define _GNU_SOURCE
#include <string.h>
#ifdef PHP_WIN32
@@ -50,7 +48,7 @@ extern "C" {
#include <ext/standard/info.h>
#include <ext/spl/spl_exceptions.h>
#if HAVE_RAR
#include "unrar/rardefs.hpp"
#include "php_rar.h"
@@ -161,12 +159,8 @@ void _rar_destroy_userdata(rar_cb_user_data *udata) /* {{{ */
}
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;
@@ -240,13 +234,16 @@ int _rar_find_file_w(struct RAROpenArchiveDataEx *open_data, /* IN */
while ((result = RARReadHeaderEx(*arc_handle, used_header_data)) == 0) {
#if WCHAR_MAX > 0xffff
_rar_fix_wide(used_header_data->FileNameW, NM);
_rar_fix_wide(used_header_data->FileNameW,
ARR_SIZE(used_header_data->FileNameW));
#endif
if (wcsncmp(used_header_data->FileNameW, file_name, NM) == 0) {
if (wcsncmp(used_header_data->FileNameW, file_name,
ARR_SIZE(used_header_data->FileNameW)) == 0) {
*found = TRUE;
goto cleanup;
} else {
}
else {
process_result = RARProcessFile(*arc_handle, RAR_SKIP, NULL, NULL);
}
if (process_result != 0) {
@@ -383,6 +380,7 @@ int CALLBACK _rar_unrar_callback(UINT msg, LPARAM UserData, LPARAM P1, LPARAM P2
return ret;
}
}
// TODO: maybe support UCM_NEEDPASSWORDW and UCM_CHANGEVOLUMEW
return 0;
}
@@ -425,7 +423,7 @@ PHP_FUNCTION(rar_wrapper_cache_stats) /* {{{ */
static void _rar_fix_wide(wchar_t *str, size_t max_size) /* {{{ */
{
wchar_t *write,
*read,
*read,
*max_fin;
max_fin = str + max_size;
for (write = str, read = str; *read != L'\0' && read != max_fin; read++) {
@@ -442,61 +440,37 @@ static void _rar_fix_wide(wchar_t *str, size_t max_size) /* {{{ */
* because, in case we're using exceptions, we want to let an exception with
* error code ERAR_EOPEN to be thrown.
*/
static int _rar_unrar_volume_user_callback(char* dst_buffer,
static int _rar_unrar_volume_user_callback(char* dst_buffer, // MAXPATHSIZE
zend_fcall_info *fci,
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);
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 */
}
else if (Z_TYPE_P(retval_ptr) == IS_STRING) {
char *filename = Z_STRVAL_P(retval_ptr);
char resolved_path[MAXPATHLEN];
char resolved_path[MAXPATHSIZE];
size_t resolved_len;
if (OPENBASEDIR_CHECKPATH(filename)) {
@@ -508,17 +482,15 @@ static int _rar_unrar_volume_user_callback(char* dst_buffer,
goto cleanup;
}
resolved_len = _rar_strnlen(resolved_path, MAXPATHLEN);
/* dst_buffer size is NM; first condition won't happen short of a bug
* in expand_filepath */
if (resolved_len == MAXPATHLEN || resolved_len > NM - 1) {
resolved_len = _rar_strnlen(resolved_path, MAXPATHSIZE);
if (resolved_len > MAXPATHSIZE - 1) {
php_error_docref(NULL TSRMLS_CC, E_WARNING,
"Resolved path is too big for the unRAR library");
goto cleanup;
}
strncpy(dst_buffer, resolved_path, NM);
dst_buffer[NM - 1] = '\0';
strncpy(dst_buffer, resolved_path, MAXPATHSIZE);
dst_buffer[MAXPATHSIZE - 1] = '\0';
ret = 1; /* try this new filename */
}
else {
@@ -529,15 +501,8 @@ 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) {
zval_ptr_dtor(&retval_ptr);
}
#else
zval_ptr_dtor(&failed_vol);
zval_ptr_dtor(&retval);
#endif
return ret;
}
/* }}} */
@@ -553,17 +518,6 @@ static int _rar_make_userdata_fcall(zval *callable,
*cache = empty_fcall_info_cache;
#if PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION == 2
if (zend_fcall_info_init(callable, fci, cache TSRMLS_CC) != SUCCESS) {
php_error_docref(NULL TSRMLS_CC, E_WARNING,
"The RAR file was not opened in rar_open/RarArchive::open with a "
"valid callback.", error);
return FAILURE;
}
else {
return SUCCESS;
}
#else
if (zend_fcall_info_init(callable, IS_CALLABLE_STRICT, fci, cache, NULL,
&error TSRMLS_CC) == SUCCESS) {
if (error) {
@@ -583,7 +537,6 @@ static int _rar_make_userdata_fcall(zval *callable,
}
return FAILURE;
}
#endif
}
/* }}} */
@@ -634,6 +587,7 @@ ZEND_END_ARG_INFO()
/* {{{ rar_functions[]
*
*/
/* clang-format off */
static zend_function_entry rar_functions[] = {
PHP_FE(rar_open, arginfo_rar_open)
PHP_FE(rar_list, arginfo_rar_void_archmeth)
@@ -646,16 +600,13 @@ static zend_function_entry rar_functions[] = {
PHP_FE(rar_wrapper_cache_stats, arginfo_rar_wrapper_cache_stats)
{NULL, NULL, NULL}
};
/* clang-format on */
/* }}} */
/* {{{ 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);
}
@@ -673,13 +624,7 @@ static void _rar_contents_cache_put(const char *key,
assert(zend_hash_num_elements(cc->data) == cur_size - 1);
}
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,
@@ -688,15 +633,7 @@ static zval *_rar_contents_cache_get(const char *key,
{
rar_contents_cache *cc = &RAR_G(contents_cache);
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++;
@@ -755,16 +692,14 @@ ZEND_MODULE_STARTUP_D(rar)
php_register_url_stream_wrapper("rar", &php_stream_rar_wrapper TSRMLS_CC);
/* clang-format off */
REGISTER_LONG_CONSTANT("RAR_HOST_MSDOS", HOST_MSDOS, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("RAR_HOST_OS2", HOST_OS2, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("RAR_HOST_WIN32", HOST_WIN32, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("RAR_HOST_UNIX", HOST_UNIX, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("RAR_HOST_MACOS", HOST_MACOS, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("RAR_HOST_BEOS", HOST_BEOS, CONST_CS | CONST_PERSISTENT);
/* PHP < 5.3 doesn't have the PHP_MAXPATHLEN constant */
#if PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION < 3
REGISTER_LONG_CONSTANT("RAR_MAXPATHLEN", MAXPATHLEN, CONST_CS | CONST_PERSISTENT);
#endif
/* clang-format on */
return SUCCESS;
}
/* }}} */
@@ -829,12 +764,6 @@ zend_module_entry rar_module_entry = {
};
/* }}} */
#endif /* HAVE_RAR */
#ifdef __cplusplus
}
#endif
/*
* Local variables:
* tab-width: 4

View File

@@ -25,10 +25,6 @@
+----------------------------------------------------------------------+
*/
#ifdef __cplusplus
extern "C" {
#endif
#include <php.h>
#include <zend_exceptions.h>
#include "php_rar.h"
@@ -70,11 +66,7 @@ void _rar_handle_ext_error(const char *format TSRMLS_DC, ...) /* {{{ */
va_list arg;
char *message;
#if defined(ZTS) && PHP_MAJOR_VERSION < 7
va_start(arg, TSRMLS_C);
#else
va_start(arg, format);
#endif
vspprintf(&message, 0, format, arg);
va_end(arg);
@@ -91,13 +83,8 @@ int _rar_using_exceptions(TSRMLS_D)
zval *pval;
pval = zend_read_static_property(rarexception_ce_ptr, "usingExceptions",
sizeof("usingExceptions") -1, (zend_bool) 1 TSRMLS_CC);
#if PHP_MAJOR_VERSION < 7
assert(Z_TYPE_P(pval) == IS_BOOL);
return Z_BVAL_P(pval);
#else
assert(Z_TYPE_P(pval) == IS_TRUE || Z_TYPE_P(pval) == IS_FALSE);
return Z_TYPE_P(pval) == IS_TRUE;
#endif
}
/* returns a string or NULL if not an error */
@@ -186,39 +173,22 @@ 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);
#elif PHP_MAJOR_VERSION < 7
pval = zend_std_get_static_property(rarexception_ce_ptr, "usingExceptions",
sizeof("usingExceptions") -1, (zend_bool) 0, NULL TSRMLS_CC);
#else
zend_string *prop_name =
zend_string_init("usingExceptions", sizeof("usingExceptions") - 1, 0);
pval = zend_std_get_static_property(rarexception_ce_ptr, prop_name,
(zend_bool) 0);
zend_string_release(prop_name);
#endif
/* property always exists */
assert(pval != NULL);
#if PHP_MAJOR_VERSION < 7
assert(Z_TYPE_PP(pval) == IS_BOOL);
RETURN_ZVAL(*pval, 0, 0);
#else
assert(Z_TYPE_P(pval) == IS_TRUE || Z_TYPE_P(pval) == IS_FALSE);
RETURN_ZVAL(pval, 0, 0);
#endif
}
/* }}} */
@@ -231,31 +201,24 @@ ZEND_BEGIN_ARG_INFO(arginfo_rarexception_void, 0)
ZEND_END_ARG_INFO()
/* }}} */
/* clang-format off */
static zend_function_entry php_rarexception_class_functions[] = {
PHP_ME(rarexception, setUsingExceptions, arginfo_rarexception_sue, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
PHP_ME(rarexception, isUsingExceptions, arginfo_rarexception_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
{NULL, NULL, NULL}
};
/* clang-format on */
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
/* zend_exception_get_default() was removed in PHP 8.5; use the global directly */
rarexception_ce_ptr = zend_register_internal_class_ex(&ce, zend_ce_exception);
rarexception_ce_ptr->ce_flags |= ZEND_ACC_FINAL;
zend_declare_property_bool(rarexception_ce_ptr, "usingExceptions",
sizeof("usingExceptions") -1, 0L /* FALSE */,
ZEND_ACC_PRIVATE | ZEND_ACC_STATIC TSRMLS_CC);
ZEND_ACC_STATIC TSRMLS_CC);
}
/* }}} */
#ifdef __cplusplus
}
#endif

View File

@@ -25,21 +25,16 @@
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#ifdef __cplusplus
extern "C" {
# include "config.h"
#endif
#include <php.h>
#include <wchar.h>
#include "php_rar.h"
#if HAVE_RAR
/* {{{ Structure definitions */
/* clang-format off */
typedef struct _rar_find_state {
rar_find_output out;
rar_file_t *rar;
@@ -49,7 +44,7 @@ typedef struct _rar_find_state {
struct _rar_unique_entry {
size_t id; /* position in the entries_array */
struct RARHeaderDataEx entry; /* last entry */
unsigned long packed_size;
zend_ulong packed_size;
int depth; /* number of directory separators */
size_t name_wlen; /* excluding L'\0' terminator */
};
@@ -65,6 +60,7 @@ struct _rar_entries {
struct _rar_unique_entry *last_accessed;
int list_result; /* tell whether the archive's broken */
};
/* clang-format on */
/* }}} */
@@ -73,9 +69,7 @@ static void _rar_nav_get_depth_and_length(wchar_t *filenamew, const size_t file_
int *depth_out, size_t *wlen_out TSRMLS_DC);
static int _rar_nav_get_depth(const wchar_t *filenamew, const size_t file_size);
static int _rar_nav_compare_entries(const void *op1, const void *op2 TSRMLS_DC);
#if PHP_MAJOR_VERSION >= 7
static void _rar_nav_swap_entries(void *op1, void *op2);
#endif
static int _rar_nav_compare_entries_std(const void *op1, const void *op2);
static inline int _rar_nav_compare_values(const wchar_t *str1, const int depth1,
const wchar_t *str2, const int depth2,
@@ -116,15 +110,9 @@ void _rar_entry_search_start(rar_file_t *rar,
sizeof rar->entries->entries_array_s[0]);
memcpy(rar->entries->entries_array_s, rar->entries->entries_array,
rar->entries->num_entries * sizeof rar->entries->entries_array[0]);
#if PHP_MAJOR_VERSION < 7
zend_qsort(rar->entries->entries_array_s, rar->entries->num_entries,
sizeof *rar->entries->entries_array_s, _rar_nav_compare_entries
TSRMLS_CC);
#else
zend_qsort(rar->entries->entries_array_s, rar->entries->num_entries,
sizeof *rar->entries->entries_array_s, _rar_nav_compare_entries,
_rar_nav_swap_entries);
#endif
}
}
/* }}} */
@@ -336,7 +324,7 @@ int _rar_list_files(rar_file_t *rar TSRMLS_DC) /* {{{ */
int result = 0;
size_t capacity = 0;
int first_file_check = TRUE;
unsigned long packed_size = 0UL;
zend_ulong packed_size = 0;
struct _rar_entries *ents;
if (rar->entries != NULL) {
@@ -378,22 +366,16 @@ int _rar_list_files(rar_file_t *rar TSRMLS_DC) /* {{{ */
/* reset packed size if not split before */
if ((entry.Flags & RHDF_SPLITBEFORE) == 0)
packed_size = 0UL;
packed_size = 0;
/* we would exceed size of ulong. cap at ulong_max
* equivalent to packed_size + entry.PackSize > ULONG_MAX,
* but without overflowing */
if (ULONG_MAX - packed_size < entry.PackSize)
packed_size = ULONG_MAX;
else {
packed_size += entry.PackSize;
if (entry.PackSizeHigh != 0) {
#if ULONG_MAX > 0xffffffffUL
packed_size += ((unsigned long) entry.PackSizeHigh) << 32;
#else
packed_size = ULONG_MAX; /* cap */
#endif
}
/* accumulate packed size; cap at ZEND_LONG_MAX (the PHP int ceiling) */
{
zend_ulong entry_packed = ((zend_ulong)entry.PackSizeHigh << 32) | entry.PackSize;
if (entry_packed > (zend_ulong)ZEND_LONG_MAX ||
packed_size > (zend_ulong)ZEND_LONG_MAX - entry_packed)
packed_size = (zend_ulong)ZEND_LONG_MAX;
else
packed_size += entry_packed;
}
if (entry.Flags & RHDF_SPLITAFTER) /* do not commit */
@@ -502,7 +484,6 @@ static int _rar_nav_compare_entries(const void *op1, const void *op2 TSRMLS_DC)
}
/* }}} */
#if PHP_MAJOR_VERSION >= 7
static void _rar_nav_swap_entries(void *op1, void *op2) /* {{{ */
{
/* just swaps two pointer values */
@@ -515,7 +496,6 @@ static void _rar_nav_swap_entries(void *op1, void *op2) /* {{{ */
}
/* }}} */
#endif
static int _rar_nav_compare_entries_std(const void *op1, const void *op2) /* {{{ */
{
@@ -620,12 +600,6 @@ static size_t _rar_nav_position_on_dir_start(const wchar_t *dir_name,
/* end functions with internal linkage */
#endif /* HAVE_RAR */
#ifdef __cplusplus
}
#endif
/*
* Local variables:
* tab-width: 4
@@ -634,5 +608,3 @@ static size_t _rar_nav_position_on_dir_start(const wchar_t *dir_name,
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/

View File

@@ -27,17 +27,11 @@
/* $Id$ */
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#ifdef __cplusplus
extern "C" {
# include "config.h"
#endif
#include <php.h>
#if HAVE_RAR
#include <wchar.h>
#include "php_rar.h"
@@ -47,14 +41,16 @@ extern "C" {
#include <ext/standard/php_string.h>
#include <ext/standard/file.h>
/* clang-format off */
typedef struct php_rar_stream_data_t {
struct RAROpenArchiveDataEx open_data;
struct RARHeaderDataEx header_data;
HANDLE rar_handle;
size_t file_size;
/* TODO: consider encapsulating a php memory/tmpfile stream */
unsigned char *buffer;
size_t buffer_size;
size_t buffer_cont_size; /* content size */
size_t buffer_read_size; /* content size */
size_t buffer_pos;
uint64 cursor;
int no_more_data;
@@ -72,12 +68,15 @@ typedef struct php_rar_dir_stream_data_t {
int no_encode; /* do not urlencode entry names */
php_stream *stream;
} php_rar_dir_stream_data, *php_rar_dir_stream_data_P;
/* clang-format on */
/* clang-format off */
#define STREAM_DATA_FROM_STREAM \
php_rar_stream_data_P self = (php_rar_stream_data_P) stream->abstract;
#define STREAM_DIR_DATA_FROM_STREAM \
php_rar_dir_stream_data_P self = (php_rar_dir_stream_data_P) stream->abstract;
/* clang-format on */
/* len can be -1 (calculate) */
static char *_rar_wide_to_utf_with_alloc(const wchar_t *wide, int len)
@@ -98,7 +97,11 @@ static char *_rar_wide_to_utf_with_alloc(const wchar_t *wide, int len)
/* {{{ RAR file streams */
/* {{{ php_rar_ops_read */
#if PHP_VERSION_ID < 70400
static size_t php_rar_ops_read(php_stream *stream, char *buf, size_t count TSRMLS_DC)
#else
static ssize_t php_rar_ops_read(php_stream *stream, char *buf, size_t count)
#endif
{
size_t n = 0;
STREAM_DATA_FROM_STREAM
@@ -113,12 +116,12 @@ static size_t php_rar_ops_read(php_stream *stream, char *buf, size_t count TSRML
while (left > 0) {
size_t this_read_size;
/* if nothing in the buffer or buffer already read, fill buffer */
if (/*self->buffer_cont_size == 0 || > condition not necessary */
self->buffer_pos == self->buffer_cont_size)
if (/*self->buffer_read_size == 0 || > condition not necessary */
self->buffer_pos == self->buffer_read_size)
{
int res;
self->buffer_pos = 0;
self->buffer_cont_size = 0;
self->buffer_read_size = 0;
/* Note: this condition is important, you cannot rely on
* having a call to RARProcessFileChunk return no data and
* break on the condition self->buffer_cont_size == 0 because
@@ -128,25 +131,25 @@ static size_t php_rar_ops_read(php_stream *stream, char *buf, size_t count TSRML
if (self->no_more_data)
break;
res = RARProcessFileChunk(self->rar_handle, self->buffer,
self->buffer_size, &self->buffer_cont_size,
self->buffer_size, &self->buffer_read_size,
&self->no_more_data);
if (_rar_handle_error(res TSRMLS_CC) == FAILURE) {
break; /* finish in case of failure */
}
assert(self->buffer_cont_size <= self->buffer_size);
assert(self->buffer_read_size <= self->buffer_size);
/* we did not read anything. no need to continue */
if (self->buffer_cont_size == 0)
if (self->buffer_read_size == 0)
break;
}
/* if we get here we have data to be read in the buffer */
this_read_size = MIN(left,
self->buffer_cont_size - self->buffer_pos);
self->buffer_read_size - self->buffer_pos);
assert(this_read_size > 0);
memcpy(&buf[count-left], &self->buffer[self->buffer_pos],
this_read_size);
left -= this_read_size;
n += this_read_size;
self->buffer_pos += this_read_size;
self->buffer_pos += this_read_size;
assert(left >= 0);
}
@@ -155,9 +158,16 @@ static size_t php_rar_ops_read(php_stream *stream, char *buf, size_t count TSRML
/* no more data upstream (for sure), buffer already read and
* caller asked for more data than we're giving */
if (self->no_more_data && self->buffer_pos == self->buffer_cont_size &&
((size_t) n) < count)
if (self->no_more_data && self->buffer_pos == self->buffer_read_size &&
n < count && stream->eof != 1) {
stream->eof = 1;
if (self->cursor > self->file_size) {
php_error_docref(NULL TSRMLS_CC, E_WARNING,
"The file size is supposed to be %lu bytes, but "
"we read more: %" PRIu64 " bytes (corruption/wrong pwd)",
self->file_size, self->cursor);
}
}
/* we should only give no data if we have no more */
if (!self->no_more_data && n == 0) {
@@ -167,17 +177,25 @@ static size_t php_rar_ops_read(php_stream *stream, char *buf, size_t count TSRML
stream->eof = 1;
}
return n;
return (ssize_t) n;
}
/* }}} */
/* {{{ php_rar_ops_write */
#if PHP_VERSION_ID < 70400
static size_t php_rar_ops_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC)
#else
static ssize_t php_rar_ops_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC)
#endif
{
php_error_docref(NULL TSRMLS_CC, E_WARNING,
"Write operation not supported for RAR streams.");
if (!stream) {
#if PHP_VERSION_ID < 70400
return 0;
#else
return -1;
#endif
}
return count;
@@ -293,7 +311,7 @@ static int _rar_stat_from_header(struct RARHeaderDataEx *header,
* SUBHEAD_TYPE_UOWNER), but it is not exposed in unRAR */
ssb->sb.st_uid = 0;
ssb->sb.st_gid = 0;
#ifdef HAVE_ST_RDEV
#if defined(HAVE_ST_RDEV) || defined(HAVE_STRUCT_STAT_ST_RDEV)
ssb->sb.st_rdev = 0;
#endif
/* never mind signedness, we'll never get sizes big enough for that to
@@ -324,10 +342,10 @@ static int _rar_stat_from_header(struct RARHeaderDataEx *header,
&ssb->sb.st_mtime);
}
#ifdef HAVE_ST_BLKSIZE
#if defined(HAVE_ST_BLKSIZE) || defined(HAVE_STRUCT_STAT_ST_BLKSIZE)
ssb->sb.st_blksize = 0;
#endif
#ifdef HAVE_ST_BLOCKS
#if defined(HAVE_ST_BLOCKS) || defined (HAVE_STRUCT_STAT_ST_BLOCKS)
ssb->sb.st_blocks = 0;
#endif
/* php_stat in filestat.c doesn't check this one, so don't touch it */
@@ -363,19 +381,32 @@ static php_stream_ops php_stream_rario_ops = {
/* {{{ RAR directory streams */
/* {{{ php_rar_dir_ops_read */
#if PHP_VERSION_ID < 70400
static size_t php_rar_dir_ops_read(php_stream *stream, char *buf, size_t count TSRMLS_DC)
#else
static ssize_t php_rar_dir_ops_read(php_stream *stream, char *buf, size_t count TSRMLS_DC)
#endif
{
php_stream_dirent entry;
int offset;
size_t offset;
STREAM_DIR_DATA_FROM_STREAM
if (count != sizeof(entry))
if (count != sizeof(entry)) {
#if PHP_VERSION_ID < 70400
return 0;
#else
return -1;
#endif
}
_rar_entry_search_advance(self->state, self->directory, self->dir_size, 1);
if (!self->state->found) {
stream->eof = 1;
#if PHP_VERSION_ID < 70400
return 0;
#else
return -1;
#endif
}
if (self->dir_size == 1) /* root */
@@ -387,19 +418,10 @@ 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
}
@@ -415,11 +437,7 @@ 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);
@@ -431,7 +449,11 @@ static int php_rar_dir_ops_close(php_stream *stream, int close_handle TSRMLS_DC)
/* }}} */
/* {{{ php_rar_dir_ops_rewind */
#if PHP_VERSION_ID < 70400
static int php_rar_dir_ops_rewind(php_stream *stream, off_t offset, int whence, off_t *newoffset TSRMLS_DC)
#else
static int php_rar_dir_ops_rewind(php_stream *stream, zend_off_t offset, int whence, zend_off_t *newoffset)
#endif
{
STREAM_DIR_DATA_FROM_STREAM
@@ -508,16 +530,18 @@ php_stream *php_stream_rar_open(char *arc_name,
TSRMLS_CC, position, arc_name);
else {
/* no need to allocate a buffer bigger than the file uncomp size */
size_t buffer_size = (size_t)
MIN((uint64) RAR_CHUNK_BUFFER_SIZE,
INT32TO64(self->header_data.UnpSizeHigh,
self->header_data.UnpSize));
size_t file_size = INT32TO64(self->header_data.UnpSizeHigh,
self->header_data.UnpSize);
size_t buffer_size = MIN(
MAX(RAR_CHUNK_BUFFER_SIZE, self->header_data.WinSize),
file_size);
int process_result = RARProcessFileChunkInit(self->rar_handle);
if (_rar_handle_error(process_result TSRMLS_CC) == FAILURE) {
goto cleanup;
}
self->file_size = file_size;
self->buffer = emalloc(buffer_size);
self->buffer_size = buffer_size;
stream = php_stream_alloc(&php_stream_rario_ops, self, NULL, "rb");
@@ -544,67 +568,6 @@ cleanup:
/* {{{ Wrapper stuff */
#if PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION < 3
/* PHP 5.2 has no zend_resolve_path. Adapted from 5.3's php_resolve_path */
static char *zend_resolve_path(const char *filename,
int filename_length TSRMLS_DC) /* {{{ */
{
const char *path = PG(include_path);
char resolved_path[MAXPATHLEN];
char trypath[MAXPATHLEN];
const char *ptr, *end;
char *actual_path;
if (filename == NULL || filename[0] == '\0') {
return NULL;
}
/* do not use the include path in these circumstances */
if ((*filename == '.' && (IS_SLASH(filename[1]) ||
((filename[1] == '.') && IS_SLASH(filename[2])))) ||
IS_ABSOLUTE_PATH(filename, filename_length) ||
path == NULL || path[0] == '\0') {
if (tsrm_realpath(filename, resolved_path TSRMLS_CC)) {
return estrdup(resolved_path);
} else {
return NULL;
}
}
ptr = path;
while (ptr && *ptr) {
end = strchr(ptr, DEFAULT_DIR_SEPARATOR);
if (end) {
if ((end-ptr) + 1 + filename_length + 1 >= MAXPATHLEN) {
ptr = end + 1;
continue;
}
memcpy(trypath, ptr, end-ptr);
trypath[end-ptr] = '/';
memcpy(trypath+(end-ptr)+1, filename, filename_length+1);
ptr = end+1;
} else {
int len = strlen(ptr);
if (len + 1 + filename_length + 1 >= MAXPATHLEN) {
break;
}
memcpy(trypath, ptr, len);
trypath[len] = '/';
memcpy(trypath+len+1, filename, filename_length+1);
ptr = NULL;
}
actual_path = trypath;
if (tsrm_realpath(actual_path, resolved_path TSRMLS_CC)) {
return estrdup(resolved_path);
}
} /* end provided path */
return NULL;
}
/* }}} */
#endif
/* {{{ php_rar_process_context */
/* memory is to be managed externally */
static void php_rar_process_context(php_stream_context *context,
@@ -615,9 +578,6 @@ static void php_rar_process_context(php_stream_context *context,
zval **volume_cb TSRMLS_DC)
{
zval *ctx_opt;
#if PHP_MAJOR_VERSION < 7
zval **ctx_opt_p = NULL;
#endif
assert(context != NULL);
assert(open_password != NULL);
@@ -627,14 +587,8 @@ 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_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.");
@@ -642,14 +596,8 @@ static void php_rar_process_context(php_stream_context *context,
*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_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.");
@@ -657,19 +605,9 @@ static void php_rar_process_context(php_stream_context *context,
*file_password = Z_STRVAL_P(ctx_opt);
}
#if PHP_MAJOR_VERSION < 7
if (php_stream_context_get_option(context, "rar", "volume_callback",
&ctx_opt_p) == SUCCESS) {
ctx_opt = *ctx_opt_p;
#else
if ((ctx_opt = php_stream_context_get_option(
context, "rar", "volume_callback"))) {
#endif
#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
@@ -738,17 +676,19 @@ static int _rar_get_archive_and_fragment(php_stream_wrapper *wrapper,
if (!(options & STREAM_ASSUME_REALPATH)) {
if (options & USE_PATH) {
#if PHP_MAJOR_VERSION < 7
*archive = zend_resolve_path(tmp_archive, tmp_arch_len TSRMLS_CC);
#else
#if PHP_VERSION_ID < 80100
zend_string *arc_str = zend_resolve_path(tmp_archive, tmp_arch_len);
#else
zend_string *tmp_archive_str = zend_string_init_fast(tmp_archive, tmp_arch_len);
zend_string *arc_str = zend_resolve_path(tmp_archive_str);
zend_string_free(tmp_archive_str);
#endif
if (arc_str != NULL) {
*archive = estrndup(arc_str->val, arc_str->len);
} else {
*archive = NULL;
}
zend_string_release(arc_str);
#endif
}
if (*archive == NULL) {
if ((*archive = expand_filepath(tmp_archive, NULL TSRMLS_CC))
@@ -816,17 +756,10 @@ 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)
{
@@ -909,21 +842,23 @@ static php_stream *php_stream_rar_opener(php_stream_wrapper *wrapper,
{
/* no need to allocate a buffer bigger than the file uncomp size */
size_t buffer_size = (size_t)
MIN((uint64) RAR_CHUNK_BUFFER_SIZE,
INT32TO64(self->header_data.UnpSizeHigh,
self->header_data.UnpSize));
size_t file_size = INT32TO64(self->header_data.UnpSizeHigh,
self->header_data.UnpSize);
size_t buffer_size = MIN(
MAX(RAR_CHUNK_BUFFER_SIZE, self->header_data.WinSize),
file_size);
rar_result = RARProcessFileChunkInit(self->rar_handle);
if ((rar_error = _rar_error_to_string(rar_result)) != NULL) {
char *mb_entry = _rar_wide_to_utf_with_alloc(fragment, -1);
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC,
"Error opening file %s inside RAR archive %s: %s",
mb_entry, tmp_open_path, rar_error);
"Error opening file %s inside RAR archive %s: %s",
mb_entry, tmp_open_path, rar_error);
efree(mb_entry);
goto cleanup;
}
self->file_size = file_size;
self->buffer = emalloc(buffer_size);
self->buffer_size = buffer_size;
stream = php_stream_alloc(&php_stream_rario_ops, self, NULL, mode);
@@ -936,12 +871,8 @@ cleanup:
if (tmp_open_path != NULL) {
if (opened_path != NULL) {
#if PHP_MAJOR_VERSION < 7
*opened_path = tmp_open_path;
#else
*opened_path =
zend_string_init(tmp_open_path, strlen(tmp_open_path), 0);
#endif
} else {
efree(tmp_open_path);
}
@@ -997,11 +928,7 @@ static int _rar_get_cachable_rararch(php_stream_wrapper *wrapper,
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);
@@ -1027,7 +954,7 @@ static int _rar_get_cachable_rararch(php_stream_wrapper *wrapper,
int res;
const char *err_str;
if (_rar_get_file_resource_ex(rar_obj, rar, 1 TSRMLS_CC)
if (_rar_get_file_resource_zv_ex(rar_obj, rar, 1 TSRMLS_CC)
== FAILURE) {
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC,
"Bug: could not retrieve RarArchive object from zval");
@@ -1051,7 +978,7 @@ static int _rar_get_cachable_rararch(php_stream_wrapper *wrapper,
else { /* cache hit */
/* 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) {
if (_rar_get_file_resource_zv_ex(rar_obj, rar, 1 TSRMLS_CC) == FAILURE) {
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC,
"Bug: could not retrieve RarArchive object from zval");
goto cleanup;
@@ -1064,56 +991,26 @@ cleanup:
efree(cache_key);
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);
ZVAL_UNDEF(rar_obj);
#endif
}
return ret;
}
/* }}} */
/* {{{ _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)
{
if (wrapper) {
/* tidy up the error stack */
int i;
for (i = 0; i < wrapper->err_count; i++) {
efree(wrapper->err_stack[i]);
}
if (wrapper->err_stack) {
efree(wrapper->err_stack);
}
wrapper->err_stack = NULL;
wrapper->err_count = 0;
}
}
#else
/* {{{ _rar_stream_tidy_wrapper_error_log */
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)
@@ -1132,11 +1029,7 @@ static int php_stream_rar_stater(php_stream_wrapper *wrapper,
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) {
@@ -1187,11 +1080,7 @@ cleanup:
}
if (Z_TYPE(rararch) == IS_OBJECT) {
#if PHP_MAJOR_VERSION < 7
zval_dtor(&rararch);
#else
zval_ptr_dtor(&rararch);
#endif
}
if (state != NULL) {
_rar_entry_search_end(state);
@@ -1214,17 +1103,10 @@ cleanup:
/* {{{ php_stream_rar_dir_opener */
static php_stream *php_stream_rar_dir_opener(php_stream_wrapper *wrapper,
#if PHP_MAJOR_VERSION < 7
char *filename,
char *mode,
int options,
char **opened_path,
#else
const char *filename,
const char *mode,
int options,
zend_string **opened_path,
#endif
php_stream_context *context
STREAMS_DC TSRMLS_DC)
{
@@ -1323,12 +1205,8 @@ cleanup:
if (tmp_open_path != NULL) {
if (opened_path != NULL) {
#if PHP_MAJOR_VERSION < 7
*opened_path = tmp_open_path;
#else
*opened_path =
zend_string_init(tmp_open_path, strlen(tmp_open_path), 0);
#endif
} else {
efree(tmp_open_path);
}
@@ -1339,11 +1217,7 @@ cleanup:
if (stream == NULL) { /* failed */
if (self != 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);
#endif
}
if (self->directory != NULL) {
efree(self->directory);
@@ -1380,12 +1254,6 @@ php_stream_wrapper php_stream_rar_wrapper = {
/* end wrapper stuff }}} */
#endif /* HAVE_RAR */
#ifdef __cplusplus
}
#endif
/*
* Local variables:
* tab-width: 4

View File

@@ -1,7 +1,3 @@
#ifdef __cplusplus
extern "C" {
#endif
#include <php.h>
#include "php_rar.h"
@@ -57,7 +53,3 @@ int rar_dos_time_convert(unsigned dos_time, time_t *to) /* {{{ */
return SUCCESS;
}
/* }}} */
#ifdef __cplusplus
}
#endif

467
rararch.c
View File

@@ -27,39 +27,34 @@
/* $Id$ */
#ifdef __cplusplus
extern "C" {
#endif
#include "zend_types.h"
#include <zend_API.h>
#define _GNU_SOURCE
#ifndef _GNU_SOURCE
# define _GNU_SOURCE
#endif
#include <string.h>
#include <wchar.h>
#include <php.h>
#include <zend_interfaces.h>
#include "php_rar.h"
#include "php_compat.h"
/* {{{ Type definitions reserved for this translation unit */
/* clang-format off */
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;
/* clang-format on */
/* }}} */
/* {{{ Globals with internal linkage */
@@ -83,39 +78,46 @@ static zend_object_handlers rararch_object_handlers;
/* {{{ Function prototypes for functions with internal linkage */
static inline rar_obj_ref rar_obj_ref_fetch(zval *zv);
static inline void rar_obj_ref_make_zv(rar_obj_ref zo, zval *zv TSRMLS_DC);
#if PHP_MAJOR_VERSION >= 7
static inline ze_rararch_object *rararch_object_fetch(zend_object *zobj);
static ze_rararch_object *rararch_object_from_zv(const zval *zv);
static ze_rararch_object *rararch_object_from_ref(const rar_obj_ref ref);
static zend_object *rararch_ce_create_object(zend_class_entry *ce);
static void rararch_ce_free_object_storage(zend_object *zobj);
#else
#define rararch_object_from_zv zend_object_store_get_object
static zend_object_value rararch_ce_create_object(zend_class_entry *class_type TSRMLS_DC);
static void rararch_ce_free_object_storage(ze_rararch_object *object TSRMLS_DC);
#endif
/* }}} */
/* {{{ RarArchive handlers */
static int rararch_handlers_preamble(zval *object, rar_file_t **rar TSRMLS_DC);
static int rararch_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);
static int rararch_handlers_preamble(handler_this_t *object, rar_file_t **rar TSRMLS_DC);
static int rararch_dimensions_preamble(rar_file_t *rar, zval *offset, zend_long *index, int quiet TSRMLS_DC);
static int rararch_count_elements(handler_this_t *object, zend_long *count TSRMLS_DC);
static zval *rararch_read_dimension(handler_this_t *object, zval *offset, int type, zval *rv);
static void rararch_write_dimension(handler_this_t *object, zval *offset, zval *value TSRMLS_DC);
static int rararch_has_dimension(handler_this_t *object, zval *offset, int check_empty TSRMLS_DC);
/* }}} */
/* {{{ Function definitions with external linkage */
int _rar_get_file_resource(zval *zval_file, rar_file_t **rar_file TSRMLS_DC) /* {{{ */
int _rar_get_file_resource_zv(zval *zv, rar_file_t **rar_file TSRMLS_DC) /* {{{ */
{
return _rar_get_file_resource_ex(zval_file, rar_file, FALSE TSRMLS_CC);
return _rar_get_file_resource_ex(rar_obj_ref_fetch(zv),
rar_file, FALSE TSRMLS_CC);
}
int _rar_get_file_resource_zv_ex(zval *zv, rar_file_t **rar_file, int allow_closed TSRMLS_DC)
{
return _rar_get_file_resource_ex(rar_obj_ref_fetch(zv),
rar_file, allow_closed TSRMLS_CC);
}
/* }}} */
static int _rar_get_file_resource_handler(handler_this_t *thiz,
rar_file_t **rar_file TSRMLS_DC)
{
#if PHP_MAJOR_VERSION < 8
return _rar_get_file_resource_zv(thiz, rar_file TSRMLS_CC);
#else
return _rar_get_file_resource_ex(thiz, rar_file, FALSE);
#endif
}
/* Creates a RarArchive object, all three in args will be dupped */
int _rar_create_rararch_obj(const char* resolved_path,
const char* open_password,
@@ -181,20 +183,21 @@ void _rar_close_file_resource(rar_file_t *rar) /* {{{ */
/* When changed from resource to custom object, instead of fiddling
* with the refcount to force object destruction, an indication that
* the file is already closed is given by setting rar->arch_handle
* to NULL. This is checked by _rar_get_file_resource. */
* to NULL. This is checked by _rar_get_file_resource_zv. */
RARCloseArchive(rar->arch_handle);
rar->arch_handle = NULL;
}
/* }}} */
/* Receives archive zval, returns object struct.
* If silent is FALSE, it checks whether the archive is alredy closed, and if it
* If allow_closed is FALSE, it checks whether the archive is alredy closed, and if it
* is, an exception/error is raised and FAILURE is returned
*/
int _rar_get_file_resource_ex(zval *zval_file, rar_file_t **rar_file, int silent TSRMLS_DC) /* {{{ */
int _rar_get_file_resource_ex(rar_obj_ref zobjref_file, rar_file_t **rar_file,
int allow_closed TSRMLS_DC) /* {{{ */
{
ze_rararch_object *zobj;
zobj = rararch_object_from_zv(zval_file TSRMLS_CC);
zobj = rararch_object_from_ref(zobjref_file);
if (zobj == NULL) {
php_error_docref(NULL TSRMLS_CC, E_WARNING,
"Could not find object in the store. This is a bug, please report it.");
@@ -202,7 +205,7 @@ int _rar_get_file_resource_ex(zval *zval_file, rar_file_t **rar_file, int silent
}
*rar_file = zobj->rar_file;
if ((*rar_file)->arch_handle == NULL && !silent) { /* rar_close was called */
if ((*rar_file)->arch_handle == NULL && !allow_closed) { /* rar_close was called */
_rar_handle_ext_error("The archive is already closed" TSRMLS_CC);
return FAILURE;
}
@@ -234,25 +237,17 @@ static void _rar_raw_entries_to_array(rar_file_t *rar, zval *target TSRMLS_DC) /
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) */
* obj). Free the allocation. */
efree(entry_obj);
#endif
}
} while (state->eof == 0);
_rar_entry_search_end(state);
#if PHP_MAJOR_VERSION < 7
zval_dtor(&rararch_obj);
#else
zval_ptr_dtor(&rararch_obj);
#endif
}
/* }}} */
#if PHP_MAJOR_VERSION >=7
static inline rar_obj_ref rar_obj_ref_fetch(zval *zv)
{
return Z_OBJ(*zv);
@@ -262,24 +257,7 @@ 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 *)
@@ -289,35 +267,12 @@ static ze_rararch_object *rararch_object_from_zv(const zval *zv)
{
return rararch_object_fetch(Z_OBJ_P(zv));
}
#endif
static ze_rararch_object *rararch_object_from_ref(const rar_obj_ref ref)
{
return rararch_object_fetch(ref);
}
/* {{{ */
#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;
zobj = emalloc(sizeof *zobj);
/* rararch_ce_free_object_storage will attempt to access it otherwise */
zobj->rar_file = NULL;
zend_object_std_init((zend_object*) zobj, class_type TSRMLS_CC);
#if PHP_VERSION_ID < 50399
zend_hash_copy(((zend_object*)zobj)->properties,
&(class_type->default_properties),
(copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval*));
#else
object_properties_init((zend_object*)zobj, class_type);
#endif
zov.handle = zend_objects_store_put(zobj,
(zend_objects_store_dtor_t) zend_objects_destroy_object,
(zend_objects_free_object_storage_t) rararch_ce_free_object_storage,
NULL TSRMLS_CC);
zov.handlers = &rararch_object_handlers;
return zov;
}
#else
static zend_object *rararch_ce_create_object(zend_class_entry *ce)
{
ze_rararch_object *zobj =
@@ -329,18 +284,12 @@ static zend_object *rararch_ce_create_object(zend_class_entry *ce)
return &zobj->parent;
}
#endif
/* }}} */
/* {{{ */
#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() */
@@ -364,20 +313,18 @@ static void rararch_ce_free_object_storage(zend_object *zobj)
/* could call zend_objects_free_object_storage here (not before!), but
* instead I'll mimic its behaviour */
zend_object_std_dtor(&object->parent TSRMLS_CC);
#if PHP_MAJOR_VERSION < 7
efree(object);
#endif
}
/* }}} */
/* }}} */
/* {{{ RarArchive handlers */
static int rararch_handlers_preamble(zval *object, rar_file_t **rar TSRMLS_DC) /* {{{ */
static int rararch_handlers_preamble(handler_this_t *object,
rar_file_t **rar TSRMLS_DC) /* {{{ */
{
/* don't call zend_objects_get_address or zend_object_store_get directly;
* _rar_get_file_resource checks if the archive was closed */
if (_rar_get_file_resource(object, rar TSRMLS_CC) == FAILURE) {
* _rar_get_file_resource_zv checks if the archive was closed */
if (_rar_get_file_resource_handler(object, rar TSRMLS_CC) == FAILURE) {
return FAILURE;
}
@@ -391,7 +338,7 @@ static int rararch_handlers_preamble(zval *object, rar_file_t **rar TSRMLS_DC) /
/* {{{ rararch_dimensions_preamble - semi-strict parsing of int argument */
static int rararch_dimensions_preamble(rar_file_t *rar,
zval *offset,
long *index,
zend_long *index,
int quiet TSRMLS_DC)
{
if (offset == NULL) {
@@ -415,34 +362,32 @@ static int rararch_dimensions_preamble(rar_file_t *rar,
return FAILURE;
}
else if (type == IS_DOUBLE) {
if (d > LONG_MAX || d < LONG_MIN) {
if (d > (double) ZEND_LONG_MAX || d < (double) ZEND_LONG_MIN) {
RAR_DOCREF_IF_UNQUIET(NULL TSRMLS_CC, E_WARNING,
"Dimension index is out of integer bounds");
return FAILURE;
}
*index = (long) d;
*index = (zend_long) d;
}
}
else if (Z_TYPE_P(offset) == IS_DOUBLE) {
if (Z_DVAL_P(offset) > LONG_MAX || Z_DVAL_P(offset) < LONG_MIN) {
if (Z_DVAL_P(offset) > (double) ZEND_LONG_MAX ||
Z_DVAL_P(offset) < (double) ZEND_LONG_MIN) {
RAR_DOCREF_IF_UNQUIET(NULL TSRMLS_CC, E_WARNING,
"Dimension index is out of integer bounds");
return FAILURE;
}
*index = (long) Z_DVAL_P(offset);
*index = (zend_long) Z_DVAL_P(offset);
}
else if (Z_TYPE_P(offset) == IS_OBJECT) {
#if PHP_MAJOR_VERSION < 8
if (Z_OBJ_HT_P(offset)->get) {
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);
@@ -455,12 +400,28 @@ static int rararch_dimensions_preamble(rar_file_t *rar,
ret = rararch_dimensions_preamble(rar, newoffset, index, quiet
TSRMLS_CC);
#if PHP_MAJOR_VERSION < 7
zval_ptr_dtor(&newoffset);
#else
zval_ptr_dtor(newoffset);
#endif
return ret;
} else
#endif // PHP < 8
if (Z_OBJ_HT_P(offset)->cast_object) {
zval newoffset;
int res = Z_OBJ_HT_P(offset)->cast_object(
ZV_TO_THIS_FOR_HANDLER(offset), &newoffset, IS_LONG TSRMLS_CC);
if (res == FAILURE) {
RAR_DOCREF_IF_UNQUIET(NULL TSRMLS_CC, E_WARNING,
"Could not convert object given as dimension index into "
"an integer (cast_object failed)");
return FAILURE;
}
if (Z_TYPE(newoffset) != IS_LONG) {
zval_dtor(&newoffset);
RAR_DOCREF_IF_UNQUIET(NULL TSRMLS_CC, E_WARNING,
"Could not convert object given as dimension index into "
"an integer (cast_object did not return int as asked)");
return FAILURE;
}
*index = Z_LVAL(newoffset);
}
else {
RAR_DOCREF_IF_UNQUIET(NULL TSRMLS_CC, E_WARNING,
@@ -476,9 +437,9 @@ static int rararch_dimensions_preamble(rar_file_t *rar,
return FAILURE;
}
if (*index < 0L) {
if (*index < 0) {
RAR_DOCREF_IF_UNQUIET(NULL TSRMLS_CC, E_WARNING,
"Dimension index must be non-negative, given %ld", *index);
"Dimension index must be non-negative, given " ZEND_LONG_FMT, *index);
return FAILURE;
}
if ((size_t) *index >= _rar_entry_count(rar)) {
@@ -493,34 +454,30 @@ 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(handler_this_t *object, zend_long *count TSRMLS_DC)
{
rar_file_t *rar = NULL;
size_t entry_count;
if (rararch_handlers_preamble(object, &rar TSRMLS_CC) == FAILURE) {
*count = 0L;
*count = 0;
return SUCCESS; /* intentional */
}
entry_count = _rar_entry_count(rar);
if (entry_count > LONG_MAX)
entry_count = (size_t) LONG_MAX;
if (entry_count > ZEND_LONG_MAX)
entry_count = (size_t) ZEND_LONG_MAX;
*count = (long) entry_count;
*count = (zend_long) entry_count;
return SUCCESS;
}
/* }}} */
/* {{{ RarArchive read_dimension handler */
#if PHP_MAJOR_VERSION < 7
static zval *rararch_read_dimension(zval *object, zval *offset, int type TSRMLS_DC)
#else
static zval *rararch_read_dimension(zval *object, zval *offset, int type, zval *rv)
#endif
static zval *rararch_read_dimension(handler_this_t *object, zval *offset, int type, zval *rv)
{
long index;
zend_long index;
rar_file_t *rar = NULL;
struct _rar_find_output *out;
zval *ret = NULL;
@@ -541,23 +498,24 @@ static zval *rararch_read_dimension(zval *object, zval *offset, int type, zval *
_rar_entry_search_seek(out, (size_t) index);
_rar_entry_search_advance(out, NULL, 0, 0);
assert(out->found);
#if PHP_MAJOR_VERSION < 7
ALLOC_INIT_ZVAL(ret);
#else
ret = rv;
#endif
#if PHP_MAJOR_VERSION >= 8
zval object_zv;
ZVAL_OBJ(&object_zv, object);
_rar_entry_to_zval(&object_zv, out->header, out->packed_size, out->position,
ret TSRMLS_CC);
#else
_rar_entry_to_zval(object, out->header, out->packed_size, out->position,
ret TSRMLS_CC);
_rar_entry_search_end(out);
#if PHP_MAJOR_VERSION < 7
Z_DELREF_P(ret); /* set refcount to 0 */
#endif
_rar_entry_search_end(out);
return ret;
}
/* }}} */
/* {{{ RarArchive write_dimension handler */
static void rararch_write_dimension(zval *object, zval *offset, zval *value TSRMLS_DC)
static void rararch_write_dimension(handler_this_t *object, zval *offset, zval *value TSRMLS_DC)
{
php_error_docref(NULL TSRMLS_CC, E_ERROR,
"A RarArchive object is not writable");
@@ -565,9 +523,9 @@ static void rararch_write_dimension(zval *object, zval *offset, zval *value TSRM
/* }}} */
/* {{{ RarArchive has_dimension handler */
static int rararch_has_dimension(zval *object, zval *offset, int check_empty TSRMLS_DC)
static int rararch_has_dimension(handler_this_t *object, zval *offset, int check_empty TSRMLS_DC)
{
long index;
zend_long index;
rar_file_t *rar = NULL;
(void) check_empty; /* don't care */
@@ -582,7 +540,7 @@ static int rararch_has_dimension(zval *object, zval *offset, int check_empty TSR
/* }}} */
/* {{{ RarArchive unset_dimension handler */
static void rararch_unset_dimension(zval *object, zval *offset TSRMLS_DC)
static void rararch_unset_dimension(handler_this_t *object, zval *offset TSRMLS_DC)
{
php_error_docref(NULL TSRMLS_CC, E_ERROR,
"A RarArchive object is not writable");
@@ -622,11 +580,7 @@ PHP_FUNCTION(rar_open)
assert(strnlen(resolved_path, MAXPATHLEN) < MAXPATHLEN);
if (callable != NULL) { /* given volume resolver callback */
#if PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION == 2
if (!zend_is_callable(callable, IS_CALLABLE_STRICT, NULL)) {
#else
if (!zend_is_callable(callable, IS_CALLABLE_STRICT, NULL TSRMLS_CC)) {
#endif
_rar_handle_ext_error("%s" TSRMLS_CC, "Expected the third "
"argument, if provided, to be a valid callback");
RETURN_FALSE;
@@ -661,7 +615,7 @@ PHP_FUNCTION(rar_list)
RAR_THIS_OR_NO_ARGS(file);
if (_rar_get_file_resource(file, &rar TSRMLS_CC) == FAILURE) {
if (_rar_get_file_resource_zv(file, &rar TSRMLS_CC) == FAILURE) {
RETURN_FALSE;
}
@@ -696,7 +650,7 @@ PHP_FUNCTION(rar_entry_get)
return;
}
if (_rar_get_file_resource(file, &rar TSRMLS_CC) == FAILURE) {
if (_rar_get_file_resource_zv(file, &rar TSRMLS_CC) == FAILURE) {
RETURN_FALSE;
}
@@ -733,7 +687,7 @@ PHP_FUNCTION(rar_solid_is)
RAR_THIS_OR_NO_ARGS(file);
if (_rar_get_file_resource(file, &rar TSRMLS_CC) == FAILURE) {
if (_rar_get_file_resource_zv(file, &rar TSRMLS_CC) == FAILURE) {
RETURN_FALSE;
}
@@ -751,7 +705,7 @@ PHP_FUNCTION(rar_comment_get)
RAR_THIS_OR_NO_ARGS(file);
if (_rar_get_file_resource(file, &rar TSRMLS_CC) == FAILURE) {
if (_rar_get_file_resource_zv(file, &rar TSRMLS_CC) == FAILURE) {
RETURN_FALSE;
}
@@ -782,7 +736,7 @@ PHP_FUNCTION(rar_broken_is)
RAR_THIS_OR_NO_ARGS(file);
if (_rar_get_file_resource(file, &rar TSRMLS_CC) == FAILURE) {
if (_rar_get_file_resource_zv(file, &rar TSRMLS_CC) == FAILURE) {
RETURN_FALSE;
}
@@ -813,7 +767,7 @@ PHP_FUNCTION(rar_allow_broken_set)
return;
}
if (_rar_get_file_resource(file, &rar TSRMLS_CC) == FAILURE) {
if (_rar_get_file_resource_zv(file, &rar TSRMLS_CC) == FAILURE) {
RETURN_FALSE;
}
@@ -831,7 +785,7 @@ PHP_FUNCTION(rar_close)
RAR_THIS_OR_NO_ARGS(file);
if (_rar_get_file_resource(file, &rar TSRMLS_CC) == FAILURE) {
if (_rar_get_file_resource_zv(file, &rar TSRMLS_CC) == FAILURE) {
RETURN_FALSE;
}
@@ -855,7 +809,8 @@ PHP_METHOD(rararch, __toString)
RAR_RETNULL_ON_ARGS();
if (_rar_get_file_resource_ex(arch_obj, &rar, TRUE TSRMLS_CC) == FAILURE) {
if (_rar_get_file_resource_zv_ex(arch_obj, &rar, TRUE TSRMLS_CC)
== FAILURE) {
RETURN_FALSE; /* should never happen */
}
@@ -876,6 +831,18 @@ PHP_METHOD(rararch, __toString)
}
/* }}} */
/* {{{ proto string RarEntry::getIterator() */
#if PHP_MAJOR_VERSION >= 8
PHP_METHOD(rararch, getIterator)
{
if (zend_parse_parameters_none() == FAILURE) {
return;
}
zend_create_internal_iterator_zval(return_value, getThis());
}
#endif
/* }}} */
/* {{{ arginfo */
ZEND_BEGIN_ARG_INFO_EX(arginfo_rararchive_open, 0, 0, 1)
ZEND_ARG_INFO(0, filename)
@@ -891,10 +858,23 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_rararchive_setallowbroken, 0, 0, 1)
ZEND_ARG_INFO(0, allow_broken)
ZEND_END_ARG_INFO()
#if PHP_MAJOR_VERSION >= 8
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_rararchive_getiterator, 0, 0, Traversable, 0)
ZEND_END_ARG_INFO()
#endif
ZEND_BEGIN_ARG_INFO(arginfo_rararchive_void, 0)
ZEND_END_ARG_INFO()
#if PHP_VERSION_ID >= 80200
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_rararchive_tostring, 0, 0, IS_STRING, 0)
ZEND_END_ARG_INFO()
#else
#define arginfo_rararchive_tostring arginfo_rararchive_void
#endif
/* }}} */
/* clang-format off */
static zend_function_entry php_rararch_class_functions[] = {
PHP_ME_MAPPING(open, rar_open, arginfo_rararchive_open, ZEND_ACC_STATIC | ZEND_ACC_PUBLIC)
PHP_ME_MAPPING(getEntries, rar_list, arginfo_rararchive_void, ZEND_ACC_PUBLIC)
@@ -907,10 +887,14 @@ static zend_function_entry php_rararch_class_functions[] = {
PHP_ME_MAPPING(isBroken, rar_broken_is, arginfo_rararchive_void, ZEND_ACC_PUBLIC)
PHP_ME_MAPPING(setAllowBroken, rar_allow_broken_set, arginfo_rararchive_setallowbroken, ZEND_ACC_PUBLIC)
PHP_ME_MAPPING(close, rar_close, arginfo_rararchive_void, ZEND_ACC_PUBLIC)
PHP_ME(rararch, __toString, arginfo_rararchive_void, ZEND_ACC_PUBLIC)
PHP_ME(rararch, __toString, arginfo_rararchive_tostring, ZEND_ACC_PUBLIC)
PHP_ME_MAPPING(__construct, rar_bogus_ctor, arginfo_rararchive_void, ZEND_ACC_PRIVATE | ZEND_ACC_CTOR)
#if PHP_MAJOR_VERSION >= 8
PHP_ME(rararch, getIterator, arginfo_rararchive_getiterator, ZEND_ACC_PUBLIC)
#endif
{NULL, NULL, NULL}
};
/* clang-format on */
/* {{{ Iteration. Very boring stuff indeed. */
@@ -922,78 +906,17 @@ static zend_object_iterator *rararch_it_get_iterator(zend_class_entry *ce,
static void rararch_it_dtor(zend_object_iterator *iter TSRMLS_DC);
static void rararch_it_fetch(rararch_iterator *it TSRMLS_DC);
static int rararch_it_valid(zend_object_iterator *iter TSRMLS_DC);
#if PHP_MAJOR_VERSION < 7
static void rararch_it_current_data(zend_object_iterator *iter,
zval ***data TSRMLS_DC);
#else
static zval *rararch_it_current_data(zend_object_iterator *iter);
#endif
static void rararch_it_move_forward(zend_object_iterator *iter TSRMLS_DC);
static void rararch_it_rewind(zend_object_iterator *iter TSRMLS_DC);
/* }}} */
/* {{{ rararch_it_get_iterator */
static zend_object_iterator *rararch_it_get_iterator(zend_class_entry *ce,
zval *object,
int by_ref TSRMLS_DC)
{
rararch_iterator *it;
rar_file_t *rar;
int res;
if (by_ref) {
php_error_docref(NULL TSRMLS_CC, E_ERROR,
"An iterator cannot be used with foreach by reference");
}
it = emalloc(sizeof *it);
#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,
"Cannot fetch RarArchive object");
if (rar->arch_handle == NULL)
php_error_docref(NULL TSRMLS_CC, E_ERROR,
"The archive is already closed, cannot give an iterator");
res = _rar_list_files(rar TSRMLS_CC);
if (_rar_handle_error(res TSRMLS_CC) == FAILURE) {
/* if it failed, do not expose the possibly incomplete entry list */
it->empty_iterator = 1;
}
else
it->empty_iterator = 0;
_rar_entry_search_start(rar, RAR_SEARCH_TRAVERSE, &it->state TSRMLS_CC);
return (zend_object_iterator*) it;
}
/* }}} */
/* {{{ rararch_it_invalidate_current */
static void rararch_it_invalidate_current(zend_object_iterator *iter TSRMLS_DC)
{
rararch_iterator *it = (rararch_iterator *) iter;
#if PHP_MAJOR_VERSION < 7
if (it->value != NULL) {
zval_ptr_dtor(&it->value);
it->value = NULL;
}
#else
zval_ptr_dtor(&it->value);
ZVAL_UNDEF(&it->value);
#endif
}
/* }}} */
@@ -1004,16 +927,9 @@ static void rararch_it_dtor(zend_object_iterator *iter TSRMLS_DC)
rararch_it_invalidate_current((zend_object_iterator *) it TSRMLS_CC);
#if PHP_MAJOR_VERSION < 7
zval_ptr_dtor((zval**) &it->parent.data); /* decrease refcount on zval object */
#else
zval_ptr_dtor(&it->parent.data);
#endif
_rar_entry_search_end(it->state);
#if PHP_MAJOR_VERSION < 7
efree(it);
#endif
}
/* }}} */
@@ -1024,91 +940,47 @@ static void rararch_it_fetch(rararch_iterator *it TSRMLS_DC)
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;
}
#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);
res = _rar_get_file_resource_zv_ex(robj, &rar_file, 1 TSRMLS_CC);
if (res == FAILURE)
php_error_docref(NULL TSRMLS_CC, E_ERROR,
"Cannot fetch RarArchive object");
_rar_entry_search_advance(it->state, NULL, 0, 0);
#if PHP_MAJOR_VERSION < 7
MAKE_STD_ZVAL(it->value);
if (it->state->found)
_rar_entry_to_zval(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)
{
zval **value = &(((rararch_iterator *) iter)->value);
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 */
@@ -1116,11 +988,7 @@ 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);
}
/* }}} */
@@ -1147,6 +1015,55 @@ static zend_object_iterator_funcs rararch_it_funcs = {
};
/* }}} */
/* {{{ rararch_it_get_iterator */
static zend_object_iterator *rararch_it_get_iterator(zend_class_entry *ce,
zval *object,
int by_ref TSRMLS_DC)
{
rar_file_t *rar;
int res;
if (by_ref) {
php_error_docref(NULL TSRMLS_CC, E_ERROR,
"An iterator cannot be used with foreach by reference");
}
res = _rar_get_file_resource_zv_ex(object, &rar, 1 TSRMLS_CC);
if (res == FAILURE) {
php_error_docref(NULL TSRMLS_CC, E_ERROR,
"Cannot fetch RarArchive object");
}
if (rar->arch_handle == NULL) {
php_error_docref(NULL TSRMLS_CC, E_ERROR,
"The archive is already closed, cannot give an iterator");
}
rararch_iterator *it = emalloc(sizeof *it);
zend_iterator_init((zend_object_iterator *) it);
ZVAL_COPY(&it->parent.data, object);
ZVAL_UNDEF(&it->value);
#if PHP_VERSION_ID < 70300
it->parent.funcs = ce->iterator_funcs.funcs;
#else
it->parent.funcs = &rararch_it_funcs;
#endif
it->state = NULL;
res = _rar_list_files(rar TSRMLS_CC);
if (_rar_handle_error(res TSRMLS_CC) == FAILURE) {
/* if it failed, do not expose the possibly incomplete entry list */
it->empty_iterator = 1;
}
else
it->empty_iterator = 0;
_rar_entry_search_start(rar, RAR_SEARCH_TRAVERSE, &it->state TSRMLS_CC);
return (zend_object_iterator*) it;
}
/* }}} */
void minit_rararch(TSRMLS_D)
{
zend_class_entry ce;
@@ -1159,10 +1076,8 @@ void minit_rararch(TSRMLS_D)
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);
@@ -1170,10 +1085,12 @@ void minit_rararch(TSRMLS_D)
rararch_ce_ptr->clone = NULL;
rararch_ce_ptr->create_object = &rararch_ce_create_object;
rararch_ce_ptr->get_iterator = rararch_it_get_iterator;
#if PHP_VERSION_ID < 70300
rararch_ce_ptr->iterator_funcs.funcs = &rararch_it_funcs;
zend_class_implements(rararch_ce_ptr TSRMLS_CC, 1, zend_ce_traversable);
}
#ifdef __cplusplus
}
#endif
#if PHP_MAJOR_VERSION >= 8
zend_class_implements(rararch_ce_ptr TSRMLS_CC, 1, zend_ce_aggregate);
#else
zend_class_implements(rararch_ce_ptr TSRMLS_CC, 1, zend_ce_traversable);
#endif
}

View File

@@ -27,11 +27,10 @@
/* $Id$ */
#ifdef __cplusplus
extern "C" {
#include <zend_types.h>
#ifndef _GNU_SOURCE
# define _GNU_SOURCE
#endif
#define _GNU_SOURCE
#include <string.h>
#include <php.h>
@@ -52,49 +51,44 @@ 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 */
/* parent is zval to RarArchive object. The object (not the zval, in PHP 5.x)
/* parent is zval to RarArchive object. The object
* will have its refcount increased */
void _rar_entry_to_zval(zval *parent,
struct RARHeaderDataEx *entry,
unsigned long packed_size,
zend_ulong packed_size,
size_t position,
zval *object TSRMLS_DC) /* {{{ */
zval *object TSRMLS_DC)
/* {{{ */
{
char tmp_s [MAX_LENGTH_OF_LONG + 1];
char time[50];
char *filename;
int filename_size,
filename_len;
long unp_size; /* zval stores PHP ints as long, so use that here */
zend_long unp_size;
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",
#if PHP_MAJOR_VERSION >= 8
zend_object *obj = Z_OBJ_P(object);
#else
zval *obj = object;
#endif
zend_update_property(rar_class_entry_ptr, obj, "rarfile",
sizeof("rararch") - 1, parent_copy TSRMLS_CC);
#if ULONG_MAX > 0xffffffffUL
unp_size = ((long) entry->UnpSize) + (((long) entry->UnpSizeHigh) << 32);
#else
/* for 32-bit long, at least don't give negative values */
if ((unsigned long) entry->UnpSize > (unsigned long) LONG_MAX
|| entry->UnpSizeHigh != 0)
unp_size = LONG_MAX;
else
unp_size = (long) entry->UnpSize;
#endif
{
uint64_t raw_size = (uint64_t)entry->UnpSizeHigh << 32 | entry->UnpSize;
unp_size = raw_size > (uint64_t)ZEND_LONG_MAX
? ZEND_LONG_MAX : (zend_long)raw_size;
}
filename_size = sizeof(entry->FileNameW) * 4;
filename = (char*) emalloc(filename_size);
if (packed_size > (unsigned long) LONG_MAX)
packed_size = LONG_MAX;
if (packed_size > (zend_ulong) ZEND_LONG_MAX)
packed_size = (zend_ulong) ZEND_LONG_MAX;
_rar_wide_to_utf(entry->FileNameW, filename, filename_size);
/* OK; safe usage below: */
filename_len = _rar_strnlen(filename, filename_size);
@@ -102,42 +96,42 @@ void _rar_entry_to_zval(zval *parent,
* properties from here with add_property_x, or
* direct call to rarentry_object_handlers.write_property
* zend_update_property_x updates the scope accordingly */
zend_update_property_long(rar_class_entry_ptr, object, "position",
sizeof("position") - 1, (long) position TSRMLS_CC);
zend_update_property_stringl(rar_class_entry_ptr, object, "name",
zend_update_property_long(rar_class_entry_ptr, obj, "position",
sizeof("position") - 1, (zend_long) position TSRMLS_CC);
zend_update_property_stringl(rar_class_entry_ptr, obj, "name",
sizeof("name") - 1, filename, filename_len TSRMLS_CC);
zend_update_property_long(rar_class_entry_ptr, object, "unpacked_size",
zend_update_property_long(rar_class_entry_ptr, obj, "unpacked_size",
sizeof("unpacked_size") - 1, unp_size TSRMLS_CC);
zend_update_property_long(rar_class_entry_ptr, object, "packed_size",
zend_update_property_long(rar_class_entry_ptr, obj, "packed_size",
sizeof("packed_size") - 1, packed_size TSRMLS_CC);
zend_update_property_long(rar_class_entry_ptr, object, "host_os",
zend_update_property_long(rar_class_entry_ptr, obj, "host_os",
sizeof("host_os") - 1, entry->HostOS TSRMLS_CC);
_rar_dos_date_to_text(entry->FileTime, time);
zend_update_property_string(rar_class_entry_ptr, object, "file_time",
zend_update_property_string(rar_class_entry_ptr, obj, "file_time",
sizeof("file_time") - 1, time TSRMLS_CC);
sprintf(tmp_s, "%x", entry->FileCRC);
zend_update_property_string(rar_class_entry_ptr, object, "crc",
zend_update_property_string(rar_class_entry_ptr, obj, "crc",
sizeof("crc") - 1, tmp_s TSRMLS_CC);
zend_update_property_long(rar_class_entry_ptr, object, "attr",
zend_update_property_long(rar_class_entry_ptr, obj, "attr",
sizeof("attr") - 1, entry->FileAttr TSRMLS_CC);
zend_update_property_long(rar_class_entry_ptr, object, "version",
zend_update_property_long(rar_class_entry_ptr, obj, "version",
sizeof("version") - 1, entry->UnpVer TSRMLS_CC);
zend_update_property_long(rar_class_entry_ptr, object, "method",
zend_update_property_long(rar_class_entry_ptr, obj, "method",
sizeof("method") - 1, entry->Method TSRMLS_CC);
zend_update_property_long(rar_class_entry_ptr, object, "flags",
zend_update_property_long(rar_class_entry_ptr, obj, "flags",
sizeof("flags") - 1, entry->Flags TSRMLS_CC);
zend_update_property_long(rar_class_entry_ptr, object, "redir_type",
zend_update_property_long(rar_class_entry_ptr, obj, "redir_type",
sizeof("redir_type") - 1, entry->RedirType TSRMLS_CC);
if (entry->RedirName) {
char *redir_target = NULL;
size_t redir_target_size;
zend_update_property_bool(rar_class_entry_ptr, object,
zend_update_property_bool(rar_class_entry_ptr, obj,
"redir_to_directory", sizeof("redir_to_directory") - 1,
!!entry->DirTarget TSRMLS_CC);
@@ -146,7 +140,7 @@ void _rar_entry_to_zval(zval *parent,
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",
zend_update_property_string(rar_class_entry_ptr, obj, "redir_target",
sizeof("redir_target") - 1, redir_target TSRMLS_CC);
efree(redir_target);
@@ -170,7 +164,7 @@ void _rar_entry_to_zval(zval *parent,
#define REG_RAR_CLASS_CONST_LONG(const_name, value) \
zend_declare_class_constant_long(rar_class_entry_ptr, const_name, \
sizeof(const_name) - 1, (long) value TSRMLS_CC)
sizeof(const_name) - 1, (zend_long) value TSRMLS_CC)
#define REG_RAR_PROPERTY(name, comment) \
_rar_decl_priv_prop_null(rar_class_entry_ptr, name, sizeof(name) -1, \
@@ -180,13 +174,6 @@ 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;
@@ -195,29 +182,32 @@ static int _rar_decl_priv_prop_null(zend_class_entry *ce, const char *name,
ZVAL_NULL(&property);
name_str = zend_string_init(name, (size_t) name_length, 1);
doc_str = zend_string_init(doc_comment, (size_t) doc_comment_len, 1);
# if PHP_MAJOR_VERSION >= 8
zend_declare_property_ex(ce, name_str, &property, ZEND_ACC_PRIVATE,
doc_str);
ret = SUCCESS;
# else
ret = zend_declare_property_ex(ce, name_str, &property, ZEND_ACC_PRIVATE,
doc_str);
#endif
zend_string_release(name_str);
zend_string_release(doc_str);
return ret;
#endif
}
/* }}} */
static zval *_rar_entry_get_property(zval *entry_obj, char *name, int namelen TSRMLS_DC) /* {{{ */
{
zval *tmp;
#if PHP_MAJOR_VERSION >= 7
zval zv;
#endif
#if PHP_VERSION_ID < 70100
zend_class_entry *orig_scope = EG(scope);
EG(scope) = rar_class_entry_ptr;
#endif
#if PHP_MAJOR_VERSION < 7
tmp = zend_read_property(Z_OBJCE_P(entry_obj), entry_obj, name, namelen, 1 TSRMLS_CC);
#if PHP_MAJOR_VERSION >= 8
tmp = zend_read_property(Z_OBJCE_P(entry_obj), Z_OBJ_P(entry_obj), name, namelen, 1, &zv);
#else
tmp = zend_read_property(Z_OBJCE_P(entry_obj), entry_obj, name, namelen, 1, &zv);
#endif
@@ -255,8 +245,8 @@ static void _rar_dos_date_to_text(unsigned dos_time, char *date_string) /* {{{ *
/* }}} */
/* {{{ Methods */
/* {{{ proto bool RarEntry::extract(string dir [, string filepath = ''
[, string password = NULL [, bool extended_data = FALSE]])
/* {{{ public function extract(?string $dir, ?string $filepath = '',
?string $password = null, bool $extended_data = false): void {}
Extract file from the archive */
PHP_METHOD(rarentry, extract)
{ /* lots of variables, but no need to be intimidated */
@@ -275,7 +265,7 @@ PHP_METHOD(rarentry, extract)
*tmp_position;
rar_file_t *rar = NULL;
zval *entry_obj = getThis();
struct RARHeaderDataEx entry;
struct RARHeaderDataEx entry = {0};
HANDLE extract_handle = NULL;
int result;
int found;
@@ -283,14 +273,14 @@ PHP_METHOD(rarentry, extract)
* password that's different from the one stored in the rar_file_t object*/
rar_cb_user_data cb_udata = {NULL};
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ss!b", &dir,
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s!|s!s!b", &dir,
&dir_len, &filepath, &filepath_len, &password, &password_len,
&process_ed) == FAILURE ) {
return;
}
RAR_GET_PROPERTY(tmp, "rarfile");
if (_rar_get_file_resource(tmp, &rar TSRMLS_CC) == FAILURE) {
if (_rar_get_file_resource_zv(tmp, &rar TSRMLS_CC) == FAILURE) {
RETURN_FALSE;
}
@@ -544,7 +534,7 @@ PHP_METHOD(rarentry, getStream)
RAR_GET_PROPERTY(position, "position");
RAR_GET_PROPERTY(tmp, "rarfile");
if (_rar_get_file_resource(tmp, &rar TSRMLS_CC) == FAILURE) {
if (_rar_get_file_resource_zv(tmp, &rar TSRMLS_CC) == FAILURE) {
RETURN_FALSE;
}
@@ -571,7 +561,7 @@ PHP_METHOD(rarentry, isDirectory)
{
zval *tmp;
zval *entry_obj = getThis();
long flags;
zend_long flags;
int is_dir;
RAR_RETNULL_ON_ARGS();
@@ -590,7 +580,7 @@ PHP_METHOD(rarentry, isEncrypted)
{
zval *tmp;
zval *entry_obj = getThis();
long flags;
zend_long flags;
int is_encrypted;
RAR_RETNULL_ON_ARGS();
@@ -699,12 +689,21 @@ PHP_METHOD(rarentry, __toString)
/* }}} */
/* {{{ arginfo */
#if PHP_MAJOR_VERSION < 8
ZEND_BEGIN_ARG_INFO_EX(arginfo_rarentry_extract, 0, 0, 1)
ZEND_ARG_INFO(0, path)
ZEND_ARG_INFO(0, filename)
ZEND_ARG_INFO(0, password)
ZEND_ARG_INFO(0, extended_data)
ZEND_END_ARG_INFO()
#else
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_rarentry_extract, 0, 1, _IS_BOOL, 0)
ZEND_ARG_TYPE_INFO(0, dir, IS_STRING, 1)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, filepath, IS_STRING, 1, "\'\'")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, password, IS_STRING, 1, "null")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, extended_data, _IS_BOOL, 0, "false")
ZEND_END_ARG_INFO()
#endif
ZEND_BEGIN_ARG_INFO_EX(arginfo_rarentry_getstream, 0, 0, 0)
ZEND_ARG_INFO(0, password)
@@ -712,8 +711,16 @@ ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO(arginfo_rar_void, 0)
ZEND_END_ARG_INFO()
#if PHP_VERSION_ID >= 80200
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_rar_tostring, 0, 0, IS_STRING, 0)
ZEND_END_ARG_INFO()
#else
#define arginfo_rar_tostring arginfo_rar_void
#endif
/* }}} */
/* clang-format off */
static zend_function_entry php_rar_class_functions[] = {
PHP_ME(rarentry, extract, arginfo_rarentry_extract, ZEND_ACC_PUBLIC)
PHP_ME(rarentry, getPosition, arginfo_rar_void, ZEND_ACC_PUBLIC)
@@ -732,10 +739,11 @@ static zend_function_entry php_rar_class_functions[] = {
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(rarentry, __toString, arginfo_rar_tostring, ZEND_ACC_PUBLIC)
PHP_ME_MAPPING(__construct, rar_bogus_ctor, arginfo_rar_void, ZEND_ACC_PRIVATE | ZEND_ACC_CTOR)
{NULL, NULL, NULL}
};
/* clang-format on */
void minit_rarentry(TSRMLS_D)
{
@@ -762,6 +770,7 @@ void minit_rarentry(TSRMLS_D)
REG_RAR_PROPERTY("redir_to_directory", "Whether the redirection target is a directory");
REG_RAR_PROPERTY("redir_target", "Target of the redirectory");
/* clang-format off */
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);
@@ -813,8 +822,5 @@ void minit_rarentry(TSRMLS_D)
REG_RAR_CLASS_CONST_LONG("ATTRIBUTE_UNIX_REGULAR_FILE", 0x08000L);
REG_RAR_CLASS_CONST_LONG("ATTRIBUTE_UNIX_SYM_LINK", 0x0A000L);
REG_RAR_CLASS_CONST_LONG("ATTRIBUTE_UNIX_SOCKET", 0x0C000L);
/* clang-format on */
}
#ifdef __cplusplus
}
#endif

3797
run-tests-rar.php Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -5,6 +5,7 @@ rar_list() function
--FILE--
<?php
require __DIR__ . "/php8compat.php.inc";
$rar_file1 = rar_open(dirname(__FILE__).'/linux_rar.rar');
$list1 = rar_list($rar_file1);
var_dump($list1);
@@ -14,8 +15,7 @@ $list2 = rar_list($rar_file2);
var_dump($list2);
$rar_file3 = rar_open(dirname(__FILE__).'/no_such_file.rar');
$list3 = rar_list($rar_file3);
var_dump($list3);
argerr(function() use ($rar_file3) { rar_list($rar_file3); });
echo "Done\n";
?>
@@ -163,6 +163,5 @@ array(2) {
Warning: rar_open(): Failed to open %s: ERAR_EOPEN (file open error) in %s on line %d
Warning: rar_list() expects parameter 1 to be RarArchive, boolean given in %s on line %d
NULL
Warning: rar_list() expects parameter 1 to be RarArchive, %s given in %s on line %d
Done

View File

@@ -5,6 +5,7 @@ rar_entry_get() function
--FILE--
<?php
require __DIR__ . "/php8compat.php.inc";
$rar_file1 = rar_open(dirname(__FILE__).'/linux_rar.rar');
$entry1 = rar_entry_get($rar_file1, 'test file with whitespaces.txt');
var_dump($entry1);
@@ -14,8 +15,9 @@ $entry2 = rar_entry_get($rar_file2, '2.txt');
var_dump($entry2);
$rar_file3 = rar_open(dirname(__FILE__).'/no_such_file.rar');
$entry3 = rar_entry_get($rar_file3, '2.txt');
var_dump($entry3);
argerr(function() use ($rar_file3) {
rar_entry_get($rar_file3, '2.txt');
});
echo "Done\n";
?>
@@ -89,6 +91,5 @@ object(RarEntry)#%d (%d) {
Warning: rar_open(): Failed to open %s: ERAR_EOPEN (file open error) in %s on line %d
Warning: rar_entry_get() expects parameter 1 to be RarArchive, boolean given in %s on line %d
NULL
Warning: rar_entry_get() expects parameter 1 to be RarArchive, %s given in %s on line %d
Done

View File

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

View File

@@ -1,7 +1,10 @@
--TEST--
RarEntry::getStream() function (good RAR file, several volumes)
--SKIPIF--
<?php if(!extension_loaded("rar")) print "skip"; ?>
<?php
if(!extension_loaded("rar")) die("skip");
if(PHP_INT_SIZE < 8) die("skip 32-bit PHP not supported");
?>
--FILE--
<?php

View File

@@ -1,7 +1,10 @@
--TEST--
RarEntry::getStream() function (store method)
--SKIPIF--
<?php if(!extension_loaded("rar")) print "skip"; ?>
<?php
if(!extension_loaded("rar")) die("skip");
if(PHP_INT_SIZE < 8) die("skip 32-bit PHP not supported");
?>
--FILE--
<?php

View File

@@ -1,7 +1,10 @@
--TEST--
RarEntry::getStream() function (solid archive)
--SKIPIF--
<?php if(!extension_loaded("rar")) print "skip"; ?>
<?php
if(!extension_loaded("rar")) die("skip");
if(PHP_INT_SIZE < 8) die("skip 32-bit PHP not supported");
?>
--FILE--
<?php

View File

@@ -12,4 +12,4 @@ foreach ($rarF as $k => $rarE) {
}
echo "Done.\n";
--EXPECTF--
Fatal error: main(): The archive is already closed, cannot give an iterator in %s on line %d
Fatal error: main(): The archive is already closed, cannot give an iterator in %s on line %d%A

View File

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

View File

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

View File

@@ -1,7 +1,10 @@
--TEST--
RarEntry::getStream() function (broken set fixed with volume callback)
--SKIPIF--
<?php if(!extension_loaded("rar")) print "skip"; ?>
<?php
if(!extension_loaded("rar")) die("skip");
if(PHP_INT_SIZE < 8) die("skip 32-bit PHP not supported");
?>
--FILE--
<?php
function resolve($vol) {

View File

@@ -1,7 +1,10 @@
--TEST--
RarEntry::extract() function (broken set fixed with volume callback)
--SKIPIF--
<?php if(!extension_loaded("rar")) print "skip"; ?>
<?php
if(!extension_loaded("rar")) die("skip");
if(PHP_INT_SIZE < 8) die("skip 32-bit PHP not supported");
?>
--FILE--
<?php
function resolve($vol) {
@@ -10,9 +13,9 @@ function resolve($vol) {
else
return null;
}
function int32_to_hex($value) {
$value &= 0xffffffff;
return str_pad(strtoupper(dechex($value)), 8, "0", STR_PAD_LEFT);
function int32_to_hex($value) {
$value &= 0xffffffff;
return str_pad(strtoupper(dechex($value)), 8, "0", STR_PAD_LEFT);
}
echo "Fail:\n";
$rar_file1 = rar_open(dirname(__FILE__).'/multi_broken.part1.rar');

View File

@@ -1,13 +1,14 @@
--TEST--
RarArchive::open() volume callback long return (case MAXPATHLEN > NM)
RarArchive::open() volume callback long return (case MAXPATHLEN > MAXPATHSIZE)
--SKIPIF--
<?php
define('MAXPATHSIZE', 0x10000);
if(!extension_loaded("rar")) die("skip");
if (!defined("PHP_MAXPATHLEN"))
define("PHP_MAXPATHLEN", RAR_MAXPATHLEN);
if (!(PHP_MAXPATHLEN > 2048))
if (!(PHP_MAXPATHLEN > MAXPATHSIZE))
die("skip test is for systems where MAXPATHLEN > 2048");
$rp = dirname(__FILE__) . "/" . str_repeat("a", 2048);
$rp = dirname(__FILE__) . "/" . str_repeat("a", MAXPATHSIZE);
if (strlen(dirname(__FILE__) > PHP_MAXPATHLEN - 1))
die("skip current directory is too deep.");
--FILE--
@@ -18,7 +19,7 @@ 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", 2048); }
function testA($vol) { if ($vol[0] != 'a') return str_repeat("a", MAXPATHSIZE); }
$rar = RarArchive::open($fn, null, 'testA');
$rar->getEntries();

View File

@@ -50,11 +50,11 @@ string(5) "11111"
Test with include path:
Should fail (not in include):
Warning: fopen(rar://tmp.rar#1.txt): failed to open stream: Error opening RAR archive %stmp.rar: ERAR_EOPEN (file open error) in %s on line %d
Warning: fopen(rar://tmp.rar#1.txt): %cailed to open stream: Error opening RAR archive %stmp.rar: ERAR_EOPEN (file open error) in %s on line %d
Should fail (include unused):
Warning: fopen(rar://tmp.rar#1.txt): failed to open stream: Error opening RAR archive %stmp.rar: ERAR_EOPEN (file open error) in %s on line %d
Warning: fopen(rar://tmp.rar#1.txt): %cailed to open stream: Error opening RAR archive %stmp.rar: ERAR_EOPEN (file open error) in %s on line %d
Should succeed:
string(5) "11111"

View File

@@ -20,9 +20,9 @@ echo "Done.\n";
--EXPECTF--
Archive not found :
Warning: fopen(rar://%snot_found.rar#1.txt): failed to open stream: Error opening RAR archive %snot_found.rar: ERAR_EOPEN (file open error) in %s on line %d
Warning: fopen(rar://%snot_found.rar#1.txt): %cailed to open stream: Error opening RAR archive %snot_found.rar: ERAR_EOPEN (file open error) in %s on line %d
File not found :
Warning: fopen(rar://%slatest_winrar.rar#not_found.txt): failed to open stream: Can't file not_found.txt in RAR archive %s on line %d
Done.
Warning: fopen(rar://%slatest_winrar.rar#not_found.txt): %cailed to open stream: Can't file not_found.txt in RAR archive %s on line %d
Done.

View File

@@ -27,21 +27,21 @@ echo "Done.\n";
--EXPECTF--
Test empty:
Warning: fopen(rar://): failed to open stream: The url must contain a path and a non-empty fragment; it must be in the form "rar://<urlencoded path to RAR archive>[*]#<urlencoded entry name>" in %s on line %d
Warning: fopen(rar://): %cailed to open stream: The url must contain a path and a non-empty fragment; it must be in the form "rar://<urlencoded path to RAR archive>[*]#<urlencoded entry name>" in %s on line %d
Test no fragment:
Warning: fopen(rar://file.rar): failed to open stream: The url must contain a path and a non-empty fragment; it must be in the form "rar://<urlencoded path to RAR archive>[*]#<urlencoded entry name>" in %s on line %d
Warning: fopen(rar://file.rar): %cailed to open stream: The url must contain a path and a non-empty fragment; it must be in the form "rar://<urlencoded path to RAR archive>[*]#<urlencoded entry name>" in %s on line %d
Test empty fragment:
Warning: fopen(rar://file.rar#): failed to open stream: The url must contain a path and a non-empty fragment; it must be in the form "rar://<urlencoded path to RAR archive>[*]#<urlencoded entry name>" in %s on line %d
Warning: fopen(rar://file.rar#): %cailed to open stream: The url must contain a path and a non-empty fragment; it must be in the form "rar://<urlencoded path to RAR archive>[*]#<urlencoded entry name>" in %s on line %d
Test no path:
Warning: fopen(rar://#frag): failed to open stream: The url must contain a path and a non-empty fragment; it must be in the form "rar://<urlencoded path to RAR archive>[*]#<urlencoded entry name>" in %s on line %d
Warning: fopen(rar://#frag): %cailed to open stream: The url must contain a path and a non-empty fragment; it must be in the form "rar://<urlencoded path to RAR archive>[*]#<urlencoded entry name>" in %s on line %d
Test no path and empty fragment:
Warning: fopen(rar://#): failed to open stream: The url must contain a path and a non-empty fragment; it must be in the form "rar://<urlencoded path to RAR archive>[*]#<urlencoded entry name>" in %s on line %d
Warning: fopen(rar://#): %cailed to open stream: The url must contain a path and a non-empty fragment; it must be in the form "rar://<urlencoded path to RAR archive>[*]#<urlencoded entry name>" in %s on line %d
Done.

View File

@@ -55,11 +55,11 @@ echo "\nDone.\n";
--EXPECTF--
Headers: should not work (no password):
Warning: fopen(rar://%sencrypted_headers.rar#encfile1.txt): failed to open stream: Error opening RAR archive %sencrypted_headers.rar: ERAR_MISSING_PASSWORD (password needed but not specified) in %s on line %d
Warning: fopen(rar://%sencrypted_headers.rar#encfile1.txt): %cailed to open stream: Error opening RAR archive %sencrypted_headers.rar: ERAR_MISSING_PASSWORD (password needed but not specified) in %s on line %d
Headers: should not work (password given was file_password):
Warning: fopen(rar://%sencrypted_headers.rar#encfile1.txt): failed to open stream: Error opening RAR archive %sencrypted_headers.rar: ERAR_MISSING_PASSWORD (password needed but not specified) in %s on line %d
Warning: fopen(rar://%sencrypted_headers.rar#encfile1.txt): %cailed to open stream: Error opening RAR archive %sencrypted_headers.rar: ERAR_MISSING_PASSWORD (password needed but not specified) in %s on line %d
Headers: should work (password given was open_password):
string(26) "Encrypted file 1 contents."
@@ -67,11 +67,11 @@ string(26) "Encrypted file 1 contents."
Files: should not work (no password):
Warning: fopen(rar://%sencrypted_only_files.rar#encfile1.txt): failed to open stream: Error opening file encfile1.txt inside RAR archive %sencrypted_only_files.rar: ERAR_MISSING_PASSWORD (password needed but not specified) in %s on line %d
Warning: fopen(rar://%sencrypted_only_files.rar#encfile1.txt): %cailed to open stream: Error opening file encfile1.txt inside RAR archive %sencrypted_only_files.rar: ERAR_MISSING_PASSWORD (password needed but not specified) in %s on line %d
Files: should not work (password given was open_password):
Warning: fopen(rar://%sencrypted_only_files.rar#encfile1.txt): failed to open stream: Error opening file encfile1.txt inside RAR archive %sencrypted_only_files.rar: ERAR_MISSING_PASSWORD (password needed but not specified) in %s on line %d
Warning: fopen(rar://%sencrypted_only_files.rar#encfile1.txt): %cailed to open stream: Error opening file encfile1.txt inside RAR archive %sencrypted_only_files.rar: ERAR_MISSING_PASSWORD (password needed but not specified) in %s on line %d
Files: should work (password given was file_password):
string(26) "Encrypted file 1 contents."

View File

@@ -3,6 +3,7 @@ Stream wrapper with volume find callback
--SKIPIF--
<?php
if(!extension_loaded("rar")) die("skip");
if(PHP_INT_SIZE < 8) die("skip 32-bit PHP not supported");
--FILE--
<?php
function resolve($vol) {

View File

@@ -12,6 +12,6 @@ var_dump(opendir($u));
echo "Done.\n";
--EXPECTF--
Warning: opendir(rar://%sdirlink_unix.rar#file): failed to open dir: Archive %sdirlink_unix.rar has an entry named file, but it is not a directory in %s on line %d
Warning: opendir(rar://%sdirlink_unix.rar#file): %cailed to open dir%S: Archive %sdirlink_unix.rar has an entry named file, but it is not a directory in %s on line %d
bool(false)
Done.

View File

@@ -1,14 +0,0 @@
--TEST--
RarArchive 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
new RarArchive();
echo "Done\n";
--EXPECTF--
Fatal error: Call to private RarArchive::__construct() from invalid context in %s on line %d

View File

@@ -1,13 +0,0 @@
--TEST--
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
new RarEntry();
echo "Done\n";
--EXPECTF--
Fatal error: Call to private RarEntry::__construct() from invalid context in %s on line %d

View File

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

View File

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

View File

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

View File

@@ -1,7 +1,10 @@
--TEST--
RarArchive write_property gives a fatal error
--SKIPIF--
<?php if(!extension_loaded("rar")) print "skip"; ?>
<?php
if(!extension_loaded("rar")) die("skip");
if (key_exists('USE_ZEND_ALLOC', $_ENV) && PHP_VERSION_ID < 70000) die('skip do not use with valgrind in PHP <7');
?>
--FILE--
<?php
@@ -13,4 +16,4 @@ $a[0] = "jjj";
echo "\n";
echo "Done.\n";
--EXPECTF--
Fatal error: main(): A RarArchive object is not writable in %s on line %d
Fatal error: main(): A RarArchive object is not writable in %s on line %d%A

View File

@@ -18,4 +18,4 @@ unset($a[0]["jj"]);
echo "\n";
echo "Done.\n";
--EXPECTF--
Fatal error: main(): A RarArchive object is not modifiable in %s on line %d
Fatal error: main(): A RarArchive object is not modifiable in %s on line %d%A

View File

@@ -1,7 +1,10 @@
--TEST--
RarArchive write_property gives a fatal error
--SKIPIF--
<?php if(!extension_loaded("rar")) print "skip"; ?>
<?php
if(!extension_loaded("rar")) die("skip");
if (key_exists('USE_ZEND_ALLOC', $_ENV) && PHP_VERSION_ID < 70000) die('skip do not use with valgrind in PHP <7')
?>
--FILE--
<?php
@@ -13,4 +16,4 @@ $a[0] = "hhh";
echo "\n";
echo "Done.\n";
--EXPECTF--
Fatal error: main(): A RarArchive object is not writable in %s on line %d
Fatal error: main(): A RarArchive object is not writable in %s on line %d%A

View File

@@ -13,4 +13,4 @@ unset($a[0]);
echo "\n";
echo "Done.\n";
--EXPECTF--
Fatal error: main(): A RarArchive object is not writable in %s on line %d
Fatal error: main(): A RarArchive object is not writable in %s on line %d%A

View File

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

View File

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

View File

@@ -15,4 +15,4 @@ foreach ($a as &$v) {
echo "\n";
echo "Done.\n";
--EXPECTF--
Fatal error: main(): An iterator cannot be used with foreach by reference in %s on line %d
Fatal error: main(): An iterator cannot be used with foreach by reference in %s on line %d%A

View File

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

View File

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

View File

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

View File

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

View File

@@ -2,7 +2,6 @@
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);
@@ -38,7 +37,7 @@ object(RarEntry)#%d (%d) {
["attr%sprivate%s=>
int(33261)
["version%sprivate%s=>
int(200)
int(50)
["method%sprivate%s=>
int(51)
["flags%sprivate%s=>

View File

@@ -11,7 +11,7 @@ new RarArchive();
echo "Done\n";
--EXPECTF--
Fatal error: Uncaught Error: Call to private RarArchive::__construct() from invalid context in %s:%d
Fatal error: Uncaught Error: Call to private RarArchive::__construct() from %s in %s:%d
Stack trace:
#0 {main}
thrown in %s on line %d

View File

@@ -10,7 +10,7 @@ new RarEntry();
echo "Done\n";
--EXPECTF--
Fatal error: Uncaught Error: Call to private RarEntry::__construct() from invalid context in %s:%d
Fatal error: Uncaught Error: Call to private RarEntry::__construct() from %s in %s:%d
Stack trace:
#0 {main}
thrown in %s on line %d

View File

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

View File

@@ -10,5 +10,5 @@ $e = $a->getEntry('file1.txt');
var_dump($e->getVersion());
echo "Done.\n";
--EXPECTF--
int(200)
int(50)
Done.

50
tests/114.phpt Normal file
View File

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

25
tests/115.phpt Normal file
View File

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

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

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

View File

@@ -1,86 +0,0 @@
#!/bin/bash -e
BUILDS_DIR=$HOME/php_builds
MIRROR=${MIRROR:-http://us1.php.net/distributions}
JOBS=3
function prefix {
local readonly version=$1 zts=$2
local zts_suffix=''
if [[ $zts = 'yes' ]]; then
zts_suffix='-zts'
fi
echo "$BUILDS_DIR/${version}$zts_suffix"
}
function install_php {
local readonly version=$1 zts=$2
local readonly url="$MIRROR/php-$version.tar.gz" \
extract_dir="/tmp/php-$version" prefix=$(prefix $version $zts)
local extra_flags=''
mkdir -p "$extract_dir"
wget -O - "$url" | tar -C "$extract_dir" --strip-components=1 -xzf -
pushd "$extract_dir"
if [[ $zts = 'yes' ]]; then
extra_flags="$extra_flags --enable-maintainer-zts"
fi
./configure --prefix="$prefix" --disable-all --enable-cli \
$extra_flags
make -j $JOBS install
popd
}
function build_ext {
local readonly prefix=$1 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)"
}

3
unrar/.clang-format Normal file
View File

@@ -0,0 +1,3 @@
---
# Disable clang-format for vendored unrar sources.
DisableFormat: true

View File

@@ -238,8 +238,10 @@
<ClCompile Include="hash.cpp" />
<ClCompile Include="headers.cpp" />
<ClCompile Include="isnt.cpp" />
<ClCompile Include="largepage.cpp" />
<ClCompile Include="list.cpp" />
<ClCompile Include="match.cpp" />
<ClCompile Include="motw.cpp" />
<ClCompile Include="options.cpp" />
<ClCompile Include="pathfn.cpp" />
<ClCompile Include="qopen.cpp" />

View File

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

View File

@@ -138,7 +138,7 @@
<ExceptionHandling>Sync</ExceptionHandling>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<StructMemberAlignment>4Bytes</StructMemberAlignment>
<StructMemberAlignment>Default</StructMemberAlignment>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>rar.hpp</PrecompiledHeaderFile>
@@ -168,7 +168,7 @@
<ExceptionHandling>Sync</ExceptionHandling>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<StructMemberAlignment>4Bytes</StructMemberAlignment>
<StructMemberAlignment>Default</StructMemberAlignment>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>rar.hpp</PrecompiledHeaderFile>
@@ -198,7 +198,7 @@
<MinimalRebuild>false</MinimalRebuild>
<ExceptionHandling>Sync</ExceptionHandling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<StructMemberAlignment>4Bytes</StructMemberAlignment>
<StructMemberAlignment>Default</StructMemberAlignment>
<BufferSecurityCheck>true</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
<EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
@@ -239,7 +239,7 @@
<MinimalRebuild>false</MinimalRebuild>
<ExceptionHandling>Sync</ExceptionHandling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<StructMemberAlignment>4Bytes</StructMemberAlignment>
<StructMemberAlignment>Default</StructMemberAlignment>
<BufferSecurityCheck>true</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
@@ -274,7 +274,7 @@
<MinimalRebuild>false</MinimalRebuild>
<ExceptionHandling>Sync</ExceptionHandling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<StructMemberAlignment>4Bytes</StructMemberAlignment>
<StructMemberAlignment>Default</StructMemberAlignment>
<BufferSecurityCheck>true</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
<EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
@@ -315,7 +315,7 @@
<MinimalRebuild>false</MinimalRebuild>
<ExceptionHandling>Sync</ExceptionHandling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<StructMemberAlignment>4Bytes</StructMemberAlignment>
<StructMemberAlignment>Default</StructMemberAlignment>
<BufferSecurityCheck>true</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
@@ -374,7 +374,9 @@
<ClCompile Include="hash.cpp" />
<ClCompile Include="headers.cpp" />
<ClCompile Include="isnt.cpp" />
<ClCompile Include="largepage.cpp" />
<ClCompile Include="match.cpp" />
<ClCompile Include="motw.cpp" />
<ClCompile Include="options.cpp" />
<ClCompile Include="pathfn.cpp" />
<ClCompile Include="qopen.cpp" />

View File

@@ -7,51 +7,18 @@
for samples and ideas allowed to make Reed-Solomon coding
more efficient.
* RAR text compression algorithm is based on Dmitry Shkarin PPMII
* RAR4 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.
You can 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.
* RAR encryption includes parts of public domain code
from Szymon Stefanek AES and Steve Reid SHA-1 implementations.
---------------------------------------------------------------------------
Copyright (c) 2002, Dr Brian Gladman < >, Worcester, UK.
All rights reserved.
* With exception of SFX modules, RAR uses CRC32 function based
on Intel Slicing-by-8 algorithm. Original Intel Slicing-by-8 code
is available here:
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/
https://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

View File

@@ -1,13 +1,20 @@
static bool IsAnsiEscComment(const wchar *Data,size_t Size);
bool Archive::GetComment(Array<wchar> *CmtData)
bool Archive::GetComment(std::wstring &CmtData)
{
if (!MainComment)
return false;
SaveFilePos SavePos(*this);
int64 SavePos=Tell();
bool Success=DoGetComment(CmtData);
Seek(SavePos,SEEK_SET);
return Success;
}
bool Archive::DoGetComment(std::wstring &CmtData)
{
#ifndef SFX_MODULE
ushort CmtLength;
uint CmtLength;
if (Format==RARFMT14)
{
Seek(SFXSize+SIZEOF_MAINHEAD14,SEEK_SET);
@@ -22,18 +29,24 @@ bool Archive::GetComment(Array<wchar> *CmtData)
// Old style (RAR 2.9) archive comment embedded into the main
// archive header.
Seek(SFXSize+SIZEOF_MARKHEAD3+SIZEOF_MAINHEAD3,SEEK_SET);
ReadHeader();
if (!ReadHeader() || GetHeaderType()!=HEAD3_CMT)
return false;
}
else
{
// Current (RAR 3.0+) version of archive comment.
Seek(GetStartPos(),SEEK_SET);
return SearchSubBlock(SUBHEAD_TYPE_CMT)!=0 && ReadCommentData(CmtData);
if (SearchSubBlock(SUBHEAD_TYPE_CMT)!=0)
if (ReadCommentData(CmtData))
return true;
else
uiMsg(UIERROR_CMTBROKEN,FileName);
return false;
}
#ifndef SFX_MODULE
// Old style (RAR 2.9) comment header embedded into the main
// archive header.
if (BrokenHeader)
if (BrokenHeader || CommHead.HeadSize<SIZEOF_COMMHEAD)
{
uiMsg(UIERROR_CMTBROKEN,FileName);
return false;
@@ -52,10 +65,12 @@ bool Archive::GetComment(Array<wchar> *CmtData)
if (Format==RARFMT14)
{
#ifdef RAR_NOCRYPT
return(false);
return false;
#else
UnpCmtLength=GetByte();
UnpCmtLength+=(GetByte()<<8);
if (CmtLength<2)
return false;
CmtLength-=2;
DataIO.SetCmt13Encryption();
CommHead.UnpVer=15;
@@ -67,6 +82,7 @@ bool Archive::GetComment(Array<wchar> *CmtData)
DataIO.EnableShowProgress(false);
DataIO.SetPackedSizeToRead(CmtLength);
DataIO.UnpHash.Init(HASH_CRC32,1);
DataIO.SetNoFileHeader(true); // this->FileHead is not filled yet.
Unpack CmtUnpack(&DataIO);
CmtUnpack.Init(0x10000,false);
@@ -83,64 +99,70 @@ bool Archive::GetComment(Array<wchar> *CmtData)
byte *UnpData;
size_t UnpDataSize;
DataIO.GetUnpackedData(&UnpData,&UnpDataSize);
if (UnpDataSize>0)
{
#ifdef _WIN_ALL
// If we ever decide to extend it to Android, we'll need to alloc
// 4x memory for OEM to UTF-8 output here.
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)));
std::string UnpStr((char*)UnpData,UnpDataSize);
CharToWide(UnpStr,CmtData);
}
}
}
else
{
Array<byte> CmtRaw(CmtLength);
Read(&CmtRaw[0],CmtLength);
if (CmtLength==0)
return false;
std::vector<byte> CmtRaw(CmtLength);
int ReadSize=Read(CmtRaw.data(),CmtLength);
if (ReadSize>=0 && (uint)ReadSize<CmtLength) // Comment is shorter than declared.
{
CmtLength=ReadSize;
CmtRaw.resize(CmtLength);
}
if (Format!=RARFMT14 && CommHead.CommCRC!=(~CRC32(0xffffffff,&CmtRaw[0],CmtLength)&0xffff))
{
uiMsg(UIERROR_CMTBROKEN,FileName);
return false;
}
CmtData->Alloc(CmtLength+1);
CmtRaw.Push(0);
// CmtData.resize(CmtLength+1);
CmtRaw.push_back(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]);
OemToCharA((char *)CmtRaw.data(),(char *)CmtRaw.data());
#endif
CharToWide((char *)&CmtRaw[0],CmtData->Addr(0),CmtLength);
CmtData->Alloc(wcslen(CmtData->Addr(0)));
}
CharToWide((const char *)CmtRaw.data(),CmtData);
// CmtData->resize(wcslen(CmtData->data()));
}
#endif
return CmtData->Size() > 0;
return CmtData.size() > 0;
}
bool Archive::ReadCommentData(Array<wchar> *CmtData)
bool Archive::ReadCommentData(std::wstring &CmtData)
{
Array<byte> CmtRaw;
if (!ReadSubData(&CmtRaw,NULL))
std::vector<byte> CmtRaw;
if (!ReadSubData(&CmtRaw,NULL,false))
return false;
size_t CmtSize=CmtRaw.Size();
CmtRaw.Push(0);
CmtData->Alloc(CmtSize+1);
size_t CmtSize=CmtRaw.size();
CmtRaw.push_back(0);
// CmtData->resize(CmtSize+1);
if (Format==RARFMT50)
UtfToWide((char *)&CmtRaw[0],CmtData->Addr(0),CmtData->Size());
UtfToWide((char *)CmtRaw.data(),CmtData);
else
if ((SubHead.SubFlags & SUBHEAD_FLAGS_CMT_UNICODE)!=0)
{
RawToWide(&CmtRaw[0],CmtData->Addr(0),CmtSize/2);
(*CmtData)[CmtSize/2]=0;
}
else
{
CharToWide((char *)&CmtRaw[0],CmtData->Addr(0),CmtData->Size());
CmtData=RawToWide(CmtRaw);
}
CmtData->Alloc(wcslen(CmtData->Addr(0))); // Set buffer size to actual comment length.
else
{
CharToWide((const char *)CmtRaw.data(),CmtData);
}
// CmtData->resize(wcslen(CmtData->data())); // Set buffer size to actual comment length.
return true;
}
@@ -149,15 +171,16 @@ void Archive::ViewComment()
{
if (Cmd->DisableComment)
return;
Array<wchar> CmtBuf;
if (GetComment(&CmtBuf)) // In GUI too, so "Test" command detects broken comments.
std::wstring CmtBuf;
if (GetComment(CmtBuf)) // In GUI too, so "Test" command detects broken comments.
{
size_t CmtSize=CmtBuf.Size();
wchar *ChPtr=wcschr(&CmtBuf[0],0x1A);
if (ChPtr!=NULL)
CmtSize=ChPtr-&CmtBuf[0];
mprintf(L"\n");
OutComment(&CmtBuf[0],CmtSize);
size_t CmtSize=CmtBuf.size();
auto EndPos=CmtBuf.find(0x1A);
if (EndPos!=std::wstring::npos)
CmtSize=EndPos;
mprintf(St(MArcComment));
mprintf(L":\n");
OutComment(CmtBuf);
}
}

View File

@@ -3,15 +3,15 @@
#include "arccmt.cpp"
Archive::Archive(RAROptions *InitCmd)
Archive::Archive(CommandData *InitCmd)
{
Cmd=NULL; // Just in case we'll have an exception in 'new' below.
DummyCmd=(InitCmd==NULL);
Cmd=DummyCmd ? (new RAROptions):InitCmd;
Cmd=DummyCmd ? (new CommandData):InitCmd;
OpenShared=Cmd->OpenShared;
Format=RARFMT15;
Format=RARFMT_NONE;
Solid=false;
Volume=false;
MainComment=false;
@@ -26,28 +26,31 @@ Archive::Archive(RAROptions *InitCmd)
FailedHeaderDecryption=false;
BrokenHeader=false;
LastReadBlock=0;
CurHeaderType=HEAD_UNKNOWN;
CurBlockPos=0;
NextBlockPos=0;
RecoverySize=-1;
RecoveryPercent=-1;
memset(&MainHead,0,sizeof(MainHead));
memset(&CryptHead,0,sizeof(CryptHead));
memset(&EndArcHead,0,sizeof(EndArcHead));
MainHead.Reset();
CryptHead={};
EndArcHead.Reset();
VolNumber=0;
VolWrite=0;
AddingFilesSize=0;
AddingHeadersSize=0;
*FirstVolumeName=0;
Splitting=false;
NewArchive=false;
SilentOpen=false;
#ifdef USE_QOPEN
ProhibitQOpen=false;
#endif
}
@@ -66,13 +69,13 @@ void Archive::CheckArc(bool EnableBroken)
// password is incorrect.
if (!FailedHeaderDecryption)
uiMsg(UIERROR_BADARCHIVE,FileName);
ErrHandler.Exit(RARX_FATAL);
ErrHandler.Exit(RARX_BADARC);
}
}
#if !defined(SFX_MODULE)
void Archive::CheckOpen(const wchar *Name)
void Archive::CheckOpen(const std::wstring &Name)
{
TOpen(Name);
CheckArc(false);
@@ -80,7 +83,7 @@ void Archive::CheckOpen(const wchar *Name)
#endif
bool Archive::WCheckOpen(const wchar *Name)
bool Archive::WCheckOpen(const std::wstring &Name)
{
if (!WOpen(Name))
return false;
@@ -108,13 +111,15 @@ RARFORMAT Archive::IsSignature(const byte *D,size_t Size)
// 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.
#ifndef SFX_MODULE
if (D[6]==0)
Type=RARFMT15;
else
#endif
if (D[6]==1)
Type=RARFMT50;
else
if (D[6]==2)
if (D[6]>1 && D[6]<5)
Type=RARFMT_FUTURE;
}
return Type;
@@ -146,9 +151,9 @@ bool Archive::IsArchive(bool EnableBroken)
}
else
{
Array<char> Buffer(MAXSFXSIZE);
std::vector<char> Buffer(MAXSFXSIZE);
long CurPos=(long)Tell();
int ReadSize=Read(&Buffer[0],Buffer.Size()-16);
int ReadSize=Read(Buffer.data(),Buffer.size()-16);
for (int I=0;I<ReadSize;I++)
if (Buffer[I]==0x52 && (Type=IsSignature((byte *)&Buffer[I],ReadSize-I))!=RARFMT_NONE)
{
@@ -175,8 +180,7 @@ bool Archive::IsArchive(bool EnableBroken)
}
if (Format==RARFMT50) // RAR 5.0 signature is by one byte longer.
{
Read(MarkHead.Mark+SIZEOF_MARKHEAD3,1);
if (MarkHead.Mark[SIZEOF_MARKHEAD3]!=0)
if (Read(MarkHead.Mark+SIZEOF_MARKHEAD3,1)!=1 || MarkHead.Mark[SIZEOF_MARKHEAD3]!=0)
return false;
MarkHead.HeadSize=SIZEOF_MARKHEAD5;
}
@@ -192,27 +196,31 @@ bool Archive::IsArchive(bool EnableBroken)
SilentOpen=true;
#endif
bool HeadersLeft; // Any headers left to read.
bool StartFound=false; // Main or encryption headers found.
// Skip the archive encryption header if any and read the main header.
while (ReadHeader()!=0)
while ((HeadersLeft=(ReadHeader()!=0))==true) // Additional parentheses to silence Clang.
{
SeekToNext();
HEADER_TYPE Type=GetHeaderType();
// In RAR 5.0 we need to quit after reading HEAD_CRYPT if we wish to
// avoid the password prompt.
if (Type==HEAD_MAIN || SilentOpen && Type==HEAD_CRYPT)
StartFound=Type==HEAD_MAIN || SilentOpen && Type==HEAD_CRYPT;
if (StartFound)
break;
SeekToNext();
}
// This check allows to make RS based recovery even if password is incorrect.
// But we should not do it for EnableBroken or we'll get 'not RAR archive'
// We should not do it for EnableBroken or we'll get 'not RAR archive'
// messages when extracting encrypted archives with wrong password.
if (FailedHeaderDecryption && !EnableBroken)
return false;
SeekToNext();
if (BrokenHeader) // Main archive header is corrupt.
if (BrokenHeader || !StartFound) // Main archive header is corrupt or missing.
{
uiMsg(UIERROR_MHEADERBROKEN,FileName);
if (!FailedHeaderDecryption) // If not reported a wrong password already.
uiMsg(UIERROR_MHEADERBROKEN,FileName);
if (!EnableBroken)
return false;
}
@@ -226,9 +234,9 @@ bool Archive::IsArchive(bool EnableBroken)
// first file header to set "comment" flag when reading service header.
// Unless we are in silent mode, we need to know about presence of comment
// immediately after IsArchive call.
if (!SilentOpen || !Encrypted)
if (HeadersLeft && (!SilentOpen || !Encrypted) && IsSeekable())
{
SaveFilePos SavePos(*this);
int64 SavePos=Tell();
int64 SaveCurBlockPos=CurBlockPos,SaveNextBlockPos=NextBlockPos;
HEADER_TYPE SaveCurHeaderType=CurHeaderType;
@@ -257,9 +265,10 @@ bool Archive::IsArchive(bool EnableBroken)
CurBlockPos=SaveCurBlockPos;
NextBlockPos=SaveNextBlockPos;
CurHeaderType=SaveCurHeaderType;
Seek(SavePos,SEEK_SET);
}
if (!Volume || FirstVolume)
wcscpy(FirstVolumeName,FileName);
FirstVolumeName=FileName;
return true;
}
@@ -295,7 +304,7 @@ uint Archive::FullHeaderSize(size_t Size)
#ifdef USE_QOPEN
bool Archive::Open(const wchar *Name,uint Mode)
bool Archive::Open(const std::wstring &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'.
@@ -330,3 +339,23 @@ int64 Archive::Tell()
}
#endif
// Return 0 if dictionary size is invalid. If size is RAR7 only, return
// the adjusted nearest bottom value. Return header flags in Flags.
uint64 Archive::GetWinSize(uint64 Size,uint &Flags)
{
Flags=0;
// Allow 128 KB - 1 TB range.
if (Size<0x20000 || Size>0x10000000000ULL)
return 0;
uint64 Pow2=0x20000; // Power of 2 dictionary size.
for (;2*Pow2<=Size;Pow2*=2)
Flags+=FCI_DICT_BIT0;
if (Size==Pow2)
return Size; // If 'Size' is the power of 2, return it as is.
// Get the number of Pow2/32 to add to Pow2 for nearest value not exceeding 'Size'.
uint64 Fraction=(Size-Pow2)/(Pow2/32);
Flags+=(uint)Fraction*FCI_DICT_FRACT0;
return Pow2+Fraction*(Pow2/32);
}

View File

@@ -20,32 +20,33 @@ enum ADDSUBDATA_FLAGS
ASDF_CRYPTIFHEADERS = 8 // Encrypt data after subheader only in -hp mode.
};
// RAR5 headers must not exceed 2 MB.
#define MAX_HEADER_SIZE_RAR5 0x200000
class Archive:public File
{
private:
void UpdateLatestTime(FileHeader *CurBlock);
void ConvertNameCase(wchar *Name);
void ConvertNameCase(std::wstring &Name);
void ConvertFileHeader(FileHeader *hd);
void WriteBlock50(HEADER_TYPE HeaderType,BaseBlock *wb,bool OnlySetSize,bool NonFinalWrite);
size_t ReadHeader14();
size_t ReadHeader15();
size_t ReadHeader50();
void ProcessExtra50(RawRead *Raw,size_t ExtraSize,BaseBlock *bb);
void RequestArcPassword();
void ProcessExtra50(RawRead *Raw,size_t ExtraSize,const BaseBlock *bb);
void RequestArcPassword(RarCheckPassword *SelPwd);
void UnexpEndArcMsg();
void BrokenHeaderMsg();
void UnkEncVerMsg(const wchar *Name);
void UnkEncVerMsg();
bool ReadCommentData(Array<wchar> *CmtData);
void UnkEncVerMsg(const std::wstring &Name,const std::wstring &Info);
bool DoGetComment(std::wstring &CmtData);
bool ReadCommentData(std::wstring &CmtData);
#if !defined(RAR_NOCRYPT)
CryptData HeadersCrypt;
#endif
ComprDataIO SubDataIO;
bool DummyCmd;
RAROptions *Cmd;
CommandData *Cmd;
int64 RecoverySize;
int RecoveryPercent;
RarTime LatestTime;
@@ -55,22 +56,22 @@ class Archive:public File
bool SilentOpen;
#ifdef USE_QOPEN
QuickOpen QOpen;
bool ProhibitQOpen;
#endif
public:
Archive(RAROptions *InitCmd=NULL);
Archive(CommandData *InitCmd=nullptr);
~Archive();
static RARFORMAT IsSignature(const byte *D,size_t Size);
bool IsArchive(bool EnableBroken);
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);}
int GetRecoveryPercent() {return RecoveryPercent;}
size_t ReadHeader();
void CheckArc(bool EnableBroken);
void CheckOpen(const wchar *Name);
bool WCheckOpen(const wchar *Name);
bool GetComment(Array<wchar> *CmtData);
void CheckOpen(const std::wstring &Name);
bool WCheckOpen(const std::wstring &Name);
bool GetComment(std::wstring &CmtData);
void ViewComment();
void SetLatestTime(RarTime *NewTime);
void SeekToNext();
@@ -80,22 +81,25 @@ class Archive:public File
void VolSubtractHeaderSize(size_t SubSize);
uint FullHeaderSize(size_t Size);
int64 GetStartPos();
void AddSubData(byte *SrcData,uint64 DataSize,File *SrcFile,
void AddSubData(const byte *SrcData,uint64 DataSize,File *SrcFile,
const wchar *Name,uint Flags);
bool ReadSubData(Array<byte> *UnpData,File *DestFile);
HEADER_TYPE GetHeaderType() {return CurHeaderType;};
RAROptions* GetRAROptions() {return Cmd;}
bool ReadSubData(std::vector<byte> *UnpData,File *DestFile,bool TestMode);
HEADER_TYPE GetHeaderType() {return CurHeaderType;}
CommandData* GetCommandData() {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();
bool Open(const std::wstring &Name,uint Mode=FMF_READ) override;
int Read(void *Data,size_t Size) override;
void Seek(int64 Offset,int Method) override;
int64 Tell() override;
void QOpenUnload() {QOpen.Unload();}
void SetProhibitQOpen(bool Mode) {ProhibitQOpen=Mode;}
#endif
static uint64 GetWinSize(uint64 Size,uint &Flags);
// Needed to see wstring based Open from File. Otherwise compiler finds
// Open in Archive and doesn't check the base class overloads.
using File::Open;
BaseBlock ShortBlock;
MarkHeader MarkHead;
@@ -107,10 +111,6 @@ class Archive:public File
FileHeader SubHead;
CommentHeader CommHead;
ProtectHeader ProtectHead;
AVHeader AVHead;
SignHeader SignHead;
UnixOwnersHeader UOHead;
MacFInfoHeader MACHead;
EAHeader EAHead;
StreamHeader StreamHead;
@@ -139,12 +139,19 @@ class Archive:public File
uint VolNumber;
int64 VolWrite;
// Total size of files adding to archive. Might also include the size of
// files repacked in solid archive.
uint64 AddingFilesSize;
uint64 AddingHeadersSize;
bool NewArchive;
wchar FirstVolumeName[NM];
std::wstring FirstVolumeName;
#ifdef PROPAGATE_MOTW
MarkOfTheWeb Motw;
#endif
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,191 +0,0 @@
#ifndef _RAR_ARRAY_
#define _RAR_ARRAY_
extern ErrorHandler ErrHandler;
template <class T> class Array
{
private:
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) 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);
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;
}
template <class T> Array<T>::Array()
{
CleanData();
}
template <class T> Array<T>::Array(size_t Size)
{
CleanData();
Add(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) const
{
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;
}
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);
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;
}
}
template <class T> void Array<T>::Alloc(size_t Items)
{
if (Items>AllocSize)
Add(Items-BufSize);
else
BufSize=Items;
}
template <class T> void Array<T>::Reset()
{
if (Buffer!=NULL)
{
free(Buffer);
Buffer=NULL;
}
BufSize=0;
AllocSize=0;
}
// 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();
Alloc(Src.BufSize);
if (Src.BufSize!=0)
memcpy((void *)Buffer,(void *)Src.Buffer,Src.BufSize*sizeof(T));
}
template <class T> void Array<T>::Push(T Item)
{
Add(1);
(*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

@@ -2,6 +2,20 @@
#include "rar.hpp"
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 } ,
};
#ifdef USE_SSE
#include "blake2s_sse.cpp"
#endif
@@ -18,20 +32,6 @@ static const uint32 blake2s_IV[8] =
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;
@@ -134,11 +134,7 @@ void blake2s_update( blake2s_state *S, const byte *in, size_t inlen )
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

View File

@@ -3,13 +3,11 @@
#define _RAR_BLAKE2_
#define BLAKE2_DIGEST_SIZE 32
#define BLAKE2_THREADS_NUMBER 8
enum blake2s_constant
{
BLAKE2S_BLOCKBYTES = 64,
BLAKE2S_OUTBYTES = 32
};
// Use constexpr instead of enums for -std=c++20 compatibility.
constexpr size_t BLAKE2S_BLOCKBYTES = 64;
constexpr size_t 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.
@@ -19,10 +17,15 @@ enum blake2s_constant
// 'new' operator.
struct blake2s_state
{
enum { BLAKE_ALIGNMENT = 64 };
// Use constexpr instead of enums, because otherwise clang -std=c++20
// issues a warning about "arithmetic between different enumeration types"
// in ubuf[BLAKE_DATA_SIZE + BLAKE_ALIGNMENT] declaration.
static constexpr size_t BLAKE_ALIGNMENT = 64;
// buffer and uint32 h[8], t[2], f[2];
enum { BLAKE_DATA_SIZE = 48 + 2 * BLAKE2S_BLOCKBYTES };
// 2 * BLAKE2S_BLOCKBYTES is the buf size in blake2_code_20140114.zip.
// It might differ in later versions.
static constexpr size_t BLAKE_DATA_SIZE = 48 + 2 * BLAKE2S_BLOCKBYTES;
byte ubuf[BLAKE_DATA_SIZE + BLAKE_ALIGNMENT];

View File

@@ -1,15 +1,14 @@
// 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.
// Constants for cyclic rotation.
static __m128i crotr8, crotr16;
#endif
#ifdef __GNUC__
__attribute__((target("sse2")))
#endif
static void blake2s_init_sse()
{
// We cannot initialize these 128 bit variables in place when declaring
@@ -24,28 +23,18 @@ static void blake2s_init_sse()
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 ); \
@@ -73,14 +62,6 @@ static void blake2s_init_sse()
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
@@ -101,6 +82,9 @@ static void blake2s_init_sse()
}
#ifdef __GNUC__
__attribute__((target("ssse3")))
#endif
static int blake2s_compress_sse( blake2s_state *S, const byte block[BLAKE2S_BLOCKBYTES] )
{
__m128i row[4];

View File

@@ -20,7 +20,7 @@ void blake2sp_init( blake2sp_state *S )
blake2s_init_param( &S->R, 0, 1 ); // Init root.
for( uint i = 0; i < PARALLELISM_DEGREE; ++i )
for( uint32 i = 0; i < PARALLELISM_DEGREE; ++i )
blake2s_init_param( &S->S[i], i, 0 ); // Init leaf.
S->R.last_node = 1;
@@ -49,6 +49,8 @@ void Blake2ThreadData::Update()
if (_SSE_Version>=SSE_SSE && inlen__ >= 2 * PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES)
_mm_prefetch((char*)(in__ + PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES), _MM_HINT_T0);
#endif
// We tried to _forceinline blake2s_update and blake2s_compress_sse,
// but it didn't improve performance.
blake2s_update( S, in__, BLAKE2S_BLOCKBYTES );
in__ += PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES;
inlen__ -= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES;

File diff suppressed because it is too large Load Diff

View File

@@ -1,18 +1,30 @@
#ifndef _RAR_CMDDATA_
#define _RAR_CMDDATA_
#if defined(_WIN_ALL) && !defined(SFX_MODULE)
// In Windows we implement our own command line parser to avoid replacing
// \" by " in standard parser. Such replacing corrupts destination paths
// like "dest path\" in extraction commands.
#define CUSTOM_CMDLINE_PARSER
#endif
#define DefaultStoreList L"7z;ace;arj;bz2;cab;gz;jpeg;jpg;lha;lz;lzh;mp3;rar;taz;tgz;xz;z;zip;zipx"
#define DefaultStoreList L"7z;arj;bz2;cab;gz;jpeg;jpg;lha;lz;lzh;mp3;rar;taz;tbz;tbz2;tgz;txz;xz;z;zip;zipx;zst;tzst"
enum RAR_CMD_LIST_MODE {RCLM_AUTO,RCLM_REJECT_LISTS,RCLM_ACCEPT_LISTS};
enum IS_PROCESS_FILE_FLAGS {IPFF_EXCLUDE_PARENT=1};
class CommandData:public RAROptions
{
private:
void ProcessSwitchesString(const wchar *Str);
void ProcessSwitch(const wchar *Switch);
void BadSwitch(const wchar *Switch);
uint GetExclAttr(const wchar *Str);
uint GetExclAttr(const wchar *Str,bool &Dir);
#if !defined(SFX_MODULE)
void SetTimeFilters(const wchar *Mod,bool Before,bool Age);
void SetStoreTimeMode(const wchar *S);
#endif
int64 GetModSize(const wchar *S,uint DefMultiplier);
bool FileLists;
bool NoMoreSwitches;
@@ -23,42 +35,69 @@ class CommandData:public RAROptions
void Init();
void ParseCommandLine(bool Preprocess,int argc, char *argv[]);
void ParseArg(wchar *ArgW);
void ParseArg(const wchar *ArgW);
void ParseDone();
void ParseEnvVar();
void ReadConfig();
void PreprocessArg(const wchar *Arg);
void ProcessSwitchesString(const std::wstring &Str);
void OutTitle();
void OutHelp(RAR_EXIT ExitCode);
bool IsSwitch(int Ch);
bool ExclCheck(const wchar *CheckName,bool Dir,bool CheckFullPath,bool CheckInclList);
static bool CheckArgs(StringList *Args,bool Dir,const wchar *CheckName,bool CheckFullPath,int MatchMode);
bool ExclCheck(const std::wstring &CheckName,bool Dir,bool CheckFullPath,bool CheckInclList);
static bool CheckArgs(StringList *Args,bool Dir,const std::wstring &CheckName,bool CheckFullPath,int MatchMode);
bool ExclDirByAttr(uint FileAttr);
bool TimeCheck(RarTime &ft);
bool TimeCheck(RarTime &ftm,RarTime &ftc,RarTime &fta);
bool SizeCheck(int64 Size);
bool AnyFiltersActive();
int IsProcessFile(FileHeader &FileHead,bool *ExactMatch=NULL,int MatchType=MATCH_WILDSUBPATH,
wchar *MatchedArg=NULL,uint MatchedArgSize=0);
int IsProcessFile(FileHeader &FileHead,bool *ExactMatch,int MatchType,
bool Flags,std::wstring *MatchedArg);
void ProcessCommand();
void AddArcName(const wchar *Name);
void AddArcName(const std::wstring &Name);
bool GetArcName(wchar *Name,int MaxSize);
bool CheckWinSize();
bool GetArcName(std::wstring &Name);
int GetRecoverySize(const wchar *Str,int DefSize);
#ifndef SFX_MODULE
void ReportWrongSwitches(RARFORMAT Format);
#endif
wchar Command[NM+16];
void GetBriefMaskList(const std::wstring &Masks,StringList &Args);
wchar ArcName[NM];
std::wstring Command;
std::wstring ArcName;
std::wstring ExtrPath;
std::wstring TempPath;
std::wstring SFXModule;
std::wstring CommentFile;
std::wstring ArcPath; // For -ap<path>.
std::wstring ExclArcPath; // For -ep4<path> switch.
std::wstring LogName;
std::wstring EmailTo;
// Read data from stdin and store in archive under a name specified here
// when archiving. Read an archive from stdin if any non-empty string
// is specified here when extracting.
std::wstring UseStdin;
StringList FileArgs;
StringList ExclArgs;
StringList InclArgs;
StringList ArcNames;
StringList StoreArgs;
#ifdef PROPAGATE_MOTW
StringList MotwList; // Extensions to assign the mark of the web.
#endif
SecPassword Password;
std::vector<int64> NextVolSizes;
#ifdef RARDLL
std::wstring DllDestName;
#endif
};
#endif

380
unrar/cmdfilter.cpp Normal file
View File

@@ -0,0 +1,380 @@
// Return 'true' if we need to exclude the file from processing as result
// of -x switch. If CheckInclList is true, we also check the file against
// the include list created with -n switch.
bool CommandData::ExclCheck(const std::wstring &CheckName,bool Dir,bool CheckFullPath,bool CheckInclList)
{
if (CheckArgs(&ExclArgs,Dir,CheckName,CheckFullPath,MATCH_WILDSUBPATH))
return true;
if (!CheckInclList || InclArgs.ItemsCount()==0)
return false;
if (CheckArgs(&InclArgs,Dir,CheckName,CheckFullPath,MATCH_WILDSUBPATH))
return false;
return true;
}
bool CommandData::CheckArgs(StringList *Args,bool Dir,const std::wstring &CheckName,bool CheckFullPath,int MatchMode)
{
std::wstring Name,FullName,CurMask;
ConvertPath(&CheckName,&Name);
Args->Rewind();
while (Args->GetString(CurMask))
{
#ifdef _WIN_ALL
// 2025.09.11: Unix allows DOS slashes as a part of file name, so we do not
// convert it for Unix. In Windows we wish -xdir\file and -xdir/file both
// to exclude the file.
UnixSlashToDos(CurMask,CurMask);
#endif
wchar LastMaskChar=GetLastChar(CurMask);
bool DirMask=IsPathDiv(LastMaskChar); // Mask for directories only.
if (Dir)
{
// CheckName is a directory.
if (DirMask)
{
// We process the directory and have the directory exclusion mask.
// So let's convert "mask\" to "mask" and process it normally.
CurMask.pop_back();
}
else
{
// This code doesn't allow to apply -n and -x wildcard masks without
// trailing slash to folders unless these masks are * and *.*.
// See the changes history below.
// 2023.03.26: Previously we removed this code completely to let
// 'rar a arc dir -ndir\path\*' include empty folders in 'path' too.
// But then we received an email from user not willing -x*.avi to
// exclude folders like dir.avi with non-avi files. Also rar.txt
// mentions that masks like *.avi exclude only files. Initially
// we wanted masks like -npath\* or -xpath\* to match the entire
// contents of path including empty folders and added the special
// check for "*" and "*.*". But this is not very straightforward,
// when *.* and *.avi are processed differently, especially taking
// into account that we can specify the exact folder name without
// wildcards to process it and masks like 'dir*\' can be used to
// exclude folders. So we decided to skip all usual wildcard masks
// for folders.
// 2023.11.22: We returned the special check for "*" and "*.*",
// because users expected 'rar a arc dir -xdir\*' to exclude
// everything including subfolders in 'dir'. For now we returned it
// both for -n and -x, but we can limit it to -x only if needed.
std::wstring Name=PointToName(CurMask);
if (IsWildcard(Name) && Name!=L"*" && Name!=L"*.*")
continue;
}
}
else
{
// If we process a file inside of directory excluded by "dirmask\".
// we want to exclude such file too. So we convert "dirmask\" to
// "dirmask\*". It is important for operations other than archiving
// with -x. When archiving with -x, directory matched by "dirmask\"
// is excluded from further scanning.
if (DirMask)
CurMask+=L"*";
}
#ifndef SFX_MODULE
if (CheckFullPath && IsFullPath(CurMask))
{
// We do not need to do the special "*\" processing here, because
// unlike the "else" part of this "if", now we convert names to full
// format, so they all include the path, which is matched by "*\"
// correctly. Moreover, removing "*\" from mask would break
// the comparison, because now all names have the path.
if (FullName.empty())
ConvertNameToFull(CheckName,FullName);
if (CmpName(CurMask,FullName,MatchMode))
return true;
}
else
#endif
{
std::wstring CurName=Name;
// Important to convert before "*\" check below, so masks like
// d:*\something are processed properly.
size_t MaskOffset=ConvertPath(&CurMask,nullptr);
std::wstring CmpMask=CurMask.substr(MaskOffset);
if (CmpMask[0]=='*' && IsPathDiv(CmpMask[1]))
{
// We want "*\name" to match 'name' not only in subdirectories,
// but also in the current directory. We convert the name
// from 'name' to '.\name' to be matched by "*\" part even if it is
// in current directory.
CurName=L'.';
CurName+=CPATHDIVIDER;
CurName+=Name;
}
if (CmpName(CmpMask,CurName,MatchMode))
return true;
}
}
return false;
}
#ifndef SFX_MODULE
// Now this function performs only one task and only in Windows version:
// it skips symlinks to directories if -e1024 switch is specified.
// Symlinks are skipped in ScanTree class, so their entire contents
// is skipped too. Without this function we would check the attribute
// only directly before archiving, so we would skip the symlink record,
// but not the contents of symlinked directory.
bool CommandData::ExclDirByAttr(uint FileAttr)
{
#ifdef _WIN_ALL
if ((FileAttr & FILE_ATTRIBUTE_REPARSE_POINT)!=0 &&
(ExclFileAttr & FILE_ATTRIBUTE_REPARSE_POINT)!=0)
return true;
#endif
return false;
}
#endif
#if !defined(SFX_MODULE)
void CommandData::SetTimeFilters(const wchar *Mod,bool Before,bool Age)
{
bool ModeOR=false,TimeMods=false;
const wchar *S=Mod;
// Check if any 'mca' modifiers are present, set OR mode if 'o' is present,
// skip modifiers and set S to beginning of time string. Be sure to check
// *S!=0, because termination 0 is a part of string for wcschr.
for (;*S!=0 && wcschr(L"MCAOmcao",*S)!=NULL;S++)
if (*S=='o' || *S=='O')
ModeOR=true;
else
TimeMods=true;
if (!TimeMods) // Assume 'm' if no modifiers are specified.
Mod=L"m";
// Set the specified time for every modifier. Be sure to check *Mod!=0,
// because termination 0 is a part of string for wcschr. This check is
// important when we set Mod to "m" above.
for (;*Mod!=0 && wcschr(L"MCAOmcao",*Mod)!=NULL;Mod++)
switch(toupperw(*Mod))
{
case 'M':
if (Before)
{
Age ? FileMtimeBefore.SetAgeText(S):FileMtimeBefore.SetIsoText(S);
FileMtimeBeforeOR=ModeOR;
}
else
{
Age ? FileMtimeAfter.SetAgeText(S):FileMtimeAfter.SetIsoText(S);
FileMtimeAfterOR=ModeOR;
}
break;
case 'C':
if (Before)
{
Age ? FileCtimeBefore.SetAgeText(S):FileCtimeBefore.SetIsoText(S);
FileCtimeBeforeOR=ModeOR;
}
else
{
Age ? FileCtimeAfter.SetAgeText(S):FileCtimeAfter.SetIsoText(S);
FileCtimeAfterOR=ModeOR;
}
break;
case 'A':
if (Before)
{
Age ? FileAtimeBefore.SetAgeText(S):FileAtimeBefore.SetIsoText(S);
FileAtimeBeforeOR=ModeOR;
}
else
{
Age ? FileAtimeAfter.SetAgeText(S):FileAtimeAfter.SetIsoText(S);
FileAtimeAfterOR=ModeOR;
}
break;
}
}
#endif
#ifndef SFX_MODULE
// Return 'true' if we need to exclude the file from processing.
bool CommandData::TimeCheck(RarTime &ftm,RarTime &ftc,RarTime &fta)
{
bool FilterOR=false;
if (FileMtimeBefore.IsSet()) // Filter present.
if (ftm>=FileMtimeBefore) // Condition not matched.
if (FileMtimeBeforeOR)
FilterOR=true; // Not matched OR filter is present.
else
return true; // Exclude file in AND mode.
else // Condition matched.
if (FileMtimeBeforeOR)
return false; // Include file in OR mode.
if (FileMtimeAfter.IsSet()) // Filter present.
if (ftm<FileMtimeAfter) // Condition not matched.
if (FileMtimeAfterOR)
FilterOR=true; // Not matched OR filter is present.
else
return true; // Exclude file in AND mode.
else // Condition matched.
if (FileMtimeAfterOR)
return false; // Include file in OR mode.
if (FileCtimeBefore.IsSet()) // Filter present.
if (ftc>=FileCtimeBefore) // Condition not matched.
if (FileCtimeBeforeOR)
FilterOR=true; // Not matched OR filter is present.
else
return true; // Exclude file in AND mode.
else // Condition matched.
if (FileCtimeBeforeOR)
return false; // Include file in OR mode.
if (FileCtimeAfter.IsSet()) // Filter present.
if (ftc<FileCtimeAfter) // Condition not matched.
if (FileCtimeAfterOR)
FilterOR=true; // Not matched OR filter is present.
else
return true; // Exclude file in AND mode.
else // Condition matched.
if (FileCtimeAfterOR)
return false; // Include file in OR mode.
if (FileAtimeBefore.IsSet()) // Filter present.
if (fta>=FileAtimeBefore) // Condition not matched.
if (FileAtimeBeforeOR)
FilterOR=true; // Not matched OR filter is present.
else
return true; // Exclude file in AND mode.
else // Condition matched.
if (FileAtimeBeforeOR)
return false; // Include file in OR mode.
if (FileAtimeAfter.IsSet()) // Filter present.
if (fta<FileAtimeAfter) // Condition not matched.
if (FileAtimeAfterOR)
FilterOR=true; // Not matched OR filter is present.
else
return true; // Exclude file in AND mode.
else // Condition matched.
if (FileAtimeAfterOR)
return false; // Include file in OR mode.
return FilterOR; // Exclude if all OR filters are not matched.
}
#endif
#ifndef SFX_MODULE
// Return 'true' if we need to exclude the file from processing.
bool CommandData::SizeCheck(int64 Size)
{
if (Size==INT64NDF) // If called from archive formats like bzip2, not storing the file size.
return false;
if (FileSizeLess!=INT64NDF && Size>=FileSizeLess)
return true;
if (FileSizeMore!=INT64NDF && Size<=FileSizeMore)
return true;
return false;
}
#endif
// Return 0 if file must not be processed or a number of matched parameter otherwise.
int CommandData::IsProcessFile(FileHeader &FileHead,bool *ExactMatch,int MatchType,
bool Flags,std::wstring *MatchedArg)
{
if (MatchedArg!=NULL)
MatchedArg->clear();
bool Dir=FileHead.Dir;
if (ExclCheck(FileHead.FileName,Dir,false,true))
return 0;
#ifndef SFX_MODULE
if (TimeCheck(FileHead.mtime,FileHead.ctime,FileHead.atime))
return 0;
if ((FileHead.FileAttr & ExclFileAttr)!=0 || FileHead.Dir && ExclDir)
return 0;
if (InclAttrSet && (FileHead.FileAttr & InclFileAttr)==0 &&
(!FileHead.Dir || !InclDir))
return 0;
if (!Dir && SizeCheck(FileHead.UnpSize))
return 0;
#endif
std::wstring ArgName;
FileArgs.Rewind();
for (int StringCount=1;FileArgs.GetString(ArgName);StringCount++)
{
// Ensure that both parameters of CmpName are either C++ strings or
// pointers, so we avoid time consuming string construction for one of
// parameters in this expensive loop.
if (CmpName(ArgName,FileHead.FileName,MatchType))
{
if (ExactMatch!=NULL)
*ExactMatch=wcsicompc(ArgName,FileHead.FileName)==0;
if (MatchedArg!=NULL)
*MatchedArg=ArgName;
return StringCount;
}
}
return 0;
}
#if !defined(SFX_MODULE)
void CommandData::SetStoreTimeMode(const wchar *S)
{
if (*S==0 || IsDigit(*S) || *S=='-' || *S=='+')
{
// Apply -ts, -ts1, -ts-, -ts+ to all 3 times.
// Handle obsolete -ts[2,3,4] as ts+.
EXTTIME_MODE Mode=EXTTIME_MAX;
if (*S=='-')
Mode=EXTTIME_NONE;
if (*S=='1')
Mode=EXTTIME_1S;
xmtime=xctime=xatime=Mode;
S++;
}
while (*S!=0)
{
EXTTIME_MODE Mode=EXTTIME_MAX;
if (S[1]=='-')
Mode=EXTTIME_NONE;
if (S[1]=='1')
Mode=EXTTIME_1S;
switch(toupperw(*S))
{
case 'M':
xmtime=Mode;
break;
case 'C':
xctime=Mode;
break;
case 'A':
xatime=Mode;
break;
case 'P':
PreserveAtime=true;
break;
}
S++;
}
}
#endif

123
unrar/cmdmix.cpp Normal file
View File

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

View File

@@ -1,8 +1,8 @@
inline unsigned int RangeCoder::GetChar()
inline byte RangeCoder::GetChar()
{
return(UnpackRead->GetChar());
return UnpackRead->GetChar();
}
@@ -11,8 +11,8 @@ void RangeCoder::InitDecoder(Unpack *UnpackRead)
RangeCoder::UnpackRead=UnpackRead;
low=code=0;
range=uint(-1);
for (int i=0;i < 4;i++)
range=0xffffffff;
for (uint i = 0; i < 4; i++)
code=(code << 8) | GetChar();
}

View File

@@ -11,7 +11,7 @@ class RangeCoder
inline uint GetCurrentShiftCount(uint SHIFT);
inline void Decode();
inline void PutChar(unsigned int c);
inline unsigned int GetChar();
inline byte GetChar();
uint low, code, range;
struct SUBRANGE

View File

@@ -6,15 +6,27 @@
class PackDef
{
public:
// Maximum LZ match length we can encode even for short distances.
static const uint MAX_LZ_MATCH = 0x1001;
// We increment LZ match length for longer distances, because shortest
// matches are not allowed for them. Maximum length increment is 3
// for distances larger than 256KB (0x40000). Here we define the maximum
// incremented LZ match. Normally packer does not use it, but we must be
// ready to process it in corrupt archives.
static const uint MAX_INC_LZ_MATCH = MAX_LZ_MATCH + 3;
static const uint MAX3_LZ_MATCH = 0x101; // Maximum match length for RAR v3.
static const uint MAX3_INC_LZ_MATCH = MAX3_LZ_MATCH + 3;
static const uint LOW_DIST_REP_COUNT = 16;
static const uint NC = 306; /* alphabet = {0, 1, 2, ..., NC - 1} */
static const uint DC = 64;
static const uint DCB = 64; // Base distance codes up to 4 GB.
static const uint DCX = 80; // Extended distance codes up to 1 TB.
static const uint LDC = 16;
static const uint RC = 44;
static const uint HUFF_TABLE_SIZE = NC + DC + RC + LDC;
static const uint HUFF_TABLE_SIZEB = NC + DCB + RC + LDC;
static const uint HUFF_TABLE_SIZEX = NC + DCX + RC + LDC;
static const uint BC = 20;
static const uint NC30 = 299; /* alphabet = {0, 1, 2, ..., NC - 1} */
@@ -33,10 +45,6 @@ class PackDef
// Largest alphabet size among all values listed above.
static const uint LARGEST_TABLE_SIZE = 306;
enum {
CODE_HUFFMAN, CODE_LZ, CODE_REPEATLZ, CODE_CACHELZ, CODE_STARTFILE,
CODE_ENDFILE, CODE_FILTER, CODE_FILTERDATA
};
};
@@ -44,7 +52,10 @@ enum FilterType {
// 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
FILTER_AUDIO, FILTER_RGB, FILTER_ITANIUM, FILTER_TEXT,
// These values can be changed.
FILTER_LONGRANGE,FILTER_EXHAUSTIVE,FILTER_NONE
};
#endif

View File

@@ -3,8 +3,8 @@
static MESSAGE_TYPE MsgStream=MSG_STDOUT;
static RAR_CHARSET RedirectCharset=RCH_DEFAULT;
const int MaxMsgSize=2*NM+2048;
static bool ProhibitInput=false;
static bool ConsoleOutputPresent=false;
static bool StdoutRedirected=false,StderrRedirected=false,StdinRedirected=false;
@@ -49,54 +49,65 @@ void InitConsole()
}
void InitConsoleOptions(MESSAGE_TYPE MsgStream,RAR_CHARSET RedirectCharset)
void SetConsoleMsgStream(MESSAGE_TYPE MsgStream)
{
::MsgStream=MsgStream;
}
void SetConsoleRedirectCharset(RAR_CHARSET RedirectCharset)
{
::RedirectCharset=RedirectCharset;
}
void ProhibitConsoleInput()
{
ProhibitInput=true;
}
#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));
ConsoleOutputPresent=true;
// No need for PrintfPrepareFmt here, vwstrprintf calls it.
std::wstring s=vwstrprintf(fmt,arglist);
ReplaceEsc(s);
#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);
WriteFile(hOut,s.data(),(DWORD)s.size()*sizeof(s[0]),&Written,NULL);
else
{
// Avoid Unicode for redirect in Windows, it does not work with pipes.
safebuf char MsgA[MaxMsgSize];
std::string MsgA;
if (RedirectCharset==RCH_UTF8)
WideToUtf(Msg,MsgA,ASIZE(MsgA));
WideToUtf(s,MsgA);
else
WideToChar(Msg,MsgA,ASIZE(MsgA));
WideToChar(s,MsgA);
if (RedirectCharset==RCH_DEFAULT || RedirectCharset==RCH_OEM)
CharToOemA(MsgA,MsgA); // Console tools like 'more' expect OEM encoding.
CharToOemA(&MsgA[0],&MsgA[0]); // 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);
WriteFile(hOut,MsgA.data(),(DWORD)MsgA.size(),&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);
WriteConsole(hOut,s.data(),(DWORD)s.size(),&Written,NULL);
#else
vfwprintf(dest,fmtw,arglist);
fputws(s.c_str(),dest);
// We do not use setbuf(NULL) in Unix (see comments in InitConsole).
fflush(dest);
#endif
@@ -136,81 +147,109 @@ void eprintf(const wchar *fmt,...)
#ifndef SILENT
static void GetPasswordText(wchar *Str,uint MaxLength)
static void QuitIfInputProhibited()
{
if (MaxLength==0)
return;
// We cannot handle user prompts if -si is used to read file or archive data
// from stdin.
if (ProhibitInput)
{
mprintf(St(MStdinNoInput));
ErrHandler.Exit(RARX_FATAL);
}
}
static void GetPasswordText(std::wstring &Str)
{
QuitIfInputProhibited();
if (StdinRedirected)
getwstr(Str,MaxLength); // Read from pipe or redirected file.
getwstr(Str); // 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;
DWORD ConInMode;
GetConsoleMode(hConIn,&ConInMode);
GetConsoleMode(hConOut,&ConOutMode);
SetConsoleMode(hConIn,ENABLE_LINE_INPUT);
SetConsoleMode(hConOut,ENABLE_PROCESSED_OUTPUT|ENABLE_WRAP_AT_EOL_OUTPUT);
SetConsoleMode(hConIn,ENABLE_LINE_INPUT); // Remove ENABLE_ECHO_INPUT.
std::vector<wchar> Buf(MAXPASSWORD);
// We prefer ReadConsole to ReadFile, so we can read Unicode input.
DWORD Read=0;
ReadConsole(hConIn,Buf.data(),(DWORD)Buf.size()-1,&Read,NULL);
Buf[Read]=0;
Str=Buf.data();
cleandata(Buf.data(),Buf.size()*sizeof(Buf[0]));
ReadConsole(hConIn,Str,MaxLength-1,&Read,NULL);
Str[Read]=0;
SetConsoleMode(hConIn,ConInMode);
SetConsoleMode(hConOut,ConOutMode);
// 2023.03.12: Previously we checked for presence of "\n" in entered
// passwords, supposing that truncated strings do not include it.
// We did it to read the rest of excessively long string, so it is not
// read later as the second password for -p switch. But this "\n" check
// doesn't seem to work in Windows 10 anymore and "\r" is present even
// in truncated strings. Also we increased MAXPASSWORD, so it is larger
// than MAXPASSWORD_RAR. Thus we removed this check as not working
// and not that necessary. Low level FlushConsoleInputBuffer doesn't help
// for high level ReadConsole, which in line input mode seems to store
// the rest of string in its own internal buffer.
#else
char StrA[MAXPASSWORD];
#if defined(_EMX) || defined (__VMS)
fgets(StrA,ASIZE(StrA)-1,stdin);
std::vector<char> StrA(MAXPASSWORD*4); // "*4" for multibyte UTF-8 characters.
#ifdef __VMS
fgets(StrA.data(),StrA.size()-1,stdin);
#elif defined(__sun)
strncpyz(StrA,getpassphrase(""),ASIZE(StrA));
strncpyz(StrA.data(),getpassphrase(""),StrA.size());
#else
strncpyz(StrA,getpass(""),ASIZE(StrA));
strncpyz(StrA.data(),getpass(""),StrA.size());
#endif
CharToWide(StrA,Str,MaxLength);
cleandata(StrA,sizeof(StrA));
CharToWide(StrA.data(),Str);
cleandata(StrA.data(),StrA.size()*sizeof(StrA[0]));
#endif
}
Str[MaxLength-1]=0;
RemoveLF(Str);
}
#endif
#ifndef SILENT
bool GetConsolePassword(UIPASSWORD_TYPE Type,const wchar *FileName,SecPassword *Password)
bool GetConsolePassword(UIPASSWORD_TYPE Type,const std::wstring &FileName,SecPassword *Password)
{
if (!StdinRedirected)
uiAlarm(UIALARM_QUESTION);
while (true)
{
if (!StdinRedirected)
// if (!StdinRedirected)
if (Type==UIPASSWORD_GLOBAL)
eprintf(L"\n%s: ",St(MAskPsw));
else
eprintf(St(MAskPswFor),FileName);
eprintf(St(MAskPswFor),FileName.c_str());
wchar PlainPsw[MAXPASSWORD];
GetPasswordText(PlainPsw,ASIZE(PlainPsw));
if (*PlainPsw==0 && Type==UIPASSWORD_GLOBAL)
std::wstring PlainPsw;
GetPasswordText(PlainPsw);
if (PlainPsw.empty() && Type==UIPASSWORD_GLOBAL)
return false;
if (PlainPsw.size()>=MAXPASSWORD)
{
PlainPsw.erase(MAXPASSWORD-1);
uiMsg(UIERROR_TRUNCPSW,MAXPASSWORD-1);
}
if (!StdinRedirected && Type==UIPASSWORD_GLOBAL)
{
eprintf(St(MReAskPsw));
wchar CmpStr[MAXPASSWORD];
GetPasswordText(CmpStr,ASIZE(CmpStr));
if (*CmpStr==0 || wcscmp(PlainPsw,CmpStr)!=0)
std::wstring CmpStr;
GetPasswordText(CmpStr);
if (CmpStr.empty() || PlainPsw!=CmpStr)
{
eprintf(St(MNotMatchPsw));
cleandata(PlainPsw,sizeof(PlainPsw));
cleandata(CmpStr,sizeof(CmpStr));
cleandata(&PlainPsw[0],PlainPsw.size()*sizeof(PlainPsw[0]));
cleandata(&CmpStr[0],CmpStr.size()*sizeof(CmpStr[0]));
continue;
}
cleandata(CmpStr,sizeof(CmpStr));
cleandata(&CmpStr[0],CmpStr.size()*sizeof(CmpStr[0]));
}
Password->Set(PlainPsw);
cleandata(PlainPsw,sizeof(PlainPsw));
Password->Set(PlainPsw.c_str());
cleandata(&PlainPsw[0],PlainPsw.size()*sizeof(PlainPsw[0]));
break;
}
return true;
@@ -219,12 +258,17 @@ bool GetConsolePassword(UIPASSWORD_TYPE Type,const wchar *FileName,SecPassword *
#ifndef SILENT
bool getwstr(wchar *str,size_t n)
void getwstr(std::wstring &str)
{
// Print buffered prompt title function before waiting for input.
fflush(stderr);
*str=0;
QuitIfInputProhibited();
str.clear();
const size_t MaxRead=MAXPATHSIZE; // Large enough to read a file name.
#if defined(_WIN_ALL)
// fgetws does not work well with non-English text in Windows,
// so we do not use it.
@@ -232,33 +276,50 @@ bool getwstr(wchar *str,size_t n)
{
// 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.
std::vector<char> StrA(MaxRead*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);
SrcFile.SetLineInputMode(true);
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);
// calling Ask() or set an empty password, so let's better exit.
ErrHandler.ReadError(L"stdin");
}
StrA[ReadSize]=0;
CharToWide(&StrA[0],str,n);
cleandata(&StrA[0],StrA.Size()); // We can use this function to enter passwords.
// We expect ANSI encoding here, but "echo text|rar ..." to pipe to RAR,
// such as send passwords, we get OEM encoding by default, unless we
// use "chcp" in console. But we avoid OEM to ANSI conversion,
// because we also want to handle ANSI files redirection correctly,
// like "rar ... < ansifile.txt".
CharToWide(&StrA[0],str);
cleandata(&StrA[0],StrA.size()); // We can use this function to enter passwords.
}
else
{
std::vector<wchar> Buf(MaxRead); // Up to 4 UTF-8 characters per wchar_t.
DWORD SizeToRead=(DWORD)Buf.size()-1;
// ReadConsole fails in Windows 7 for requested input exceeding 30 KB.
// Not certain about Windows 8, so check for Windows 10 here.
if (WinNT()<=WNT_W10)
SizeToRead=Min(SizeToRead,0x4000);
DWORD ReadSize=0;
if (ReadConsole(GetStdHandle(STD_INPUT_HANDLE),str,DWORD(n-1),&ReadSize,NULL)==0)
return false;
str[ReadSize]=0;
if (ReadConsole(GetStdHandle(STD_INPUT_HANDLE),&Buf[0],SizeToRead,&ReadSize,NULL)==0)
ErrHandler.ReadError(L"stdin"); // Unknown user input, safer to abort.
Buf[ReadSize]=0;
str=Buf.data();
}
#else
if (fgetws(str,n,stdin)==NULL)
ErrHandler.Exit(RARX_USERBREAK); // Avoid infinite Ask() loop.
std::vector<wchar> Buf(MaxRead); // Up to 4 UTF-8 characters per wchar_t.
if (fgetws(&Buf[0],Buf.size(),stdin)==NULL)
ErrHandler.ReadError(L"stdin"); // Avoid infinite Ask() loop.
str=Buf.data();
#endif
RemoveLF(str);
return true;
}
#endif
@@ -272,22 +333,22 @@ int Ask(const wchar *AskStr)
{
uiAlarm(UIALARM_QUESTION);
const int MaxItems=10;
const uint MaxItems=10;
wchar Item[MaxItems][40];
int ItemKeyPos[MaxItems],NumItems=0;
uint ItemKeyPos[MaxItems],NumItems=0;
for (const wchar *NextItem=AskStr;NextItem!=NULL;NextItem=wcschr(NextItem+1,'_'))
for (const wchar *NextItem=AskStr;NextItem!=nullptr;NextItem=wcschr(NextItem+1,'_'))
{
wchar *CurItem=Item[NumItems];
wcsncpyz(CurItem,NextItem+1,ASIZE(Item[0]));
wchar *EndItem=wcschr(CurItem,'_');
if (EndItem!=NULL)
if (EndItem!=nullptr)
*EndItem=0;
int KeyPos=0,CurKey;
uint KeyPos=0,CurKey;
while ((CurKey=CurItem[KeyPos])!=0)
{
bool Found=false;
for (int I=0;I<NumItems && !Found;I++)
for (uint I=0;I<NumItems && !Found;I++)
if (toupperw(Item[I][ItemKeyPos[I]])==toupperw(CurKey))
Found=true;
if (!Found && CurKey!=' ')
@@ -298,19 +359,19 @@ int Ask(const wchar *AskStr)
NumItems++;
}
for (int I=0;I<NumItems;I++)
for (uint I=0;I<NumItems;I++)
{
eprintf(I==0 ? (NumItems>4 ? L"\n":L" "):L", ");
int KeyPos=ItemKeyPos[I];
for (int J=0;J<KeyPos;J++)
eprintf(I==0 ? (NumItems>3 ? L"\n":L" "):L", ");
uint KeyPos=ItemKeyPos[I];
for (uint J=0;J<KeyPos;J++)
eprintf(L"%c",Item[I][J]);
eprintf(L"[%c]%ls",Item[I][KeyPos],&Item[I][KeyPos+1]);
}
eprintf(L" ");
wchar Str[50];
getwstr(Str,ASIZE(Str));
std::wstring Str;
getwstr(Str);
wchar Ch=toupperw(Str[0]);
for (int I=0;I<NumItems;I++)
for (uint I=0;I<NumItems;I++)
if (Ch==Item[I][ItemKeyPos[I]])
return I+1;
return 0;
@@ -318,11 +379,11 @@ int Ask(const wchar *AskStr)
#endif
static bool IsCommentUnsafe(const wchar *Data,size_t Size)
static bool IsCommentUnsafe(const std::wstring &Data)
{
for (size_t I=0;I<Size;I++)
for (size_t I=0;I<Data.size();I++)
if (Data[I]==27 && Data[I+1]=='[')
for (size_t J=I+2;J<Size;J++)
for (size_t J=I+2;J<Data.size();J++)
{
// Return true for <ESC>[{key};"{string}"p used to redefine
// a keyboard key on some terminals.
@@ -335,18 +396,21 @@ static bool IsCommentUnsafe(const wchar *Data,size_t Size)
}
void OutComment(const wchar *Comment,size_t Size)
void OutComment(const std::wstring &Comment)
{
if (IsCommentUnsafe(Comment,Size))
if (IsCommentUnsafe(Comment))
return;
const size_t MaxOutSize=0x400;
for (size_t I=0;I<Size;I+=MaxOutSize)
for (size_t I=0;I<Comment.size();I+=MaxOutSize)
{
wchar Msg[MaxOutSize+1];
size_t CopySize=Min(MaxOutSize,Size-I);
wcsncpy(Msg,Comment+I,CopySize);
Msg[CopySize]=0;
mprintf(L"%s",Msg);
size_t CopySize=Min(MaxOutSize,Comment.size()-I);
mprintf(L"%s",Comment.substr(I,CopySize).c_str());
}
mprintf(L"\n");
}
bool IsConsoleOutputPresent()
{
return ConsoleOutputPresent;
}

View File

@@ -2,11 +2,14 @@
#define _RAR_CONSIO_
void InitConsole();
void InitConsoleOptions(MESSAGE_TYPE MsgStream,RAR_CHARSET RedirectCharset);
void OutComment(const wchar *Comment,size_t Size);
void SetConsoleMsgStream(MESSAGE_TYPE MsgStream);
void SetConsoleRedirectCharset(RAR_CHARSET RedirectCharset);
void ProhibitConsoleInput();
void OutComment(const std::wstring &Comment);
bool IsConsoleOutputPresent();
#ifndef SILENT
bool GetConsolePassword(UIPASSWORD_TYPE Type,const wchar *FileName,SecPassword *Password);
bool GetConsolePassword(UIPASSWORD_TYPE Type,const std::wstring &FileName,SecPassword *Password);
#endif
#ifdef SILENT
@@ -14,13 +17,13 @@ bool GetConsolePassword(UIPASSWORD_TYPE Type,const wchar *FileName,SecPassword *
inline void eprintf(const wchar *fmt,...) {}
inline void Alarm() {}
inline int Ask(const wchar *AskStr) {return 0;}
inline bool getwstr(wchar *str,size_t n) {return false;}
inline void getwstr(std::wstring &str) {}
#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);
void getwstr(std::wstring &str);
#endif
#endif

View File

@@ -14,7 +14,17 @@
#include "rar.hpp"
static uint crc_tables[8][256]; // Tables for Slicing-by-8.
#ifndef SFX_MODULE
// User suggested to avoid BSD license in SFX module, so they do not need
// to include the license to SFX archive.
#define USE_SLICING
#endif
static uint crc_tables[16][256]; // Tables for Slicing-by-16.
#ifdef USE_NEON_CRC32
static bool CRC_Neon;
#endif
// Build the classic CRC32 lookup table.
@@ -30,6 +40,19 @@ void InitCRC32(uint *CRCTab)
C=(C & 1) ? (C>>1)^0xEDB88320 : (C>>1);
CRCTab[I]=C;
}
#ifdef USE_NEON_CRC32
#ifdef _APPLE
// getauxval isn't available in OS X
uint Value=0;
size_t Size=sizeof(Value);
int RetCode=sysctlbyname("hw.optional.armv8_crc32",&Value,&Size,NULL,0);
CRC_Neon=RetCode==0 && Value!=0;
#else
CRC_Neon=(getauxval(AT_HWCAP) & HWCAP_CRC32)!=0;
#endif
#endif
}
@@ -37,15 +60,17 @@ static void InitTables()
{
InitCRC32(crc_tables[0]);
#ifdef USE_SLICING
for (uint I=0;I<256;I++) // Build additional lookup tables.
{
uint C=crc_tables[0][I];
for (uint J=1;J<8;J++)
for (uint J=1;J<16;J++)
{
C=crc_tables[0][(byte)C]^(C>>8);
crc_tables[J][I]=C;
}
}
#endif
}
@@ -55,28 +80,68 @@ 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++)
#ifdef USE_NEON_CRC32
if (CRC_Neon)
{
for (;Size>=8;Size-=8,Data+=8)
#ifdef __clang__
StartCRC = __builtin_arm_crc32d(StartCRC, RawGet8(Data));
#else
StartCRC = __builtin_aarch64_crc32x(StartCRC, RawGet8(Data));
#endif
for (;Size>0;Size--,Data++) // Process left data.
#ifdef __clang__
StartCRC = __builtin_arm_crc32b(StartCRC, *Data);
#else
StartCRC = __builtin_aarch64_crc32b(StartCRC, *Data);
#endif
return StartCRC;
}
#endif
#ifdef USE_SLICING
// Align Data to 16 for better performance and to avoid ALLOW_MISALIGNED
// check below.
for (;Size>0 && ((size_t)Data & 15)!=0;Size--,Data++)
StartCRC=crc_tables[0][(byte)(StartCRC^Data[0])]^(StartCRC>>8);
for (;Size>=8;Size-=8,Data+=8)
// 2023.12.06: We switched to slicing-by-16, which seems to be faster than
// slicing-by-8 on modern CPUs. Slicing-by-32 would require 32 KB for tables
// and could be limited by L1 cache size on some CPUs.
for (;Size>=16;Size-=16,Data+=16)
{
#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);
StartCRC ^= RawGet4(Data);
uint D1 = RawGet4(Data+4);
uint D2 = RawGet4(Data+8);
uint D3 = RawGet4(Data+12);
#else
// We avoid RawGet4 here for performance reason, to access uint32
// directly even if ALLOW_MISALIGNED isn't defined. We can do it,
// because we aligned 'Data' above.
StartCRC ^= *(uint32 *) Data;
uint NextData = *(uint32 *) (Data +4);
uint D1 = *(uint32 *) (Data+4);
uint D2 = *(uint32 *) (Data+8);
uint D3 = *(uint32 *) (Data+12);
#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)];
StartCRC = crc_tables[15][(byte) StartCRC ] ^
crc_tables[14][(byte)(StartCRC >> 8) ] ^
crc_tables[13][(byte)(StartCRC >> 16)] ^
crc_tables[12][(byte)(StartCRC >> 24)] ^
crc_tables[11][(byte) D1 ] ^
crc_tables[10][(byte)(D1 >> 8) ] ^
crc_tables[ 9][(byte)(D1 >> 16)] ^
crc_tables[ 8][(byte)(D1 >> 24)] ^
crc_tables[ 7][(byte) D2 ] ^
crc_tables[ 6][(byte)(D2 >> 8)] ^
crc_tables[ 5][(byte)(D2 >> 16)] ^
crc_tables[ 4][(byte)(D2 >> 24)] ^
crc_tables[ 3][(byte) D3 ] ^
crc_tables[ 2][(byte)(D3 >> 8)] ^
crc_tables[ 1][(byte)(D3 >> 16)] ^
crc_tables[ 0][(byte)(D3 >> 24)];
}
#endif
for (;Size>0;Size--,Data++) // Process left data.
StartCRC=crc_tables[0][(byte)(StartCRC^Data[0])]^(StartCRC>>8);
@@ -100,3 +165,116 @@ ushort Checksum14(ushort StartCRC,const void *Addr,size_t Size)
#endif
#if 0
static void TestCRC();
struct TestCRCStruct {TestCRCStruct() {TestCRC();exit(0);}} GlobalTesCRC;
void TestCRC()
{
// This function is invoked from global object and _SSE_Version is global
// and can be initialized after this function. So we explicitly initialize
// it here to enable SSE support in Blake2sp.
_SSE_Version=GetSSEVersion();
const uint FirstSize=300;
byte b[FirstSize];
if ((CRC32(0xffffffff,(byte*)"testtesttest",12)^0xffffffff)==0x44608e84)
mprintf(L"\nCRC32 test1 OK");
else
mprintf(L"\nCRC32 test1 FAILED");
if (CRC32(0,(byte*)"te\x80st",5)==0xB2E5C5AE)
mprintf(L"\nCRC32 test2 OK");
else
mprintf(L"\nCRC32 test2 FAILED");
for (uint I=0;I<14;I++) // Check for possible int sign extension.
b[I]=(byte)0x7f+I;
if ((CRC32(0xffffffff,b,14)^0xffffffff)==0x1DFA75DA)
mprintf(L"\nCRC32 test3 OK");
else
mprintf(L"\nCRC32 test3 FAILED");
for (uint I=0;I<FirstSize;I++)
b[I]=(byte)I;
uint r32=CRC32(0xffffffff,b,FirstSize);
for (uint I=FirstSize;I<1024;I++)
{
b[0]=(byte)I;
r32=CRC32(r32,b,1);
}
if ((r32^0xffffffff)==0xB70B4C26)
mprintf(L"\nCRC32 test4 OK");
else
mprintf(L"\nCRC32 test4 FAILED");
if ((CRC64(0xffffffffffffffff,(byte*)"testtesttest",12)^0xffffffffffffffff)==0x7B1C2D230EDEB436)
mprintf(L"\nCRC64 test1 OK");
else
mprintf(L"\nCRC64 test1 FAILED");
if (CRC64(0,(byte*)"te\x80st",5)==0xB5DBF9583A6EED4A)
mprintf(L"\nCRC64 test2 OK");
else
mprintf(L"\nCRC64 test2 FAILED");
for (uint I=0;I<14;I++) // Check for possible int sign extension.
b[I]=(byte)0x7f+I;
if ((CRC64(0xffffffffffffffff,b,14)^0xffffffffffffffff)==0xE019941C05B2820C)
mprintf(L"\nCRC64 test3 OK");
else
mprintf(L"\nCRC64 test3 FAILED");
for (uint I=0;I<FirstSize;I++)
b[I]=(byte)I;
uint64 r64=CRC64(0xffffffffffffffff,b,FirstSize);
for (uint I=FirstSize;I<1024;I++)
{
b[0]=(byte)I;
r64=CRC64(r64,b,1);
}
if ((r64^0xffffffffffffffff)==0xD51FB58DC789C400)
mprintf(L"\nCRC64 test4 OK");
else
mprintf(L"\nCRC64 test4 FAILED");
const size_t BufSize=0x100000;
byte *Buf=new byte[BufSize];
GetRnd(Buf,BufSize);
clock_t StartTime=clock();
r32=0xffffffff;
const uint64 BufCount=5000;
for (uint I=0;I<BufCount;I++)
r32=CRC32(r32,Buf,BufSize);
if (r32!=0) // Otherwise compiler optimizer removes CRC calculation.
mprintf(L"\nCRC32 speed: %llu MB/s",BufCount*CLOCKS_PER_SEC/(clock()-StartTime));
StartTime=clock();
DataHash Hash;
Hash.Init(HASH_CRC32,MaxPoolThreads);
const uint64 BufCountMT=20000;
for (uint I=0;I<BufCountMT;I++)
Hash.Update(Buf,BufSize);
HashValue Result;
Hash.Result(&Result);
mprintf(L"\nCRC32 MT speed: %llu MB/s",BufCountMT*CLOCKS_PER_SEC/(clock()-StartTime));
StartTime=clock();
Hash.Init(HASH_BLAKE2,MaxPoolThreads);
for (uint I=0;I<BufCount;I++)
Hash.Update(Buf,BufSize);
Hash.Result(&Result);
mprintf(L"\nBlake2sp speed: %llu MB/s",BufCount*CLOCKS_PER_SEC/(clock()-StartTime));
StartTime=clock();
r64=0xffffffffffffffff;
for (uint I=0;I<BufCount;I++)
r64=CRC64(r64,Buf,BufSize);
if (r64!=0) // Otherwise compiler optimizer removes CRC calculation.
mprintf(L"\nCRC64 speed: %llu MB/s",BufCount*CLOCKS_PER_SEC/(clock()-StartTime));
}
#endif

View File

@@ -11,21 +11,12 @@
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)
@@ -56,16 +47,28 @@ 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)
if (Method==CRYPT_NONE || !Password->IsSet())
return false;
CryptData::Method=Method;
wchar PwdW[MAXPASSWORD];
Password->Get(PwdW,ASIZE(PwdW));
// Display this warning only when encrypting. Users complained that
// it is distracting when decrypting. It still can be useful when encrypting,
// so users do not waste time to excessively long passwords.
if (Encrypt && wcslen(PwdW)>=MAXPASSWORD_RAR)
uiMsg(UIERROR_TRUNCPSW,MAXPASSWORD_RAR-1);
PwdW[Min(MAXPASSWORD_RAR,MAXPASSWORD)-1]=0; // For compatibility with existing archives.
char PwdA[MAXPASSWORD];
WideToChar(PwdW,PwdA,ASIZE(PwdA));
PwdA[Min(MAXPASSWORD_RAR,MAXPASSWORD)-1]=0; // For compatibility with existing archives.
bool Success=true;
switch(Method)
{
#ifndef SFX_MODULE
@@ -83,12 +86,12 @@ bool CryptData::SetCryptKeys(bool Encrypt,CRYPT_METHOD Method,
SetKey30(Encrypt,Password,PwdW,Salt);
break;
case CRYPT_RAR50:
SetKey50(Encrypt,Password,PwdW,Salt,InitV,Lg2Cnt,HashKey,PswCheck);
Success=SetKey50(Encrypt,Password,PwdW,Salt,InitV,Lg2Cnt,HashKey,PswCheck);
break;
}
cleandata(PwdA,sizeof(PwdA));
cleandata(PwdW,sizeof(PwdW));
return true;
return Success;
}
@@ -117,7 +120,7 @@ void GetRnd(byte *RndBuf,size_t BufSize)
HCRYPTPROV hProvider = 0;
if (CryptAcquireContext(&hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
{
Success=CryptGenRandom(hProvider, (DWORD)BufSize, RndBuf) == TRUE;
Success=CryptGenRandom(hProvider, (DWORD)BufSize, RndBuf) != FALSE;
CryptReleaseContext(hProvider, 0);
}
#elif defined(_UNIX)

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