Compare commits

...

153 Commits

Author SHA1 Message Date
Andy Vandijck
9ae1473f36 Fix 8 bit PNG recording
Fix 8 bit PNG recording
2025-08-02 11:27:21 +02:00
Andy Vandijck
9cd0c5c04c Fix 8 bit video recording
Fix 8 bit video recording
2025-08-02 11:10:00 +02:00
Andy Vandijck
9e41c5476a Fix 8 bit color
Fix 8 bit color
2025-08-02 10:20:05 +02:00
Andy Vandijck
e91171459d Fix policy in newer CMake 2025-08-02 09:49:22 +02:00
Andy Vandijck
16f008b448 Fix macOS build
Fix macOS build
2025-08-02 09:38:42 +02:00
Rafael Kitover
bad10342bd build: use pkg-config on UNIX for SDL3
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-02 06:20:37 +00:00
Squall Leonhart
06b3cb094e Merge pull request #1484 from Squall-Leonhart/Correct24bit
24bit was prone to corrupting g_pix on all renderers
2025-08-02 07:50:07 +10:00
Squall-Leonhart
82617ea75d correct memory alignment 2025-08-02 07:48:03 +10:00
Andy Vandijck
0561ef91a4 Fix CoreAudio stall
Fix CoreAudio stall
2025-08-01 09:48:58 +02:00
Rafael Kitover
afc6a1cc3a build: fix build, de translation removed
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-01 04:40:38 +00:00
Rafael Kitover
35df9d7647 translations: remove German, not German
Remove the `de` translation as it does not contain a German translation.
Also deleted from Transifex.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-01 03:10:01 +00:00
Rafael Kitover
031ae2ebf6 build: fix CMake slowness
Optimize the `find_wx_util` function to try the major and minor version
parsed from the lib file first, avoiding a very slow exhaustive search
of possible version numbers.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-01 03:05:55 +00:00
Squall Leonhart
6242679e23 initialise stereo_buffer to 0 to prevent a race condition 2025-08-01 12:12:44 +10:00
Rafael Kitover
537393a0ab translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-31 16:00:20 +00:00
Rafael Kitover
616f7abc4e translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-31 13:00:21 +00:00
Rafael Kitover
f1414000e6 doc: fix release commit instructions
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-30 11:49:27 +00:00
Rafael Kitover
e2a235768e release v2.2.2
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-30 11:46:32 +00:00
Rafael Kitover
1d54ee2135 translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-30 07:00:21 +00:00
Rafael Kitover
013a9b87ac translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-30 03:00:20 +00:00
Rafael Kitover
a06d3ed1b4 translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-30 01:00:22 +00:00
Rafael Kitover
b1bad9d53d translations: rebuild source .pot
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-30 01:00:06 +00:00
Rafael Kitover
d2eed85c28 Move Languages menu to the top level
Move the new Languages menu to the top level after Help to make it
easier to find.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-30 00:09:05 +00:00
Rafael Kitover
d5a37e06aa translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-29 10:00:20 +00:00
Rafael Kitover
cea049161d translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-29 05:00:20 +00:00
Rafael Kitover
3eadc6e78f translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-28 16:00:19 +00:00
Rafael Kitover
4f3ed0dc8b translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-28 15:00:23 +00:00
Rafael Kitover
d38e1d0f89 translations: rebuild source .pot
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-28 15:00:06 +00:00
Andy Vandijck
f870bf252d Merge branch 'master' of github.com:visualboyadvance-m/visualboyadvance-m 2025-07-28 16:46:15 +02:00
Andy Vandijck
536ea705ab Add option for external translations (windows) and fix retain of language selection
Add option for external translations (windows) and fix retain of language selection
2025-07-28 16:46:12 +02:00
Rafael Kitover
802162ad97 translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-28 14:00:26 +00:00
Rafael Kitover
25895e8636 translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-28 12:00:24 +00:00
Rafael Kitover
27e7aa6864 translations: rebuild source .pot
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-28 12:00:07 +00:00
Andy Vandijck
dd7461103b Fix resource load for catalogs for Windows
Fix resource load for catalogs for Windows
2025-07-28 13:54:30 +02:00
Andy Vandijck
c892c269fa Merge branch 'master' of github.com:visualboyadvance-m/visualboyadvance-m 2025-07-28 13:14:10 +02:00
Andy Vandijck
dcf87c0a71 Implement refresh of GUI on language load
Implement refresh of GUI on language load
2025-07-28 13:13:57 +02:00
Rafael Kitover
6d1e7e8069 translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-28 09:00:20 +00:00
Rafael Kitover
b8868fce37 translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-28 08:00:18 +00:00
Rafael Kitover
d92c4e465f translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-27 16:00:20 +00:00
Andy Vandijck
bceb138961 Fix SDL crash on Windows
Fix SDL crash on Windows
2025-07-27 14:48:38 +02:00
Rafael Kitover
83aa80440e translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-27 12:00:25 +00:00
Rafael Kitover
4bd54ba128 translations: rebuild source .pot
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-27 12:00:07 +00:00
Andy Vandijck
27acf80b80 Make language configurable (requires restart)
Make language configurable (requires restart)
2025-07-27 13:27:09 +02:00
Andy Vandijck
ae09ab7189 Embed translations for Windows
Embed translations for Windows
2025-07-26 15:19:45 +02:00
Andy Vandijck
ce8de563e3 Merge branch 'master' of github.com:visualboyadvance-m/visualboyadvance-m 2025-07-26 12:28:50 +02:00
Andy Vandijck
47a8e7e8ed Update wxWidgets for Mac builder to 3.3.1
Update wxWidgets for Mac builder to 3.3.1
2025-07-26 12:28:47 +02:00
Rafael Kitover
adbaeacf20 build: use OpenSSL for FFmpeg for Mac builder
Link FFmpeg to OpenSSL for the Mac builder for the TLS functionality it
needs.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-25 11:53:22 -07:00
Rafael Kitover
8d8ecd8dfa build: remove glib from Mac builder
Remove glib from the Mac builder, it is not a dependency of anything on
Mac.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-25 01:55:50 -07:00
Andy Vandijck
cfbfc9ecb0 Fix glib build
Fix glib build
2025-07-25 10:35:42 +02:00
Andy Vandijck
4445a20d9c Merge branch 'master' of github.com:visualboyadvance-m/visualboyadvance-m 2025-07-25 10:06:24 +02:00
Andy Vandijck
b83a7c8aa2 Add Wii U ARM instruction to the instruction table
Add Wii U ARM instruction to the instruction table
2025-07-25 10:06:21 +02:00
Rafael Kitover
66aabab61f build: yet another Mac builder fix
Remove header paths from flags, keep frameworks path.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-24 20:46:37 -07:00
Rafael Kitover
a5e6b57fd8 translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-24 16:00:21 +00:00
Rafael Kitover
b9061ddafd translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-24 15:00:22 +00:00
Rafael Kitover
3c291ef3ac translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-24 14:00:21 +00:00
Andy Vandijck
e44c83e1d0 log Wii U VC opcodes and address
log Wii U VC opcodes and address
2025-07-24 13:09:42 +02:00
Andy Vandijck
8ce4848dd6 Fix Wii U VC opcodes
Fix Wii U VC opcodes
2025-07-24 13:06:09 +02:00
Andy Vandijck
34cba3bb2c Fix build for macOS
Fix build for macOS
2025-07-24 12:00:45 +02:00
Andy Vandijck
9b78b26010 Fix dependency build
Fix dependency build
2025-07-24 11:26:46 +02:00
Andy Vandijck
94f9df4baa Fix build for macOS
Fix build for macOS
2025-07-24 11:12:56 +02:00
Rafael Kitover
c726989d67 build: improve Metal toolchain detection on Mac
Use `xcrun -f metal` to set the path to the Metal compiler, falling back
to the `CheckLanguage` CMake module if that fails.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-23 17:29:58 -07:00
Rafael Kitover
3344e7cf71 build: add path to Metal compiler for Mac
Try to add the path to the Metal compiler on Mac to `CMAKE_PROGRAM_PATH`
to help it find the Metal compiler.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-23 13:12:51 -07:00
Rafael Kitover
3d69bde8cb build: fix adding/removing Mac SDK paths in flags
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-23 13:04:48 -07:00
Andy Vandijck
09984eed2f Fix path for metal
Fix path for metal
2025-07-23 21:42:25 +02:00
Andy Vandijck
69809ff556 Fix compile of flac
Fix compile of flac
2025-07-23 21:05:10 +02:00
Andy Vandijck
80dec6a38d Fix glib macOS frameworks
Fix glib macOS frameworks
2025-07-23 20:39:54 +02:00
Andy Vandijck
ea7b9e5049 Fix glib build
Fix glib build
2025-07-23 20:29:56 +02:00
Andy Vandijck
18701fc0a4 Fix glib patch
Fix glib patch
2025-07-23 20:10:54 +02:00
Andy Vandijck
6b596c7ad7 Fix patch for glib 2025-07-23 20:06:36 +02:00
Andy Vandijck
3c01643112 Fix glib build
Fix glib build
2025-07-23 20:00:54 +02:00
Rafael Kitover
0895c7a52e build: fix Intel zip name building on Mac ARM64
Try to set the architecture correctly when compiling for Intel on ARM64
Macs, this also sets the zip name correctly for our releases.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-23 09:21:53 -07:00
Andy Vandijck
1e52787078 Fix build on macOS
Fix build on macOS
2025-07-23 18:05:07 +02:00
Andy Vandijck
fc0e63d554 Fix libicu build
Fix libicu build
2025-07-23 17:32:35 +02:00
Andy Vandijck
9b573f4465 Update 7z to 2500 and fix 7zip build
Update 7z to 2500 and fix 7zip build
2025-07-23 16:14:51 +02:00
Rafael Kitover
51ae605850 build: fix -intel build for Mac builder
Make some adjustments to the Mac builder for the Intel build to build
with `-intel`.

Remove unzip and zip and replace with 7zip.

Remove `-mtune=generic` from the base flags.

Remove flex and swig and use them from brew.

Add giflib, needed by libwebp.

Add the `no_autotools_cross_options` and
`remove_arch_flags_from_build_ninja` dist flags.

Set intel macOS target to 10.10 when on an ARM64 host.

Add a patch for glib to build with an older macOS.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-23 06:31:36 -07:00
Andy Vandijck
ac4b39b6d8 Fix save/load state for matrixed ROMs
Fix save/load state for matrixed ROMs
2025-07-23 10:40:39 +02:00
Andy Vandijck
97ca69d050 Fix build
Fix build
2025-07-23 10:09:28 +02:00
Andy Vandijck
b1bcaed3a2 Remap matrix on load
Remap matrix on load
2025-07-23 10:07:32 +02:00
Andy Vandijck
2a1b41040d Fix matrix save state data and fix libretro 64MB ROM
Fix matrix save state data and fix libretro 64MB ROM
2025-07-23 09:57:46 +02:00
Andy Vandijck
930d0e282c A few extra fixes 2025-07-22 19:09:10 +02:00
Andy Vandijck
df23826721 Fix g_rom2 free
Fix g_rom2 free
2025-07-22 19:01:23 +02:00
Andy Vandijck
de46284747 Implement 64MB ROM files and fix ROM load
Implement 64MB ROM files and fix ROM load
2025-07-22 18:57:17 +02:00
Andy Vandijck
715f685447 Fix multi cart
Fix multi cart
2025-07-21 13:21:23 +02:00
Andy Vandijck
eabf319c9a Fix ROM load
Fix ROM load
2025-07-21 12:51:08 +02:00
Rafael Kitover
c98263603d build: fix Mac build
Followup on 9d46f8e6 (build: fix Mac builder regression, 2025-07-20) to
add this `DIST_FLAGS` flag for bison as well, because it also uses this
header file.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-20 18:41:14 +00:00
Rafael Kitover
9d46f8e6d1 build: fix Mac builder regression
Fix the Mac build, broken by 8c3d0f09 (build: fix regression in Mac
builder, 2025-07-19) due to the SDK paths conflicting with a gettext
header.

Fix this regression by introducing the `DIST_FLAGS` feature with a
`no_sdk_paths_in_flags` flag that `build_dist()` treats specially to
remove the include and lib SDK paths from `CPPFLAGS` and `LDFLAGS`.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-20 16:14:00 +00:00
Andy Vandijck
dab91fc8ca Fix bigger than 32MB ROM files
Fix bigger than 32MB ROM files
2025-07-20 15:44:39 +02:00
Andy Vandijck
d672d425be Get BZ2 uncompressed size
Get BZ2 uncompressed size
2025-07-20 14:45:01 +02:00
Andy Vandijck
53d60b726d Merge branch 'master' of github.com:visualboyadvance-m/visualboyadvance-m 2025-07-20 12:58:27 +02:00
Andy Vandijck
b6ce89bff8 Fix BZ2 max cart size
Fix BZ2 max cart size
2025-07-20 12:58:24 +02:00
Rafael Kitover
8c3d0f0984 build: fix regression in Mac builder
Fix the Mac builder, broken by 3d4c03d0 (build: fix Mac M1 build on my
Mini, 2025-07-19). Remove `-lintl -liconv` from `LDFLAGS` because they
are not available before they are built.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-19 17:23:18 +00:00
Rafael Kitover
3d4c03d0e6 build: fix Mac M1 build on my Mini
Fix the Mac builder on my M1 Mini.

Update glib and get it building.

Add command line tools include and lib directories to flags.

Add a necessary clang flag to fix vbam build with CoreAudio.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-19 17:16:20 +00:00
Rafael Kitover
92230e0003 release v2.2.1
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-19 10:23:56 +00:00
Rafael Kitover
88d58db0e9 translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-19 02:00:23 +00:00
Rafael Kitover
4d4c06b26b build: fix bundled SFML includes for Win32
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-18 18:32:42 +00:00
Rafael Kitover
23a3d0b20f build: fix include paths for bundled SFML
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-18 01:30:16 +00:00
Rafael Kitover
53f5ec7b7d build: fix building with OpenAL enabled
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-16 16:26:38 +00:00
Rafael Kitover
61f93348ca build: make bundled SFML includes SYSTEM BEFORE
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-16 16:14:34 +00:00
Andy Vandijck
9a78ecbab3 src/wx/widgets/wxmisc.cpp from Squall-Leonhart/TaskbarFixWin
Several fixes for windows
2025-07-16 11:15:23 +02:00
Rafael Kitover
3ffbe7816a translations: remove ja_JP, 0% and ja exists
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-16 01:53:34 +00:00
Squall Leonhart
2064af05b4 comment for BindAppIcon change 2025-07-16 09:07:03 +10:00
Squall-Leonhart
ae8bfb4ab3 Several fixes for windows
improve on the fex type check, so it works on windows x86/64
move BindAppIcon from BindControls in guiinit.cpp to wxvbam to avoid a timing issue that see's the icon not populated on windows till late.
adds 3 more icon sizes to the icon on windows.
2025-07-16 07:56:24 +10:00
Rafael Kitover
1f3a1cb9dc build: fix re-downloading vcpkg binary packages
Fix re-installing binary packages on next cached run by clearing the
cache entries for `vcpkg list`. Also remove the binary packages
directory after installing.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-15 21:05:07 +00:00
Rafael Kitover
bbaf70c083 build: fix slow CMake vcpkg startup time
Set the CMake cache variables for `vcpkg list` in `CACHE` instead of
`PARENT_SCOPE`, because the parent scope is now a transient function and
nothing was being cached, causing very slow run speed.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-15 16:46:17 +00:00
Rafael Kitover
b96e0ad35c build: remove vcpkg update, it does nothing
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-15 15:25:39 +00:00
Andy Vandijck
96324ddb92 Fix load
Fix load
2025-07-15 10:47:07 +02:00
Andy Vandijck
dca119905a Fix GBA sound
Fix GBA sound
2025-07-15 10:11:51 +02:00
Andy Vandijck
6a702ad09b Fix type detection for file extractor
Fix type detection for file extractor
2025-07-14 13:58:00 +02:00
Andy Vandijck
796ecee8cf Fix type detection for file extractor
Fix type detection for file extractor
2025-07-14 13:57:40 +02:00
Rafael Kitover
c1d3d19d6b translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-13 21:00:19 +00:00
Rafael Kitover
f7a79bfe2e build: fix binpkg deps resolution yet again
Keep a list of already installed dependencies and use the count to
determine if any are not installed.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-13 18:12:37 +00:00
Rafael Kitover
f8c52377a3 build: fix binpkg hostdeps again
Followup on 357eccc6 (build: fix checking if bin pkg host deps
installed, 2025-07-13) keep a count of already installed host deps, and
when the host deps count is equal to it rather than zero, break out of
the loop. This fixes the infinite loop and hang caused by host deps
being required but already being installed.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-13 16:17:48 +00:00
Rafael Kitover
357eccc6eb build: fix checking if bin pkg host deps installed
Fix the check for host dependency packages being downloaded to not run
if the package is already installed.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-13 16:03:31 +00:00
Andy Vandijck
80f595c0b0 Fix debug build
Fix debug build
2025-07-13 15:18:00 +02:00
Andy Vandijck
1c73f0c7d3 Fix configure
Fix configure
2025-07-13 15:06:21 +02:00
Andy Vandijck
3aff3784cf Update BZ2 library for windows debug
Update BZ2 library for windows debug
2025-07-13 14:58:33 +02:00
Andy Vandijck
59fa419820 Reduce allocated memory after read for BZ2
Reduce allocated memory after read for BZ2
2025-07-13 14:13:46 +02:00
Rafael Kitover
b0820a28b6 translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-13 10:00:19 +00:00
Andy Vandijck
a782c1c5fe Fix CI
Fix CI
2025-07-13 11:12:57 +02:00
Andy Vandijck
16a73fcbcf Fix LZMA MSVC build
Fix LZMA MSVC build
2025-07-13 10:24:00 +02:00
Andy Vandijck
9ff3b9e3b7 Merge branch 'master' of github.com:visualboyadvance-m/visualboyadvance-m 2025-07-13 10:11:06 +02:00
Andy Vandijck
379be68f69 Tar recognition
Tar recognition
2025-07-13 10:11:02 +02:00
Rafael Kitover
8bfb39b3ad translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-13 08:00:26 +00:00
Rafael Kitover
d97c8eabf5 translations: rebuild source .pot
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-13 08:00:07 +00:00
Andy Vandijck
e42e6323e8 Merge branch 'master' of github.com:visualboyadvance-m/visualboyadvance-m 2025-07-13 09:39:50 +02:00
Andy Vandijck
d0463ddb5e Initial tar support
Initial tar support
2025-07-13 09:39:38 +02:00
Rafael Kitover
1da359ba22 translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-12 16:00:19 +00:00
Andy Vandijck
15612c2bcc Add BZ2 and LZMA support options
Add BZ2 and LZMA support options
2025-07-12 17:32:28 +02:00
Andy Vandijck
11a941f33d Set max rom size (32MB) to BZ2 and fix block size
Set max rom size (32MB) to BZ2 and fix block size
2025-07-12 14:25:02 +02:00
Andy Vandijck
a808cfb6f5 Update macOS plist
Update macOS plist
2025-07-12 13:44:52 +02:00
Andy Vandijck
0266b9e4d1 Optimize LZ size detection
Optimize LZ size detection
2025-07-12 13:27:47 +02:00
Andy Vandijck
ef01f4c491 Fix bz2
Fix bz2
2025-07-12 13:14:37 +02:00
Andy Vandijck
d784b60aaa Fix BZ2 size
Fix BZ2 size
2025-07-12 13:11:59 +02:00
Rafael Kitover
67b17f50ec translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-12 09:00:22 +00:00
Rafael Kitover
be6addf034 translations: rebuild source .pot
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-12 09:00:06 +00:00
Andy Vandijck
d9b58d683e Add .lz extension
Add .lz extension
2025-07-12 10:54:22 +02:00
Andy Vandijck
604f5412a6 Add LZIP support
Add LZIP support
2025-07-12 10:52:17 +02:00
Rafael Kitover
de64dfd9e9 translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-12 07:00:23 +00:00
Rafael Kitover
024ae098e6 translations: rebuild source .pot
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-12 07:00:06 +00:00
Andy Vandijck
3d7cce05aa Fix Linux build 2025-07-12 08:18:51 +02:00
Rafael Kitover
205459f7ae build: add bzip2 and liblzma[tools] to vcpkg ports
Add `bzip2` and `liblzma[tools]` to the vcpkg ports dependencies list
for the new `.bz2` and `.xz` support.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-11 19:31:20 +00:00
Andy Vandijck
3ac5aa4f27 Add .xz extension
Add .xz extension
2025-07-11 19:57:32 +02:00
Andy Vandijck
6fedbdc512 Add .xz support
Add .xz support
2025-07-11 19:55:09 +02:00
Andy Vandijck
996a827d8e Merge branch 'master' of github.com:visualboyadvance-m/visualboyadvance-m 2025-07-11 16:38:50 +02:00
Andy Vandijck
0c91d45627 Add .bz2 file support
Add .bz2 file support
2025-07-11 16:38:46 +02:00
Andy Vandijck
3cf6ac5a80 Optimize unrar for MinGW
Optimize unrar for MinGW
2025-07-11 15:56:47 +02:00
Rafael Kitover
c5d1862e4e build: fix x86-mingw build
Amend the cpp macro checks in the unrar code to fix the build for MinGW.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-11 06:33:10 +00:00
Andy Vandijck
c63469ac63 Fix warnings 2025-07-10 13:54:40 +02:00
Andy Vandijck
3e0541c639 Update unrar to V7.1.8
Update unrar to V7.1.8
2025-07-10 11:14:41 +02:00
Andy Vandijck
00e48e11e6 Fix RAR support
Fix RAR support
2025-07-10 11:03:05 +02:00
Rafael Kitover
07c6e3119e build: remove vcpkg pkgconf dep
Remove pkgconf from the list of vcpkg dependency packages, because it is
automatically installed as a host build dependency and an explicit
dependency on the target triplet package is not required.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-09 14:42:37 +00:00
Andy Vandijck
3d8ed512cf Use macOS 10.10 Sparkle 2025-07-09 16:14:06 +02:00
Andy Vandijck
e49cce5b9e Update win32-deps submodule to latest version
Update win32-deps submodule to latest version
2025-07-09 14:29:11 +02:00
Rafael Kitover
1dfd7ec121 translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-09 07:00:24 +00:00
230 changed files with 26564 additions and 14934 deletions

View File

@@ -4,6 +4,33 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
## [2.2.2] - 2025-07-30
========================
* 27acf80b - Make language configurable (requires restart) [andyvand]
* ae09ab71 - Embed translations for Windows [andyvand]
* 47a8e7e8 - Update wxWidgets for Mac builder to 3.3.1 [andyvand]
* 8ce4848d - Fix Wii U VC opcodes [andyvand]
* dab91fc8 - Fix bigger than 32MB ROM files [andyvand]
## [2.2.1] - 2025-07-19
=======================
* 23a3d0b2 - build: fix include paths for bundled SFML [rkitover]
* 53f5ec7b - build: fix building with OpenAL enabled [rkitover]
* 3ffbe781 - translations: remove ja_JP, 0% and ja exists [rkitover]
* ae8bfb4a - Several fixes for windows [danialhorton]
* bbaf70c0 - build: fix slow CMake vcpkg startup time [rkitover]
* dca11990 - Fix GBA sound [andyvand]
* 357eccc6 - build: fix checking if bin pkg host deps installed [rkitover]
* d0463ddb - Initial tar support [andyvand]
* a808cfb6 - Update macOS plist [andyvand]
* 604f5412 - Add LZIP support [andyvand]
* 6fedbdc5 - Add .xz support [andyvand]
* 0c91d456 - Add .bz2 file support [andyvand]
* 3e0541c6 - Update unrar to V7.1.8 [andyvand]
* 00e48e11 - Fix RAR support [andyvand]
* 3d8ed512 - Use macOS 10.10 Sparkle [andyvand]
## [2.2.0] - 2025-07-08
========================
* 865add06 - Adjust throttle limit 450 -> 1000 [rkitover]

View File

@@ -1,6 +1,11 @@
cmake_minimum_required(VERSION 3.19)
cmake_policy(VERSION 3.19...3.28.3)
# Use new link library de-duplication behavior.
cmake_policy(SET CMP0156 NEW)
cmake_policy(SET CMP0179 NEW)
# cmake_policy(SET CMP0181 NEW)
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)
if(WIN32)
@@ -24,7 +29,7 @@ endif()
option(VCPKG_BINARY_PACKAGES "Use vcpkg binary packages" TRUE)
set(VCPKG_DEPS pkgconf zlib pthreads gettext-libintl wxwidgets nanosvg)
set(VCPKG_DEPS zlib bzip2 "liblzma[tools]" pthreads gettext-libintl wxwidgets nanosvg)
set(VCPKG_DEPS_OPTIONAL
"sdl3[vulkan]" ENABLE_SDL3
@@ -83,7 +88,16 @@ if(APPLE)
include(CheckLanguage)
include(MetalShaderSupport)
check_language(Metal)
execute_process(
COMMAND xcrun -f metal
OUTPUT_STRIP_TRAILING_WHITESPACE
OUTPUT_VARIABLE CMAKE_Metal_COMPILER
)
if(NOT CMAKE_Metal_COMPILER)
check_language(Metal)
endif()
if(CMAKE_Metal_COMPILER)
enable_language(Metal)
endif()

View File

@@ -31,6 +31,15 @@ elseif(VCPKG_TARGET_TRIPLET MATCHES "^[aA][rR][mM]-")
set(CMAKE_SYSTEM_PROCESSOR ARM)
endif()
if(APPLE AND
(CMAKE_OSX_ARCHITECTURES MATCHES "[xX]86_64") OR
(ENV{CFLAGS} MATCHES "[xX]86_64") OR
(ENV{CXXFLAGS} MATCHES "[xX]86_64") OR
(ENV{LDFLAGS} MATCHES "[xX]86_64"))
set(CMAKE_SYSTEM_PROCESSOR "x86_64")
endif()
# Turn asm on by default on 32bit x86 and set WINARCH for windows stuff.
if(CMAKE_SYSTEM_PROCESSOR MATCHES "[xX]86|i[3-9]86|[aA][mM][dD]64")
if(CMAKE_C_SIZEOF_DATA_PTR EQUAL 4) # 32 bit
@@ -46,14 +55,6 @@ if(CMAKE_SYSTEM_PROCESSOR MATCHES "[xX]86|i[3-9]86|[aA][mM][dD]64")
set(WINARCH x64)
set(ARCH_NAME x86_64)
endif()
if(DEFINED VCPKG_TARGET_TRIPLET)
string(REGEX MATCH "^x[86][64]" target_arch ${VCPKG_TARGET_TRIPLET})
if(NOT WINARCH STREQUAL target_arch)
message(FATAL_ERROR "Wrong build environment architecture for VCPKG_TARGET_TRIPLET, you specified ${target_arch} but your compiler is for ${WINARCH}")
endif()
endif()
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "[aA][aA][rR][cC][hH]|[aA][rR][mM]")
if(CMAKE_C_SIZEOF_DATA_PTR EQUAL 4) # 32 bit
set(ARM32 ON)
@@ -70,6 +71,14 @@ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "[aA][aA][rR][cC][hH]|[aA][rR][mM]")
endif()
endif()
if(DEFINED VCPKG_TARGET_TRIPLET)
string(REGEX MATCH "^[^-]+" target_arch ${VCPKG_TARGET_TRIPLET})
if(NOT WINARCH STREQUAL target_arch)
message(FATAL_ERROR "Wrong build environment architecture for VCPKG_TARGET_TRIPLET, you specified ${target_arch} but your compiler is for ${WINARCH}")
endif()
endif()
# We do not support amd64 asm yet
if(X86_64 AND (ENABLE_ASM_CORE OR ENABLE_ASM_SCALERS OR ENABLE_MMX))
message(FATAL_ERROR "The options ASM_CORE, ASM_SCALERS and MMX are not supported on X86_64 yet.")

View File

@@ -48,16 +48,20 @@ if((NOT ENABLE_SDL3) AND CMAKE_TOOLCHAIN_FILE MATCHES "vcpkg")
endif()
if(ENABLE_SDL3)
if(VBAM_STATIC)
set(VBAM_SDL_LIBS SDL3::SDL3-static ${SDL_LIBRARY_TEMP})
if(UNIX AND NOT APPLE)
set(VBAM_SDL_LIBS "${SDL3_LIBRARIES}")
else()
set(VBAM_SDL_LIBS SDL3::SDL3 ${SDL_LIBRARY_TEMP})
if(VBAM_STATIC)
set(VBAM_SDL_LIBS SDL3::SDL3-static ${SDL_LIBRARY_TEMP})
else()
set(VBAM_SDL_LIBS SDL3::SDL3 ${SDL_LIBRARY_TEMP})
endif()
endif()
else()
if(VBAM_STATIC)
set(VBAM_SDL_LIBS SDL2::SDL2-static ${SDL_LIBRARY_TEMP})
set(VBAM_SDL_LIBS SDL2::SDL2-static ${SDL_LIBRARY_TEMP})
else()
set(VBAM_SDL_LIBS SDL2::SDL2 ${SDL_LIBRARY_TEMP})
set(VBAM_SDL_LIBS SDL2::SDL2 ${SDL_LIBRARY_TEMP})
endif()
endif()
@@ -70,7 +74,7 @@ if(ENABLE_FFMPEG)
list(APPEND FFMPEG_LDFLAGS "SHELL:-framework CoreText" "SHELL:-framework ApplicationServices")
if(UPSTREAM_RELEASE)
list(APPEND FFMPEG_LDFLAGS -lbz2 -ltiff "SHELL:-framework DiskArbitration" -lfreetype -lfontconfig -llzma -lxml2 -lharfbuzz)
list(APPEND FFMPEG_LDFLAGS -lbz2 -ltiff "SHELL:-framework DiskArbitration" -lfreetype -lfontconfig -llzma -lxml2 -lharfbuzz -lcrypto -lssl)
endif()
elseif(WIN32)
set(WIN32_MEDIA_FOUNDATION_LIBS dxva2 evr mf mfplat mfplay mfreadwrite mfuuid amstrmid)

View File

@@ -221,7 +221,7 @@ release notes.
Run the following commands to commit the change:
git commit -m'release ${new_tag}' --signoff -S
git commit -a -m'release ${new_tag}' --signoff -S
git tag -s -m'${new_tag}' ${new_tag}
To rollback these changes, run this command:

View File

@@ -40,14 +40,28 @@ if(VBAM_STATIC)
endif()
endif()
find_package(SDL3 QUIET)
if(CMAKE_TOOLCHAIN_FILE MATCHES "vcpkg" AND CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "^([xX]86_64|[aA][mM][dD]64)$")
set(PKG_CONFIG_EXECUTABLE "$ENV{VCPKG_ROOT}/installed/x64-windows/tools/pkgconf/pkgconf.exe")
endif()
find_package(PkgConfig)
if(UNIX AND NOT APPLE)
pkg_check_modules(SDL3 sdl3 QUIET)
else()
find_package(SDL3 QUIET)
endif()
option(ENABLE_SDL3 "Use SDL3" "${SDL3_FOUND}")
if(ENABLE_SDL3)
find_package(SDL3 CONFIG REQUIRED)
else()
find_package(SDL2 CONFIG REQUIRED)
if(NOT TRANSLATIONS_ONLY)
if(ENABLE_SDL3)
if(NOT UNIX)
find_package(SDL3 REQUIRED)
endif()
else()
find_package(SDL2 REQUIRED)
endif()
endif()
option(ENABLE_GENERIC_FILE_DIALOGS "Use generic file dialogs" OFF)
@@ -56,6 +70,8 @@ option(ENABLE_SDL "Build the SDL port" ${ENABLE_SDL_DEFAULT})
option(ENABLE_WX "Build the wxWidgets port" ${BUILD_DEFAULT})
option(ENABLE_DEBUGGER "Enable the debugger" ON)
option(ENABLE_ASAN "Enable -fsanitize=address by default. Requires debug build with GCC/Clang" OFF)
option(ENABLE_BZ2 "Enable BZ2 archive support" ON)
option(ENABLE_LZMA "Enable LZMA archive support" ON)
if(ENABLE_SDL3)
set(CMAKE_C_FLAGS "-DENABLE_SDL3 ${CMAKE_C_FLAGS}")
@@ -89,12 +105,6 @@ if(APPLE AND NOT DISABLE_MACOS_PACKAGE_MANAGERS)
include(MacPackageManagers)
endif()
if(CMAKE_TOOLCHAIN_FILE MATCHES "vcpkg" AND CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "^([xX]86_64|[aA][mM][dD]64)$")
set(PKG_CONFIG_EXECUTABLE "$ENV{VCPKG_ROOT}/installed/x64-windows/tools/pkgconf/pkgconf.exe")
endif()
find_package(PkgConfig)
# Link / SFML
if(NOT TRANSLATIONS_ONLY)
set(ENABLE_LINK_DEFAULT ON)

View File

@@ -159,7 +159,7 @@ function(vcpkg_is_installed vcpkg_exe pkg_name pkg_ver pkg_triplet powershell ou
string(REGEX REPLACE "\r?\n" ";" vcpkg_list_raw "${vcpkg_list_text}")
set(VCPKG_INSTALLED_COUNT 0 PARENT_SCOPE)
set(VCPKG_INSTALLED_COUNT 0 CACHE INTERNAL "Number of installed vcpkg packages" FORCE)
foreach(pkg ${vcpkg_list_raw})
if(NOT pkg MATCHES "^([^:[]+)[^:]*:([^ ]+) +([0-9][^ ]*) +.*\$")
continue()
@@ -181,8 +181,8 @@ function(vcpkg_is_installed vcpkg_exe pkg_name pkg_ver pkg_triplet powershell ou
list(APPEND VCPKG_INSTALLED ${inst_pkg_name} ${inst_pkg_ver} ${inst_pkg_rev} ${inst_pkg_triplet})
math(EXPR VCPKG_INSTALLED_COUNT "${VCPKG_INSTALLED_COUNT} + 1")
endforeach()
set(VCPKG_INSTALLED ${VCPKG_INSTALLED} PARENT_SCOPE)
set(VCPKG_INSTALLED_COUNT ${VCPKG_INSTALLED_COUNT} PARENT_SCOPE)
set(VCPKG_INSTALLED ${VCPKG_INSTALLED} CACHE INTERNAL "List of installed vcpkg packages" FORCE)
set(VCPKG_INSTALLED_COUNT ${VCPKG_INSTALLED_COUNT} CACHE INTERNAL "Number of installed vcpkg packages" FORCE)
endif()
if(NOT VCPKG_INSTALLED_COUNT GREATER 0)
@@ -267,6 +267,13 @@ function(zip_is_installed vcpkg_exe zip outvar)
set(${outvar} ${pkg_installed} PARENT_SCOPE)
endfunction()
function(cleanup_binary_packages)
file(REMOVE_RECURSE "${CMAKE_BINARY_DIR}/vcpkg-binary-packages")
unset(VCPKG_INSTALLED CACHE)
unset(VCPKG_INSTALLED_COUNT CACHE)
endfunction()
function(get_binary_packages vcpkg_exe)
set(binary_packages_installed FALSE PARENT_SCOPE)
@@ -318,6 +325,8 @@ function(get_binary_packages vcpkg_exe)
endif()
endforeach()
unset(installed_host_deps)
while(TRUE)
# -command "import-module ($env:USERPROFILE + '/source/repos/vcpkg-binpkg-prototype/vcpkg-binpkg.psm1'); vcpkg-listmissing ."
execute_process(
@@ -334,9 +343,13 @@ function(get_binary_packages vcpkg_exe)
return()
endif()
string(REGEX REPLACE "\r?\n" ";" host_deps "${host_deps}")
string(REGEX REPLACE "\r?\n" ";" host_deps "${host_deps}")
string(REGEX REPLACE " *;+ *$" "" host_deps "${host_deps}")
if(NOT host_deps)
list(LENGTH host_deps host_deps_count)
list(LENGTH installed_host_deps installed_host_deps_count)
if(host_deps_count EQUAL installed_host_deps_count)
break()
endif()
@@ -361,15 +374,21 @@ function(get_binary_packages vcpkg_exe)
string(REGEX REPLACE "<a href=\"([^\"]+[.]zip)\"" "\\1" pkg ${links})
zip_is_installed(${vcpkg_exe} ${pkg} pkg_installed)
list(FIND installed_host_deps "${pkg}" found_idx)
if(NOT pkg_installed)
download_package("${pkg}" "${bin_pkgs_dir}")
endif()
if(found_idx EQUAL -1)
zip_is_installed(${vcpkg_exe} ${pkg} pkg_installed)
if(NOT EXISTS "${bin_pkgs_dir}/${pkg}")
message(STATUS "Failed to download host dependency package '${pkg}', aborting.")
return()
if(NOT pkg_installed)
download_package("${pkg}" "${bin_pkgs_dir}")
if(NOT EXISTS "${bin_pkgs_dir}/${pkg}")
message(STATUS "Failed to download host dependency package '${pkg}', aborting.")
return()
endif()
else()
list(APPEND installed_host_deps "${pkg}")
endif()
endif()
endforeach()
endwhile()
@@ -384,6 +403,8 @@ function(get_binary_packages vcpkg_exe)
file(REMOVE_RECURSE ${bin_pkgs_dir})
endif()
cleanup_binary_packages()
set(binary_packages_installed TRUE PARENT_SCOPE)
endfunction()
@@ -554,12 +575,6 @@ function(vcpkg_set_toolchain)
set(vcpkg_exe "${VCPKG_ROOT}/vcpkg")
endif()
# update portfiles
execute_process(
COMMAND ${vcpkg_exe} update
WORKING_DIRECTORY ${VCPKG_ROOT}
)
if (NOT (NO_VCPKG_UPDATES OR (NOT VCPKG_BINARY_PACKAGES)))
get_binary_packages(${vcpkg_exe})
endif()

View File

@@ -37,8 +37,48 @@ function(check_clean_exit var)
set(${var} ${exit_status} PARENT_SCOPE)
endfunction()
function(try_wx_util var util conf_suffix major_version minor_version)
unset(suffix)
if(conf_suffix)
set(suffix "-${conf_suffix}")
endif()
if(major_version)
set(suffix "${suffix}-${major_version}")
if(NOT minor_version EQUAL -1)
set(suffix "${suffix}.${minor_version}")
endif()
endif()
# find_program caches the result
set(exe NOTFOUND CACHE INTERNAL "" FORCE)
find_program(exe NAMES "${util}${suffix}")
# try infix variant, as on FreeBSD
if(NOT EXISTS "${exe}")
string(REGEX REPLACE "^-" "" suffix "${suffix}")
string(REGEX REPLACE "-" "${suffix}-" try "${util}")
set(exe NOTFOUND CACHE INTERNAL "" FORCE)
find_program(exe NAMES "${try}")
endif()
if(EXISTS "${exe}")
# check that the utility can be executed cleanly
# in case we find e.g. the wrong architecture binary
# when cross-compiling
check_clean_exit(exit_status "${exe}" --help)
if(exit_status EQUAL 0)
set("${var}" "${exe}" PARENT_SCOPE)
return()
endif()
endif()
endfunction()
function(find_wx_util var util)
if(WIN32 OR EXISTS /etc/gentoo-release)
if((WIN32 AND (NOT CMAKE_TOOLCHAIN_FILE MATCHES "vcpkg")) OR EXISTS /etc/gentoo-release)
# On win32, including cross builds we prefer the plain utility
# name first from PATH, with the exception of -static for static
# builds.
@@ -57,48 +97,34 @@ function(find_wx_util var util)
set(major_versions ";")
endif()
list(APPEND conf_suffixes gtk4u gtk4 gtk3u gtk3 gtk2u gtk2 "")
list(APPEND major_versions 4 3 2 "")
list(APPEND conf_suffixes "" gtk3u gtk3 gtk2u gtk2)
list(APPEND major_versions "" 3)
get_target_property(wx_base_lib_prop wx::base LOCATION)
string(STRIP "${wx_base_lib_prop}" wx_base_lib)
if(wx_base_lib MATCHES "wx_baseu?-([0-9]+)\\.([0-9]+)\\.")
set(lib_major "${CMAKE_MATCH_1}")
set(lib_minor "${CMAKE_MATCH_2}")
endif()
foreach(conf_suffix IN LISTS conf_suffixes)
if(lib_major AND lib_minor)
try_wx_util(exe "${util}" "${conf_suffix}" "${lib_major}" "${lib_minor}")
if(exe)
set("${var}" "${exe}" PARENT_SCOPE)
return()
endif()
endif()
foreach(major_version IN LISTS major_versions)
foreach(minor_version RANGE 100 -1 -1)
unset(suffix)
if(conf_suffix)
set(suffix "-${conf_suffix}")
endif()
if(major_version)
set(suffix "${suffix}-${major_version}")
foreach(minor_version RANGE 30 -1 -1)
try_wx_util(exe "${util}" "${conf_suffix}" "${major_version}" "${minor_version}")
if(NOT minor_version EQUAL -1)
set(suffix "${suffix}.${minor_version}")
endif()
endif()
# find_program caches the result
set(exe NOTFOUND CACHE INTERNAL "" FORCE)
find_program(exe NAMES "${util}${suffix}")
# try infix variant, as on FreeBSD
if(NOT EXISTS ${exe})
string(REGEX REPLACE "^-" "" suffix "${suffix}")
string(REGEX REPLACE "-" "${suffix}-" try ${util})
set(exe NOTFOUND CACHE INTERNAL "" FORCE)
find_program(exe NAMES ${try})
endif()
if(EXISTS ${exe})
# check that the utility can be executed cleanly
# in case we find e.g. the wrong architecture binary
# when cross-compiling
check_clean_exit(exit_status ${exe} --help)
if(exit_status EQUAL 0)
set(${var} ${exe} PARENT_SCOPE)
return()
endif()
if(exe)
set("${var}" "${exe}" PARENT_SCOPE)
return()
endif()
# don't iterate over minor versions for empty major version

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

BIN
resource.xrs Normal file

Binary file not shown.

View File

@@ -278,7 +278,7 @@ recording::MediaRet recording::MediaRecorder::setup_video_stream_info(int width,
switch (pixsize)
{
case 1:
tbord = 1; rbord = 2;
tbord = 1; rbord = 4;
break;
case 2:
// 16-bit: 2 @ right, 1 @ top

View File

@@ -120,9 +120,7 @@ if(ENABLE_LINK)
gba/gbaLink.h
)
target_include_directories(vbam-core
PRIVATE ${SFML_INCLUDE_DIR}
)
target_include_directories(vbam-core PRIVATE ${SFML_INCLUDE_DIR} ${SFML_INCLUDE_DIR}/SFML/Network ${SFML_INCLUDE_DIR}/SFML/System)
target_link_libraries(vbam-core
PRIVATE ${SFML_LIBRARIES}

View File

@@ -26,6 +26,7 @@ uint8_t *utilLoad(const char *, bool (*)(const char *), uint8_t *, int &);
IMAGE_TYPE utilFindType(const char *);
bool utilIsGBAImage(const char *);
bool utilIsGBImage(const char *);
bool utilIsTARAchive(const char *);
#if defined(__LIBRETRO__)
@@ -58,4 +59,4 @@ void utilWriteInt(gzFile, int);
#endif // defined(__LIBRETRO__)
#endif // VBAM_CORE_BASE_FILE_UTIL_H_
#endif // VBAM_CORE_BASE_FILE_UTIL_H_

View File

@@ -39,6 +39,15 @@ FILE* utilOpenFile(const char* filename, const char* mode) {
#endif // _WIN32
}
bool utilIsTARAchive(const char* file) {
const char* p = strrchr(file, '.');
if ((strcasecmp(p, ".tar") == 0))
return true;
return false;
}
bool utilIsGBAImage(const char* file) {
coreOptions.cpuIsMultiBoot = false;
if (strlen(file) > 4) {

View File

@@ -141,6 +141,7 @@ uint8_t* utilLoad(const char* file, bool (*accept)(const char*), uint8_t* data,
int read = fileSize <= size ? fileSize : size; // do not read beyond file
err = fex_read(fe, image, read);
fex_close(fe);
if (err) {
systemMessage(MSG_ERROR_READING_IMAGE, N_("Error reading image from %s: %s"), buffer, err);
if (data == nullptr)

View File

@@ -10,8 +10,6 @@ extern "C" {
#include "core/base/system.h"
#include "core/base/message.h"
bool no_border = false;
bool utilWritePNGFile(const char* fileName, int w, int h, uint8_t* pix) {
static constexpr size_t kNumChannels = 3;
uint8_t* writeBuffer = new uint8_t[w * h * kNumChannels];
@@ -23,7 +21,7 @@ bool utilWritePNGFile(const char* fileName, int w, int h, uint8_t* pix) {
switch (systemColorDepth) {
case 8: {
uint8_t* pixU8 = (uint8_t*)pix + (w);
uint8_t* pixU8 = (uint8_t*)pix + (w + 4);
for (int y = 0; y < sizeY; y++) {
for (int x = 0; x < sizeX; x++, pixU8++) {
// White color fix
@@ -38,9 +36,7 @@ bool utilWritePNGFile(const char* fileName, int w, int h, uint8_t* pix) {
}
}
if (no_border == false) {
pixU8 += 2;
}
pixU8 += 4;
}
} break;
case 16: {
@@ -155,11 +151,7 @@ bool utilWriteBMPFile(const char* fileName, int w, int h, uint8_t* pix) {
switch (systemColorDepth) {
case 8: {
uint8_t* pixU8 = 0;
if (no_border == false) {
pixU8 = (uint8_t*)pix + ((w + 2) * (h));
} else {
pixU8 = (uint8_t*)pix + ((w) * (h));
}
pixU8 = (uint8_t*)pix + ((w + 4) * (h));
for (int y = 0; y < sizeY; y++) {
for (int x = 0; x < sizeX; x++, pixU8++) {
@@ -175,13 +167,11 @@ bool utilWriteBMPFile(const char* fileName, int w, int h, uint8_t* pix) {
}
}
if (no_border == false) {
pixU8++;
pixU8++;
pixU8 -= 2 * (w + 2);
} else {
pixU8 -= 2 * (w);
}
pixU8++;
pixU8++;
pixU8++;
pixU8++;
pixU8 -= 2 * (w + 4);
fwrite(writeBuffer, 1, 3 * w, fp);
b = writeBuffer;

View File

@@ -1,5 +1,5 @@
/* Compiler.h : Compiler specific defines and pragmas
2024-01-22 : Igor Pavlov : Public domain */
: Igor Pavlov : Public domain */
#ifndef ZIP7_INC_COMPILER_H
#define ZIP7_INC_COMPILER_H
@@ -183,6 +183,16 @@ typedef void (*Z7_void_Function)(void);
#define Z7_ATTRIB_NO_VECTORIZE
#endif
#if defined(Z7_MSC_VER_ORIGINAL) && (Z7_MSC_VER_ORIGINAL >= 1920)
#define Z7_PRAGMA_OPTIMIZE_FOR_CODE_SIZE _Pragma("optimize ( \"s\", on )")
#define Z7_PRAGMA_OPTIMIZE_DEFAULT _Pragma("optimize ( \"\", on )")
#else
#define Z7_PRAGMA_OPTIMIZE_FOR_CODE_SIZE
#define Z7_PRAGMA_OPTIMIZE_DEFAULT
#endif
#if defined(MY_CPU_X86_OR_AMD64) && ( \
defined(__clang__) && (__clang_major__ >= 4) \
|| defined(__GNUC__) && (__GNUC__ >= 5))

View File

@@ -47,6 +47,12 @@ MY_CPU_64BIT means that processor can work with 64-bit registers.
#define MY_CPU_SIZEOF_POINTER 4
#endif
#if defined(__SSE2__) \
|| defined(MY_CPU_AMD64) \
|| defined(_M_IX86_FP) && (_M_IX86_FP >= 2)
#define MY_CPU_SSE2
#endif
#if defined(_M_ARM64) \
|| defined(_M_ARM64EC) \
@@ -571,10 +577,12 @@ problem-4 : performace:
#define Z7_CONV_BE_TO_NATIVE_CONST32(v) (v)
#define Z7_CONV_LE_TO_NATIVE_CONST32(v) Z7_BSWAP32_CONST(v)
#define Z7_CONV_NATIVE_TO_BE_32(v) (v)
// #define Z7_GET_NATIVE16_FROM_2_BYTES(b0, b1) ((b1) | ((b0) << 8))
#elif defined(MY_CPU_LE)
#define Z7_CONV_BE_TO_NATIVE_CONST32(v) Z7_BSWAP32_CONST(v)
#define Z7_CONV_LE_TO_NATIVE_CONST32(v) (v)
#define Z7_CONV_NATIVE_TO_BE_32(v) Z7_BSWAP32(v)
// #define Z7_GET_NATIVE16_FROM_2_BYTES(b0, b1) ((b0) | ((b1) << 8))
#else
#error Stop_Compiling_Unknown_Endian_CONV
#endif

View File

@@ -57,15 +57,64 @@ target_sources(vbam-fex
fex/Gzip_Extractor.h
fex/Gzip_Reader.cpp
fex/Gzip_Reader.h
fex/BZ2_Extractor.cpp
fex/BZ2_Extractor.h
fex/BZ2_Reader.cpp
fex/BZ2_Reader.h
fex/XZ_Extractor.cpp
fex/XZ_Extractor.h
fex/XZ_Reader.cpp
fex/XZ_Reader.h
fex/LZ_Extractor.cpp
fex/LZ_Extractor.h
fex/LZ_Reader.cpp
fex/LZ_Reader.h
fex/Rar_Extractor.cpp
fex/Rar_Extractor.h
fex/Tar_Extractor.cpp
fex/Tar_Extractor.h
fex/Zip7_Extractor.cpp
fex/Zip7_Extractor.h
fex/Zip_Extractor.cpp
fex/Zip_Extractor.h
fex/Zlib_Inflater.cpp
fex/Zlib_Inflater.h
fex/LZMA_Inflater.cpp
fex/LZMA_Inflater.h
fex/BZ2_Inflater.cpp
fex/BZ2_Inflater.h
unrar/archive.cpp
unrar/arcread.cpp
unrar/blake2s_sse.cpp
unrar/blake2s.cpp
unrar/blake2sp.cpp
unrar/coder.cpp
unrar/crc.cpp
unrar/encname.cpp
unrar/extract.cpp
unrar/getbits.cpp
unrar/hash.cpp
unrar/headers.cpp
unrar/model.cpp
unrar/pathfn.cpp
unrar/rarvm.cpp
unrar/rarvmtbl.cpp
unrar/rawread.cpp
unrar/secpassword.cpp
unrar/strfn.cpp
unrar/suballoc.cpp
unrar/timefn.cpp
unrar/unicode.cpp
unrar/unpack.cpp
unrar/unpack15.cpp
unrar/unpack20.cpp
unrar/unpack30.cpp
unrar/unpack50.cpp
unrar/unpack50frag.cpp
unrar/unpackinline.cpp
unrar/unrar_misc.cpp
unrar/unrar_open.cpp
unrar/unrar.cpp
PUBLIC
fex.h
)
@@ -74,6 +123,28 @@ target_include_directories(vbam-fex
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${ZLIB_INCLUDE_DIRS}
)
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
find_library(BZ2_LIBRARY NAMES bz2d bz2)
else()
find_library(BZ2_LIBRARY bz2)
endif()
find_library(LZMA_LIBRARY lzma)
if (BZ2_LIBRARY AND ENABLE_BZ2)
target_compile_definitions(vbam-fex PRIVATE FEX_ENABLE_BZ2=1)
target_link_libraries(vbam-fex
PRIVATE ${BZ2_LIBRARY}
)
endif()
if (LZMA_LIBRARY AND ENABLE_LZMA)
target_compile_definitions(vbam-fex PRIVATE FEX_ENABLE_LZMA=1)
target_link_libraries(vbam-fex
PRIVATE ${LZMA_LIBRARY}
)
endif()
target_link_libraries(vbam-fex
PRIVATE ${ZLIB_LIBRARY}
)

View File

@@ -56,7 +56,7 @@ int fex_has_extension(const char str[], const char extension[]);
Returns usual file extension this should have (e.g. ".zip", ".gz", etc.).
Returns "" if file header is not recognized. */
const char *fex_identify_header(const void *header);
enum { fex_identify_header_size = 16 };
enum { fex_identify_header_size = 263 };
/** Determines type based on extension of a file path, or just a lone extension
(must include '.', e.g. ".zip", NOT just "zip"). Returns NULL if extension is

View File

@@ -0,0 +1,103 @@
// File_Extractor 1.0.0. http://www.slack.net/~ant/
#if FEX_ENABLE_BZ2
#include "BZ2_Extractor.h"
#include <zlib.h>
/* Copyright (C) 2005-2009 Shay Green. This module is free software; you
can redistribute it and/or modify it under the terms of the GNU Lesser
General Public License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version. This
module is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
details. You should have received a copy of the GNU Lesser General Public
License along with this module; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
#include "blargg_source.h"
// TODO: could close file once data has been read into memory
static blargg_err_t init_bz2_file()
{
get_crc_table(); // initialize zlib's CRC-32 tables
return blargg_ok;
}
static File_Extractor* new_bzip2()
{
return BLARGG_NEW BZ2_Extractor;
}
fex_type_t_ const fex_bz2_type [1] = {{
".bz2",
&new_bzip2,
"bzip2 file",
&init_bz2_file
}};
BZ2_Extractor::BZ2_Extractor() :
File_Extractor( fex_bz2_type )
{ }
BZ2_Extractor::~BZ2_Extractor()
{
close();
}
blargg_err_t BZ2_Extractor::open_path_v()
{
// skip opening file
return open_v();
}
blargg_err_t BZ2_Extractor::stat_v()
{
RETURN_ERR( open_arc_file( true ) );
if ( !gr.opened() || gr.tell() != 0 )
RETURN_ERR( gr.open( &arc() ) );
set_info( gr.remain(), 0, gr.crc32() );
return blargg_ok;
}
blargg_err_t BZ2_Extractor::open_v()
{
// Remove .gz suffix
size_t len = strlen( arc_path() );
if ( fex_has_extension( arc_path(), ".bz2" ) )
len -= 4;
RETURN_ERR( name.resize( len + 1 ) );
memcpy( name.begin(), arc_path(), name.size() );
name [name.size() - 1] = '\0';
set_name( name.begin() );
return blargg_ok;
}
void BZ2_Extractor::close_v()
{
name.clear();
gr.close();
}
blargg_err_t BZ2_Extractor::next_v()
{
return blargg_ok;
}
blargg_err_t BZ2_Extractor::rewind_v()
{
set_name( name.begin() );
return blargg_ok;
}
blargg_err_t BZ2_Extractor::extract_v( void* p, int n )
{
return gr.read( p, n );
}
#endif

View File

@@ -0,0 +1,35 @@
// Presents a gzipped file as an "archive" of just that file.
// Also handles non-gzipped files.
// File_Extractor 1.0.0
#ifndef BZ2_EXTRACTOR_H
#define BZ2_EXTRACTOR_H
#include "File_Extractor.h"
#include "BZ2_Reader.h"
class BZ2_Extractor : public File_Extractor
{
public:
BZ2_Extractor();
virtual ~BZ2_Extractor();
protected:
virtual blargg_err_t open_path_v();
virtual blargg_err_t open_v();
virtual void close_v();
virtual blargg_err_t next_v();
virtual blargg_err_t rewind_v();
virtual blargg_err_t stat_v();
virtual blargg_err_t extract_v(void *, int);
private:
BZ2_Reader gr;
blargg_vector<char> name;
void set_info_();
};
#endif

View File

@@ -0,0 +1,284 @@
// File_Extractor 1.0.0. http://www.slack.net/~ant/
#if FEX_ENABLE_BZ2
#include "BZ2_Inflater.h"
/* Copyright (C) 2025 Andy Vandijck. This module is free software; you
can redistribute it and/or modify it under the terms of the GNU Lesser
General Public License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version. This
module is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
details. You should have received a copy of the GNU Lesser General Public
License along with this module; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
#include "blargg_source.h"
int const block_size = 100 * 1024;
static const char* get_bz2_err( int code )
{
assert( code != BZ_OK );
switch ( code )
{
case BZ_MEM_ERROR: return blargg_err_memory;
case BZ_DATA_ERROR: return blargg_err_file_corrupt;
// TODO: handle more error codes
}
const char* str = BLARGG_ERR( BLARGG_ERR_GENERIC, "problem unzipping data" );
return str;
}
void BZ2_Inflater::end()
{
if ( deflated_ )
{
deflated_ = false;
if ( BZ2_bzDecompressEnd ( &zbuf ) )
check( false );
}
buf.clear();
static bz_stream const empty = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
memcpy( &zbuf, &empty, sizeof zbuf );
}
BZ2_Inflater::BZ2_Inflater()
{
deflated_ = false;
end(); // initialize things
}
BZ2_Inflater::~BZ2_Inflater()
{
end();
}
blargg_err_t BZ2_Inflater::skip_buf( int count )
{
byte* out = buf.end() - count;
zbuf.avail_in = count;
zbuf.next_in = (char *)out;
return blargg_ok;
}
blargg_err_t BZ2_Inflater::fill_buf( int count )
{
byte* out = buf.end() - count;
RETURN_ERR( callback( user_data, out, &count ) );
zbuf.avail_in = count;
zbuf.next_in = (char *)out;
return blargg_ok;
}
blargg_err_t BZ2_Inflater::resize_buffer( int count )
{
return buf.resize(count);
}
blargg_err_t BZ2_Inflater::begin( callback_t new_callback, void* new_user_data,
int new_buf_size, int initial_read )
{
callback = new_callback;
user_data = new_user_data;
end();
// TODO: decide whether using different size on alloc failure is a good idea
//RETURN_ERR( buf.resize( new_buf_size ? new_buf_size : 4 * block_size ) );
if ( new_buf_size && buf.resize( new_buf_size ) )
{
ACK_FAILURE();
new_buf_size = 0;
}
if ( !new_buf_size )
{
RETURN_ERR( buf.resize( 9 * block_size ) );
initial_read = 0;
}
// Fill buffer with some data, less than normal buffer size since caller might
// just be examining beginning of file.
return fill_buf( initial_read ? initial_read : block_size );
}
blargg_err_t BZ2_Inflater::set_mode( mode_t mode, int data_offset )
{
zbuf.next_in += data_offset;
zbuf.avail_in -= data_offset;
if ( mode == mode_auto )
{
// examine buffer for gzip header
mode = mode_copy;
unsigned const min_gzip_size = 2 + 8 + 8;
if ( zbuf.avail_in >= min_gzip_size &&
zbuf.next_in [0] == 0x42 && zbuf.next_in [1] == 0x5A )
mode = mode_unbz2;
}
if ( mode != mode_copy )
{
int zerr = BZ2_bzDecompressInit( &zbuf, 0, 0 );
if ( zerr )
{
zbuf.next_in = NULL;
return get_bz2_err( zerr );
}
deflated_ = true;
}
return blargg_ok;
}
/*
// Reads/inflates entire stream. All input must be in buffer, and count must be total
// of all output.
blargg_err_t read_all( void* out, int count );
// zlib automatically applies this optimization (uses inflateFast)
// TODO: remove
blargg_err_t BZ2_Inflater::read_all( void* out, int count )
{
if ( deflated_ )
{
zbuf.next_out = (char*) out;
zbuf.avail_out = count;
int err = BZ2_bzDecompress( &zbuf );
if ( zbuf.avail_out || err != Z_STREAM_END )
return blargg_err_file_corrupt;
}
else
{
if ( zbuf.avail_in < count )
return blargg_err_file_corrupt;
memcpy( out, zbuf.next_in, count );
zbuf.next_in += count;
zbuf.avail_in -= count;
}
return blargg_ok;
}
*/
blargg_err_t BZ2_Inflater::get_size( int* count_io )
{
char *buffer = (char *)malloc(*count_io);
if (buffer == NULL) {
return blargg_err_memory;
}
read(buffer, count_io);
free(buffer);
return blargg_ok;
}
blargg_err_t BZ2_Inflater::read( void* out, int* count_io )
{
int remain = *count_io;
if ( remain && zbuf.next_in )
{
if ( deflated_ )
{
zbuf.next_out = (char*) out;
zbuf.avail_out = remain;
while ( 1 )
{
unsigned int old_avail_in = (unsigned int)zbuf.avail_in;
int err = BZ2_bzDecompress( &zbuf );
if ( err == BZ_STREAM_END )
{
remain = zbuf.avail_out;
fprintf(stderr, "BZ2 stream end: %d remaining, %u total size\n", remain, zbuf.total_out_lo32);
end();
break; // no more data to inflate
}
if ( err && (err != BZ_OUTBUFF_FULL || old_avail_in) )
return get_bz2_err( err );
if ( !zbuf.avail_out )
{
remain = 0;
break; // requested number of bytes inflated
}
if ( zbuf.avail_in )
{
// inflate() should never leave input if there's still space for output
check( false );
return blargg_err_file_corrupt;
}
RETURN_ERR( fill_buf( (int)buf.size() ) );
if ( !zbuf.avail_in )
return blargg_err_file_corrupt; // stream didn't end but there's no more data
}
}
else
{
while ( 1 )
{
// copy buffered data
if ( zbuf.avail_in )
{
long count = zbuf.avail_in;
if ( count > remain )
count = remain;
memcpy( out, zbuf.next_in, count );
zbuf.total_out_lo32 += count;
out = (char*) out + count;
remain -= count;
zbuf.next_in += count;
zbuf.avail_in -= count;
}
if ( !zbuf.avail_in && zbuf.next_in < (char *)buf.end() )
{
end();
break;
}
// read large request directly
if ( remain + zbuf.total_out_lo32 % block_size >= buf.size() )
{
int count = remain;
RETURN_ERR( callback( user_data, out, &count ) );
zbuf.total_out_lo32 += count;
out = (char*) out + count;
remain -= count;
if ( remain )
{
end();
break;
}
}
if ( !remain )
break;
RETURN_ERR( fill_buf( (int)(buf.size() - zbuf.total_out_lo32 % block_size) ) );
}
}
}
*count_io -= remain;
return blargg_ok;
}
#endif

View File

@@ -0,0 +1,92 @@
// Simplifies use of zlib for inflating data
// File_Extractor 1.0.0
#ifndef BZ2_INFLATER_H
#define BZ2_INFLATER_H
#include <bzlib.h>
#include "Data_Reader.h"
#include "blargg_common.h"
class BZ2_Inflater
{
public:
// Reads at most min(*count,bytes_until_eof()) bytes into *out and set *count
// to that number, or returns error if that many can't be read.
typedef blargg_err_t (*callback_t)(void *user_data, void *out, int *count);
// Begins by setting callback and filling buffer. Default buffer is 16K and
// filled to 4K, or specify buf_size and initial_read for custom buffer size
// and how much to read initially.
blargg_err_t begin(callback_t, void *user_data, int buf_size = 0, int initial_read = 0);
blargg_err_t get_size(int *count_io);
// Data read into buffer by begin()
const unsigned char *data() const
{
return (const unsigned char *)zbuf.next_in;
}
int filled() const
{
return zbuf.avail_in;
}
int totalOut() const
{
return zbuf.total_out_lo32;
}
// Begins inflation using specified mode. Using mode_auto selects between
// mode_copy and mode_ungz by examining first two bytes of buffer. Use
// buf_offset to specify where data begins in buffer, in case there is
// header data that should be skipped.
enum mode_t { mode_copy, mode_unbz2, mode_raw_deflate, mode_auto };
blargg_err_t set_mode(mode_t, int buf_offset = 0);
// True if set_mode() has been called with mode_ungz or mode_raw_deflate
bool deflated() const
{
return deflated_;
}
// Reads/inflates at most *count_io bytes into *out and sets *count_io to actual
// number of bytes read (less than requested if end of data was reached).
// Buffers source data internally, even in copy mode, so input file can be
// unbuffered without sacrificing performance.
blargg_err_t read(void *out, int *count_io);
// Total number of bytes read since begin()
int tell() const
{
return zbuf.total_out_lo32;
}
blargg_err_t resize_buffer(int count);
// Ends inflation and frees memory
void end();
private:
// noncopyable
BZ2_Inflater(const BZ2_Inflater &);
BZ2_Inflater &operator=(const BZ2_Inflater &);
// Implementation
public:
BZ2_Inflater();
~BZ2_Inflater();
private:
bz_stream zbuf;
blargg_vector<unsigned char> buf;
bool deflated_;
callback_t callback;
void *user_data;
blargg_err_t fill_buf(int count);
blargg_err_t skip_buf(int count);
};
#endif

View File

@@ -0,0 +1,90 @@
// File_Extractor 1.0.0. http://www.slack.net/~ant/
#if FEX_ENABLE_BZ2
#include "BZ2_Reader.h"
#include "blargg_endian.h"
/* Copyright (C) 2025 Andy Vandijck. This module is free software; you
can redistribute it and/or modify it under the terms of the GNU Lesser
General Public License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version. This
module is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
details. You should have received a copy of the GNU Lesser General Public
License along with this module; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
#include "blargg_source.h"
#include <bzlib.h>
BZ2_Reader::BZ2_Reader()
{
close();
}
BZ2_Reader::~BZ2_Reader()
{ }
static blargg_err_t BZ2_reader_read( void* file, void* out, int* count )
{
return STATIC_CAST(File_Reader*,file)->read_avail( out, count );
}
blargg_err_t BZ2_Reader::calc_size()
{
size_ = 0x8000000; // Max cart size
crc32_ = 0;
set_remain(size_);
inflater.get_size(&size_);
fprintf(stderr, "Calculated BZ2 size: %d\n", size_);
in->seek(0);
return blargg_ok;
}
blargg_err_t BZ2_Reader::open( File_Reader* new_in )
{
close();
in = new_in;
RETURN_ERR( in->seek( 0 ) );
RETURN_ERR( inflater.begin( BZ2_reader_read, new_in ) );
RETURN_ERR( inflater.set_mode( inflater.mode_auto ) );
RETURN_ERR( calc_size() );
inflater.end();
RETURN_ERR( inflater.begin( BZ2_reader_read, new_in ) );
RETURN_ERR( inflater.set_mode( inflater.mode_auto ) );
set_remain( size_ );
return blargg_ok;
}
void BZ2_Reader::close()
{
in = NULL;
inflater.end();
}
blargg_err_t BZ2_Reader::read_v( void* out, int count )
{
assert( in );
int actual = count;
RETURN_ERR( inflater.read( out, &actual ) );
if ( actual < size_ ) {
size_ = actual;
inflater.resize_buffer(actual);
set_remain(0);
}
return blargg_ok;
}
#endif

View File

@@ -0,0 +1,59 @@
// Transparently decompresses gzip files, as well as uncompressed
// File_Extractor 1.0.0
#ifndef BZ2_READER_H
#define BZ2_READER_H
#include "Data_Reader.h"
#include "BZ2_Inflater.h"
class BZ2_Reader : public Data_Reader
{
public:
// Keeps pointer to reader until close(). If
blargg_err_t open(File_Reader *);
// True if file is open
bool opened() const
{
return in != NULL;
}
// Frees memory
void close();
// True if file is compressed
bool deflated() const
{
return inflater.deflated();
}
// CRC-32 of data, of 0 if unavailable
unsigned int crc32() const
{
return crc32_;
}
// Number of bytes read since opening
int tell() const
{
return size_ - remain();
}
public:
BZ2_Reader();
virtual ~BZ2_Reader();
protected:
virtual blargg_err_t read_v(void *, int);
private:
File_Reader *in;
unsigned crc32_;
int size_;
BZ2_Inflater inflater;
blargg_err_t calc_size();
};
#endif

View File

@@ -6,7 +6,7 @@
#include "Data_Reader.h"
#include "blargg_common.h"
#include "fex.h"
#include "../fex.h"
struct fex_t : private Data_Reader {
public:
@@ -26,6 +26,7 @@ struct fex_t : private Data_Reader {
// See fex.h
blargg_err_t open(const char path[]);
fex_type_t type() const
{
return type_;
@@ -213,7 +214,7 @@ struct fex_type_t_ {
blargg_err_t (*init)(); // Called by fex_init(). Can be NULL.
};
extern const fex_type_t_ fex_7z_type[1], fex_gz_type[1], fex_rar_type[1], fex_zip_type[1],
extern const fex_type_t_ fex_7z_type[1], fex_gz_type[1], fex_bz2_type[1], fex_xz_type[1], fex_lz_type[1], fex_tar_type[1], fex_rar_type[1], fex_zip_type[1],
fex_bin_type[1];
inline blargg_err_t File_Extractor::open_v()

View File

@@ -0,0 +1,371 @@
// File_Extractor 1.0.0. http://www.slack.net/~ant/
#if FEX_ENABLE_LZMA
#include <stdio.h>
#include "LZMA_Inflater.h"
/* Copyright (C) 2025 Andy Vandijck. This module is free software; you
can redistribute it and/or modify it under the terms of the GNU Lesser
General Public License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version. This
module is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
details. You should have received a copy of the GNU Lesser General Public
License along with this module; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
#include "blargg_source.h"
int const block_size = 4096;
static const char* get_lzma_err( int code )
{
assert( code != LZMA_OK );
switch ( code )
{
case LZMA_MEM_ERROR: return blargg_err_memory;
case LZMA_DATA_ERROR: return blargg_err_file_corrupt;
// TODO: handle more error codes
}
const char* str = BLARGG_ERR( BLARGG_ERR_GENERIC, "problem uncompressing LZMA data" );
return str;
}
void LZMA_Inflater::end()
{
if ( deflated_ )
{
deflated_ = false;
lzma_end(&zbuf);
}
buf.clear();
static lzma_stream const empty = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (lzma_reserved_enum)0, (lzma_reserved_enum)0 };
memcpy( &zbuf, &empty, sizeof zbuf );
}
LZMA_Inflater::LZMA_Inflater()
{
deflated_ = false;
end(); // initialize things
}
LZMA_Inflater::~LZMA_Inflater()
{
end();
}
blargg_err_t LZMA_Inflater::fill_buf( int count )
{
byte* out = buf.end() - count;
RETURN_ERR( callback( user_data, out, &count ) );
zbuf.avail_in = count;
zbuf.next_in = (uint8_t *)out;
return blargg_ok;
}
blargg_err_t LZMA_Inflater::begin( callback_t new_callback, void* new_user_data,
int new_buf_size, int initial_read )
{
callback = new_callback;
user_data = new_user_data;
end();
// TODO: decide whether using different size on alloc failure is a good idea
//RETURN_ERR( buf.resize( new_buf_size ? new_buf_size : 4 * block_size ) );
if ( new_buf_size && buf.resize( new_buf_size ) )
{
ACK_FAILURE();
new_buf_size = 0;
}
if ( !new_buf_size )
{
RETURN_ERR( buf.resize( 4 * block_size ) );
initial_read = 0;
}
// Fill buffer with some data, less than normal buffer size since caller might
// just be examining beginning of file.
return fill_buf( initial_read ? initial_read : block_size );
}
bool LZMA_Inflater::is_format_xz(void)
{
// Specify the magic as hex to be compatible with EBCDIC systems.
static const uint8_t magic[6] = { 0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00 };
return zbuf.avail_in >= sizeof(magic)
&& memcmp(zbuf.next_in, magic, sizeof(magic)) == 0;
}
/// Return true if the data in in_buf seems to be in the .lzma format.
bool LZMA_Inflater::is_format_lzma(void)
{
// The .lzma header is 13 bytes.
if (zbuf.avail_in < 13)
return false;
// Decode the LZMA1 properties.
lzma_filter filter;
filter.id = LZMA_FILTER_LZMA1;
if (lzma_properties_decode(&filter, NULL, zbuf.next_in, 5) != LZMA_OK)
return false;
// A hack to ditch tons of false positives: We allow only dictionary
// sizes that are 2^n or 2^n + 2^(n-1) or UINT32_MAX. LZMA_Alone
// created only files with 2^n, but accepts any dictionary size.
// If someone complains, this will be reconsidered.
lzma_options_lzma *opt = (lzma_options_lzma *)filter.options;
const uint32_t dict_size = opt->dict_size;
free(opt);
if (dict_size != UINT32_MAX) {
uint32_t d = dict_size - 1;
d |= d >> 2;
d |= d >> 3;
d |= d >> 4;
d |= d >> 8;
d |= d >> 16;
++d;
if (d != dict_size || dict_size == 0)
return false;
}
// Another hack to ditch false positives: Assume that if the
// uncompressed size is known, it must be less than 256 GiB.
// Again, if someone complains, this will be reconsidered.
uint64_t uncompressed_size = 0;
for (size_t i = 0; i < 8; ++i)
uncompressed_size |= (uint64_t)(zbuf.next_in[5 + i]) << (i * 8);
if (uncompressed_size != UINT64_MAX
&& uncompressed_size > (UINT64_C(1) << 38))
return false;
return true;
}
/// Return true if the data in in_buf seems to be in the .lz format.
bool LZMA_Inflater::is_format_lzip(void)
{
static const uint8_t magic[4] = { 0x4C, 0x5A, 0x49, 0x50 };
return zbuf.avail_in >= sizeof(magic)
&& memcmp(zbuf.next_in, magic, sizeof(magic)) == 0;
}
blargg_err_t LZMA_Inflater::set_mode( mode_t mode, int data_offset )
{
int err = LZMA_OK;
zbuf.next_in += data_offset;
zbuf.avail_in -= data_offset;
buf_ptr = zbuf.next_in;
if ( mode == mode_auto )
{
// examine buffer for gzip header
mode = mode_copy;
if ( is_format_lzip() ) {
fprintf(stderr, "LZIP detected\n");
mode = mode_unlz;
}
if ( is_format_xz() ) {
fprintf(stderr, "XZ detected\n");
mode = mode_unxz;
}
if ( is_format_lzma() ) {
fprintf(stderr, "LZMA detected\n");
mode = mode_raw_deflate;
}
}
if ( mode != mode_copy )
{
zbuf = LZMA_STREAM_INIT;
if (mode == mode_raw_deflate)
err = lzma_alone_decoder( &zbuf, UINT64_MAX);
else if (mode == mode_unlz)
err = lzma_lzip_decoder( &zbuf, UINT64_MAX, LZMA_CONCATENATED);
else
err = lzma_stream_decoder( &zbuf, UINT64_MAX, LZMA_CONCATENATED);
if (err != LZMA_OK) {
fprintf(stderr, "Couldn't initialize LZMA stream decoder\n");
return blargg_err_file_corrupt;
}
deflated_ = true;
}
mode_ = mode;
return blargg_ok;
}
/*
// Reads/inflates entire stream. All input must be in buffer, and count must be total
// of all output.
blargg_err_t read_all( void* out, int count );
// zlib automatically applies this optimization (uses inflateFast)
// TODO: remove
blargg_err_t LZMA_Inflater::read_all( void* out, int count )
{
int err = LZMA_OK;
if ( deflated_ )
{
zbuf.next_out = (char*) out;
zbuf.avail_out = count;
if ((buf.size() - zbuf.total_out) <= block_size)
action = LZMA_FINISH;
else
action = LZMA_RUN;
err = lzma_code(&zbuf, action);
if ( zbuf.avail_out || err != Z_STREAM_END )
return blargg_err_file_corrupt;
}
else
{
if ( zbuf.avail_in < count )
return blargg_err_file_corrupt;
memcpy( out, zbuf.next_in, count );
zbuf.next_in += count;
zbuf.avail_in -= count;
}
return blargg_ok;
}
*/
blargg_err_t LZMA_Inflater::read( void* out, int* count_io )
{
int remain = *count_io;
zbuf.next_in = buf_ptr;
fprintf(stderr, "LZMA - Read remaining: %d, next in: 0x%p\n", remain, zbuf.next_in);
if ( remain && zbuf.next_in )
{
fprintf(stderr, "LZMA - deflated: %d\n", deflated_);
if ( deflated_ )
{
zbuf.next_out = (uint8_t*) out;
zbuf.avail_out = remain;
while ( 1 )
{
int err = LZMA_OK;
unsigned int old_avail_in = (unsigned int)zbuf.avail_in;
if ((buf.size() - zbuf.total_out) <= block_size)
action = LZMA_FINISH;
else
action = LZMA_RUN;
err = lzma_code(&zbuf, action);
if ( err == LZMA_STREAM_END )
{
remain = zbuf.avail_out;
end();
break; // no more data to inflate
}
if ( err && (err != LZMA_BUF_ERROR || old_avail_in) ) {
fprintf(stderr, "LZMA error: %d, old available in: %d\n", err, old_avail_in);
return get_lzma_err( err );
}
if ( !zbuf.avail_out )
{
remain = 0;
break; // requested number of bytes inflated
}
if ( zbuf.avail_in )
{
fprintf(stderr, "Available in: %zu, file corrupt\n", zbuf.avail_in);
// inflate() should never leave input if there's still space for output
check( false );
return blargg_err_file_corrupt;
}
RETURN_ERR( fill_buf( (int)buf.size() ) );
if ( !zbuf.avail_in ) {
fprintf(stderr, "No more available input data\n");
return blargg_err_file_corrupt; // stream didn't end but there's no more data
}
}
}
else
{
while ( 1 )
{
// copy buffered data
if ( zbuf.avail_in )
{
long count = zbuf.avail_in;
if ( count > remain )
count = remain;
memcpy( out, zbuf.next_in, count );
zbuf.total_out += count;
out = (char*) out + count;
remain -= count;
zbuf.next_in += count;
zbuf.avail_in -= count;
}
if ( !zbuf.avail_in && zbuf.next_in < (uint8_t *)buf.end() )
{
end();
break;
}
// read large request directly
if ( remain + zbuf.total_out % block_size >= buf.size() )
{
int count = remain;
RETURN_ERR( callback( user_data, out, &count ) );
zbuf.total_out += count;
out = (char*) out + count;
remain -= count;
if ( remain )
{
end();
break;
}
}
if ( !remain )
break;
RETURN_ERR( fill_buf( (int)(buf.size() - zbuf.total_out % block_size) ) );
}
}
}
*count_io -= remain;
return blargg_ok;
}
#endif

View File

@@ -0,0 +1,94 @@
// Simplifies use of zlib for inflating data
// File_Extractor 1.0.0
#ifndef LZMA_INFLATER_H
#define LZMA_INFLATER_H
#include <lzma.h>
#include "Data_Reader.h"
#include "blargg_common.h"
class LZMA_Inflater
{
public:
// Reads at most min(*count,bytes_until_eof()) bytes into *out and set *count
// to that number, or returns error if that many can't be read.
typedef blargg_err_t (*callback_t)(void *user_data, void *out, int *count);
// Begins by setting callback and filling buffer. Default buffer is 16K and
// filled to 4K, or specify buf_size and initial_read for custom buffer size
// and how much to read initially.
blargg_err_t begin(callback_t, void *user_data, int buf_size = 0, int initial_read = 0);
// Data read into buffer by begin()
const unsigned char *data() const
{
return (const unsigned char *)zbuf.next_in;
}
int filled() const
{
return zbuf.avail_in;
}
int totalOut() const
{
return zbuf.total_out;
}
// Begins inflation using specified mode. Using mode_auto selects between
// mode_copy and mode_ungz by examining first two bytes of buffer. Use
// buf_offset to specify where data begins in buffer, in case there is
// header data that should be skipped.
enum mode_t { mode_copy, mode_unxz, mode_unlz, mode_raw_deflate, mode_auto };
blargg_err_t set_mode(mode_t, int buf_offset = 0);
// True if set_mode() has been called with mode_ungz or mode_raw_deflate
bool deflated() const
{
return deflated_;
}
// Reads/inflates at most *count_io bytes into *out and sets *count_io to actual
// number of bytes read (less than requested if end of data was reached).
// Buffers source data internally, even in copy mode, so input file can be
// unbuffered without sacrificing performance.
blargg_err_t read(void *out, int *count_io);
// Total number of bytes read since begin()
int tell() const
{
return zbuf.total_out;
}
// Ends inflation and frees memory
void end();
private:
// noncopyable
LZMA_Inflater(const LZMA_Inflater &);
LZMA_Inflater &operator=(const LZMA_Inflater &);
// Implementation
public:
LZMA_Inflater();
~LZMA_Inflater();
bool is_format_xz(void);
bool is_format_lzma(void);
bool is_format_lzip(void);
private:
lzma_stream zbuf;
lzma_action action;
blargg_vector<unsigned char> buf;
bool deflated_;
callback_t callback;
void *user_data;
int mode_;
const uint8_t *buf_ptr;
blargg_err_t fill_buf(int count);
};
#endif

View File

@@ -0,0 +1,103 @@
// File_Extractor 1.0.0. http://www.slack.net/~ant/
#if FEX_ENABLE_LZMA
#include "LZ_Extractor.h"
#include <zlib.h>
/* Copyright (C) 2005-2009 Shay Green. This module is free software; you
can redistribute it and/or modify it under the terms of the GNU Lesser
General Public License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version. This
module is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
details. You should have received a copy of the GNU Lesser General Public
License along with this module; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
#include "blargg_source.h"
// TODO: could close file once data has been read into memory
static blargg_err_t init_lz_file()
{
get_crc_table(); // initialize zlib's CRC-32 tables
return blargg_ok;
}
static File_Extractor* new_lz()
{
return BLARGG_NEW LZ_Extractor;
}
fex_type_t_ const fex_lz_type [1] = {{
".lz",
&new_lz,
"lzip file",
&init_lz_file
}};
LZ_Extractor::LZ_Extractor() :
File_Extractor( fex_lz_type )
{ }
LZ_Extractor::~LZ_Extractor()
{
close();
}
blargg_err_t LZ_Extractor::open_path_v()
{
// skip opening file
return open_v();
}
blargg_err_t LZ_Extractor::stat_v()
{
RETURN_ERR( open_arc_file( true ) );
if ( !gr.opened() || gr.tell() != 0 )
RETURN_ERR( gr.open( &arc() ) );
set_info( gr.remain(), 0, gr.crc32() );
return blargg_ok;
}
blargg_err_t LZ_Extractor::open_v()
{
// Remove .gz suffix
size_t len = strlen( arc_path() );
if ( fex_has_extension( arc_path(), ".lz" ) )
len -= 3;
RETURN_ERR( name.resize( len + 1 ) );
memcpy( name.begin(), arc_path(), name.size() );
name [name.size() - 1] = '\0';
set_name( name.begin() );
return blargg_ok;
}
void LZ_Extractor::close_v()
{
name.clear();
gr.close();
}
blargg_err_t LZ_Extractor::next_v()
{
return blargg_ok;
}
blargg_err_t LZ_Extractor::rewind_v()
{
set_name( name.begin() );
return blargg_ok;
}
blargg_err_t LZ_Extractor::extract_v( void* p, int n )
{
return gr.read( p, n );
}
#endif

View File

@@ -0,0 +1,35 @@
// Presents a gzipped file as an "archive" of just that file.
// Also handles non-gzipped files.
// File_Extractor 1.0.0
#ifndef LZ_EXTRACTOR_H
#define LZ_EXTRACTOR_H
#include "File_Extractor.h"
#include "LZ_Reader.h"
class LZ_Extractor : public File_Extractor
{
public:
LZ_Extractor();
virtual ~LZ_Extractor();
protected:
virtual blargg_err_t open_path_v();
virtual blargg_err_t open_v();
virtual void close_v();
virtual blargg_err_t next_v();
virtual blargg_err_t rewind_v();
virtual blargg_err_t stat_v();
virtual blargg_err_t extract_v(void *, int);
private:
LZ_Reader gr;
blargg_vector<char> name;
void set_info_();
};
#endif

View File

@@ -0,0 +1,121 @@
// File_Extractor 1.0.0. http://www.slack.net/~ant/
#if FEX_ENABLE_LZMA
#include <stdio.h>
#include "LZ_Reader.h"
#include "blargg_endian.h"
/* Copyright (C) 2025 Andy Vandijck. This module is free software; you
can redistribute it and/or modify it under the terms of the GNU Lesser
General Public License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version. This
module is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
details. You should have received a copy of the GNU Lesser General Public
License along with this module; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
#include "blargg_source.h"
LZ_Reader::LZ_Reader()
{
close();
}
LZ_Reader::~LZ_Reader()
{ }
static blargg_err_t LZ_reader_read( void* file, void* out, int* count )
{
return STATIC_CAST(File_Reader*,file)->read_avail( out, count );
}
enum { header_size = 6, trailer_size = 20 };
size_t LZ_Reader::get_uncompressed_size()
{
uint8_t *header_ptr = (uint8_t *)malloc(header_size);
uint8_t *trailer_ptr = (uint8_t *)malloc(trailer_size);
if ((header_ptr == NULL) || (trailer_ptr == NULL)) {
fprintf(stderr, "Error: Couldn't allocate data\n");
return 0;
}
in->seek(0);
in->read((void *)header_ptr, header_size);
unsigned dict_size = 1 << (header_ptr[5] & 0x1F);
dict_size -= (dict_size / 16) * ((header_ptr[5] >> 5 ) & 7);
if(dict_size < (1 << 12) || dict_size > (1 << 29))
{
fprintf(stderr, "Invalid dictionary size in member header.\n");
free((void *)header_ptr);
free((void *)trailer_ptr);
return 0;
}
in->seek(in->size() - trailer_size);
in->read((void *)trailer_ptr, trailer_size);
unsigned long long data_size = 0;
for (int i = 11; i >= 4; --i)
data_size = ( data_size << 8 ) + trailer_ptr[i];
in->seek(0);
free((void *)header_ptr);
free((void *)trailer_ptr);
return (size_t)data_size;
}
blargg_err_t LZ_Reader::calc_size()
{
size_ = (int)get_uncompressed_size();
fprintf(stderr, "LZ uncompressed size: %d\n", size_);
crc32_ = 0;
return blargg_ok;
}
blargg_err_t LZ_Reader::open( File_Reader* new_in )
{
close();
in = new_in;
RETURN_ERR( in->seek( 0 ) );
RETURN_ERR( inflater.begin( LZ_reader_read, new_in ) );
RETURN_ERR( inflater.set_mode( inflater.mode_auto ) );
RETURN_ERR( calc_size() );
set_remain( size_ );
return blargg_ok;
}
void LZ_Reader::close()
{
in = NULL;
inflater.end();
}
blargg_err_t LZ_Reader::read_v( void* out, int count )
{
assert( in );
int actual = count;
RETURN_ERR( inflater.read( out, &actual ) );
fprintf(stderr, "LZ: Actual read: %d, count: %d\n", actual, count);
if ( actual != count )
return blargg_err_file_corrupt;
return blargg_ok;
}
#endif

View File

@@ -0,0 +1,60 @@
// Transparently decompresses gzip files, as well as uncompressed
// File_Extractor 1.0.0
#ifndef LZ_READER_H
#define LZ_READER_H
#include "Data_Reader.h"
#include "LZMA_Inflater.h"
class LZ_Reader : public Data_Reader
{
public:
// Keeps pointer to reader until close(). If
blargg_err_t open(File_Reader *);
// True if file is open
bool opened() const
{
return in != NULL;
}
// Frees memory
void close();
// True if file is compressed
bool deflated() const
{
return inflater.deflated();
}
// CRC-32 of data, of 0 if unavailable
unsigned int crc32() const
{
return crc32_;
}
// Number of bytes read since opening
int tell() const
{
return size_ - remain();
}
public:
LZ_Reader();
virtual ~LZ_Reader();
size_t get_uncompressed_size();
protected:
virtual blargg_err_t read_v(void *, int);
private:
File_Reader *in;
unsigned crc32_;
int size_;
LZMA_Inflater inflater;
blargg_err_t calc_size();
};
#endif

View File

@@ -0,0 +1,102 @@
// File_Extractor 1.0.0. http://www.slack.net/~ant/
#include <stdio.h>
#include <stdlib.h>
#include <zlib.h>
#include "Tar_Extractor.h"
/* Copyright (C) 2025 Andy Vandijck. This module is free software; you
can redistribute it and/or modify it under the terms of the GNU Lesser
General Public License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version. This
module is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
details. You should have received a copy of the GNU Lesser General Public
License along with this module; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
#include "blargg_source.h"
// TODO: could close file once data has been read into memory
static blargg_err_t init_tar_file()
{
get_crc_table(); // initialize zlib's CRC-32 tables
return blargg_ok;
}
static File_Extractor* new_tar()
{
return BLARGG_NEW Tar_Extractor;
}
fex_type_t_ const fex_tar_type [1] = {{
".tar",
&new_tar,
"tar file",
&init_tar_file
}};
Tar_Extractor::Tar_Extractor() :
File_Extractor( fex_tar_type )
{ }
Tar_Extractor::~Tar_Extractor()
{
close();
}
blargg_err_t Tar_Extractor::open_path_v()
{
RETURN_ERR( open_arc_file(true) );
RETURN_ERR( arc().seek( 0 ) );
return open_v();
}
blargg_err_t Tar_Extractor::stat_v()
{
set_info( arc().remain(), 0, 0 );
return blargg_ok;
}
blargg_err_t Tar_Extractor::open_v()
{
arc().read(&header, BLOCKSIZE);
set_name( header.name );
#if __STDC_WANT_SECURE_LIB__
sscanf_s(header.size, "%o", &tarsize);
#else
sscanf(header.size, "%o", &tarsize);
#endif
return blargg_ok;
}
void Tar_Extractor::close_v()
{
name.clear();
}
blargg_err_t Tar_Extractor::next_v()
{
arc().read(&header, BLOCKSIZE);
set_name( header.name );
#if __STDC_WANT_SECURE_LIB__
sscanf_s(header.size, "%o", &tarsize);
#else
sscanf(header.size, "%o", &tarsize);
#endif
return blargg_ok;
}
blargg_err_t Tar_Extractor::rewind_v()
{
arc().seek(0);
return blargg_ok;
}
blargg_err_t Tar_Extractor::extract_v( void* p, int n )
{
return arc().read( p, n );
}

View File

@@ -0,0 +1,76 @@
// Presents a gzipped file as an "archive" of just that file.
// Also handles non-gzipped files.
// File_Extractor 1.0.0
#ifndef TAR_EXTRACTOR_H
#define TAR_EXTRACTOR_H
#include "File_Extractor.h"
typedef struct posix_header
{ /* byte offset */
char name[100]; /* 0 */
char mode[8]; /* 100 */
char uid[8]; /* 108 */
char gid[8]; /* 116 */
char size[12]; /* 124 */
char mtime[12]; /* 136 */
char chksum[8]; /* 148 */
char typeflag; /* 156 */
char linkname[100]; /* 157 */
char magic[6]; /* 257 */
char version[2]; /* 263 */
char uname[32]; /* 265 */
char gname[32]; /* 297 */
char devmajor[8]; /* 329 */
char devminor[8]; /* 337 */
char prefix[155]; /* 345 */
char padding[12]; /* 500 */
/* 512 */
} posix_header;
#define BLOCKSIZE 512
#define TMAGIC "ustar" /* ustar and a null */
#define TMAGLEN 6
#define TVERSION "00" /* 00 and no null */
#define TVERSLEN 2
/* Values used in typeflag field. */
#define REGTYPE '0' /* regular file */
#define AREGTYPE '\0' /* regular file */
#define LNKTYPE '1' /* link */
#define SYMTYPE '2' /* reserved */
#define CHRTYPE '3' /* character special */
#define BLKTYPE '4' /* block special */
#define DIRTYPE '5' /* directory */
#define FIFOTYPE '6' /* FIFO special */
#define CONTTYPE '7' /* reserved */
class Tar_Extractor : public File_Extractor
{
public:
Tar_Extractor();
virtual ~Tar_Extractor();
protected:
virtual blargg_err_t open_path_v();
virtual blargg_err_t open_v();
virtual void close_v();
virtual blargg_err_t next_v();
virtual blargg_err_t rewind_v();
virtual blargg_err_t stat_v();
virtual blargg_err_t extract_v(void *, int);
private:
File_Reader *gr;
posix_header header;
unsigned int tarsize;
blargg_vector<char> name;
void set_info_();
};
#endif

View File

@@ -0,0 +1,103 @@
// File_Extractor 1.0.0. http://www.slack.net/~ant/
#if FEX_ENABLE_LZMA
#include "XZ_Extractor.h"
#include <zlib.h>
/* Copyright (C) 2005-2009 Shay Green. This module is free software; you
can redistribute it and/or modify it under the terms of the GNU Lesser
General Public License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version. This
module is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
details. You should have received a copy of the GNU Lesser General Public
License along with this module; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
#include "blargg_source.h"
// TODO: could close file once data has been read into memory
static blargg_err_t init_xz_file()
{
get_crc_table(); // initialize zlib's CRC-32 tables
return blargg_ok;
}
static File_Extractor* new_xz()
{
return BLARGG_NEW XZ_Extractor;
}
fex_type_t_ const fex_xz_type [1] = {{
".xz",
&new_xz,
"xz file",
&init_xz_file
}};
XZ_Extractor::XZ_Extractor() :
File_Extractor( fex_xz_type )
{ }
XZ_Extractor::~XZ_Extractor()
{
close();
}
blargg_err_t XZ_Extractor::open_path_v()
{
// skip opening file
return open_v();
}
blargg_err_t XZ_Extractor::stat_v()
{
RETURN_ERR( open_arc_file( true ) );
if ( !gr.opened() || gr.tell() != 0 )
RETURN_ERR( gr.open( &arc() ) );
set_info( gr.remain(), 0, gr.crc32() );
return blargg_ok;
}
blargg_err_t XZ_Extractor::open_v()
{
// Remove .gz suffix
size_t len = strlen( arc_path() );
if ( fex_has_extension( arc_path(), ".xz" ) )
len -= 3;
RETURN_ERR( name.resize( len + 1 ) );
memcpy( name.begin(), arc_path(), name.size() );
name [name.size() - 1] = '\0';
set_name( name.begin() );
return blargg_ok;
}
void XZ_Extractor::close_v()
{
name.clear();
gr.close();
}
blargg_err_t XZ_Extractor::next_v()
{
return blargg_ok;
}
blargg_err_t XZ_Extractor::rewind_v()
{
set_name( name.begin() );
return blargg_ok;
}
blargg_err_t XZ_Extractor::extract_v( void* p, int n )
{
return gr.read( p, n );
}
#endif

View File

@@ -0,0 +1,35 @@
// Presents a gzipped file as an "archive" of just that file.
// Also handles non-gzipped files.
// File_Extractor 1.0.0
#ifndef XZ_EXTRACTOR_H
#define XZ_EXTRACTOR_H
#include "File_Extractor.h"
#include "XZ_Reader.h"
class XZ_Extractor : public File_Extractor
{
public:
XZ_Extractor();
virtual ~XZ_Extractor();
protected:
virtual blargg_err_t open_path_v();
virtual blargg_err_t open_v();
virtual void close_v();
virtual blargg_err_t next_v();
virtual blargg_err_t rewind_v();
virtual blargg_err_t stat_v();
virtual blargg_err_t extract_v(void *, int);
private:
XZ_Reader gr;
blargg_vector<char> name;
void set_info_();
};
#endif

View File

@@ -0,0 +1,129 @@
// File_Extractor 1.0.0. http://www.slack.net/~ant/
#if FEX_ENABLE_LZMA
#include <stdio.h>
#include "XZ_Reader.h"
#include "blargg_endian.h"
/* Copyright (C) 2025 Andy Vandijck. This module is free software; you
can redistribute it and/or modify it under the terms of the GNU Lesser
General Public License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version. This
module is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
details. You should have received a copy of the GNU Lesser General Public
License along with this module; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
#include "blargg_source.h"
XZ_Reader::XZ_Reader()
{
close();
}
XZ_Reader::~XZ_Reader()
{ }
static blargg_err_t XZ_reader_read( void* file, void* out, int* count )
{
return STATIC_CAST(File_Reader*,file)->read_avail( out, count );
}
size_t XZ_Reader::get_uncompressed_size()
{
lzma_stream_flags stream_flags;
const uint8_t *footer_ptr = NULL;
const uint8_t *index_ptr = NULL;
const uint8_t *data = (const uint8_t *)malloc(in->size());
if (data == NULL) {
fprintf(stderr, "Error: Couldn't allocate data\n");
return 0;
}
in->seek(0);
in->read((void *)data, in->size());
// 12 is the size of the footer per the file-spec...
footer_ptr = data + (in->size() - 12);
// Decode the footer, so we have the backward_size pointing to the index
(void)lzma_stream_footer_decode(&stream_flags, (const uint8_t *)footer_ptr);
// This is the index pointer, where the size is ultimately stored...
index_ptr = data + ((in->size() - 12) - stream_flags.backward_size);
// Allocate an index
lzma_index *index = lzma_index_init(NULL);
uint64_t memlimit;
size_t in_pos = 0;
// decode the index we calculated
lzma_index_buffer_decode(&index, &memlimit, NULL, (const uint8_t *)index_ptr, &in_pos, footer_ptr - index_ptr);
// Just make sure the whole index was decoded, otherwise, we might be
// dealing with something utterly corrupt
if (in_pos != stream_flags.backward_size) {
lzma_index_end(index, NULL);
free((void *)data);
fprintf(stderr, "Error: input position %u is not equal to backward size %llu\n", in_pos, stream_flags.backward_size);
return 0;
}
// Finally get the size
lzma_vli uSize = lzma_index_uncompressed_size(index);
lzma_index_end(index, NULL);
free((void *)data);
in->seek(0);
return (size_t) uSize;
}
blargg_err_t XZ_Reader::calc_size()
{
size_ = (int)get_uncompressed_size();
fprintf(stderr, "XZ uncompressed size: %d\n", size_);
crc32_ = 0;
return blargg_ok;
}
blargg_err_t XZ_Reader::open( File_Reader* new_in )
{
close();
in = new_in;
RETURN_ERR( in->seek( 0 ) );
RETURN_ERR( inflater.begin( XZ_reader_read, new_in ) );
RETURN_ERR( inflater.set_mode( inflater.mode_auto ) );
RETURN_ERR( calc_size() );
set_remain( size_ );
return blargg_ok;
}
void XZ_Reader::close()
{
in = NULL;
inflater.end();
}
blargg_err_t XZ_Reader::read_v( void* out, int count )
{
assert( in );
int actual = count;
RETURN_ERR( inflater.read( out, &actual ) );
fprintf(stderr, "XZ: Actual read: %d, count: %d\n", actual, count);
if ( actual != count )
return blargg_err_file_corrupt;
return blargg_ok;
}
#endif

View File

@@ -0,0 +1,60 @@
// Transparently decompresses gzip files, as well as uncompressed
// File_Extractor 1.0.0
#ifndef XZ_READER_H
#define XZ_READER_H
#include "Data_Reader.h"
#include "LZMA_Inflater.h"
class XZ_Reader : public Data_Reader
{
public:
// Keeps pointer to reader until close(). If
blargg_err_t open(File_Reader *);
// True if file is open
bool opened() const
{
return in != NULL;
}
// Frees memory
void close();
// True if file is compressed
bool deflated() const
{
return inflater.deflated();
}
// CRC-32 of data, of 0 if unavailable
unsigned int crc32() const
{
return crc32_;
}
// Number of bytes read since opening
int tell() const
{
return size_ - remain();
}
public:
XZ_Reader();
virtual ~XZ_Reader();
size_t get_uncompressed_size();
protected:
virtual blargg_err_t read_v(void *, int);
private:
File_Reader *in;
unsigned crc32_;
int size_;
LZMA_Inflater inflater;
blargg_err_t calc_size();
};
#endif

View File

@@ -17,8 +17,23 @@
// Enable support for as building DLL on Windows.
//#define BLARGG_BUILD_DLL 1
// Support only the listed archive types. Remove any you don't need.
#define FEX_TYPE_LIST fex_7z_type, fex_gz_type, fex_zip_type,
#ifndef FEX_ENABLE_RAR
#define FEX_ENABLE_RAR 1
#endif
#if FEX_ENABLE_BZ2
#define FEX_TYPE_BZ2 fex_bz2_type,
#else
#define FEX_TYPE_BZ2
#endif
#if FEX_ENABLE_LZMA
#define FEX_TYPE_LZMA fex_xz_type, fex_lz_type,
#else
#define FEX_TYPE_LZMA
#endif
#define FEX_TYPE_LIST fex_7z_type, fex_gz_type, fex_zip_type, fex_tar_type, fex_rar_type, FEX_TYPE_BZ2 FEX_TYPE_LZMA
// Use standard config.h if present
#ifdef HAVE_CONFIG_H

View File

@@ -33,6 +33,14 @@ BLARGG_EXPORT const fex_type_t* fex_type_list( void )
// Modify blargg_config.h to change type list, NOT this file
fex_7z_type,
fex_gz_type,
fex_tar_type,
#if FEX_ENABLE_LZMA
fex_xz_type,
fex_lz_type,
#endif
#if FEX_ENABLE_BZ2
fex_bz2_type,
#endif
#if FEX_ENABLE_RAR
fex_rar_type,
#endif
@@ -41,7 +49,7 @@ BLARGG_EXPORT const fex_type_t* fex_type_list( void )
fex_bin_type,
NULL
};
return fex_type_list_;
}
@@ -60,8 +68,19 @@ BLARGG_EXPORT fex_err_t fex_init( void )
return blargg_ok;
}
BLARGG_EXPORT const char* fex_identify_header( void const* header )
BLARGG_EXPORT const char* fex_identify_header(const void* header)
{
const unsigned char* data = static_cast<const unsigned char*>(header);
// Safely detect .xz (magic bytes at offset 0)
if (memcmp(data, "\xFD\x37\x7A\x58\x5A\x00", 6) == 0)
return ".xz";
// Safely detect .tar (magic string at offset 257)
const char tar_magic[] = "ustar";
if (memcmp(data + 257, tar_magic, sizeof(tar_magic)) == 0 && data[262] == 0x00)
return ".tar";
unsigned four = get_be32( header );
switch ( four )
{
@@ -77,6 +96,8 @@ BLARGG_EXPORT const char* fex_identify_header( void const* header )
case 0x41724301: return ".arc";
case 0x4D534346: return ".cab";
case 0x5A4F4F20: return ".zoo";
case 0x04224D18: return ".lz4";
case 0x4C5A4950: return ".lz";
}
unsigned three = four >> 8;
@@ -130,6 +151,7 @@ static int is_archive_extension( const char str [] )
".dmg",
".gz",
".lha",
".lz4",
".lz",
".lzh",
".lzma",
@@ -139,8 +161,10 @@ static int is_archive_extension( const char str [] )
".rar",
".sit",
".sitx",
".tar",
".tgz",
".tlz",
".xz",
".z",
".zip",
".zoo",
@@ -177,7 +201,7 @@ BLARGG_EXPORT fex_err_t fex_identify_file( fex_type_t* type_out, const char path
*type_out = NULL;
fex_type_t type = fex_identify_extension( path );
// Unsupported extension?
if ( !type )
return blargg_ok; // reject
@@ -192,11 +216,11 @@ BLARGG_EXPORT fex_err_t fex_identify_file( fex_type_t* type_out, const char path
{
char h [fex_identify_header_size];
RETURN_ERR( in.read( h, sizeof h ) );
type = fex_identify_extension( fex_identify_header( h ) );
}
}
*type_out = type;
return blargg_ok;
}

View File

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

View File

@@ -0,0 +1,100 @@
#include <stdio.h>
#include "rar.hpp"
#include "unrar.h"
Archive::Archive() : Raw( this )
{
Format=RARFMT15;
Solid=false;
CurBlockPos=0;
NextBlockPos=0;
memset(&MainHead,0,sizeof(MainHead));
memset(&EndArcHead,0,sizeof(EndArcHead));
HeaderCRC=0;
}
RARFORMAT Archive::IsSignature(const byte *D,size_t Size)
{
RARFORMAT Type=RARFMT_NONE;
if (Size>=1 && D[0]==0x52) {
#ifndef SFX_MODULE
if (Size>=4 && D[1]==0x45 && D[2]==0x7e && D[3]==0x5e)
Type=RARFMT14;
else {
#endif
if (Size>=7 && D[1]==0x61 && D[2]==0x72 && D[3]==0x21 && D[4]==0x1a && D[5]==0x07)
{
// We check for non-zero last signature byte, so we can return
// a sensible warning in case we'll want to change the archive
// format sometimes in the future.
if (D[6]==0)
Type=RARFMT15;
else if (D[6]==1)
Type=RARFMT50;
else if (D[6]==2)
Type=RARFMT_FUTURE;
}
#ifndef SFX_MODULE
}
#endif
}
return Type;
}
unrar_err_t Archive::IsArchive()
{
if (Read(MarkHead.Mark,SIZEOF_MARKHEAD3)!=SIZEOF_MARKHEAD3)
return unrar_err_not_arc;
RARFORMAT Type;
if ((Type=IsSignature(MarkHead.Mark,SIZEOF_MARKHEAD3))!=RARFMT_NONE)
{
Format=Type;
if (Format==RARFMT14)
Seek(Tell()-SIZEOF_MARKHEAD3,SEEK_SET);
}
else
{
if (SFXSize==0)
return unrar_err_not_arc;
}
if (Format==RARFMT_FUTURE)
return unrar_err_new_algo;
if (Format==RARFMT50) // RAR 5.0 signature is one byte longer.
{
Read(MarkHead.Mark+SIZEOF_MARKHEAD3,1);
if (MarkHead.Mark[SIZEOF_MARKHEAD3]!=0)
return unrar_err_not_arc;
MarkHead.HeadSize=SIZEOF_MARKHEAD5;
}
else
MarkHead.HeadSize=SIZEOF_MARKHEAD3;
unrar_err_t error;
size_t HeaderSize;
while ((error=ReadHeader(&HeaderSize))==unrar_ok && HeaderSize!=0)
{
HEADER_TYPE Type=GetHeaderType();
// In RAR 5.0 we need to quit after reading HEAD_CRYPT if we wish to
// avoid the password prompt.
if (Type==HEAD_MAIN)
break;
SeekToNext();
}
if ( error != unrar_ok )
return error;
SeekToNext();
return unrar_ok;
}
void Archive::SeekToNext()
{
Seek(NextBlockPos,SEEK_SET);
}

View File

@@ -0,0 +1,55 @@
#ifndef _RAR_ARCHIVE_
#define _RAR_ARCHIVE_
typedef ComprDataIO File;
#include "rawread.hpp"
enum RARFORMAT {RARFMT_NONE,RARFMT14,RARFMT15,RARFMT50,RARFMT_FUTURE};
class Archive:public File
{
private:
void ConvertFileHeader(FileHeader *hd);
void WriteBlock50(HEADER_TYPE HeaderType,BaseBlock *wb,bool OnlySetSize,bool NonFinalWrite);
unrar_err_t ReadHeader14(size_t *ReadSize);
unrar_err_t ReadHeader15(size_t *ReadSize);
unrar_err_t ReadHeader50(size_t *ReadSize);
unrar_err_t ProcessExtra50(RawRead *Raw,size_t ExtraSize,BaseBlock *bb);
RawRead Raw;
HEADER_TYPE CurHeaderType;
public:
Archive();
RARFORMAT IsSignature(const byte *D,size_t Size);
unrar_err_t IsArchive();
size_t SearchBlock(HEADER_TYPE HeaderType);
size_t SearchSubBlock(const wchar *Type);
size_t SearchRR();
unrar_err_t ReadHeader(size_t *ReadSize);
void SeekToNext();
bool IsArcDir();
bool IsArcLabel();
int64 GetStartPos();
HEADER_TYPE GetHeaderType() {return(CurHeaderType);};
BaseBlock ShortBlock;
MarkHeader MarkHead;
MainHeader MainHead;
FileHeader FileHead;
EndArcHeader EndArcHead;
SubBlockHeader SubBlockHead;
FileHeader SubHead;
ProtectHeader ProtectHead;
int64 CurBlockPos;
int64 NextBlockPos;
RARFORMAT Format;
bool Solid;
enum { SFXSize = 0 }; // self-extracting not supported
ushort HeaderCRC;
};
#endif

View File

@@ -0,0 +1,739 @@
#include "rar.hpp"
#include "unrar.h"
#include "unicode.hpp"
#include "encname.hpp"
// arcread.cpp
unrar_err_t Archive::ReadHeader(size_t * ReadSize_)
{
CurBlockPos=Tell();
unrar_err_t Error;
size_t ReadSize;
switch(Format)
{
#ifndef SFX_MODULE
case RARFMT14:
Error=ReadHeader14(&ReadSize);
break;
#endif
case RARFMT15:
Error=ReadHeader15(&ReadSize);
break;
case RARFMT50:
Error=ReadHeader50(&ReadSize);
break;
default: // unreachable
Error=unrar_err_corrupt;
break;
}
if (Error!=unrar_ok)
return Error;
if (ReadSize>0 && NextBlockPos<=CurBlockPos)
return unrar_err_corrupt;
*ReadSize_ = ReadSize;
return unrar_ok;
}
unrar_err_t Archive::ReadHeader15(size_t *ReadSize)
{
Raw.Reset();
Raw.Read(SIZEOF_SHORTBLOCKHEAD);
if (Raw.Size()==0)
return unrar_err_corrupt;
ShortBlock.HeadCRC=Raw.Get2();
ShortBlock.Reset();
uint HeaderType=Raw.Get1();
ShortBlock.Flags=Raw.Get2();
ShortBlock.SkipIfUnknown=(ShortBlock.Flags & SKIP_IF_UNKNOWN)!=0;
ShortBlock.HeadSize=Raw.Get2();
ShortBlock.HeaderType=(HEADER_TYPE)HeaderType;
if (ShortBlock.HeadSize<SIZEOF_SHORTBLOCKHEAD)
return unrar_err_corrupt;
// For simpler further processing we map header types common
// for RAR 1.5 and 5.0 formats to RAR 5.0 values. It does not include
// header types specific for RAR 1.5 - 4.x only.
switch(ShortBlock.HeaderType)
{
case HEAD3_MAIN: ShortBlock.HeaderType=HEAD_MAIN; break;
case HEAD3_FILE: ShortBlock.HeaderType=HEAD_FILE; break;
case HEAD3_SERVICE: ShortBlock.HeaderType=HEAD_SERVICE; break;
case HEAD3_ENDARC: ShortBlock.HeaderType=HEAD_ENDARC; break;
default: break;
}
CurHeaderType=ShortBlock.HeaderType;
if (ShortBlock.HeaderType==HEAD3_CMT)
{
// Old style (up to RAR 2.9) comment header embedded into main
// or file header. We must not read the entire ShortBlock.HeadSize here
// to not break the comment processing logic later.
Raw.Read(SIZEOF_COMMHEAD-SIZEOF_SHORTBLOCKHEAD);
}
else
if (ShortBlock.HeaderType==HEAD_MAIN && (ShortBlock.Flags & MHD_COMMENT)!=0)
{
// Old style (up to RAR 2.9) main archive comment embedded into
// the main archive header found. While we can read the entire
// ShortBlock.HeadSize here and remove this part of "if", it would be
// waste of memory, because we'll read and process this comment data
// in other function anyway and we do not need them here now.
Raw.Read(SIZEOF_MAINHEAD3-SIZEOF_SHORTBLOCKHEAD);
}
else
Raw.Read(ShortBlock.HeadSize-SIZEOF_SHORTBLOCKHEAD);
NextBlockPos=CurBlockPos+ShortBlock.HeadSize;
switch(ShortBlock.HeaderType)
{
case HEAD_MAIN:
MainHead.Reset();
*(BaseBlock *)&MainHead=ShortBlock;
MainHead.HighPosAV=Raw.Get2();
MainHead.PosAV=Raw.Get4();
Solid=(MainHead.Flags & MHD_SOLID)!=0;
MainHead.CommentInHeader=(MainHead.Flags & MHD_COMMENT)!=0;
break;
case HEAD_FILE:
case HEAD_SERVICE:
{
bool FileBlock=ShortBlock.HeaderType==HEAD_FILE;
FileHeader *hd=FileBlock ? &FileHead:&SubHead;
hd->Reset();
*(BaseBlock *)hd=ShortBlock;
hd->SplitBefore=(hd->Flags & LHD_SPLIT_BEFORE)!=0;
hd->SplitAfter=(hd->Flags & LHD_SPLIT_AFTER)!=0;
hd->Encrypted=(hd->Flags & LHD_PASSWORD)!=0;
hd->Solid=FileBlock && (hd->Flags & LHD_SOLID)!=0;
hd->SubBlock=!FileBlock && (hd->Flags & LHD_SOLID)!=0;
hd->Dir=(hd->Flags & LHD_WINDOWMASK)==LHD_DIRECTORY;
hd->WinSize=hd->Dir ? 0:0x10000<<((hd->Flags & LHD_WINDOWMASK)>>5);
hd->CommentInHeader=(hd->Flags & LHD_COMMENT)!=0;
hd->Version=(hd->Flags & LHD_VERSION)!=0;
hd->DataSize=Raw.Get4();
uint LowUnpSize=Raw.Get4();
hd->HostOS=Raw.Get1();
hd->FileHash.Type=HASH_CRC32;
hd->FileHash.CRC32=Raw.Get4();
uint FileTime=Raw.Get4();
hd->UnpVer=Raw.Get1();
hd->Method=Raw.Get1()-0x30;
size_t NameSize=Raw.Get2();
hd->FileAttr=Raw.Get4();
if (hd->Encrypted)
return unrar_err_encrypted;
hd->HSType=HSYS_UNKNOWN;
if (hd->HostOS==HOST_UNIX || hd->HostOS==HOST_BEOS)
hd->HSType=HSYS_UNIX;
else
if (hd->HostOS<HOST_MAX)
hd->HSType=HSYS_WINDOWS;
hd->RedirType=FSREDIR_NONE;
// RAR 4.x Unix symlink.
if (hd->HostOS==HOST_UNIX && (hd->FileAttr & 0xF000)==0xA000)
{
hd->RedirType=FSREDIR_UNIXSYMLINK;
*hd->RedirName=0;
}
hd->Inherited=!FileBlock && (hd->SubFlags & SUBHEAD_FLAGS_INHERITED)!=0;
hd->LargeFile=(hd->Flags & LHD_LARGE)!=0;
uint HighPackSize,HighUnpSize;
if (hd->LargeFile)
{
HighPackSize=Raw.Get4();
HighUnpSize=Raw.Get4();
hd->UnknownUnpSize=(LowUnpSize==0xffffffff && HighUnpSize==0xffffffff);
}
else
{
HighPackSize=HighUnpSize=0;
// UnpSize equal to 0xffffffff without LHD_LARGE flag indicates
// that we do not know the unpacked file size and must unpack it
// until we find the end of file marker in compressed data.
hd->UnknownUnpSize=(LowUnpSize==0xffffffff);
}
hd->PackSize=int32to64(HighPackSize,hd->DataSize);
hd->UnpSize=int32to64(HighUnpSize,LowUnpSize);
if (hd->UnknownUnpSize)
hd->UnpSize=INT64NDF;
char FileName[NM*4];
size_t ReadNameSize=Min(NameSize,ASIZE(FileName)-1);
Raw.GetB((byte *)FileName,ReadNameSize);
FileName[ReadNameSize]=0;
if (FileBlock)
{
if ((hd->Flags & LHD_UNICODE)!=0)
{
EncodeFileName NameCoder;
size_t Length=strlen(FileName);
Length++;
NameCoder.Decode(FileName,(byte *)FileName+Length,
NameSize-Length,hd->FileName,
ASIZE(hd->FileName));
}
else
*hd->FileName=0;
char AnsiName[NM];
IntToExt(FileName,AnsiName,ASIZE(AnsiName));
GetWideName(AnsiName,hd->FileName,hd->FileName,ASIZE(hd->FileName));
ConvertFileHeader(hd);
}
else
{
CharToWide(FileName,hd->FileName,ASIZE(hd->FileName));
// Calculate the size of optional data.
int DataSize=int(hd->HeadSize-NameSize-SIZEOF_FILEHEAD3);
if ((hd->Flags & LHD_SALT)!=0)
return unrar_err_encrypted;
if (DataSize>0)
{
// Here we read optional additional fields for subheaders.
// They are stored after the file name and before salt.
hd->SubData.Alloc(DataSize);
Raw.GetB(&hd->SubData[0],DataSize);
}
}
if ((hd->Flags & LHD_SALT)!=0)
return unrar_err_encrypted;
hd->mtime.SetDos(FileTime);
if ((hd->Flags & LHD_EXTTIME)!=0)
{
ushort Flags=Raw.Get2();
RarTime *tbl[4];
tbl[0]=&FileHead.mtime;
tbl[1]=&FileHead.ctime;
tbl[2]=&FileHead.atime;
tbl[3]=NULL; // Archive time is not used now.
for (int I=0;I<4;I++)
{
RarTime *CurTime=tbl[I];
uint rmode=Flags>>(3-I)*4;
if ((rmode & 8)==0 || CurTime==NULL)
continue;
if (I!=0)
{
uint DosTime=Raw.Get4();
CurTime->SetDos(DosTime);
}
RarLocalTime rlt;
CurTime->GetLocal(&rlt);
if (rmode & 4)
rlt.Second++;
rlt.Reminder=0;
int count=rmode&3;
for (int J=0;J<count;J++)
{
byte CurByte=Raw.Get1();
rlt.Reminder|=(((uint)CurByte)<<((J+3-count)*8));
}
CurTime->SetLocal(&rlt);
}
}
NextBlockPos+=hd->PackSize;
bool CRCProcessedOnly=hd->CommentInHeader;
ushort HeaderCRC=Raw.GetCRC15(CRCProcessedOnly);
if (hd->HeadCRC!=HeaderCRC)
return unrar_err_corrupt;
}
break;
case HEAD_ENDARC:
*(BaseBlock *)&EndArcHead=ShortBlock;
EndArcHead.NextVolume=(EndArcHead.Flags & EARC_NEXT_VOLUME)!=0;
EndArcHead.DataCRC=(EndArcHead.Flags & EARC_DATACRC)!=0;
EndArcHead.RevSpace=(EndArcHead.Flags & EARC_REVSPACE)!=0;
EndArcHead.StoreVolNumber=(EndArcHead.Flags & EARC_VOLNUMBER)!=0;
if (EndArcHead.DataCRC)
EndArcHead.ArcDataCRC=Raw.Get4();
if (EndArcHead.StoreVolNumber)
return unrar_err_segmented;
break;
default:
if (ShortBlock.Flags & LONG_BLOCK)
NextBlockPos+=Raw.Get4();
break;
}
ushort HeaderCRC=Raw.GetCRC15(false);
// Old AV header does not have header CRC properly set.
if (ShortBlock.HeadCRC!=HeaderCRC && ShortBlock.HeaderType!=HEAD3_SIGN &&
ShortBlock.HeaderType!=HEAD3_AV)
return unrar_err_corrupt;
if (NextBlockPos<=CurBlockPos)
return unrar_err_corrupt;
*ReadSize=Raw.Size();
return unrar_ok;
}
unrar_err_t Archive::ReadHeader50(size_t *ReadSize)
{
Raw.Reset();
// Header size must not occupy more than 3 variable length integer bytes
// resulting in 2 MB maximum header size, so here we read 4 byte CRC32
// followed by 3 bytes or less of header size.
const size_t FirstReadSize=7; // Smallest possible block size.
if (Raw.Read(FirstReadSize)<FirstReadSize)
return unrar_err_arc_eof;
ShortBlock.Reset();
ShortBlock.HeadCRC=Raw.Get4();
uint SizeBytes=Raw.GetVSize(4);
uint64 BlockSize=Raw.GetV();
if (BlockSize==0 || SizeBytes==0)
return unrar_err_corrupt;
int SizeToRead=int(BlockSize);
SizeToRead-=FirstReadSize-SizeBytes-4; // Adjust overread size bytes if any.
uint HeaderSize=4+SizeBytes+(uint)BlockSize;
if (SizeToRead<0 || HeaderSize<SIZEOF_SHORTBLOCKHEAD5)
return unrar_err_corrupt;
Raw.Read(SizeToRead);
if (Raw.Size()<HeaderSize)
return unrar_err_arc_eof;
uint HeaderCRC=Raw.GetCRC50();
ShortBlock.HeaderType=(HEADER_TYPE)Raw.GetV();
ShortBlock.Flags=(uint)Raw.GetV();
ShortBlock.SkipIfUnknown=(ShortBlock.Flags & HFL_SKIPIFUNKNOWN)!=0;
ShortBlock.HeadSize=HeaderSize;
CurHeaderType=ShortBlock.HeaderType;
bool BadCRC=(ShortBlock.HeadCRC!=HeaderCRC);
if (BadCRC)
return unrar_err_corrupt;
uint64 ExtraSize=0;
if ((ShortBlock.Flags & HFL_EXTRA)!=0)
{
ExtraSize=Raw.GetV();
if (ExtraSize>=ShortBlock.HeadSize)
return unrar_err_corrupt;
}
uint64 DataSize=0;
if ((ShortBlock.Flags & HFL_DATA)!=0)
DataSize=Raw.GetV();
NextBlockPos=CurBlockPos+ShortBlock.HeadSize+DataSize;
switch(ShortBlock.HeaderType)
{
case HEAD_CRYPT:
return unrar_err_encrypted;
case HEAD_MAIN:
{
MainHead.Reset();
*(BaseBlock *)&MainHead=ShortBlock;
uint ArcFlags=(uint)Raw.GetV();
Solid=(ArcFlags & MHFL_SOLID)!=0;
if (ExtraSize!=0)
{
unrar_err_t Error;
if ((Error=ProcessExtra50(&Raw,(size_t)ExtraSize,&MainHead))!=unrar_ok)
return Error;
}
}
break;
case HEAD_FILE:
case HEAD_SERVICE:
{
FileHeader *hd=ShortBlock.HeaderType==HEAD_FILE ? &FileHead:&SubHead;
hd->Reset();
*(BaseBlock *)hd=ShortBlock;
bool FileBlock=ShortBlock.HeaderType==HEAD_FILE;
hd->LargeFile=true;
hd->PackSize=DataSize;
hd->FileFlags=(uint)Raw.GetV();
hd->UnpSize=Raw.GetV();
hd->UnknownUnpSize=(hd->FileFlags & FHFL_UNPUNKNOWN)!=0;
if (hd->UnknownUnpSize)
hd->UnpSize=INT64NDF;
hd->MaxSize=Max(hd->PackSize,hd->UnpSize);
hd->FileAttr=(uint)Raw.GetV();
if ((hd->FileFlags & FHFL_UTIME)!=0)
hd->mtime=(time_t)Raw.Get4();
hd->FileHash.Type=HASH_NONE;
if ((hd->FileFlags & FHFL_CRC32)!=0)
{
hd->FileHash.Type=HASH_CRC32;
hd->FileHash.CRC32=Raw.Get4();
}
hd->RedirType=FSREDIR_NONE;
uint CompInfo=(uint)Raw.GetV();
hd->Method=(CompInfo>>7) & 7;
hd->UnpVer=CompInfo & 0x3f;
hd->HostOS=(byte)Raw.GetV();
size_t NameSize=(size_t)Raw.GetV();
hd->Inherited=(ShortBlock.Flags & HFL_INHERITED)!=0;
hd->HSType=HSYS_UNKNOWN;
if (hd->HostOS==HOST5_UNIX)
hd->HSType=HSYS_UNIX;
else
if (hd->HostOS==HOST5_WINDOWS)
hd->HSType=HSYS_WINDOWS;
hd->SplitBefore=(hd->Flags & HFL_SPLITBEFORE)!=0;
hd->SplitAfter=(hd->Flags & HFL_SPLITAFTER)!=0;
hd->SubBlock=(hd->Flags & HFL_CHILD)!=0;
hd->Solid=FileBlock && (CompInfo & FCI_SOLID)!=0;
hd->Dir=(hd->FileFlags & FHFL_DIRECTORY)!=0;
hd->WinSize=hd->Dir ? 0:size_t(0x20000)<<((CompInfo>>10)&0xf);
if (hd->Encrypted)
return unrar_err_encrypted;
char FileName[NM*4];
size_t ReadNameSize=Min(NameSize,ASIZE(FileName)-1);
Raw.GetB((byte *)FileName,ReadNameSize);
FileName[ReadNameSize]=0;
UtfToWide(FileName,hd->FileName,ASIZE(hd->FileName)-1);
// Should do it before converting names, because extra fields can
// affect name processing, like in case of NTFS streams.
if (ExtraSize!=0)
ProcessExtra50(&Raw,(size_t)ExtraSize,hd);
if (FileBlock)
ConvertFileHeader(hd);
if (BadCRC) // Add the file name to broken header message displayed above.
return unrar_err_corrupt;
}
break;
case HEAD_ENDARC:
{
*(BaseBlock *)&EndArcHead=ShortBlock;
uint ArcFlags=(uint)Raw.GetV();
EndArcHead.NextVolume=(ArcFlags & EHFL_NEXTVOLUME)!=0;
EndArcHead.StoreVolNumber=false;
EndArcHead.DataCRC=false;
EndArcHead.RevSpace=false;
}
break;
case HEAD_MARK:
case HEAD3_MARK:
case HEAD3_MAIN:
break;
}
if (NextBlockPos<=CurBlockPos)
return unrar_err_corrupt;
*ReadSize=Raw.Size();
return unrar_ok;
}
unrar_err_t Archive::ProcessExtra50(RawRead *Raw,size_t ExtraSize,BaseBlock *bb)
{
// Read extra data from the end of block skipping any fields before it.
size_t ExtraStart=Raw->Size()-ExtraSize;
if (ExtraStart<Raw->GetPos())
return unrar_err_corrupt;
Raw->SetPos(ExtraStart);
while (Raw->DataLeft()>=2)
{
int64 FieldSize=Raw->GetV();
if (FieldSize==0 || Raw->DataLeft()==0 || FieldSize>(int64)Raw->DataLeft())
break;
size_t NextPos=size_t(Raw->GetPos()+FieldSize);
uint64 FieldType=Raw->GetV();
FieldSize=Raw->DataLeft(); // Field size without size and type fields.
if (bb->HeaderType==HEAD_MAIN)
{
MainHeader *hd=(MainHeader *)bb;
if (FieldType==MHEXTRA_LOCATOR)
{
hd->Locator=true;
uint Flags=(uint)Raw->GetV();
if ((Flags & MHEXTRA_LOCATOR_QLIST)!=0)
{
uint64 Offset=Raw->GetV();
if (Offset!=0) // 0 means that reserved space was not enough to write the offset.
hd->QOpenOffset=Offset+CurBlockPos;
}
if ((Flags & MHEXTRA_LOCATOR_RR)!=0)
{
uint64 Offset=Raw->GetV();
if (Offset!=0) // 0 means that reserved space was not enough to write the offset.
hd->RROffset=Offset+CurBlockPos;
}
}
}
if (bb->HeaderType==HEAD_FILE || bb->HeaderType==HEAD_SERVICE)
{
FileHeader *hd=(FileHeader *)bb;
switch(FieldType)
{
case FHEXTRA_CRYPT:
return unrar_err_encrypted;
case FHEXTRA_HASH:
{
FileHeader *hd=(FileHeader *)bb;
uint Type=(uint)Raw->GetV();
if (Type==FHEXTRA_HASH_BLAKE2)
{
hd->FileHash.Type=HASH_BLAKE2;
Raw->GetB(hd->FileHash.Digest,BLAKE2_DIGEST_SIZE);
}
}
break;
case FHEXTRA_HTIME:
if (FieldSize>=9)
{
byte Flags=(byte)Raw->GetV();
bool UnixTime=(Flags & FHEXTRA_HTIME_UNIXTIME)!=0;
if ((Flags & FHEXTRA_HTIME_MTIME)!=0)
{
if (UnixTime)
hd->mtime=(time_t)Raw->Get4();
else
hd->mtime.SetRaw(Raw->Get8());
}
if ((Flags & FHEXTRA_HTIME_CTIME)!=0)
{
if (UnixTime)
hd->ctime=(time_t)Raw->Get4();
else
hd->ctime.SetRaw(Raw->Get8());
}
if ((Flags & FHEXTRA_HTIME_ATIME)!=0)
{
if (UnixTime)
hd->atime=(time_t)Raw->Get4();
else
hd->atime.SetRaw(Raw->Get8());
}
}
break;
case FHEXTRA_REDIR:
{
hd->RedirType=(FILE_SYSTEM_REDIRECT)Raw->GetV();
uint Flags=(uint)Raw->GetV();
hd->DirTarget=(Flags & FHEXTRA_REDIR_DIR)!=0;
size_t NameSize=(size_t)Raw->GetV();
char UtfName[NM*4];
*UtfName=0;
if (NameSize<ASIZE(UtfName)-1)
{
Raw->GetB(UtfName,NameSize);
UtfName[NameSize]=0;
}
#ifdef _WIN_ALL
UnixSlashToDos(UtfName,UtfName,ASIZE(UtfName));
#endif
UtfToWide(UtfName,hd->RedirName,ASIZE(hd->RedirName));
}
break;
case FHEXTRA_UOWNER:
{
uint Flags=(uint)Raw->GetV();
hd->UnixOwnerNumeric=(Flags & FHEXTRA_UOWNER_NUMUID)!=0;
hd->UnixGroupNumeric=(Flags & FHEXTRA_UOWNER_NUMGID)!=0;
*hd->UnixOwnerName=*hd->UnixGroupName=0;
if ((Flags & FHEXTRA_UOWNER_UNAME)!=0)
{
size_t Length=(size_t)Raw->GetV();
Length=Min(Length,ASIZE(hd->UnixOwnerName)-1);
Raw->GetB(hd->UnixOwnerName,Length);
hd->UnixOwnerName[Length]=0;
}
if ((Flags & FHEXTRA_UOWNER_GNAME)!=0)
{
size_t Length=(size_t)Raw->GetV();
Length=Min(Length,ASIZE(hd->UnixGroupName)-1);
Raw->GetB(hd->UnixGroupName,Length);
hd->UnixGroupName[Length]=0;
}
#ifdef _UNIX
if (hd->UnixOwnerNumeric)
hd->UnixOwnerID=(uid_t)Raw->GetV();
if (hd->UnixGroupNumeric)
hd->UnixGroupID=(uid_t)Raw->GetV();
#else
// Need these fields in Windows too for 'list' command,
// but uid_t and gid_t are not defined.
if (hd->UnixOwnerNumeric)
hd->UnixOwnerID=(uint)Raw->GetV();
if (hd->UnixGroupNumeric)
hd->UnixGroupID=(uint)Raw->GetV();
#endif
hd->UnixOwnerSet=true;
}
break;
case FHEXTRA_SUBDATA:
{
hd->SubData.Alloc((size_t)FieldSize);
Raw->GetB(hd->SubData.Addr(0),(size_t)FieldSize);
}
break;
}
}
Raw->SetPos(NextPos);
}
return unrar_ok;
}
#ifndef SFX_MODULE
unrar_err_t Archive::ReadHeader14(size_t *ReadSize)
{
Raw.Reset();
if (CurBlockPos<=(int64)SFXSize)
{
Raw.Read(SIZEOF_MAINHEAD14);
MainHead.Reset();
byte Mark[4];
Raw.GetB(Mark,4);
uint HeadSize=Raw.Get2();
byte Flags=Raw.Get1();
NextBlockPos=CurBlockPos+HeadSize;
CurHeaderType=HEAD_MAIN;
Solid=(Flags & MHD_SOLID)!=0;
MainHead.CommentInHeader=(Flags & MHD_COMMENT)!=0;
MainHead.PackComment=(Flags & MHD_PACK_COMMENT)!=0;
}
else
{
Raw.Read(SIZEOF_FILEHEAD14);
FileHead.Reset();
FileHead.HeaderType=HEAD_FILE;
FileHead.DataSize=Raw.Get4();
FileHead.UnpSize=Raw.Get4();
FileHead.FileHash.Type=HASH_RAR14;
FileHead.FileHash.CRC32=Raw.Get2();
FileHead.HeadSize=Raw.Get2();
uint FileTime=Raw.Get4();
FileHead.FileAttr=Raw.Get1();
FileHead.Flags=Raw.Get1()|LONG_BLOCK;
FileHead.UnpVer=(Raw.Get1()==2) ? 13 : 10;
size_t NameSize=Raw.Get1();
FileHead.Method=Raw.Get1();
FileHead.SplitBefore=(FileHead.Flags & LHD_SPLIT_BEFORE)!=0;
FileHead.SplitAfter=(FileHead.Flags & LHD_SPLIT_AFTER)!=0;
FileHead.Encrypted=(FileHead.Flags & LHD_PASSWORD)!=0;
if (FileHead.Encrypted)
return unrar_err_encrypted;
FileHead.PackSize=FileHead.DataSize;
FileHead.WinSize=0x10000;
FileHead.mtime.SetDos(FileTime);
Raw.Read(NameSize);
char FileName[NM];
Raw.GetB((byte *)FileName,Min(NameSize,ASIZE(FileName)));
FileName[NameSize]=0;
IntToExt(FileName,FileName,ASIZE(FileName));
CharToWide(FileName,FileHead.FileName,ASIZE(FileHead.FileName));
if (Raw.Size()!=0)
NextBlockPos=CurBlockPos+FileHead.HeadSize+FileHead.PackSize;
CurHeaderType=HEAD_FILE;
}
*ReadSize=(NextBlockPos>CurBlockPos ? Raw.Size():0);
return unrar_ok;
}
#endif
// (removed name case and attribute conversion)
bool Archive::IsArcDir()
{
return FileHead.Dir;
}
bool Archive::IsArcLabel()
{
return(FileHead.HostOS<=HOST_WIN32 && (FileHead.FileAttr & 8));
}
void Archive::ConvertFileHeader(FileHeader *hd)
{
if (Format==RARFMT15 && hd->UnpVer<20 && (hd->FileAttr & 0x10))
hd->Dir=true;
if (hd->HSType==HSYS_UNKNOWN)
if (hd->Dir)
hd->FileAttr=0x10;
else
hd->FileAttr=0x20;
}
int64 Archive::GetStartPos()
{
int64 StartPos=SFXSize+MarkHead.HeadSize;
StartPos+=MainHead.HeadSize;
return StartPos;
}

View File

@@ -0,0 +1,171 @@
#ifndef _RAR_ARRAY_
#define _RAR_ARRAY_
#include <new>
template <class T> class Array
{
private:
T *Buffer;
size_t BufSize;
size_t AllocSize;
size_t MaxSize;
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();
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;}
};
template <class T> void Array<T>::CleanData()
{
Buffer=NULL;
BufSize=0;
AllocSize=0;
MaxSize=0;
}
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)
rarfree(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)
{
size_t NewBufSize=BufSize+Items;
if (NewBufSize>AllocSize)
{
if (MaxSize!=0 && NewBufSize>MaxSize)
throw std::bad_alloc();
size_t Suggested=AllocSize+AllocSize/4+32;
size_t NewSize=Max(NewBufSize,Suggested);
T *NewBuffer=(T *)rarrealloc(Buffer,NewSize*sizeof(T));
if (NewBuffer==NULL)
throw std::bad_alloc();
Buffer=NewBuffer;
AllocSize=NewSize;
}
BufSize=NewBufSize;
}
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()
{
// Keep memory allocated if it's small
// Eliminates constant reallocation when scanning archive
if ( AllocSize < 1024/sizeof(T) )
{
BufSize = 0;
return;
}
if (Buffer!=NULL)
{
rarfree(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

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,141 @@
unrar_core source code changes
------------------------------
Unrar_core is based on UnRAR (unrarsrc-3.8.5.tar.gz) by Alexander L.
Roshal. The original sources have been HEAVILY modified, trimmed down,
and purged of all OS-specific calls for file access and other
unnecessary operations. Support for encryption, recovery records, and
segmentation has been REMOVED. See license.txt for licensing. In
particular, this code cannot be used to re-create the RAR compression
algorithm, which is proprietary.
If you obtained this code as a part of my File_Extractor library and
want to use it on its own, get my unrar_core library, which includes
examples and documentation.
The source is as close as possible to the original, to make it simple to
update when a new version of UnRAR comes out. In many places the
original names and object nesting are kept, even though it's a bit
harder to follow. See rar.hpp for the main "glue".
Website: http://www.slack.net/~ant/
E-mail : Shay Green <gblargg@gmail.com>
Contents
--------
* Diff-friendly changes
* Removal of features
* Error reporting changes
* Minor tweaks
* Unrar findings
Diff-friendly changes
---------------------
To make my source code changes more easily visible with a line-based
file diff, I've tried to make changes by inserting or deleting lines,
rather than modifying them. So if the original declared a static array
static int array [4] = { 1, 2, 3, 4 };
and I want to make it const, I add the const on a line before
const // added
static int array [4] = { 1, 2, 3, 4 };
rather than on the same line
static const int array [4] = { 1, 2, 3, 4 };
This way a diff will simply show an added line, making it clear what was
added. If I simply inserted const on the same line, it wouldn't be as
clear what all I had changed.
I've also made use of several macros rather than changing the source
text. For example, since a class name like Unpack might easily conflict,
I've renamed it to Rar_Unpack by using #define Unpack Rar_Unpack rather
than changing the source text. These macros are only defined when
compiling the library sources; the user-visible unrar.h is very clean.
Removal of features
-------------------
This library is meant for simple access to common archives without
having to extract them first. Encryption, segmentation, huge files, and
self-extracting archives aren't common for things that need to be
accessed in this manner, so I've removed support for them. Also,
encryption adds complexity to the code that must be maintained.
Segmentation would require a way to specify the other segments.
Error reporting changes
-----------------------
The original used C++ exceptions to report errors. I've eliminated use
of these through a combination of error codes and longjmp. This allows
use of the library from C or some other language which doesn't easily
support exceptions.
I tried to make as few changes as possible in the conversion. Due to the
number of places file reads occur, propagating an error code via return
statements would have required too many code changes. Instead, I perform
the read, save the error code, and return 0 bytes read in case of an
error. I also ensure that the calling code interprets this zero in an
acceptable way. I then check this saved error code after the operation
completes, and have it take priority over the error the RAR code
returned. I do a similar thing for write errors.
Minor tweaks
------------
- Eliminated as many GCC warnings as reasonably possible.
- Non-class array allocations now use malloc(), allowing the code to be
linked without the standard C++ library (particularly, operator new).
Class object allocations use a class-specific allocator that just calls
malloc(), also avoiding calls to operator new.
- Made all unchanging static data const. Several pieces of static data
in the original code weren't marked const where they could be.
- Initialization of some static tables was done on an as-needed basis,
creating a problem when extracting from archives in multiple threads.
This initialization can now be done by the user before any archives are
opened.
- Tweaked CopyString, the major bottleneck during compression. I inlined
it, cached some variables in locals in case the compiler couldn't easily
see that the memory accesses don't modify them, and made them use
memcpy() where possible. This improved performance by at least 20% on
x86. Perhaps it won't work as well on files with lots of smaller string
matches.
- Some .cpp files are #included by others. I've added guards to these so
that you can simply compile all .cpp files and not get any redefinition
errors.
- The current solid extraction position is kept track of, allowing the
user to randomly extract files without regard to proper extraction
order. The library optimizes solid extraction and only restarts it if
the user is extracting a file earlier in the archive than the last
solid-extracted one.
- Most of the time a solid file's data is already contiguously in the
internal Unpack::Window, which unrar_extract_mem() takes advantage of.
This avoids extra allocation in many cases.
- Allocation of Unpack is delayed until the first extraction, rather
than being allocated immediately on opening the archive. This allows
scanning with minimal memory usage.
Unrar findings
--------------
- Apparently the LHD_SOLID flag indicates that file depends on previous
files, rather than that later files depend on the current file's
contents. Thus this flag can't be used to intelligently decide which
files need to be internally extracted when skipping them, making it
necessary to internally extract every file before the one to be
extracted, if the archive is solid.
--
Shay Green <gblargg@gmail.com>

View File

@@ -0,0 +1,50 @@
// #included by unpack.cpp
#ifdef RAR_COMMON_HPP
inline unsigned int RangeCoder::GetChar()
{
return(UnpackRead->GetChar());
}
void RangeCoder::InitDecoder(Unpack *UnpackRead)
{
RangeCoder::UnpackRead=UnpackRead;
low=code=0;
range=uint(-1);
for (int i=0;i < 4;i++)
code=(code << 8) | GetChar();
}
// (int) cast before "low" added only to suppress compiler warnings.
#define ARI_DEC_NORMALIZE(code,low,range,read) \
{ \
while ((low^(low+range))<TOP || range<BOT && ((range=-(int)low&(BOT-1)),1)) \
{ \
code=(code << 8) | read->GetChar(); \
range <<= 8; \
low <<= 8; \
} \
}
inline int RangeCoder::GetCurrentCount()
{
return (code-low)/(range /= SubRange.scale);
}
inline uint RangeCoder::GetCurrentShiftCount(uint SHIFT)
{
return (code-low)/(range >>= SHIFT);
}
inline void RangeCoder::Decode()
{
low += range*SubRange.LowCount;
range *= SubRange.HighCount-SubRange.LowCount;
}
#endif

View File

@@ -0,0 +1,23 @@
/****************************************************************************
* Contents: 'Carryless rangecoder' by Dmitry Subbotin *
****************************************************************************/
class RangeCoder
{
public:
void InitDecoder(Unpack *UnpackRead);
inline int GetCurrentCount();
inline uint GetCurrentShiftCount(uint SHIFT);
inline void Decode();
inline void PutChar(unsigned int c);
inline unsigned int GetChar();
uint low, code, range;
struct SUBRANGE
{
uint LowCount, HighCount, scale;
} SubRange;
Unpack *UnpackRead;
};

View File

@@ -0,0 +1,50 @@
#ifndef _RAR_COMPRESS_
#define _RAR_COMPRESS_
// Combine pack and unpack constants to class to avoid polluting global
// namespace with numerous short names.
class PackDef
{
public:
static const uint MAX_LZ_MATCH = 0x1001;
static const uint MAX3_LZ_MATCH = 0x101; // Maximum match length for RAR v3.
static const uint LOW_DIST_REP_COUNT = 16;
static const uint NC = 306; /* alphabet = {0, 1, 2, ..., NC - 1} */
static const uint DC = 64;
static const uint LDC = 16;
static const uint RC = 44;
static const uint HUFF_TABLE_SIZE = NC + DC + RC + LDC;
static const uint BC = 20;
static const uint NC30 = 299; /* alphabet = {0, 1, 2, ..., NC - 1} */
static const uint DC30 = 60;
static const uint LDC30 = 17;
static const uint RC30 = 28;
static const uint BC30 = 20;
static const uint HUFF_TABLE_SIZE30 = NC30 + DC30 + RC30 + LDC30;
static const uint NC20 = 298; /* alphabet = {0, 1, 2, ..., NC - 1} */
static const uint DC20 = 48;
static const uint RC20 = 28;
static const uint BC20 = 19;
static const uint MC20 = 257;
// 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
};
};
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
};
#endif

View File

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

View File

@@ -0,0 +1,57 @@
#include "rar.hpp"
EncodeFileName::EncodeFileName()
{
Flags=0;
FlagBits=0;
FlagsPos=0;
DestSize=0;
}
void EncodeFileName::Decode(char *Name,byte *EncName,size_t EncSize,wchar *NameW,
size_t MaxDecSize)
{
size_t EncPos=0,DecPos=0;
byte HighByte=EncName[EncPos++];
while (EncPos<EncSize && DecPos<MaxDecSize)
{
if (FlagBits==0)
{
Flags=EncName[EncPos++];
FlagBits=8;
}
switch(Flags>>6)
{
case 0:
NameW[DecPos++]=EncName[EncPos++];
break;
case 1:
NameW[DecPos++]=EncName[EncPos++]+(HighByte<<8);
break;
case 2:
NameW[DecPos++]=EncName[EncPos]+(EncName[EncPos+1]<<8);
EncPos+=2;
break;
case 3:
{
int Length=EncName[EncPos++];
if (Length & 0x80)
{
byte Correction=EncName[EncPos++];
for (Length=(Length&0x7f)+2;Length>0 && DecPos<MaxDecSize;Length--,DecPos++)
NameW[DecPos]=((Name[DecPos]+Correction)&0xff)+(HighByte<<8);
}
else
for (Length+=2;Length>0 && DecPos<MaxDecSize;Length--,DecPos++)
NameW[DecPos]=Name[DecPos];
}
break;
}
Flags<<=2;
FlagBits-=2;
}
NameW[DecPos<MaxDecSize ? DecPos:MaxDecSize-1]=0;
}

View File

@@ -0,0 +1,20 @@
#ifndef _RAR_ENCNAME_
#define _RAR_ENCNAME_
class EncodeFileName
{
private:
void AddFlags(int Value);
byte *EncName;
byte Flags;
size_t FlagBits;
size_t FlagsPos;
size_t DestSize;
public:
EncodeFileName();
size_t Encode(char *Name,wchar *NameW,byte *EncName);
void Decode(char *Name,byte *EncName,size_t EncSize,wchar *NameW,size_t MaxDecSize);
};
#endif

View File

@@ -0,0 +1,114 @@
#include <stdio.h>
#include "rar.hpp"
#include "unrar.h"
#define DataIO Arc
unrar_err_t CmdExtract::ExtractCurrentFile( bool SkipSolid, bool check_compatibility_only )
{
check( Arc.GetHeaderType() == FILE_HEAD );
if ( Arc.FileHead.SplitBefore || Arc.FileHead.SplitAfter )
return unrar_err_segmented;
if ( Arc.FileHead.Encrypted )
return unrar_err_encrypted;
if ( !check_compatibility_only )
{
check( Arc.NextBlockPos-Arc.FileHead.PackSize == Arc.Tell() );
Arc.Seek(Arc.NextBlockPos-Arc.FileHead.PackSize,SEEK_SET);
}
// (removed lots of command-line handling)
#ifdef SFX_MODULE
if ((Arc.FileHead.UnpVer!=UNP_VER && Arc.FileHead.UnpVer!=29) &&
Arc.FileHead.Method!=0x30)
#else
if (Arc.FileHead.UnpVer!=VER_UNPACK5 &&
(Arc.FileHead.UnpVer<13 || Arc.FileHead.UnpVer>VER_UNPACK))
#endif
{
if (Arc.FileHead.UnpVer>VER_UNPACK)
return unrar_err_new_algo;
return unrar_err_old_algo;
}
if ( check_compatibility_only )
return unrar_ok;
// (removed lots of command-line/encryption/volume handling)
update_first_file_pos();
FileCount++;
DataIO.UnpFileCRC=Arc.OldFormat ? 0 : 0xffffffff;
// (removed decryption)
DataIO.UnpHash.Init(Arc.FileHead.FileHash.Type,1);
DataIO.PackedDataHash.Init(Arc.FileHead.FileHash.Type,1);
DataIO.SetPackedSizeToRead(Arc.FileHead.PackSize);
DataIO.SetSkipUnpCRC(SkipSolid);
// (removed command-line handling)
DataIO.SetSkipUnpCRC(SkipSolid);
if (Arc.FileHead.Method==0)
UnstoreFile(Arc.FileHead.UnpSize);
else
{
// Defer creation of Unpack until first extraction
if ( !Unp )
{
Unp = new Unpack( &Arc );
if ( !Unp )
return unrar_err_memory;
}
Unp->Init(Arc.FileHead.WinSize,Arc.FileHead.Solid);
Unp->SetDestSize(Arc.FileHead.UnpSize);
#ifndef SFX_MODULE
if (Arc.Format!=RARFMT50 && Arc.FileHead.UnpVer<=15)
Unp->DoUnpack(15,FileCount>1 && Arc.Solid);
else
#endif
Unp->DoUnpack(Arc.FileHead.UnpVer,Arc.FileHead.Solid);
}
// (no need to seek to next file)
if (!SkipSolid)
{
HashValue UnpHash;
DataIO.UnpHash.Result(&UnpHash);
if (UnpHash==Arc.FileHead.FileHash)
{
// CRC is correct
}
else
{
return unrar_err_corrupt;
}
}
// (removed broken file handling)
// (removed command-line handling)
return unrar_ok;
}
void CmdExtract::UnstoreFile(int64 DestUnpSize)
{
Buffer.Alloc((int)Min(DestUnpSize,0x10000));
while (1)
{
unsigned int Code=DataIO.UnpRead(&Buffer[0],(uint)Buffer.Size());
if (Code==0 || (int)Code==-1)
break;
Code=Code<DestUnpSize ? Code:int64to32(DestUnpSize);
DataIO.UnpWrite(&Buffer[0],Code);
if (DestUnpSize>=0)
DestUnpSize-=Code;
}
Buffer.Reset();
}

View File

@@ -0,0 +1,56 @@
#include "rar.hpp"
BitInput::BitInput(bool AllocBuffer)
{
ExternalBuffer=false;
if (AllocBuffer)
{
// getbits32 attempts to read data from InAddr, ... InAddr+3 positions.
// So let's allocate 3 additional bytes for situation, when we need to
// read only 1 byte from the last position of buffer and avoid a crash
// from access to next 3 bytes, which contents we do not need.
size_t BufSize=MAX_SIZE+3;
InBuf=new byte[BufSize];
// Ensure that we get predictable results when accessing bytes in area
// not filled with read data.
memset(InBuf,0,BufSize);
}
else
InBuf=NULL;
}
BitInput::~BitInput()
{
if (!ExternalBuffer)
delete[] InBuf;
}
void BitInput::handle_mem_error( Rar_Error_Handler& ErrHandler )
{
if ( !InBuf )
ErrHandler.MemoryError();
}
void BitInput::faddbits(uint Bits)
{
// Function wrapped version of inline addbits to save code size.
addbits(Bits);
}
uint BitInput::fgetbits()
{
// Function wrapped version of inline getbits to save code size.
return(getbits());
}
void BitInput::SetExternalBuffer(byte *Buf)
{
if (InBuf!=NULL && !ExternalBuffer)
delete[] InBuf;
InBuf=Buf;
ExternalBuffer=true;
}

View File

@@ -0,0 +1,70 @@
#ifndef _RAR_GETBITS_
#define _RAR_GETBITS_
class BitInput
: public Rar_Allocator
{
public:
enum BufferSize {MAX_SIZE=0x8000}; // Size of input buffer.
int InAddr; // Curent byte position in the buffer.
int InBit; // Current bit position in the current byte.
bool ExternalBuffer;
public:
BitInput(bool AllocBuffer);
~BitInput();
void handle_mem_error( Rar_Error_Handler& );
byte *InBuf; // Dynamically allocated input buffer.
void InitBitInput()
{
InAddr=InBit=0;
}
// Move forward by 'Bits' bits.
void addbits(uint Bits)
{
Bits+=InBit;
InAddr+=Bits>>3;
InBit=Bits&7;
}
// Return 16 bits from current position in the buffer.
// Bit at (InAddr,InBit) has the highest position in returning data.
uint getbits()
{
uint BitField=(uint)InBuf[InAddr] << 16;
BitField|=(uint)InBuf[InAddr+1] << 8;
BitField|=(uint)InBuf[InAddr+2];
BitField >>= (8-InBit);
return(BitField & 0xffff);
}
// Return 32 bits from current position in the buffer.
// Bit at (InAddr,InBit) has the highest position in returning data.
uint getbits32()
{
uint BitField=(uint)InBuf[InAddr] << 24;
BitField|=(uint)InBuf[InAddr+1] << 16;
BitField|=(uint)InBuf[InAddr+2] << 8;
BitField|=(uint)InBuf[InAddr+3];
BitField <<= InBit;
BitField|=(uint)InBuf[InAddr+4] >> (8-InBit);
return(BitField & 0xffffffff);
}
void faddbits(uint Bits);
uint fgetbits();
// Check if buffer has enough space for IncPtr bytes. Returns 'true'
// if buffer will be overflown.
bool Overflow(uint IncPtr)
{
return(InAddr+IncPtr>=MAX_SIZE);
}
void SetExternalBuffer(byte *Buf);
};
#endif

118
src/core/fex/unrar/hash.cpp Normal file
View File

@@ -0,0 +1,118 @@
#include "rar.hpp"
void HashValue::Init(HASH_TYPE Type)
{
HashValue::Type=Type;
// Zero length data CRC32 is 0. It is important to set it when creating
// headers with no following data like directories or symlinks.
if (Type==HASH_RAR14 || Type==HASH_CRC32)
CRC32=0;
if (Type==HASH_BLAKE2)
{
// dd0e891776933f43c7d032b08a917e25741f8aa9a12c12e1cac8801500f2ca4f
// is BLAKE2sp hash of empty data. We init the structure to this value,
// so if we create a file or service header with no following data like
// "file copy" or "symlink", we set the checksum to proper value avoiding
// additional header type or size checks when extracting.
static byte EmptyHash[32]={
0xdd, 0x0e, 0x89, 0x17, 0x76, 0x93, 0x3f, 0x43,
0xc7, 0xd0, 0x32, 0xb0, 0x8a, 0x91, 0x7e, 0x25,
0x74, 0x1f, 0x8a, 0xa9, 0xa1, 0x2c, 0x12, 0xe1,
0xca, 0xc8, 0x80, 0x15, 0x00, 0xf2, 0xca, 0x4f
};
memcpy(Digest,EmptyHash,sizeof(Digest));
}
}
bool HashValue::operator == (const HashValue &cmp)
{
if (Type==HASH_NONE || cmp.Type==HASH_NONE)
return true;
if ((Type==HASH_RAR14 && cmp.Type==HASH_RAR14) ||
(Type==HASH_CRC32 && cmp.Type==HASH_CRC32))
return CRC32==cmp.CRC32;
if (Type==HASH_BLAKE2 && cmp.Type==HASH_BLAKE2)
return memcmp(Digest,cmp.Digest,sizeof(Digest))==0;
return false;
}
DataHash::DataHash()
{
HashType=HASH_NONE;
#ifdef RAR_SMP
ThPool=NULL;
MaxThreads=0;
#endif
}
DataHash::~DataHash()
{
#ifdef RAR_SMP
DestroyThreadPool(ThPool);
#endif
cleandata(&blake2ctx, sizeof(blake2ctx));
cleandata(&CurCRC32, sizeof(CurCRC32));
}
void DataHash::Init(HASH_TYPE Type,uint MaxThreads)
{
HashType=Type;
if (Type==HASH_RAR14)
CurCRC32=0;
if (Type==HASH_CRC32)
CurCRC32=0xffffffff; // Initial CRC32 value.
if (Type==HASH_BLAKE2)
blake2sp_init( &blake2ctx );
#ifdef RAR_SMP
DataHash::MaxThreads=Min(MaxThreads,MaxHashThreads);
#endif
}
void DataHash::Update(const void *Data,size_t DataSize)
{
#ifndef SFX_MODULE
if (HashType==HASH_RAR14)
CurCRC32=Checksum14((ushort)CurCRC32,Data,DataSize);
#endif
if (HashType==HASH_CRC32)
CurCRC32=CRC32(CurCRC32,Data,DataSize);
if (HashType==HASH_BLAKE2)
{
#ifdef RAR_SMP
if (MaxThreads>1 && ThPool==NULL)
ThPool=CreateThreadPool();
blake2ctx.ThPool=ThPool;
blake2ctx.MaxThreads=MaxThreads;
#endif
blake2sp_update( &blake2ctx, (byte *)Data, DataSize);
}
}
void DataHash::Result(HashValue *Result)
{
Result->Type=HashType;
if (HashType==HASH_RAR14)
Result->CRC32=CurCRC32;
if (HashType==HASH_CRC32)
Result->CRC32=CurCRC32^0xffffffff;
if (HashType==HASH_BLAKE2)
{
// Preserve the original context, so we can continue hashing if necessary.
blake2sp_state res=blake2ctx;
blake2sp_final( &res, Result->Digest );
}
}
uint DataHash::GetCRC32()
{
return HashType==HASH_CRC32 ? CurCRC32^0xffffffff : 0;
}

View File

@@ -0,0 +1,52 @@
#ifndef _RAR_DATAHASH_
#define _RAR_DATAHASH_
enum HASH_TYPE {HASH_NONE,HASH_RAR14,HASH_CRC32,HASH_BLAKE2};
struct HashValue
{
void Init(HASH_TYPE Type);
bool operator == (const HashValue &cmp);
bool operator != (const HashValue &cmp) {return !(*this==cmp);}
HASH_TYPE Type;
union
{
uint CRC32;
byte Digest[SHA256_DIGEST_SIZE];
};
};
#ifdef RAR_SMP
class ThreadPool;
class DataHash;
#endif
class DataHash
{
private:
HASH_TYPE HashType;
uint CurCRC32;
blake2sp_state blake2ctx;
#ifdef RAR_SMP
ThreadPool *ThPool;
uint MaxThreads;
// Upper limit for maximum threads to prevent wasting threads in pool.
static const uint MaxHashThreads=8;
#endif
public:
DataHash();
~DataHash();
void Init(HASH_TYPE Type,uint MaxThreads);
void Update(const void *Data,size_t DataSize);
void Result(HashValue *Result);
uint GetCRC32();
bool Cmp(HashValue *CmpValue,byte *Key);
HASH_TYPE Type() {return HashType;}
};
#endif

View File

@@ -0,0 +1,60 @@
#include "rar.hpp"
void FileHeader::Reset(size_t SubDataSize)
{
SubData.Alloc(SubDataSize);
BaseBlock::Reset();
#ifndef SHELL_EXT
FileHash.Init(HASH_NONE);
#endif
mtime.Reset();
atime.Reset();
ctime.Reset();
SplitBefore=false;
SplitAfter=false;
UnknownUnpSize=0;
SubFlags=0; // Important for RAR 3.0 subhead.
Encrypted=false;
UsePswCheck=false;
UseHashKey=false;
Lg2Count=0;
Solid=false;
Dir=false;
WinSize=0;
Inherited=false;
SubBlock=false;
CommentInHeader=false;
Version=false;
LargeFile=false;
RedirType=FSREDIR_NONE;
UnixOwnerSet=false;
}
FileHeader& FileHeader::operator = (FileHeader &hd)
{
SubData.Reset();
memcpy(this,&hd,sizeof(*this));
SubData.CleanData();
SubData=hd.SubData;
return *this;
}
void MainHeader::Reset()
{
HighPosAV=0;
PosAV=0;
CommentInHeader=false;
PackComment=false;
Locator=false;
QOpenOffset=0;
QOpenMaxSize=0;
RROffset=0;
RRMaxSize=0;
}

View File

@@ -0,0 +1,362 @@
#ifndef _RAR_HEADERS_
#define _RAR_HEADERS_
#define SIZEOF_MARKHEAD3 7 // Size of RAR 4.x archive mark header.
#define SIZEOF_MAINHEAD14 7 // Size of RAR 1.4 main archive header.
#define SIZEOF_MAINHEAD3 13 // Size of RAR 4.x main archive header.
#define SIZEOF_FILEHEAD14 21 // Size of RAR 1.4 file header.
#define SIZEOF_FILEHEAD3 32 // Size of RAR 3.0 file header.
#define SIZEOF_SHORTBLOCKHEAD 7
#define SIZEOF_LONGBLOCKHEAD 11
#define SIZEOF_SUBBLOCKHEAD 14
#define SIZEOF_COMMHEAD 13
#define SIZEOF_PROTECTHEAD 26
#define SIZEOF_AVHEAD 14
#define SIZEOF_SIGNHEAD 15
#define SIZEOF_UOHEAD 18
#define SIZEOF_MACHEAD 22
#define SIZEOF_EAHEAD 24
#define SIZEOF_BEEAHEAD 24
#define SIZEOF_STREAMHEAD 26
#define VER_PACK 29
#define VER_PACK5 0
#define VER_UNPACK 29
#define VER_UNPACK5 0
#define MHD_VOLUME 0x0001U
// Old style main archive comment embed into main archive header. Must not
// be used in new archives anymore.
#define MHD_COMMENT 0x0002U
#define MHD_LOCK 0x0004U
#define MHD_SOLID 0x0008U
#define MHD_PACK_COMMENT 0x0010U
#define MHD_NEWNUMBERING 0x0010U
#define MHD_AV 0x0020U
#define MHD_PROTECT 0x0040U
#define MHD_PASSWORD 0x0080U
#define MHD_FIRSTVOLUME 0x0100U
#define LHD_SPLIT_BEFORE 0x0001U
#define LHD_SPLIT_AFTER 0x0002U
#define LHD_PASSWORD 0x0004U
// Old style file comment embed into file header. Must not be used
// in new archives anymore.
#define LHD_COMMENT 0x0008U
// For non-file subheaders it denotes 'subblock having a parent file' flag.
#define LHD_SOLID 0x0010U
#define LHD_WINDOWMASK 0x00e0U
#define LHD_WINDOW64 0x0000U
#define LHD_WINDOW128 0x0020U
#define LHD_WINDOW256 0x0040U
#define LHD_WINDOW512 0x0060U
#define LHD_WINDOW1024 0x0080U
#define LHD_WINDOW2048 0x00a0U
#define LHD_WINDOW4096 0x00c0U
#define LHD_DIRECTORY 0x00e0U
#define LHD_LARGE 0x0100U
#define LHD_UNICODE 0x0200U
#define LHD_SALT 0x0400U
#define LHD_VERSION 0x0800U
#define LHD_EXTTIME 0x1000U
#define SKIP_IF_UNKNOWN 0x4000U
#define LONG_BLOCK 0x8000U
#define EARC_NEXT_VOLUME 0x0001U // Not last volume.
#define EARC_DATACRC 0x0002U // Store CRC32 of RAR archive (now is used only in volumes).
#define EARC_REVSPACE 0x0004U // Reserve space for end of REV file 7 byte record.
#define EARC_VOLNUMBER 0x0008U // Store a number of current volume.
enum HEADER_TYPE {
// RAR 5.0 header types.
HEAD_MARK=0x00, HEAD_MAIN=0x01, HEAD_FILE=0x02, HEAD_SERVICE=0x03,
HEAD_CRYPT=0x04, HEAD_ENDARC=0x05, HEAD_UNKNOWN=0xff,
// RAR 1.5 - 4.x header types.
HEAD3_MARK=0x72,HEAD3_MAIN=0x73,HEAD3_FILE=0x74,HEAD3_CMT=0x75,
HEAD3_AV=0x76,HEAD3_OLDSERVICE=0x77,HEAD3_PROTECT=0x78,HEAD3_SIGN=0x79,
HEAD3_SERVICE=0x7a,HEAD3_ENDARC=0x7b
};
enum { EA_HEAD=0x100,UO_HEAD=0x101,MAC_HEAD=0x102,BEEA_HEAD=0x103,
NTACL_HEAD=0x104,STREAM_HEAD=0x105 };
// Internal implementation, depends on archive format version.
enum HOST_SYSTEM {
// RAR 5.0 host OS
HOST5_WINDOWS=0,HOST5_UNIX=1,
// RAR 3.0 host OS.
HOST_MSDOS=0,HOST_OS2=1,HOST_WIN32=2,HOST_UNIX=3,HOST_MACOS=4,
HOST_BEOS=5,HOST_MAX
};
// Unified archive format independent implementation.
enum HOST_SYSTEM_TYPE {
HSYS_WINDOWS, HSYS_UNIX, HSYS_UNKNOWN
};
// We also use these values in extra field, so do not modify them.
enum FILE_SYSTEM_REDIRECT {
FSREDIR_NONE=0, FSREDIR_UNIXSYMLINK, FSREDIR_WINSYMLINK, FSREDIR_JUNCTION,
FSREDIR_HARDLINK, FSREDIR_FILECOPY
};
static const wchar SUBHEAD_TYPE_CMT[] = {'C', 'M', 'T', 0};
static const wchar SUBHEAD_TYPE_QOPEN[] = {'Q', 'O', 0};
static const wchar SUBHEAD_TYPE_ACL[] = {'A', 'C', 'L', 0};
static const wchar SUBHEAD_TYPE_STREAM[] = {'S', 'T', 'M', 0};
static const wchar SUBHEAD_TYPE_UOWNER[] = {'U', 'O', 'W', 0};
static const wchar SUBHEAD_TYPE_AV[] = {'A', 'V', 0};
static const wchar SUBHEAD_TYPE_RR[] = {'R', 'R', 0};
static const wchar SUBHEAD_TYPE_OS2EA[] = {'E', 'A', '2', 0};
/* new file inherits a subblock when updating a host file */
#define SUBHEAD_FLAGS_INHERITED 0x80000000
#define SUBHEAD_FLAGS_CMT_UNICODE 0x00000001
struct MarkHeader
{
byte Mark[8];
// Following fields are virtual and not present in real blocks.
uint HeadSize;
};
struct BaseBlock
{
uint HeadCRC; // 'ushort' for RAR 1.5.
HEADER_TYPE HeaderType; // 1 byte for RAR 1.5.
uint Flags; // 'ushort' for RAR 1.5.
uint HeadSize; // 'ushort' for RAR 1.5, up to 2 MB for RAR 5.0.
bool SkipIfUnknown;
void Reset()
{
SkipIfUnknown=false;
}
};
struct BlockHeader:BaseBlock
{
uint DataSize;
};
struct MainHeader:BaseBlock
{
ushort HighPosAV;
uint PosAV;
bool CommentInHeader;
bool PackComment; // For RAR 1.4 archive format only.
bool Locator;
uint64 QOpenOffset; // Offset of quick list record.
uint64 QOpenMaxSize; // Maximum size of QOpen offset in locator extra field.
uint64 RROffset; // Offset of recovery record.
uint64 RRMaxSize; // Maximum size of RR offset in locator extra field.
void Reset();
};
struct FileHeader:BlockHeader
{
byte HostOS;
byte UnpVer;
byte Method;
union {
uint FileAttr;
uint SubFlags;
};
wchar FileName[NM];
Array<byte> SubData;
RarTime mtime;
RarTime ctime;
RarTime atime;
int64 PackSize;
int64 UnpSize;
int64 MaxSize; // Reserve size bytes for vint of this size.
HashValue FileHash;
uint FileFlags;
bool SplitBefore;
bool SplitAfter;
bool UnknownUnpSize;
bool Encrypted;
bool UsePswCheck;
// Use HMAC calculated from HashKey and checksum instead of plain checksum.
bool UseHashKey;
uint Lg2Count; // Log2 of PBKDF2 repetition count.
bool Solid;
bool Dir;
bool CommentInHeader; // RAR 2.0 file comment.
bool Version; // name.ext;ver file name containing the version number.
size_t WinSize;
bool Inherited; // New file inherits a subblock when updating a host file (for subblocks only).
// 'true' if file sizes use 8 bytes instead of 4. Not used in RAR 5.0.
bool LargeFile;
// 'true' for HEAD_SERVICE block, which is a child of preceding file block.
// RAR 4.x uses 'solid' flag to indicate child subheader blocks in archives.
bool SubBlock;
HOST_SYSTEM_TYPE HSType;
FILE_SYSTEM_REDIRECT RedirType;
wchar RedirName[NM];
bool DirTarget;
bool UnixOwnerSet,UnixOwnerNumeric,UnixGroupNumeric;
char UnixOwnerName[256],UnixGroupName[256];
#ifdef _UNIX
uid_t UnixOwnerID;
uid_t UnixGroupID;
#else // Need these Unix fields in Windows too for 'list' command.
uint UnixOwnerID;
uint UnixGroupID;
#endif
void Reset(size_t SubDataSize=0);
bool CmpName(const wchar *Name)
{
return(my_wcscmp(FileName,Name)==0);
}
FileHeader& operator = (FileHeader &hd);
};
struct EndArcHeader:BaseBlock
{
// Optional CRC32 of entire archive up to start of EndArcHeader block.
// Present in RAR 4.x archives if EARC_DATACRC flag is set.
uint ArcDataCRC;
uint VolNumber; // Optional number of current volume.
// 7 additional zero bytes can be stored here if EARC_REVSPACE is set.
bool NextVolume; // Not last volume.
bool DataCRC;
bool RevSpace;
bool StoreVolNumber;
void Reset()
{
BaseBlock::Reset();
NextVolume=false;
DataCRC=false;
RevSpace=false;
StoreVolNumber=false;
}
};
// SubBlockHeader and its successors were used in RAR 2.x format.
// RAR 4.x uses FileHeader with HEAD_SERVICE HeaderType for subblocks.
struct SubBlockHeader:BlockHeader
{
ushort SubType;
byte Level;
};
struct CommentHeader:BaseBlock
{
ushort UnpSize;
byte UnpVer;
byte Method;
ushort CommCRC;
};
struct ProtectHeader:BlockHeader
{
byte Version;
ushort RecSectors;
uint TotalBlocks;
byte Mark[8];
};
struct AVHeader:BaseBlock
{
byte UnpVer;
byte Method;
byte AVVer;
uint AVInfoCRC;
};
struct SignHeader:BaseBlock
{
uint CreationTime;
ushort ArcNameSize;
ushort UserNameSize;
};
struct UnixOwnersHeader:SubBlockHeader
{
ushort OwnerNameSize;
ushort GroupNameSize;
/* dummy */
char OwnerName[256];
char GroupName[256];
};
struct EAHeader:SubBlockHeader
{
uint UnpSize;
byte UnpVer;
byte Method;
uint EACRC;
};
struct StreamHeader:SubBlockHeader
{
uint UnpSize;
byte UnpVer;
byte Method;
uint StreamCRC;
ushort StreamNameSize;
char StreamName[260];
};
struct MacFInfoHeader:SubBlockHeader
{
uint fileType;
uint fileCreator;
};
#endif

View File

@@ -0,0 +1,99 @@
#ifndef _RAR_HEADERS5_
#define _RAR_HEADERS5_
#define SIZEOF_MARKHEAD5 8 // RAR 5.0 signature length.
#define SIZEOF_SHORTBLOCKHEAD5 7 // Smallest RAR 5.0 block size.
// RAR 5.0 block flags common for all blocks.
// Additional extra area is present in the end of block header.
#define HFL_EXTRA 0x0001
// Additional data area is present in the end of block header.
#define HFL_DATA 0x0002
// Unknown blocks with this flag must be skipped when updating an archive.
#define HFL_SKIPIFUNKNOWN 0x0004
// Data area of this block is continuing from previous volume.
#define HFL_SPLITBEFORE 0x0008
// Data area of this block is continuing in next volume.
#define HFL_SPLITAFTER 0x0010
// Block depends on preceding file block.
#define HFL_CHILD 0x0020
// Preserve a child block if host is modified.
#define HFL_INHERITED 0x0040
// RAR 5.0 main archive header specific flags.
#define MHFL_VOLUME 0x0001 // Volume.
#define MHFL_VOLNUMBER 0x0002 // Volume number field is present. True for all volumes except first.
#define MHFL_SOLID 0x0004 // Solid archive.
#define MHFL_PROTECT 0x0008 // Recovery record is present.
#define MHFL_LOCK 0x0010 // Locked archive.
// RAR 5.0 file header specific flags.
#define FHFL_DIRECTORY 0x0001 // Directory.
#define FHFL_UTIME 0x0002 // Time field in Unix format is present.
#define FHFL_CRC32 0x0004 // CRC32 field is present.
#define FHFL_UNPUNKNOWN 0x0008 // Unknown unpacked size.
// RAR 5.0 end of archive header specific flags.
#define EHFL_NEXTVOLUME 0x0001 // Not last volume.
// RAR 5.0 archive encryption header specific flags.
#define CHFL_CRYPT_PSWCHECK 0x0001 // Password check data is present.
// RAR 5.0 file compression flags.
#define FCI_ALGO_BIT0 0x0001 // Version of compression algorithm.
#define FCI_ALGO_BIT1 0x0002 // 0 .. 63.
#define FCI_ALGO_BIT2 0x0004
#define FCI_ALGO_BIT3 0x0008
#define FCI_ALGO_BIT4 0x0010
#define FCI_ALGO_BIT5 0x0020
#define FCI_SOLID 0x0040 // Solid flag.
#define FCI_METHOD_BIT0 0x0080 // Compression method.
#define FCI_METHOD_BIT1 0x0100 // 0 .. 5 (6 and 7 are not used).
#define FCI_METHOD_BIT2 0x0200
#define FCI_DICT_BIT0 0x0400 // Dictionary size.
#define FCI_DICT_BIT1 0x0800 // 128 KB .. 4 GB.
#define FCI_DICT_BIT2 0x1000
#define FCI_DICT_BIT3 0x2000
// Main header extra field values.
#define MHEXTRA_LOCATOR 0x01 // Position of quick list and other blocks.
// Flags for MHEXTRA_LOCATOR.
#define MHEXTRA_LOCATOR_QLIST 0x01 // Quick open offset is present.
#define MHEXTRA_LOCATOR_RR 0x02 // Recovery record offset is present.
// File and service header extra field values.
#define FHEXTRA_CRYPT 0x01 // Encryption parameters.
#define FHEXTRA_HASH 0x02 // File hash.
#define FHEXTRA_HTIME 0x03 // High precision file time.
#define FHEXTRA_VERSION 0x04 // File version information.
#define FHEXTRA_REDIR 0x05 // File system redirection (links, etc.).
#define FHEXTRA_UOWNER 0x06 // Unix owner and group information.
#define FHEXTRA_SUBDATA 0x07 // Service header subdata array.
// Hash type values for FHEXTRA_HASH.
#define FHEXTRA_HASH_BLAKE2 0x00
// Flags for FHEXTRA_HTIME.
#define FHEXTRA_HTIME_UNIXTIME 0x01 // Use Unix time_t format.
#define FHEXTRA_HTIME_MTIME 0x02 // mtime is present.
#define FHEXTRA_HTIME_CTIME 0x04 // ctime is present.
#define FHEXTRA_HTIME_ATIME 0x08 // atime is present.
// Flags for FHEXTRA_CRYPT.
#define FHEXTRA_CRYPT_PSWCHECK 0x01 // Store password check data.
#define FHEXTRA_CRYPT_HASHMAC 0x02 // Use MAC for unpacked data checksums.
// Flags for FHEXTRA_REDIR.
#define FHEXTRA_REDIR_DIR 0x01 // Link target is directory.
// Flags for FHEXTRA_UOWNER.
#define FHEXTRA_UOWNER_UNAME 0x01 // User name string is present.
#define FHEXTRA_UOWNER_GNAME 0x02 // Group name string is present.
#define FHEXTRA_UOWNER_NUMUID 0x04 // Numeric user ID is present.
#define FHEXTRA_UOWNER_NUMGID 0x08 // Numeric group ID is present.
#endif

View File

@@ -0,0 +1,42 @@
****** ***** ****** UnRAR - free utility for RAR archives
** ** ** ** ** ** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
****** ******* ****** License for use and distribution of
** ** ** ** ** ** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
** ** ** ** ** ** FREE portable version
~~~~~~~~~~~~~~~~~~~~~
The source code of UnRAR utility is freeware. This means:
1. All copyrights to RAR and the utility UnRAR are exclusively
owned by the author - Alexander Roshal.
2. UnRAR source code may be used in any software to handle
RAR archives without limitations free of charge, but cannot be
used to develop RAR (WinRAR) compatible archiver and to
re-create RAR compression algorithm, which is proprietary.
Distribution of modified UnRAR source code in separate form
or as a part of other software is permitted, provided that
full text of this paragraph, starting from "UnRAR source code"
words, is included in license, or in documentation if license
is not available, and in source code comments of resulting package.
3. The UnRAR utility may be freely distributed. It is allowed
to distribute UnRAR inside of other software packages.
4. THE RAR ARCHIVER AND THE UnRAR UTILITY ARE DISTRIBUTED "AS IS".
NO WARRANTY OF ANY KIND IS EXPRESSED OR IMPLIED. YOU USE AT
YOUR OWN RISK. THE AUTHOR WILL NOT BE LIABLE FOR DATA LOSS,
DAMAGES, LOSS OF PROFITS OR ANY OTHER KIND OF LOSS WHILE USING
OR MISUSING THIS SOFTWARE.
5. Installing and using the UnRAR utility signifies acceptance of
these terms and conditions of the license.
6. If you don't agree with terms of the license you must remove
UnRAR files from your storage devices and cease to use the
utility.
Thank you for your interest in RAR and UnRAR.
Alexander L. Roshal

View File

@@ -0,0 +1,621 @@
/****************************************************************************
* This file is part of PPMd project *
* Written and distributed to public domain by Dmitry Shkarin 1997, *
* 1999-2000 *
* Contents: model description and encoding/decoding routines *
****************************************************************************/
#ifdef RAR_COMMON_HPP
static const int MAX_O=64; /* maximum allowed model order */
const uint TOP=1 << 24, BOT=1 << 15;
template <class T>
inline void _PPMD_SWAP(T& t1,T& t2) { T tmp=t1; t1=t2; t2=tmp; }
inline RARPPM_CONTEXT* RARPPM_CONTEXT::createChild(ModelPPM *Model,RARPPM_STATE* pStats,
RARPPM_STATE& FirstState)
{
RARPPM_CONTEXT* pc = (RARPPM_CONTEXT*) Model->SubAlloc.AllocContext();
if ( pc )
{
pc->NumStats=1;
pc->OneState=FirstState;
pc->Suffix=this;
pStats->Successor=pc;
}
return pc;
}
ModelPPM::ModelPPM()
{
MinContext=NULL;
MaxContext=NULL;
MedContext=NULL;
}
void ModelPPM::RestartModelRare()
{
int i, k, m;
memset(CharMask,0,sizeof(CharMask));
SubAlloc.InitSubAllocator();
InitRL=-(MaxOrder < 12 ? MaxOrder:12)-1;
MinContext = MaxContext = (RARPPM_CONTEXT*) SubAlloc.AllocContext();
MinContext->Suffix=NULL;
OrderFall=MaxOrder;
MinContext->U.SummFreq=(MinContext->NumStats=256)+1;
FoundState=MinContext->U.Stats=(RARPPM_STATE*)SubAlloc.AllocUnits(256/2);
for (RunLength=InitRL, PrevSuccess=i=0;i < 256;i++)
{
MinContext->U.Stats[i].Symbol=i;
MinContext->U.Stats[i].Freq=1;
MinContext->U.Stats[i].Successor=NULL;
}
static const ushort InitBinEsc[]={
0x3CDD,0x1F3F,0x59BF,0x48F3,0x64A1,0x5ABC,0x6632,0x6051
};
for (i=0;i < 128;i++)
for (k=0;k < 8;k++)
for (m=0;m < 64;m += 8)
BinSumm[i][k+m]=BIN_SCALE-InitBinEsc[k]/(i+2);
for (i=0;i < 25;i++)
for (k=0;k < 16;k++)
SEE2Cont[i][k].init(5*i+10);
}
void ModelPPM::StartModelRare(int MaxOrder)
{
int i, k, m ,Step;
EscCount=1;
/*
if (MaxOrder < 2)
{
memset(CharMask,0,sizeof(CharMask));
OrderFall=ModelPPM::MaxOrder;
MinContext=MaxContext;
while (MinContext->Suffix != NULL)
{
MinContext=MinContext->Suffix;
OrderFall--;
}
FoundState=MinContext->U.Stats;
MinContext=MaxContext;
}
else
*/
{
ModelPPM::MaxOrder=MaxOrder;
RestartModelRare();
NS2BSIndx[0]=2*0;
NS2BSIndx[1]=2*1;
memset(NS2BSIndx+2,2*2,9);
memset(NS2BSIndx+11,2*3,256-11);
for (i=0;i < 3;i++)
NS2Indx[i]=i;
for (m=i, k=Step=1;i < 256;i++)
{
NS2Indx[i]=m;
if ( !--k )
{
k = ++Step;
m++;
}
}
memset(HB2Flag,0,0x40);
memset(HB2Flag+0x40,0x08,0x100-0x40);
DummySEE2Cont.Shift=PERIOD_BITS;
}
}
void RARPPM_CONTEXT::rescale(ModelPPM *Model)
{
int OldNS=NumStats, i=NumStats-1, Adder, EscFreq;
RARPPM_STATE* p1, * p;
for (p=Model->FoundState;p != U.Stats;p--)
_PPMD_SWAP(p[0],p[-1]);
U.Stats->Freq += 4;
U.SummFreq += 4;
EscFreq=U.SummFreq-p->Freq;
Adder=(Model->OrderFall != 0);
U.SummFreq = (p->Freq=(p->Freq+Adder) >> 1);
do
{
EscFreq -= (++p)->Freq;
U.SummFreq += (p->Freq=(p->Freq+Adder) >> 1);
if (p[0].Freq > p[-1].Freq)
{
RARPPM_STATE tmp=*(p1=p);
do
{
p1[0]=p1[-1];
} while (--p1 != U.Stats && tmp.Freq > p1[-1].Freq);
*p1=tmp;
}
} while ( --i );
if (p->Freq == 0)
{
do
{
i++;
} while ((--p)->Freq == 0);
EscFreq += i;
if ((NumStats -= i) == 1)
{
RARPPM_STATE tmp=*U.Stats;
do
{
tmp.Freq-=(tmp.Freq >> 1);
EscFreq>>=1;
} while (EscFreq > 1);
Model->SubAlloc.FreeUnits(U.Stats,(OldNS+1) >> 1);
*(Model->FoundState=&OneState)=tmp; return;
}
}
U.SummFreq += (EscFreq -= (EscFreq >> 1));
int n0=(OldNS+1) >> 1, n1=(NumStats+1) >> 1;
if (n0 != n1)
U.Stats = (RARPPM_STATE*) Model->SubAlloc.ShrinkUnits(U.Stats,n0,n1);
Model->FoundState=U.Stats;
}
inline RARPPM_CONTEXT* ModelPPM::CreateSuccessors(bool Skip,RARPPM_STATE* p1)
{
#ifdef __ICL
static
#endif
RARPPM_STATE UpState;
RARPPM_CONTEXT* pc=MinContext, * UpBranch=FoundState->Successor;
RARPPM_STATE * p, * ps[MAX_O], ** pps=ps;
if ( !Skip )
{
*pps++ = FoundState;
if ( !pc->Suffix )
goto NO_LOOP;
}
if ( p1 )
{
p=p1;
pc=pc->Suffix;
goto LOOP_ENTRY;
}
do
{
pc=pc->Suffix;
if (pc->NumStats != 1)
{
if ((p=pc->U.Stats)->Symbol != FoundState->Symbol)
do
{
p++;
} while (p->Symbol != FoundState->Symbol);
}
else
p=&(pc->OneState);
LOOP_ENTRY:
if (p->Successor != UpBranch)
{
pc=p->Successor;
break;
}
*pps++ = p;
} while ( pc->Suffix );
NO_LOOP:
if (pps == ps)
return pc;
UpState.Symbol=*(byte*) UpBranch;
UpState.Successor=(RARPPM_CONTEXT*) (((byte*) UpBranch)+1);
if (pc->NumStats != 1)
{
if ((byte*) pc <= SubAlloc.pText)
return(NULL);
if ((p=pc->U.Stats)->Symbol != UpState.Symbol)
do
{
p++;
} while (p->Symbol != UpState.Symbol);
uint cf=p->Freq-1;
uint s0=pc->U.SummFreq-pc->NumStats-cf;
UpState.Freq=1+((2*cf <= s0)?(5*cf > s0):((2*cf+3*s0-1)/(2*s0)));
}
else
UpState.Freq=pc->OneState.Freq;
do
{
pc = pc->createChild(this,*--pps,UpState);
if ( !pc )
return NULL;
} while (pps != ps);
return pc;
}
inline void ModelPPM::UpdateModel()
{
RARPPM_STATE fs = *FoundState, *p = NULL;
RARPPM_CONTEXT *pc, *Successor;
uint ns1, ns, cf, sf, s0;
if (fs.Freq < MAX_FREQ/4 && (pc=MinContext->Suffix) != NULL)
{
if (pc->NumStats != 1)
{
if ((p=pc->U.Stats)->Symbol != fs.Symbol)
{
do
{
p++;
} while (p->Symbol != fs.Symbol);
if (p[0].Freq >= p[-1].Freq)
{
_PPMD_SWAP(p[0],p[-1]);
p--;
}
}
if (p->Freq < MAX_FREQ-9)
{
p->Freq += 2;
pc->U.SummFreq += 2;
}
}
else
{
p=&(pc->OneState);
p->Freq += (p->Freq < 32);
}
}
if ( !OrderFall )
{
MinContext=MaxContext=FoundState->Successor=CreateSuccessors(TRUE,p);
if ( !MinContext )
goto RESTART_MODEL;
return;
}
*SubAlloc.pText++ = fs.Symbol;
Successor = (RARPPM_CONTEXT*) SubAlloc.pText;
if (SubAlloc.pText >= SubAlloc.FakeUnitsStart)
goto RESTART_MODEL;
if ( fs.Successor )
{
if ((byte*) fs.Successor <= SubAlloc.pText &&
(fs.Successor=CreateSuccessors(FALSE,p)) == NULL)
goto RESTART_MODEL;
if ( !--OrderFall )
{
Successor=fs.Successor;
SubAlloc.pText -= (MaxContext != MinContext);
}
}
else
{
FoundState->Successor=Successor;
fs.Successor=MinContext;
}
s0=MinContext->U.SummFreq-(ns=MinContext->NumStats)-(fs.Freq-1);
for (pc=MaxContext;pc != MinContext;pc=pc->Suffix)
{
if ((ns1=pc->NumStats) != 1)
{
if ((ns1 & 1) == 0)
{
pc->U.Stats=(RARPPM_STATE*) SubAlloc.ExpandUnits(pc->U.Stats,ns1 >> 1);
if ( !pc->U.Stats )
goto RESTART_MODEL;
}
pc->U.SummFreq += (2*ns1 < ns)+2*((4*ns1 <= ns) & (pc->U.SummFreq <= 8*ns1));
}
else
{
p=(RARPPM_STATE*) SubAlloc.AllocUnits(1);
if ( !p )
goto RESTART_MODEL;
*p=pc->OneState;
pc->U.Stats=p;
if (p->Freq < MAX_FREQ/4-1)
p->Freq += p->Freq;
else
p->Freq = MAX_FREQ-4;
pc->U.SummFreq=p->Freq+InitEsc+(ns > 3);
}
cf=2*fs.Freq*(pc->U.SummFreq+6);
sf=s0+pc->U.SummFreq;
if (cf < 6*sf)
{
cf=1+(cf > sf)+(cf >= 4*sf);
pc->U.SummFreq += 3;
}
else
{
cf=4+(cf >= 9*sf)+(cf >= 12*sf)+(cf >= 15*sf);
pc->U.SummFreq += cf;
}
p=pc->U.Stats+ns1;
p->Successor=Successor;
p->Symbol = fs.Symbol;
p->Freq = cf;
pc->NumStats=++ns1;
}
MaxContext=MinContext=fs.Successor;
return;
RESTART_MODEL:
RestartModelRare();
EscCount=0;
}
// Tabulated escapes for exponential symbol distribution
static const byte ExpEscape[16]={ 25,14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 };
#define GET_MEAN(SUMM,SHIFT,ROUND) ((SUMM+(1 << (SHIFT-ROUND))) >> (SHIFT))
inline void RARPPM_CONTEXT::decodeBinSymbol(ModelPPM *Model)
{
RARPPM_STATE& rs=OneState;
Model->HiBitsFlag=Model->HB2Flag[Model->FoundState->Symbol];
ushort& bs=Model->BinSumm[rs.Freq-1][Model->PrevSuccess+
Model->NS2BSIndx[Suffix->NumStats-1]+
Model->HiBitsFlag+2*Model->HB2Flag[rs.Symbol]+
((Model->RunLength >> 26) & 0x20)];
if (Model->Coder.GetCurrentShiftCount(TOT_BITS) < bs)
{
Model->FoundState=&rs;
rs.Freq += (rs.Freq < 128);
Model->Coder.SubRange.LowCount=0;
Model->Coder.SubRange.HighCount=bs;
bs = GET_SHORT16(bs+INTERVAL-GET_MEAN(bs,PERIOD_BITS,2));
Model->PrevSuccess=1;
Model->RunLength++;
}
else
{
Model->Coder.SubRange.LowCount=bs;
bs = GET_SHORT16(bs-GET_MEAN(bs,PERIOD_BITS,2));
Model->Coder.SubRange.HighCount=BIN_SCALE;
Model->InitEsc=ExpEscape[bs >> 10];
Model->NumMasked=1;
Model->CharMask[rs.Symbol]=Model->EscCount;
Model->PrevSuccess=0;
Model->FoundState=NULL;
}
}
inline void RARPPM_CONTEXT::update1(ModelPPM *Model,RARPPM_STATE* p)
{
(Model->FoundState=p)->Freq += 4;
U.SummFreq += 4;
if (p[0].Freq > p[-1].Freq)
{
_PPMD_SWAP(p[0],p[-1]);
Model->FoundState=--p;
if (p->Freq > MAX_FREQ)
rescale(Model);
}
}
inline bool RARPPM_CONTEXT::decodeSymbol1(ModelPPM *Model)
{
Model->Coder.SubRange.scale=U.SummFreq;
RARPPM_STATE* p=U.Stats;
int i, HiCnt;
int count=Model->Coder.GetCurrentCount();
if (count>=(int)Model->Coder.SubRange.scale)
return(false);
if (count < (HiCnt=p->Freq))
{
Model->PrevSuccess=(2*(Model->Coder.SubRange.HighCount=HiCnt) > Model->Coder.SubRange.scale);
Model->RunLength += Model->PrevSuccess;
(Model->FoundState=p)->Freq=(HiCnt += 4);
U.SummFreq += 4;
if (HiCnt > MAX_FREQ)
rescale(Model);
Model->Coder.SubRange.LowCount=0;
return(true);
}
else
if (Model->FoundState==NULL)
return(false);
Model->PrevSuccess=0;
i=NumStats-1;
while ((HiCnt += (++p)->Freq) <= count)
if (--i == 0)
{
Model->HiBitsFlag=Model->HB2Flag[Model->FoundState->Symbol];
Model->Coder.SubRange.LowCount=HiCnt;
Model->CharMask[p->Symbol]=Model->EscCount;
i=(Model->NumMasked=NumStats)-1;
Model->FoundState=NULL;
do
{
Model->CharMask[(--p)->Symbol]=Model->EscCount;
} while ( --i );
Model->Coder.SubRange.HighCount=Model->Coder.SubRange.scale;
return(true);
}
Model->Coder.SubRange.LowCount=(Model->Coder.SubRange.HighCount=HiCnt)-p->Freq;
update1(Model,p);
return(true);
}
inline void RARPPM_CONTEXT::update2(ModelPPM *Model,RARPPM_STATE* p)
{
(Model->FoundState=p)->Freq += 4;
U.SummFreq += 4;
if (p->Freq > MAX_FREQ)
rescale(Model);
Model->EscCount++;
Model->RunLength=Model->InitRL;
}
inline RARPPM_SEE2_CONTEXT* RARPPM_CONTEXT::makeEscFreq2(ModelPPM *Model,int Diff)
{
RARPPM_SEE2_CONTEXT* psee2c;
if (NumStats != 256)
{
psee2c=Model->SEE2Cont[Model->NS2Indx[Diff-1]]+
(Diff < Suffix->NumStats-NumStats)+
2*(U.SummFreq < 11*NumStats)+4*(Model->NumMasked > Diff)+
Model->HiBitsFlag;
Model->Coder.SubRange.scale=psee2c->getMean();
}
else
{
psee2c=&Model->DummySEE2Cont;
Model->Coder.SubRange.scale=1;
}
return psee2c;
}
inline bool RARPPM_CONTEXT::decodeSymbol2(ModelPPM *Model)
{
int count, HiCnt, i=NumStats-Model->NumMasked;
RARPPM_SEE2_CONTEXT* psee2c=makeEscFreq2(Model,i);
RARPPM_STATE* ps[256], ** pps=ps, * p=U.Stats-1;
HiCnt=0;
do
{
do
{
p++;
} while (Model->CharMask[p->Symbol] == Model->EscCount);
HiCnt += p->Freq;
*pps++ = p;
} while ( --i );
Model->Coder.SubRange.scale += HiCnt;
count=Model->Coder.GetCurrentCount();
if (count>=(int)Model->Coder.SubRange.scale)
return(false);
p=*(pps=ps);
if (count < HiCnt)
{
HiCnt=0;
while ((HiCnt += p->Freq) <= count)
p=*++pps;
Model->Coder.SubRange.LowCount = (Model->Coder.SubRange.HighCount=HiCnt)-p->Freq;
psee2c->update();
update2(Model,p);
}
else
{
Model->Coder.SubRange.LowCount=HiCnt;
Model->Coder.SubRange.HighCount=Model->Coder.SubRange.scale;
i=NumStats-Model->NumMasked;
pps--;
do
{
Model->CharMask[(*++pps)->Symbol]=Model->EscCount;
} while ( --i );
psee2c->Summ += Model->Coder.SubRange.scale;
Model->NumMasked = NumStats;
}
return(true);
}
inline void ModelPPM::ClearMask()
{
EscCount=1;
memset(CharMask,0,sizeof(CharMask));
}
// reset PPM variables after data error allowing safe resuming
// of further data processing
void ModelPPM::CleanUp()
{
SubAlloc.StopSubAllocator();
SubAlloc.StartSubAllocator(1);
StartModelRare(2);
}
bool ModelPPM::DecodeInit(Unpack *UnpackRead,int &EscChar)
{
int MaxOrder=UnpackRead->GetChar();
bool Reset=(MaxOrder & 0x20)!=0;
int MaxMB;
if (Reset)
MaxMB=UnpackRead->GetChar();
else
if (SubAlloc.GetAllocatedMemory()==0)
return(false);
if (MaxOrder & 0x40)
EscChar=UnpackRead->GetChar();
Coder.InitDecoder(UnpackRead);
if (Reset)
{
MaxOrder=(MaxOrder & 0x1f)+1;
if (MaxOrder>16)
MaxOrder=16+(MaxOrder-16)*3;
if (MaxOrder==1)
{
SubAlloc.StopSubAllocator();
return(false);
}
SubAlloc.StartSubAllocator(MaxMB+1);
StartModelRare(MaxOrder);
}
return(MinContext!=NULL);
}
int ModelPPM::DecodeChar()
{
if ((byte*)MinContext <= SubAlloc.pText || (byte*)MinContext>SubAlloc.HeapEnd)
return(-1);
if (MinContext->NumStats != 1)
{
if ((byte*)MinContext->U.Stats <= SubAlloc.pText || (byte*)MinContext->U.Stats>SubAlloc.HeapEnd)
return(-1);
if (!MinContext->decodeSymbol1(this))
return(-1);
}
else
MinContext->decodeBinSymbol(this);
Coder.Decode();
while ( !FoundState )
{
ARI_DEC_NORMALIZE(Coder.code,Coder.low,Coder.range,Coder.UnpackRead);
do
{
OrderFall++;
MinContext=MinContext->Suffix;
if ((byte*)MinContext <= SubAlloc.pText || (byte*)MinContext>SubAlloc.HeapEnd)
return(-1);
} while (MinContext->NumStats == NumMasked);
if (!MinContext->decodeSymbol2(this))
return(-1);
Coder.Decode();
}
int Symbol=FoundState->Symbol;
if (!OrderFall && (byte*) FoundState->Successor > SubAlloc.pText)
MinContext=MaxContext=FoundState->Successor;
else
{
UpdateModel();
if (EscCount == 0)
ClearMask();
}
ARI_DEC_NORMALIZE(Coder.code,Coder.low,Coder.range,Coder.UnpackRead);
return(Symbol);
}
#endif

View File

@@ -0,0 +1,122 @@
#ifndef _RAR_PPMMODEL_
#define _RAR_PPMMODEL_
#include "coder.hpp"
#include "suballoc.hpp"
#ifdef ALLOW_MISALIGNED
#pragma pack(1)
#endif
struct RARPPM_DEF
{
static const int INT_BITS=7, PERIOD_BITS=7, TOT_BITS=INT_BITS+PERIOD_BITS,
INTERVAL=1 << INT_BITS, BIN_SCALE=1 << TOT_BITS, MAX_FREQ=124;
};
struct RARPPM_SEE2_CONTEXT : RARPPM_DEF
{ // SEE-contexts for PPM-contexts with masked symbols
ushort Summ;
byte Shift, Count;
void init(int InitVal)
{
Summ=InitVal << (Shift=PERIOD_BITS-4);
Count=4;
}
uint getMean()
{
uint RetVal=GET_SHORT16(Summ) >> Shift;
Summ -= RetVal;
return RetVal+(RetVal == 0);
}
void update()
{
if (Shift < PERIOD_BITS && --Count == 0)
{
Summ += Summ;
Count=3 << Shift++;
}
}
};
class ModelPPM;
struct RARPPM_CONTEXT;
struct RARPPM_STATE
{
byte Symbol;
byte Freq;
RARPPM_CONTEXT* Successor;
};
struct RARPPM_CONTEXT : RARPPM_DEF
{
ushort NumStats;
struct FreqData
{
ushort SummFreq;
RARPPM_STATE RARPPM_PACK_ATTR * Stats;
};
union
{
FreqData U;
RARPPM_STATE OneState;
};
RARPPM_CONTEXT* Suffix;
inline void encodeBinSymbol(ModelPPM *Model,int symbol); // MaxOrder:
inline void encodeSymbol1(ModelPPM *Model,int symbol); // ABCD context
inline void encodeSymbol2(ModelPPM *Model,int symbol); // BCD suffix
inline void decodeBinSymbol(ModelPPM *Model); // BCDE successor
inline bool decodeSymbol1(ModelPPM *Model); // other orders:
inline bool decodeSymbol2(ModelPPM *Model); // BCD context
inline void update1(ModelPPM *Model,RARPPM_STATE* p); // CD suffix
inline void update2(ModelPPM *Model,RARPPM_STATE* p); // BCDE successor
void rescale(ModelPPM *Model);
inline RARPPM_CONTEXT* createChild(ModelPPM *Model,RARPPM_STATE* pStats,RARPPM_STATE& FirstState);
inline RARPPM_SEE2_CONTEXT* makeEscFreq2(ModelPPM *Model,int Diff);
};
#ifdef ALLOW_MISALIGNED
#ifdef _AIX
#pragma pack(pop)
#else
#pragma pack()
#endif
#endif
class ModelPPM : RARPPM_DEF
{
private:
friend struct RARPPM_CONTEXT;
RARPPM_SEE2_CONTEXT SEE2Cont[25][16], DummySEE2Cont;
struct RARPPM_CONTEXT *MinContext, *MedContext, *MaxContext;
RARPPM_STATE* FoundState; // found next state transition
int NumMasked, InitEsc, OrderFall, MaxOrder, RunLength, InitRL;
byte CharMask[256], NS2Indx[256], NS2BSIndx[256], HB2Flag[256];
byte EscCount, PrevSuccess, HiBitsFlag;
ushort BinSumm[128][64]; // binary SEE-contexts
RangeCoder Coder;
SubAllocator SubAlloc;
void RestartModelRare();
void StartModelRare(int MaxOrder);
inline RARPPM_CONTEXT* CreateSuccessors(bool Skip,RARPPM_STATE* p1);
inline void UpdateModel();
inline void ClearMask();
public:
ModelPPM();
void CleanUp(); // reset PPM variables after data error
bool DecodeInit(Unpack *UnpackRead,int &EscChar);
int DecodeChar();
};
#endif

View File

@@ -0,0 +1,56 @@
#include "rar.hpp"
wchar* GetWideName(const char *Name,const wchar *NameW,wchar *DestW,size_t DestSize)
{
if (NameW!=NULL && *NameW!=0)
{
if (DestW!=NameW)
my_wcsncpy(DestW,NameW,DestSize);
}
else
if (Name!=NULL)
CharToWide(Name,DestW,DestSize);
else
*DestW=0;
// Ensure that we return a zero terminate string for security reasons.
if (DestSize>0)
DestW[DestSize-1]=0;
return(DestW);
}
void UnixSlashToDos(const char *SrcName, char *DestName, size_t MaxLength)
{
size_t Copied = 0;
for (; Copied<MaxLength - 1 && SrcName[Copied] != 0; Copied++)
DestName[Copied] = SrcName[Copied] == '/' ? '\\' : SrcName[Copied];
DestName[Copied] = 0;
}
void DosSlashToUnix(const char *SrcName, char *DestName, size_t MaxLength)
{
size_t Copied = 0;
for (; Copied<MaxLength - 1 && SrcName[Copied] != 0; Copied++)
DestName[Copied] = SrcName[Copied] == '\\' ? '/' : SrcName[Copied];
DestName[Copied] = 0;
}
void UnixSlashToDos(const wchar *SrcName, wchar *DestName, size_t MaxLength)
{
size_t Copied = 0;
for (; Copied<MaxLength - 1 && SrcName[Copied] != 0; Copied++)
DestName[Copied] = SrcName[Copied] == '/' ? '\\' : SrcName[Copied];
DestName[Copied] = 0;
}
void DosSlashToUnix(const wchar *SrcName, wchar *DestName, size_t MaxLength)
{
size_t Copied = 0;
for (; Copied<MaxLength - 1 && SrcName[Copied] != 0; Copied++)
DestName[Copied] = SrcName[Copied] == '\\' ? '/' : SrcName[Copied];
DestName[Copied] = 0;
}

249
src/core/fex/unrar/rar.hpp Normal file
View File

@@ -0,0 +1,249 @@
// This source code is a heavily modified version based on the unrar package.
// It may NOT be used to develop a RAR (WinRAR) compatible archiver.
// See license.txt for copyright and licensing.
// unrar_core 5.1.7
#ifndef RAR_COMMON_HPP
#define RAR_COMMON_HPP
#include "unrar.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <setjmp.h>
#include <limits.h>
//// Glue
// One goal is to keep source code as close to original as possible, so
// that changes to the original can be found and merged more easily.
// These names are too generic and might clash (or have already, hmpf)
#define Array Rar_Array
#define uint32 rar_uint32
#define int32 rar_int32
#define Unpack Rar_Unpack
#define Archive Rar_Archive
#define RawRead Rar_RawRead
#define BitInput Rar_BitInput
#define ModelPPM Rar_ModelPPM
#define RangeCoder Rar_RangeCoder
#define SubAllocator Rar_SubAllocator
#define UnpackFilter Rar_UnpackFilter
#define VM_PreparedProgram Rar_VM_PreparedProgram
#define CRCTab Rar_CRCTab
// original source used rar* names for these as well
#define rarmalloc malloc
#define rarrealloc realloc
#define rarfree free
// Internal flags, possibly set later
#undef SFX_MODULE
#undef VM_OPTIMIZE
#undef VM_STANDARDFILTERS
#undef NORARVM
// During debugging if expr is false, prints message then continues execution
#ifndef check
#define check( expr ) ((void) 0)
#endif
struct Rar_Error_Handler
{
jmp_buf jmp_env;
void MemoryError();
void ReportError( unrar_err_t );
};
// throw spec is mandatory in ISO C++ if operator new can return NULL
#if __cplusplus >= 199711 || __GNUC__ >= 3
#define UNRAR_NOTHROW throw ()
#else
#define UNRAR_NOTHROW
#endif
struct Rar_Allocator
{
// provides allocator that doesn't throw an exception on failure
static void operator delete ( void* p ) { free( p ); }
static void* operator new ( size_t s ) UNRAR_NOTHROW { return malloc( s ); }
static void* operator new ( size_t, void* p ) UNRAR_NOTHROW { return p; }
};
//// os.hpp
#define FALSE 0
#define TRUE 1
#undef STRICT_ALIGNMENT_REQUIRED
#undef LITTLE_ENDIAN
#define NM 1024
#if defined (__i386__) || defined (__x86_64__) || defined (_M_IX86) || defined (_M_X64)
// Optimizations mostly only apply to x86
#define LITTLE_ENDIAN
#define ALLOW_NOT_ALIGNED_INT
#endif
#if defined(__sparc) || defined(sparc) || defined(__sparcv9)
/* prohibit not aligned access to data structures in text comression
algorithm, increases memory requirements */
#define STRICT_ALIGNMENT_REQUIRED
#endif
//// rartypes.hpp
#if INT_MAX == 0x7FFFFFFF && UINT_MAX == 0xFFFFFFFF
typedef unsigned int uint32; //32 bits exactly
typedef int int32; //signed 32 bits exactly
#define PRESENT_INT32
#endif
typedef unsigned char byte; //8 bits
typedef unsigned short ushort; //preferably 16 bits, but can be more
typedef unsigned int uint; //32 bits or more
typedef wchar_t wchar;
#define GET_SHORT16(x) (sizeof(ushort)==2 ? (ushort)(x):((x)&0xffff))
#define GET_UINT32(x) (sizeof(uint )==4 ? (uint )(x):((x)&0xffffffff))
//// rardefs.hpp
#define Min(x,y) (((x)<(y)) ? (x):(y))
#define Max(x,y) (((x)>(y)) ? (x):(y))
#define ALIGN_VALUE(v,a) (size_t(v) + ( (~size_t(v) + 1) & (a - 1) ) )
#define ASIZE(x) (sizeof(x)/sizeof(x[0]))
//// int64.hpp
typedef unrar_long_long int64;
typedef unrar_ulong_long uint64;
#define int64to32(x) ((uint)(x))
#define int32to64(high,low) ((((int64)(high))<<31<<1)+(low))
#define is64plus(x) (x>=0)
#define INT64MAX int32to64(0x7fffffff,0)
#define INT64NDF int32to64(0x7fffffff,0x7fffffff)
//// crc.hpp
extern uint crc_tables[8][256];
void InitCRCTables();
uint CRC32(uint StartCRC,const void *Addr,size_t Size);
ushort Checksum14(ushort StartCRC,const void *Addr,size_t Size);
#define SHA256_DIGEST_SIZE 32
#include "blake2s.hpp"
#include "hash.hpp"
//// rdwrfn.hpp
class ComprDataIO
: public Rar_Error_Handler
{
public:
unrar_read_func user_read;
unrar_write_func user_write;
void* user_read_data;
void* user_write_data;
unrar_err_t write_error; // once write error occurs, no more writes are made
int64 Tell_;
bool OldFormat;
private:
int64 UnpPackedSize;
bool SkipUnpCRC;
public:
int UnpRead(byte *Addr,uint Count);
void UnpWrite(byte *Addr,uint Count);
void SetSkipUnpCRC( bool b ) { SkipUnpCRC = b; }
void SetPackedSizeToRead( int64 n ) { UnpPackedSize = n; }
uint UnpFileCRC;
void Seek(int64 Offset, int Method = 0 ) { (void)Method; Tell_ = Offset; }
int64 Tell() { return Tell_; }
int Read( void* p, int n );
DataHash PackedDataHash; // Packed write and unpack read hash.
DataHash PackHash; // Pack read hash.
DataHash UnpHash; // Unpack write hash.
};
//// secpassword.hpp
void cleandata(void *data,size_t size);
//// pathfn.hpp
wchar* GetWideName(const char *Name,const wchar *NameW,wchar *DestW,size_t DestSize);
void UnixSlashToDos(const char *SrcName, char *DestName, size_t MaxLength);
void DosSlashToUnix(const char *SrcName, char *DestName, size_t MaxLength);
void UnixSlashToDos(const wchar *SrcName, wchar *DestName, size_t MaxLength);
void DosSlashToUnix(const wchar *SrcName, wchar *DestName, size_t MaxLength);
//// rar.hpp
class Unpack;
#include "array.hpp"
#include "unicode.hpp"
#include "timefn.hpp"
#include "headers.hpp"
#include "headers5.hpp"
#include "getbits.hpp"
#include "archive.hpp"
#include "rawread.hpp"
#include "encname.hpp"
#include "compress.hpp"
#include "rarvm.hpp"
#include "model.hpp"
#include "strfn.hpp"
#include "unpack.hpp"
//// savepos.hpp
class SaveFilePos
{
private:
File *SaveFile;
int64 SavePos;
public:
SaveFilePos(File &Src)
{
SaveFile=&Src;
SavePos=Src.Tell();
}
~SaveFilePos()
{
SaveFile->Seek(SavePos,SEEK_SET);
}
};
//// extract.hpp
/** RAR archive */
struct unrar_t
: public Rar_Allocator
{
unrar_info_t info;
unrar_pos_t begin_pos;
unrar_pos_t solid_pos;
unrar_pos_t first_file_pos;
void const* data_;
void* own_data_;
void (*close_file)( void* ); // func ptr to avoid linking fclose() in unnecessarily
bool done;
long FileCount;
Unpack* Unp;
Array<byte> Buffer;
// large items last
Archive Arc;
unrar_t();
~unrar_t();
void UnstoreFile( int64 );
unrar_err_t ExtractCurrentFile( bool SkipSolid = false, bool check_compatibility_only = false );
void update_first_file_pos()
{
if ( FileCount == 0 )
first_file_pos = Arc.CurBlockPos;
}
};
typedef unrar_t CmdExtract;
#endif

1152
src/core/fex/unrar/rarvm.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,115 @@
#ifndef _RAR_VM_
#define _RAR_VM_
#define VM_STANDARDFILTERS
#ifndef SFX_MODULE
#define VM_OPTIMIZE
#endif
#define VM_MEMSIZE 0x40000
#define VM_MEMMASK (VM_MEMSIZE-1)
#define VM_GLOBALMEMADDR 0x3C000
#define VM_GLOBALMEMSIZE 0x2000
#define VM_FIXEDGLOBALSIZE 64
enum VM_Commands
{
VM_MOV, VM_CMP, VM_ADD, VM_SUB, VM_JZ, VM_JNZ, VM_INC, VM_DEC,
VM_JMP, VM_XOR, VM_AND, VM_OR, VM_TEST, VM_JS, VM_JNS, VM_JB,
VM_JBE, VM_JA, VM_JAE, VM_PUSH, VM_POP, VM_CALL, VM_RET, VM_NOT,
VM_SHL, VM_SHR, VM_SAR, VM_NEG, VM_PUSHA,VM_POPA, VM_PUSHF,VM_POPF,
VM_MOVZX,VM_MOVSX,VM_XCHG, VM_MUL, VM_DIV, VM_ADC, VM_SBB, VM_PRINT,
#ifdef VM_OPTIMIZE
VM_MOVB, VM_MOVD, VM_CMPB, VM_CMPD,
VM_ADDB, VM_ADDD, VM_SUBB, VM_SUBD, VM_INCB, VM_INCD, VM_DECB, VM_DECD,
VM_NEGB, VM_NEGD,
#endif
VM_STANDARD
};
enum VM_StandardFilters {
VMSF_NONE, VMSF_E8, VMSF_E8E9, VMSF_ITANIUM, VMSF_RGB, VMSF_AUDIO,
VMSF_DELTA
};
enum VM_Flags {VM_FC=1,VM_FZ=2,VM_FS=0x80000000};
enum VM_OpType {VM_OPREG,VM_OPINT,VM_OPREGMEM,VM_OPNONE};
struct VM_PreparedOperand
{
VM_OpType Type;
uint Data;
uint Base;
uint *Addr;
};
struct VM_PreparedCommand
{
VM_Commands OpCode;
bool ByteMode;
VM_PreparedOperand Op1,Op2;
};
struct VM_PreparedProgram
{
VM_PreparedProgram()
{
AltCmd=NULL;
FilteredDataSize=0;
CmdCount=0;
}
Array<VM_PreparedCommand> Cmd;
VM_PreparedCommand *AltCmd;
int CmdCount;
Array<byte> GlobalData;
Array<byte> StaticData; // static data contained in DB operators
uint InitR[7];
byte *FilteredData;
uint FilteredDataSize;
};
class RarVM:private BitInput
{
private:
inline uint GetValue(bool ByteMode,uint *Addr);
inline void SetValue(bool ByteMode,uint *Addr,uint Value);
inline uint* GetOperand(VM_PreparedOperand *CmdOp);
void DecodeArg(VM_PreparedOperand &Op,bool ByteMode);
#ifdef VM_OPTIMIZE
void Optimize(VM_PreparedProgram *Prg);
#endif
bool ExecuteCode(VM_PreparedCommand *PreparedCode,uint CodeSize);
#ifdef VM_STANDARDFILTERS
VM_StandardFilters IsStandardFilter(byte *Code,uint CodeSize);
void ExecuteStandardFilter(VM_StandardFilters FilterType);
unsigned int FilterItanium_GetBits(byte *Data,int BitPos,int BitCount);
void FilterItanium_SetBits(byte *Data,uint BitField,int BitPos,int BitCount);
#endif
byte *Mem;
uint R[8];
uint Flags;
public:
RarVM();
~RarVM();
void Init();
void handle_mem_error( Rar_Error_Handler& );
friend class Unpack;
void Prepare(byte *Code,uint CodeSize,VM_PreparedProgram *Prg);
void Execute(VM_PreparedProgram *Prg);
void SetLowEndianValue(uint *Addr,uint Value);
void SetMemory(size_t Pos,byte *Data,size_t DataSize);
static uint ReadData(BitInput &Inp);
};
#endif

View File

@@ -0,0 +1,57 @@
// #included by rarvm.cpp
#ifdef RAR_COMMON_HPP
#define VMCF_OP0 0
#define VMCF_OP1 1
#define VMCF_OP2 2
#define VMCF_OPMASK 3
#define VMCF_BYTEMODE 4
#define VMCF_JUMP 8
#define VMCF_PROC 16
#define VMCF_USEFLAGS 32
#define VMCF_CHFLAGS 64
const
static byte VM_CmdFlags[]=
{
/* VM_MOV */ VMCF_OP2 | VMCF_BYTEMODE ,
/* VM_CMP */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS ,
/* VM_ADD */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS ,
/* VM_SUB */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS ,
/* VM_JZ */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS ,
/* VM_JNZ */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS ,
/* VM_INC */ VMCF_OP1 | VMCF_BYTEMODE | VMCF_CHFLAGS ,
/* VM_DEC */ VMCF_OP1 | VMCF_BYTEMODE | VMCF_CHFLAGS ,
/* VM_JMP */ VMCF_OP1 | VMCF_JUMP ,
/* VM_XOR */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS ,
/* VM_AND */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS ,
/* VM_OR */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS ,
/* VM_TEST */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS ,
/* VM_JS */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS ,
/* VM_JNS */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS ,
/* VM_JB */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS ,
/* VM_JBE */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS ,
/* VM_JA */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS ,
/* VM_JAE */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS ,
/* VM_PUSH */ VMCF_OP1 ,
/* VM_POP */ VMCF_OP1 ,
/* VM_CALL */ VMCF_OP1 | VMCF_PROC ,
/* VM_RET */ VMCF_OP0 | VMCF_PROC ,
/* VM_NOT */ VMCF_OP1 | VMCF_BYTEMODE ,
/* VM_SHL */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS ,
/* VM_SHR */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS ,
/* VM_SAR */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS ,
/* VM_NEG */ VMCF_OP1 | VMCF_BYTEMODE | VMCF_CHFLAGS ,
/* VM_PUSHA */ VMCF_OP0 ,
/* VM_POPA */ VMCF_OP0 ,
/* VM_PUSHF */ VMCF_OP0 | VMCF_USEFLAGS ,
/* VM_POPF */ VMCF_OP0 | VMCF_CHFLAGS ,
/* VM_MOVZX */ VMCF_OP2 ,
/* VM_MOVSX */ VMCF_OP2 ,
/* VM_XCHG */ VMCF_OP2 | VMCF_BYTEMODE ,
/* VM_MUL */ VMCF_OP2 | VMCF_BYTEMODE ,
/* VM_DIV */ VMCF_OP2 | VMCF_BYTEMODE ,
/* VM_ADC */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_USEFLAGS | VMCF_CHFLAGS ,
/* VM_SBB */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_USEFLAGS | VMCF_CHFLAGS ,
/* VM_PRINT */ VMCF_OP0
};
#endif

View File

@@ -0,0 +1,159 @@
#include "rar.hpp"
RawRead::RawRead(ComprDataIO *SrcFile)
{
RawRead::SrcFile=SrcFile;
Reset();
}
void RawRead::Reset()
{
ReadPos=0;
DataSize=0;
Data.Reset();
}
size_t RawRead::Read(size_t Size)
{
size_t ReadSize=0;
// (removed decryption)
if (Size!=0)
{
Data.Add(Size);
ReadSize=SrcFile->Read(&Data[DataSize],Size);
DataSize+=ReadSize;
}
return ReadSize;
}
void RawRead::Read(byte *SrcData,size_t Size)
{
if (Size!=0)
{
Data.Add(Size);
memcpy(&Data[DataSize],SrcData,Size);
DataSize+=Size;
}
}
byte RawRead::Get1()
{
return ReadPos<DataSize ? Data[ReadPos++]:0;
}
ushort RawRead::Get2()
{
if (ReadPos+1<DataSize)
{
ushort Result=Data[ReadPos]+(Data[ReadPos+1]<<8);
ReadPos+=2;
return Result;
}
return 0;
}
uint RawRead::Get4()
{
if (ReadPos+3<DataSize)
{
uint Result=Data[ReadPos]+(Data[ReadPos+1]<<8)+(Data[ReadPos+2]<<16)+
(Data[ReadPos+3]<<24);
ReadPos+=4;
return Result;
}
return 0;
}
uint64 RawRead::Get8()
{
uint Low=Get4(),High=Get4();
return int32to64(High,Low);
}
uint64 RawRead::GetV()
{
uint64 Result=0;
for (uint Shift=0;ReadPos<DataSize;Shift+=7)
{
byte CurByte=Data[ReadPos++];
Result+=uint64(CurByte & 0x7f)<<Shift;
if ((CurByte & 0x80)==0)
return Result; // Decoded successfully.
}
return 0; // Out of buffer border.
}
// Return a number of bytes in current variable length integer.
uint RawRead::GetVSize(size_t Pos)
{
for (size_t CurPos=Pos;CurPos<DataSize;CurPos++)
if ((Data[CurPos] & 0x80)==0)
return int(CurPos-Pos+1);
return 0; // Buffer overflow.
}
size_t RawRead::GetB(void *Field,size_t Size)
{
byte *F=(byte *)Field;
size_t CopySize=Min(DataSize-ReadPos,Size);
if (CopySize>0)
memcpy(F,&Data[ReadPos],CopySize);
if (Size>CopySize)
memset(F+CopySize,0,Size-CopySize);
ReadPos+=CopySize;
return CopySize;
}
void RawRead::GetW(wchar *Field,size_t Size)
{
if (ReadPos+2*Size-1<DataSize)
{
RawToWide(&Data[ReadPos],Field,Size);
ReadPos+=sizeof(wchar)*Size;
}
else
memset(Field,0,sizeof(wchar)*Size);
}
uint RawRead::GetCRC15(bool ProcessedOnly) // RAR 1.5 block CRC.
{
if (DataSize<=2)
return 0;
uint HeaderCRC=CRC32(0xffffffff,&Data[2],(ProcessedOnly ? ReadPos:DataSize)-2);
return ~HeaderCRC & 0xffff;
}
uint RawRead::GetCRC50() // RAR 5.0 block CRC.
{
if (DataSize<=4)
return 0xffffffff;
return CRC32(0xffffffff,&Data[4],DataSize-4) ^ 0xffffffff;
}
// Read vint from arbitrary byte array.
uint64 RawGetV(const byte *Data,uint &ReadPos,uint DataSize,bool &Overflow)
{
Overflow=false;
uint64 Result=0;
for (uint Shift=0;ReadPos<DataSize;Shift+=7)
{
byte CurByte=Data[ReadPos++];
Result+=uint64(CurByte & 0x7f)<<Shift;
if ((CurByte & 0x80)==0)
return Result; // Decoded successfully.
}
Overflow=true;
return 0; // Out of buffer border.
}

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