Compare commits

...

203 Commits

Author SHA1 Message Date
Rafael Kitover
043956753b translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-30 15:00:20 +00:00
Rafael Kitover
e0eb3b3dab translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-30 08:00:21 +00:00
Rafael Kitover
e3e14232f7 Set gba_darken opt default to 37
Set the GBA darken value default to 37 instead of 50, seems to look
pretty good.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-28 04:23:51 +00:00
Squall Leonhart
7565cac230 Update 2xSaI.cpp
The previous interpolation operator could cause the channels to bleed into the next when the LCD Color filter was enabled, on some starts, some settings.
2025-08-25 17:41:04 +10:00
Rafael Kitover
33c5aeb80e Default LCD Filter to enabled for GBA/GB
Set the defaults for GB and GBA LCD Filter to enabled and rewrite the
values in previous versions of the config to enabled as well.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-24 02:49:59 +00:00
Rafael Kitover
c5510ba28f ci: update install-nix-action to v31
Update the GitHub CI action install-nix-action to v31 and remove
references to apple_sdk from default.nix, they have been deprecated.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-23 22:04:19 +00:00
Rafael Kitover
96c23628ba Set default for gba_darken to 50
Set the default for the color correction option gba_darken to 50, which
is the nicest looking value.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-23 16:39:22 +00:00
Rafael Kitover
37fb449fc9 Remove gbafilter_pad/gbcfilter_pad, dead code
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-23 16:35:06 +00:00
Rafael Kitover
7519c9b818 translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-23 01:00:20 +00:00
Rafael Kitover
24b779c09e translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-23 00:00:20 +00:00
Rafael Kitover
a17df26e52 build: fix Debian installdeps for current Ubuntu
Fix installdeps for Debian variants by checking for `libsdl3-dev` and
falling back to `libsdl2-dev` if not available.

Also add `libx264-dev` and `libx265-dev` to the list of FFmpeg packages
as we now require them.

Fix #1486

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-21 22:53:33 +00:00
Rafael Kitover
b2dd03c6cb build: guard cmake_policy() w if(POLICY)
Check if CMake policies being set exist to prevent errors on older CMake
versions.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-21 20:49:32 +00:00
Andy Vandijck
967426e2f0 Fix color change with previous check 2025-08-21 09:17:54 +02:00
Rafael Kitover
ee2678c13c translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-20 20:00:20 +00:00
Rafael Kitover
337e465741 translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-20 19:00:19 +00:00
Andy Vandijck
5007977189 Add capital begin letter 2025-08-20 16:36:27 +02:00
Andy Vandijck
99f97138a2 Add LCD filter parameters and add GBC filter 2025-08-20 16:31:05 +02:00
Andy Vandijck
5b867c1483 Fix color name 2025-08-19 15:27:37 +02:00
Andy Vandijck
fe08f4d326 Remove quoted code 2025-08-19 15:26:12 +02:00
Andy Vandijck
c334e3ffca Fix PS2 colors for libretro 2025-08-19 15:20:49 +02:00
Andy Vandijck
35f8ba0b8f Add libretro PlayStation2 support 2025-08-18 16:12:29 +02:00
Andy Vandijck
fca5fae329 Check file size for GBA ROM and reduce memory footprint 2025-08-17 16:02:26 +02:00
Andy Vandijck
56ea6456f5 Check file size for GBA ROM and reduce memory footprint 2025-08-17 16:01:20 +02:00
Rafael Kitover
0510656ca3 translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-13 00:00:20 +00:00
Squall-Leonhart
b92fcf7e31 prevent the zip program from being incompletely downloaded
\
2025-08-11 14:41:19 +00:00
Andy Vandijck
22f381a19e Update macOS SDL3 to 3.2.20 2025-08-08 10:01:06 +02:00
Andy Vandijck
e9fc6c8e13 Update macOS SDL3 to 3.2.20 2025-08-08 10:00:04 +02:00
Rafael Kitover
bd20c79013 translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-07 10:00:21 +00:00
Andy Vandijck
203be42665 Fix typo 2025-08-07 11:45:40 +02:00
Andy Vandijck
d75072009b Set params when no image is loaded 2025-08-07 11:39:59 +02:00
Andy Vandijck
0e32b90002 Fix LCD color filter 2025-08-07 10:45:11 +02:00
Rafael Kitover
2640716496 translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-07 07:00:20 +00:00
Rafael Kitover
b065db66d9 translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-06 10:00:20 +00:00
Rafael Kitover
4d837fd739 translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-05 21:00:19 +00:00
Rafael Kitover
1ef356c6f0 translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-05 08:00:23 +00:00
Rafael Kitover
a8c82bb4a1 translations: rebuild source .pot
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-05 08:00:07 +00:00
Rafael Kitover
1778d605f4 Add config for color correction
Add display config dialog and config file options for GBA and GBC color
correction.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-05 07:29:50 +00:00
Rafael Kitover
d6d2a83e7e translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-04 15:00:19 +00:00
Rafael Kitover
881667a5f8 translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-04 13:00:24 +00:00
Rafael Kitover
b332aa693d translations: rebuild source .pot
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-04 13:00:07 +00:00
Rafael Kitover
7f7035a07b translations: finish removing German
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-04 12:01:47 +00:00
Rafael Kitover
3e355509e9 build: restore FindFFmpeg.cmake
Restore `FindFFmpeg.cmake`, because FFmpeg does not come with CMake
import modules.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-04 11:56:18 +00:00
Rafael Kitover
e68681ffda translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-03 15:00:19 +00:00
Andy Vandijck
f83aa940d7 Fix GB reset
Fix GB reset
2025-08-03 13:27:26 +02:00
Andy Vandijck
a18559678c Fix MS compile
Fix MS compile
2025-08-03 13:09:59 +02:00
Andy Vandijck
d927594af2 Fix MS compile
Fix MS compile
2025-08-03 13:06:32 +02:00
Andy Vandijck
06507775e8 Replace nullptr with NULL
Replace nullptr with NULL
2025-08-03 11:52:14 +02:00
Andy Vandijck
b08ecd123d Fix libretro 24 bit color
Fix libretro 24 bit color
2025-08-03 10:44:43 +02:00
Andy Vandijck
d154a6abc8 Add games app category for macOS (optimisations)
Add games app category for macOS (optimisations)
2025-08-03 10:33:47 +02:00
Andy Vandijck
b134bacc45 Fix SDL audio on Windows
Fix SDL audio on Windows
2025-08-03 10:08:27 +02:00
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
282 changed files with 30587 additions and 16741 deletions

View File

@@ -36,7 +36,7 @@ jobs:
with:
submodules: recursive
- name: Install nix
uses: cachix/install-nix-action@v22
uses: cachix/install-nix-action@v31
with:
nix_path: nixpkgs=channel:nixos-unstable

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,17 @@
cmake_minimum_required(VERSION 3.19)
cmake_policy(VERSION 3.19...3.28.3)
# Use new link library de-duplication behavior.
if(POLICY CMP0156)
cmake_policy(SET CMP0156 NEW)
endif()
if(POLICY CMP0179)
cmake_policy(SET CMP0179 NEW)
endif()
#if(POLICY CMP0181)
# cmake_policy(SET CMP0181 NEW)
#endif()
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)
if(WIN32)
@@ -24,7 +35,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 +94,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)
@@ -106,31 +116,25 @@ set(FFMPEG_DEFAULT OFF)
set(FFMPEG_COMPONENTS AVFORMAT AVCODEC SWSCALE AVUTIL SWRESAMPLE X264 X265)
set(FFMPEG_COMPONENT_VERSIONS AVFORMAT>=58.12.100 AVCODEC>=58.18.100 SWSCALE>=5.1.100 AVUTIL>=56.14.100 SWRESAMPLE>=3.1.100 X264>=0 X265>=0)
option(FIND_FFMPEG_APPLE "Find using Apple FFMPEG function" OFF)
if(NOT TRANSLATIONS_ONLY AND (NOT DEFINED ENABLE_FFMPEG OR ENABLE_FFMPEG))
set(FFMPEG_DEFAULT ON)
if (APPLE OR FIND_FFMPEG_APPLE)
find_package(AppleFFMPEG COMPONENTS ${FFMPEG_COMPONENTS})
else()
find_package(FFMPEG COMPONENTS ${FFMPEG_COMPONENTS})
endif()
find_package(FFmpeg COMPONENTS ${FFMPEG_COMPONENTS})
# check versions, but only if pkgconfig is available
if(FFMPEG_FOUND AND PKG_CONFIG_FOUND AND NOT CMAKE_TOOLCHAIN_FILE MATCHES vcpkg)
if(FFmpeg_FOUND AND PKG_CONFIG_FOUND AND NOT CMAKE_TOOLCHAIN_FILE MATCHES vcpkg)
foreach(component ${FFMPEG_COMPONENT_VERSIONS})
string(REPLACE ">=" ";" parts ${component})
list(GET parts 0 name)
list(GET parts 1 version)
if((NOT DEFINED ${name}_VERSION) OR ${name}_VERSION VERSION_LESS ${version})
set(FFMPEG_FOUND OFF)
set(FFmpeg_FOUND OFF)
endif()
endforeach()
endif()
if(NOT FFMPEG_FOUND)
if(NOT FFmpeg_FOUND)
set(FFMPEG_DEFAULT OFF)
endif()
endif()

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

View File

@@ -2,7 +2,7 @@ with import <nixpkgs> {};
stdenv.mkDerivation {
name = "visualboyadvance-m";
buildInputs = if stdenv.isDarwin then
[ ninja cmake nasm faudio gettext libintl libtiff pkg-config zip zlib openal ffmpeg wxGTK32 sdl3 pcre pcre2 darwin.apple_sdk.frameworks.System darwin.apple_sdk.frameworks.IOKit darwin.apple_sdk.frameworks.Carbon darwin.apple_sdk.frameworks.Cocoa darwin.apple_sdk.frameworks.QuartzCore darwin.apple_sdk.frameworks.AudioToolbox darwin.apple_sdk.frameworks.OpenGL darwin.apple_sdk.frameworks.OpenAL llvmPackages_latest.clang llvmPackages_latest.bintools ]
[ ninja cmake nasm faudio gettext libintl libtiff pkg-config zip zlib openal ffmpeg wxGTK32 sdl3 pcre pcre2 llvmPackages_latest.clang llvmPackages_latest.bintools ]
else
[ ninja cmake gcc clang llvm llvmPackages.libcxx nasm faudio gettext libintl libtiff pkg-config zip zlib openal ffmpeg wxGTK32 libGL libGLU glfw sdl3 gtk3-x11 pcre pcre2 util-linuxMinimal libselinux libsepol libthai libdatrie xorg.libXdmcp xorg.libXtst libxkbcommon libepoxy dbus at-spi2-core ];
}

View File

@@ -342,9 +342,12 @@ debian_installdeps() {
;;
esac
pkgs="build-essential g++ nasm cmake ccache gettext zlib1g-dev libgl1-mesa-dev libgettextpo-dev libsdl3-dev libglu1-mesa-dev libglu1-mesa libgles2-mesa-dev $glew_lib $wx_libs libgtk2.0-dev libgtk-3-dev ccache zip ninja-build libopenal-dev"
sdl_lib=$(apt-cache search libsdl3-dev | grep libsdl3-dev | awk '{ print $1 }')
[ -z "$sdl_lib" ] && sdl_lib=libsdl2-dev
[ -n "$ENABLE_FFMPEG" ] && pkgs="$pkgs libavcodec-dev libavformat-dev libswscale-dev libavutil-dev $libswresample_dev"
pkgs="build-essential g++ nasm cmake ccache gettext zlib1g-dev libgl1-mesa-dev libgettextpo-dev $sdl_lib libglu1-mesa-dev libglu1-mesa libgles2-mesa-dev $glew_lib $wx_libs libgtk2.0-dev libgtk-3-dev ccache zip ninja-build libopenal-dev"
[ -n "$ENABLE_FFMPEG" ] && pkgs="$pkgs libavcodec-dev libavformat-dev libswscale-dev libavutil-dev $libswresample_dev libx264-dev libx265-dev"
check sudo apt-get -qy install $pkgs
else

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

@@ -2,5 +2,6 @@ add_subdirectory(av_recording)
add_subdirectory(draw_text)
add_subdirectory(filters)
add_subdirectory(filters_agb)
add_subdirectory(filters_cgb)
add_subdirectory(filters_interframe)
add_subdirectory(user_config)

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

@@ -26,10 +26,6 @@ extern "C"
bool cpu_mmx = 1;
#endif
}
static uint32_t colorMask = 0xF7DEF7DE;
static uint32_t lowPixelMask = 0x08210821;
static uint32_t qcolorMask = 0xE79CE79C;
static uint32_t qlowpixelMask = 0x18631863;
static uint32_t redblueMask = 0xF81F;
static uint32_t greenMask = 0x7E0;
@@ -41,20 +37,12 @@ int Init_2xSaI(uint32_t BitFormat)
{
if(systemColorDepth == 16) {
if (BitFormat == 565) {
colorMask = 0xF7DEF7DE;
lowPixelMask = 0x08210821;
qcolorMask = 0xE79CE79C;
qlowpixelMask = 0x18631863;
redblueMask = 0xF81F;
greenMask = 0x7E0;
qRGB_COLOR_MASK[0] = qRGB_COLOR_MASK[1] = 0xF7DEF7DE;
hq2x_init(16);
RGB_LOW_BITS_MASK = 0x0821;
} else if (BitFormat == 555) {
colorMask = 0x7BDE7BDE;
lowPixelMask = 0x04210421;
qcolorMask = 0x739C739C;
qlowpixelMask = 0x0C630C63;
redblueMask = 0x7C1F;
greenMask = 0x3E0;
qRGB_COLOR_MASK[0] = qRGB_COLOR_MASK[1] = 0x7BDE7BDE;
@@ -64,10 +52,6 @@ int Init_2xSaI(uint32_t BitFormat)
return 0;
}
} else if(systemColorDepth == 32) {
colorMask = 0xfefefe;
lowPixelMask = 0x010101;
qcolorMask = 0xfcfcfc;
qlowpixelMask = 0x030303;
qRGB_COLOR_MASK[0] = qRGB_COLOR_MASK[1] = 0xfefefe;
hq2x_init(32);
RGB_LOW_BITS_MASK = 0x010101;
@@ -146,25 +130,24 @@ static inline int GetResult (uint32_t A, uint32_t B, uint32_t C, uint32_t D)
return r;
}
static inline uint32_t INTERPOLATE (uint32_t A, uint32_t B)
{
if (A != B) {
return (((A & colorMask) >> 1) + ((B & colorMask) >> 1) +
(A & B & lowPixelMask));
} else
return A;
static inline uint32_t INTERPOLATE(uint32_t A, uint32_t B) {
if (A == B) {
return A;
}
return (
(((((A >> 16) & 0xFF) & 0xFE) >> 1) + ((((B >> 16) & 0xFF) & 0xFE) >> 1) + (((A >> 16) & 0xFF) & ((B >> 16) & 0xFF) & 0x01)) << 16) |
((((((A >> 8) & 0xFF) & 0xFE) >> 1) + ((((B >> 8) & 0xFF) & 0xFE) >> 1) + (((A >> 8) & 0xFF) & ((B >> 8) & 0xFF) & 0x01)) << 8) |
(((((A & 0xFF) & 0xFE) >> 1) + (((B & 0xFF) & 0xFE) >> 1) + ((A & 0xFF) & (B & 0xFF) & 0x01)));
}
static inline uint32_t Q_INTERPOLATE (uint32_t A, uint32_t B, uint32_t C, uint32_t D)
{
uint32_t x = ((A & qcolorMask) >> 2) +
((B & qcolorMask) >> 2) +
((C & qcolorMask) >> 2) + ((D & qcolorMask) >> 2);
uint32_t y = (A & qlowpixelMask) +
(B & qlowpixelMask) + (C & qlowpixelMask) + (D & qlowpixelMask);
y = (y >> 2) & qlowpixelMask;
return x + y;
static inline uint32_t Q_INTERPOLATE(uint32_t A, uint32_t B, uint32_t C, uint32_t D) {
return (
(((((A >> 16) & 0xFC) >> 2) + (((B >> 16) & 0xFC) >> 2) + (((C >> 16) & 0xFC) >> 2) + (((D >> 16) & 0xFC) >> 2) +
(((A >> 16) & 0x03) + ((B >> 16) & 0x03) + ((C >> 16) & 0x03) + ((D >> 16) & 0x03))) << 16) |
(((((A >> 8) & 0xFC) >> 2) + (((B >> 8) & 0xFC) >> 2) + (((C >> 8) & 0xFC) >> 2) + (((D >> 8) & 0xFC) >> 2) +
(((A >> 8) & 0x03) + ((B >> 8) & 0x03) + ((C >> 8) & 0x03) + ((D >> 8) & 0x03))) << 8) |
((((A & 0xFC) >> 2) + ((B & 0xFC) >> 2) + ((C & 0xFC) >> 2) + ((D & 0xFC) >> 2) +
((A & 0x03) + (B & 0x03) + (C & 0x03) + (D & 0x03)))));
}
static inline int GetResult1_32 (uint32_t A, uint32_t B, uint32_t C, uint32_t D,
@@ -1275,4 +1258,3 @@ void Scale_2xSaI (uint8_t *srcPtr, uint32_t srcPitch, uint8_t * /* deltaPtr */,
dstPtr += dstPitch;
}
}

View File

@@ -1,4 +1,17 @@
/*
* GBA Color Correction Shader Implementation
*
* Shader modified by Pokefan531.
* Color Mangler
* Original Author: hunterk
* Original License: Public domain
*
* This code is adapted from the original shader logic.
*/
#include "components/filters_agb/filters_agb.h"
#include <cmath>
#include <algorithm>
extern int systemColorDepth;
extern int systemRedShift;
@@ -9,272 +22,332 @@ extern uint8_t systemColorMap8[0x10000];
extern uint16_t systemColorMap16[0x10000];
extern uint32_t systemColorMap32[0x10000];
static const unsigned char curve[32] = { 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0e, 0x10, 0x12,
0x14, 0x16, 0x18, 0x1c, 0x20, 0x28, 0x30, 0x38,
0x40, 0x48, 0x50, 0x58, 0x60, 0x68, 0x70, 0x80,
0x88, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0 };
// --- Global Constants and Variables for GBA Color Correction ---
// Define the color profile matrix as a static const float 2D array
// This replicates the column-major order of GLSL mat4 for easier translation.
// Format: { {col0_row0, col0_row1, col0_row2, col0_row3}, ... }
static const float GBA_sRGB[4][4] = {
{0.905f, 0.10f, 0.1575f, 0.0f}, // Column 0 (R output contributions from R, G, B, A)
{0.195f, 0.65f, 0.1425f, 0.0f}, // Column 1 (G output contributions from R, G, B, A)
{-0.10f, 0.25f, 0.70f, 0.0f}, // Column 2 (B output contributions from R, G, B, A)
{0.0f, 0.0f, 0.0f, 0.91f} // Column 3 (A/Luminance contribution)
};
// output R G B
static const unsigned char influence[3 * 3] = { 16, 4, 4, // red
8, 16, 8, // green
0, 8, 16 }; // blue
static const float GBA_DCI[4][4] = {
{0.76f, 0.125f, 0.16f, 0.0f},
{0.27f, 0.6375f, 0.18f, 0.0f},
{-0.03f, 0.2375f, 0.66f, 0.0f},
{0.0f, 0.0f, 0.0f, 0.97f}
};
inline void swap(short& a, short& b)
{
short temp = a;
a = b;
b = temp;
static const float GBA_Rec2020[4][4] = {
{0.61f, 0.155f, 0.16f, 0.0f},
{0.345f, 0.615f, 0.1875f, 0.0f},
{0.045f, 0.23f, 0.6525f, 0.0f},
{0.0f, 0.0f, 0.0f, 1.0f}
};
// Screen darkening factor. Default to 0.0f
static float darken_screen = 0.0f;
// Color mode (0 for sRGB, 1 for DCI, 2 for Rec2020). Default to sRGB (0).
static int color_mode = 0;
// Pointer to the currently selected color profile matrix.
static const float (*profile)[4];
// Global constants from the shader for gamma correction values
static const float target_gamma = 2.2f;
static const float display_gamma = 2.2f;
// --- Function Implementations ---
// Forward declaration of a helper function to set the profile based on color_mode
static void set_profile_from_mode();
// This constructor-like function runs once when the program starts.
struct GbafilterInitializer {
GbafilterInitializer() {
set_profile_from_mode();
}
};
static GbafilterInitializer __gbafilter_initializer;
// Helper function to set the 'profile' pointer based on the 'color_mode' variable.
static void set_profile_from_mode() {
if (color_mode == 0) {
profile = GBA_sRGB;
}
else if (color_mode == 1) {
profile = GBA_DCI;
}
else if (color_mode == 2) {
profile = GBA_Rec2020;
}
else {
profile = GBA_sRGB; // Default to sRGB if an invalid mode is set
}
}
// Public function to set color mode and darken screen from external calls
void gbafilter_set_params(int new_color_mode, float new_darken_screen) {
color_mode = new_color_mode;
darken_screen = fmaxf(0.0f, fminf(1.0f, new_darken_screen)); // Clamp to 0.0-1.0
// Call the helper to update 'profile' based on the new 'color_mode'
set_profile_from_mode();
}
void gbafilter_update_colors(bool lcd) {
switch (systemColorDepth) {
case 8: {
for (int i = 0; i < 0x10000; i++) {
systemColorMap8[i] = (uint8_t)((((i & 0x1f) << 3) & 0xE0) |
((((i & 0x3e0) >> 5) << 0) & 0x1C) |
((((i & 0x7c00) >> 10) >> 3) & 0x3));
}
} break;
case 16: {
for (int i = 0; i < 0x10000; i++) {
systemColorMap16[i] = ((i & 0x1f) << systemRedShift) |
(((i & 0x3e0) >> 5) << systemGreenShift) |
(((i & 0x7c00) >> 10) << systemBlueShift);
}
if (lcd)
gbafilter_pal(systemColorMap16, 0x10000);
} break;
case 24:
case 32: {
for (int i = 0; i < 0x10000; i++) {
systemColorMap32[i] = ((i & 0x1f) << systemRedShift) |
(((i & 0x3e0) >> 5) << systemGreenShift) |
(((i & 0x7c00) >> 10) << systemBlueShift);
}
if (lcd)
gbafilter_pal32(systemColorMap32, 0x10000);
} break;
case 8: {
for (int i = 0; i < 0x10000; i++) {
systemColorMap8[i] = (uint8_t)((((i & 0x1f) << 3) & 0xE0) |
((((i & 0x3e0) >> 5) << 0) & 0x1C) |
((((i & 0x7c00) >> 10) >> 3) & 0x3));
}
if (lcd)
gbafilter_pal8(systemColorMap8, 0x10000);
} break;
case 16: {
for (int i = 0x0; i < 0x10000; i++) {
systemColorMap16[i] = ((i & 0x1f) << systemRedShift) |
(((i & 0x3e0) >> 5) << systemGreenShift) |
(((i & 0x7c00) >> 10) << systemBlueShift);
}
if (lcd)
gbafilter_pal(systemColorMap16, 0x10000);
} break;
case 24:
case 32: {
for (int i = 0; i < 0x10000; i++) {
systemColorMap32[i] = ((i & 0x1f) << systemRedShift) |
(((i & 0x3e0) >> 5) << systemGreenShift) |
(((i & 0x7c00) >> 10) << systemBlueShift);
}
if (lcd)
gbafilter_pal32(systemColorMap32, 0x10000);
} break;
}
}
void gbafilter_pal8(uint8_t* buf, int count)
{
// Pre-calculate constants for efficiency within function scope
const float target_gamma_exponent = target_gamma + darken_screen;
const float display_gamma_reciprocal = 1.0f / display_gamma;
const float luminance_factor = profile[3][3]; // profile[3].w from GLSL
while (count--) {
uint8_t pix = *buf;
uint8_t original_r_val_3bit = (uint8_t)((pix & 0xE0) >> 5);
uint8_t original_g_val_3bit = (uint8_t)((pix & 0x1C) >> 2);
uint8_t original_b_val_2bit = (uint8_t)(pix & 0x3);
// Normalize to 0.0-1.0 for calculations
float r = (float)original_r_val_3bit / 7.0f;
float g = (float)original_g_val_3bit / 7.0f;
float b = (float)original_b_val_2bit / 3.0f;
// 1. Apply initial gamma (including darken_screen as exponent) to convert to linear space.
// This step will affect non-"white" values.
r = powf(r, target_gamma_exponent);
g = powf(g, target_gamma_exponent);
b = powf(b, target_gamma_exponent);
// 2. Apply luminance factor and clamp.
r = fmaxf(0.0f, fminf(1.0f, r * luminance_factor));
g = fmaxf(0.0f, fminf(1.0f, g * luminance_factor));
b = fmaxf(0.0f, fminf(1.0f, b * luminance_factor));
// 3. Apply color profile matrix (using profile[column][row] access)
float transformed_r = profile[0][0] * r + profile[1][0] * g + profile[2][0] * b;
float transformed_g = profile[0][1] * r + profile[1][1] * g + profile[2][1] * b;
float transformed_b = profile[0][2] * r + profile[1][2] * g + profile[2][2] * b;
// 4. Apply display gamma to convert back for display.
transformed_r = copysignf(powf(fabsf(transformed_r), display_gamma_reciprocal), transformed_r);
transformed_g = copysignf(powf(fabsf(transformed_g), display_gamma_reciprocal), transformed_g);
transformed_b = copysignf(powf(fabsf(transformed_b), display_gamma_reciprocal), transformed_b);
// Final clamp: ensure values are within 0.0-1.0 range
transformed_r = fmaxf(0.0f, fminf(1.0f, transformed_r));
transformed_g = fmaxf(0.0f, fminf(1.0f, transformed_g));
transformed_b = fmaxf(0.0f, fminf(1.0f, transformed_b));
// Convert back to 3-bit or 2-bit (0-7 or 0-3) integer and combine into uint8_t
// Apply 5-bit to 5-bit conversion, as this palette is for 16-bit output.
uint8_t final_red = (uint8_t)(transformed_r * 7.0f + 0.5f);
uint8_t final_green = (uint8_t)(transformed_g * 7.0f + 0.5f);
uint8_t final_blue = (uint8_t)(transformed_b * 3.0f + 0.5f);
// Ensure values are strictly within 0-7 or 0-3 range after rounding
if (final_red > 7) final_red = 7;
if (final_green > 7) final_green = 7;
if (final_blue > 3) final_blue = 3;
*buf++ = ((final_red & 0x7) << 5) |
((final_green & 0x7) << 2) |
(final_blue & 0x3);
}
}
void gbafilter_pal(uint16_t* buf, int count)
{
short temp[3 * 3], s;
uint16_t pix;
uint8_t red, green, blue;
// Pre-calculate constants for efficiency within function scope
const float target_gamma_exponent = target_gamma + darken_screen;
const float display_gamma_reciprocal = 1.0f / display_gamma;
const float luminance_factor = profile[3][3]; // profile[3].w from GLSL
while (count--) {
pix = *buf;
uint16_t pix = *buf;
s = curve[(pix >> systemGreenShift) & 0x1f];
temp[3] = s * influence[3];
temp[4] = s * influence[4];
temp[5] = s * influence[5];
uint8_t original_r_val_5bit = (uint8_t)((pix >> systemRedShift) & 0x1f);
uint8_t original_g_val_5bit = (uint8_t)((pix >> systemGreenShift) & 0x1f);
uint8_t original_b_val_5bit = (uint8_t)((pix >> systemBlueShift) & 0x1f);
s = curve[(pix >> systemRedShift) & 0x1f];
temp[0] = s * influence[0];
temp[1] = s * influence[1];
temp[2] = s * influence[2];
// Normalize to 0.0-1.0 for calculations
float r = (float)original_r_val_5bit / 31.0f;
float g = (float)original_g_val_5bit / 31.0f;
float b = (float)original_b_val_5bit / 31.0f;
s = curve[(pix >> systemBlueShift) & 0x1f];
temp[6] = s * influence[6];
temp[7] = s * influence[7];
temp[8] = s * influence[8];
// 1. Apply initial gamma (including darken_screen as exponent) to convert to linear space.
// This step will affect non-"white" values.
r = powf(r, target_gamma_exponent);
g = powf(g, target_gamma_exponent);
b = powf(b, target_gamma_exponent);
if (temp[0] < temp[3])
swap(temp[0], temp[3]);
if (temp[0] < temp[6])
swap(temp[0], temp[6]);
if (temp[3] < temp[6])
swap(temp[3], temp[6]);
temp[3] <<= 1;
temp[0] <<= 2;
temp[0] += temp[3] + temp[6];
// 2. Apply luminance factor and clamp.
r = fmaxf(0.0f, fminf(1.0f, r * luminance_factor));
g = fmaxf(0.0f, fminf(1.0f, g * luminance_factor));
b = fmaxf(0.0f, fminf(1.0f, b * luminance_factor));
red = ((int(temp[0]) * 160) >> 17) + 4;
if (red > 31)
red = 31;
// 3. Apply color profile matrix (using profile[column][row] access)
float transformed_r = profile[0][0] * r + profile[1][0] * g + profile[2][0] * b;
float transformed_g = profile[0][1] * r + profile[1][1] * g + profile[2][1] * b;
float transformed_b = profile[0][2] * r + profile[1][2] * g + profile[2][2] * b;
if (temp[2] < temp[5])
swap(temp[2], temp[5]);
if (temp[2] < temp[8])
swap(temp[2], temp[8]);
if (temp[5] < temp[8])
swap(temp[5], temp[8]);
temp[5] <<= 1;
temp[2] <<= 2;
temp[2] += temp[5] + temp[8];
// 4. Apply display gamma to convert back for display.
transformed_r = copysignf(powf(fabsf(transformed_r), display_gamma_reciprocal), transformed_r);
transformed_g = copysignf(powf(fabsf(transformed_g), display_gamma_reciprocal), transformed_g);
transformed_b = copysignf(powf(fabsf(transformed_b), display_gamma_reciprocal), transformed_b);
blue = ((int(temp[2]) * 160) >> 17) + 4;
if (blue > 31)
blue = 31;
// Final clamp: ensure values are within 0.0-1.0 range
transformed_r = fmaxf(0.0f, fminf(1.0f, transformed_r));
transformed_g = fmaxf(0.0f, fminf(1.0f, transformed_g));
transformed_b = fmaxf(0.0f, fminf(1.0f, transformed_b));
if (temp[1] < temp[4])
swap(temp[1], temp[4]);
if (temp[1] < temp[7])
swap(temp[1], temp[7]);
if (temp[4] < temp[7])
swap(temp[4], temp[7]);
temp[4] <<= 1;
temp[1] <<= 2;
temp[1] += temp[4] + temp[7];
// Convert back to 5-bit (0-31) integer and combine into uint16_t
// Apply 5-bit to 5-bit conversion, as this palette is for 16-bit output.
uint8_t final_red = (uint8_t)(transformed_r * 31.0f + 0.5f);
uint8_t final_green = (uint8_t)(transformed_g * 31.0f + 0.5f);
uint8_t final_blue = (uint8_t)(transformed_b * 31.0f + 0.5f);
green = ((int(temp[1]) * 160) >> 17) + 4;
if (green > 31)
green = 31;
// Ensure values are strictly within 0-31 range after rounding
if (final_red > 31) final_red = 31;
if (final_green > 31) final_green = 31;
if (final_blue > 31) final_blue = 31;
pix = red << systemRedShift;
pix += green << systemGreenShift;
pix += blue << systemBlueShift;
*buf++ = pix;
*buf++ = (final_red << systemRedShift) |
(final_green << systemGreenShift) |
(final_blue << systemBlueShift);
}
}
void gbafilter_pal32(uint32_t* buf, int count)
{
short temp[3 * 3], s;
unsigned pix;
uint8_t red, green, blue;
// Pre-calculate constants for efficiency within function scope
const float target_gamma_exponent = target_gamma + darken_screen;
const float display_gamma_reciprocal = 1.0f / display_gamma;
const float luminance_factor = profile[3][3]; // profile[3].w from GLSL
while (count--) {
pix = *buf;
uint32_t pix = *buf;
s = curve[(pix >> systemGreenShift) & 0x1f];
temp[3] = s * influence[3];
temp[4] = s * influence[4];
temp[5] = s * influence[5];
// Extract original 5-bit R, G, B values from the shifted positions in the 32-bit pixel.
// These shifts pull out the 5-bit value from its shifted position (e.g., bits 3-7 for Red).
uint8_t original_r_val_5bit = (uint8_t)((pix >> systemRedShift) & 0x1f);
uint8_t original_g_val_5bit = (uint8_t)((pix >> systemGreenShift) & 0x1f);
uint8_t original_b_val_5bit = (uint8_t)((pix >> systemBlueShift) & 0x1f);
s = curve[(pix >> systemRedShift) & 0x1f];
temp[0] = s * influence[0];
temp[1] = s * influence[1];
temp[2] = s * influence[2];
s = curve[(pix >> systemBlueShift) & 0x1f];
temp[6] = s * influence[6];
temp[7] = s * influence[7];
temp[8] = s * influence[8];
// Normalize to 0.0-1.0 for calculations
float r = (float)original_r_val_5bit / 31.0f;
float g = (float)original_g_val_5bit / 31.0f;
float b = (float)original_b_val_5bit / 31.0f;
if (temp[0] < temp[3])
swap(temp[0], temp[3]);
if (temp[0] < temp[6])
swap(temp[0], temp[6]);
if (temp[3] < temp[6])
swap(temp[3], temp[6]);
temp[3] <<= 1;
temp[0] <<= 2;
temp[0] += temp[3] + temp[6];
// 1. Apply initial gamma (including darken_screen as exponent) to convert to linear space.
r = powf(r, target_gamma_exponent);
g = powf(g, target_gamma_exponent);
b = powf(b, target_gamma_exponent);
//red = ((int(temp[0]) * 160) >> 17) + 4;
red = ((int(temp[0]) * 160) >> 14) + 32;
// 2. Apply luminance factor and clamp.
r = fmaxf(0.0f, fminf(1.0f, r * luminance_factor));
g = fmaxf(0.0f, fminf(1.0f, g * luminance_factor));
b = fmaxf(0.0f, fminf(1.0f, b * luminance_factor));
if (temp[2] < temp[5])
swap(temp[2], temp[5]);
if (temp[2] < temp[8])
swap(temp[2], temp[8]);
if (temp[5] < temp[8])
swap(temp[5], temp[8]);
temp[5] <<= 1;
temp[2] <<= 2;
temp[2] += temp[5] + temp[8];
// 3. Apply color profile matrix
float transformed_r = profile[0][0] * r + profile[1][0] * g + profile[2][0] * b;
float transformed_g = profile[0][1] * r + profile[1][1] * g + profile[2][1] * b;
float transformed_b = profile[0][2] * r + profile[1][2] * g + profile[2][2] * b;
//blue = ((int(temp[2]) * 160) >> 17) + 4;
blue = ((int(temp[2]) * 160) >> 14) + 32;
// 4. Apply display gamma.
transformed_r = copysignf(powf(fabsf(transformed_r), display_gamma_reciprocal), transformed_r);
transformed_g = copysignf(powf(fabsf(transformed_g), display_gamma_reciprocal), transformed_g);
transformed_b = copysignf(powf(fabsf(transformed_b), display_gamma_reciprocal), transformed_b);
if (temp[1] < temp[4])
swap(temp[1], temp[4]);
if (temp[1] < temp[7])
swap(temp[1], temp[7]);
if (temp[4] < temp[7])
swap(temp[4], temp[7]);
temp[4] <<= 1;
temp[1] <<= 2;
temp[1] += temp[4] + temp[7];
// Final clamp: ensure values are within 0.0-1.0 range
transformed_r = fmaxf(0.0f, fminf(1.0f, transformed_r));
transformed_g = fmaxf(0.0f, fminf(1.0f, transformed_g));
transformed_b = fmaxf(0.0f, fminf(1.0f, transformed_b));
//green = ((int(temp[1]) * 160) >> 17) + 4;
green = ((int(temp[1]) * 160) >> 14) + 32;
//pix = red << redshift;
//pix += green << greenshift;
//pix += blue << blueshift;
// Convert the floating-point values to 8-bit integer components (0-255).
uint8_t final_red_8bit = (uint8_t)(transformed_r * 255.0f + 0.5f);
uint8_t final_green_8bit = (uint8_t)(transformed_g * 255.0f + 0.5f);
uint8_t final_blue_8bit = (uint8_t)(transformed_b * 255.0f + 0.5f);
pix = red << (systemRedShift - 3);
pix += green << (systemGreenShift - 3);
pix += blue << (systemBlueShift - 3);
// Ensure values are strictly within 0-255 range after rounding
if (final_red_8bit > 255) final_red_8bit = 255;
if (final_green_8bit > 255) final_green_8bit = 255;
if (final_blue_8bit > 255) final_blue_8bit = 255;
*buf++ = pix;
}
}
// --- NEW PACKING LOGIC ---
// This is the critical change to correctly map 8-bit color to the 5-bit shifted format,
// while allowing FFFFFF.
// It uses the top 5 bits of the 8-bit value for the GBA's 5-bit component position,
// and the bottom 3 bits to fill the lower, normally zeroed, positions.
// for palette mode to work with the three spoony filters in 32bpp depth
uint32_t final_pix = 0;
void gbafilter_pad(uint8_t* buf, int count)
{
union {
struct
{
uint8_t r;
uint8_t g;
uint8_t b;
uint8_t a;
} part;
unsigned whole;
} mask;
// Red component
// 5 most significant bits (MSBs) for the 'systemRedShift' position
final_pix |= ((final_red_8bit >> 3) & 0x1f) << systemRedShift;
// 3 least significant bits (LSBs) for the 'base' position (systemRedShift - 3)
final_pix |= (final_red_8bit & 0x07) << (systemRedShift - 3);
mask.whole = 0x1f << systemRedShift;
mask.whole += 0x1f << systemGreenShift;
mask.whole += 0x1f << systemBlueShift;
switch (systemColorDepth) {
case 24:
while (count--) {
*buf++ &= mask.part.r;
*buf++ &= mask.part.g;
*buf++ &= mask.part.b;
// Green component
// 5 MSBs for the 'systemGreenShift' position
final_pix |= ((final_green_8bit >> 3) & 0x1f) << systemGreenShift;
// 3 LSBs for the 'base' position (systemGreenShift - 3)
final_pix |= (final_green_8bit & 0x07) << (systemGreenShift - 3);
// Blue component
// 5 MSBs for the 'systemBlueShift' position
final_pix |= ((final_blue_8bit >> 3) & 0x1f) << systemBlueShift;
// 3 LSBs for the 'base' position (systemBlueShift - 3)
final_pix |= (final_blue_8bit & 0x07) << (systemBlueShift - 3);
// Preserve existing alpha if present (assuming it's at bits 24-31 for 32-bit depth)
if (systemColorDepth == 32) {
final_pix |= (pix & (0xFF << 24));
}
break;
case 32:
while (count--) {
*((uint32_t*)buf) &= mask.whole;
buf += 4;
}
}
}
/*
void UpdateSystemColorMaps(int lcd)
{
switch(systemColorDepth) {
case 8:
{
for(int i = 0; i < 0x10000; i++) {
systemColorMap8[i] = (((i & 0x1f) << systemRedShift) & 0xE0) |
((((i & 0x3e0) >> 5) << systemGreenShift) & 0x1C) |
((((i & 0x7c00) >> 10) << systemBlueShift) & 0x3);
}
*buf++ = final_pix;
}
break;
case 16:
{
for(int i = 0; i < 0x10000; i++) {
systemColorMap16[i] = ((i & 0x1f) << systemRedShift) |
(((i & 0x3e0) >> 5) << systemGreenShift) |
(((i & 0x7c00) >> 10) << systemBlueShift);
}
if (lcd == 1) gbafilter_pal(systemColorMap16, 0x10000);
}
break;
case 24:
case 32:
{
for(int i = 0; i < 0x10000; i++) {
systemColorMap32[i] = ((i & 0x1f) << systemRedShift) |
(((i & 0x3e0) >> 5) << systemGreenShift) |
(((i & 0x7c00) >> 10) << systemBlueShift);
}
if (lcd == 1) gbafilter_pal32(systemColorMap32, 0x10000);
}
break;
}
}
*/

View File

@@ -4,8 +4,9 @@
#include <cstdint>
void gbafilter_update_colors(bool lcd = false);
void gbafilter_pal8(uint8_t* buf, int count);
void gbafilter_pal(uint16_t* buf, int count);
void gbafilter_pal32(uint32_t* buf, int count);
void gbafilter_pad(uint8_t* buf, int count);
void gbafilter_set_params(int color_mode, float darken_screen);
#endif // VBAM_COMPONENTS_FILTERS_AGB_FILTERS_AGB_H_

View File

@@ -0,0 +1,6 @@
add_library(vbam-components-filters-cgb OBJECT)
target_sources(vbam-components-filters-cgb
PRIVATE filters_cgb.cpp
PUBLIC filters_cgb.h
)

View File

@@ -0,0 +1,352 @@
/*
* GBC Color Correction Shader Implementation
*
* Shader modified by Pokefan531.
* Color Mangler
* Original Author: hunterk
* Original License: Public domain
*
* This code is adapted from the original shader logic.
*/
#include "components/filters_cgb/filters_cgb.h"
#include <cmath>
#include <algorithm>
extern int systemColorDepth;
extern int systemRedShift;
extern int systemGreenShift;
extern int systemBlueShift;
extern uint8_t systemColorMap8[0x10000];
extern uint16_t systemColorMap16[0x10000];
extern uint32_t systemColorMap32[0x10000];
// --- Global Constants and Variables for GBC Color Correction ---
// Define the color profile matrix as a static const float 2D array
// This replicates the column-major order of GLSL mat4 for easier translation.
// Format: { {col0_row0, col0_row1, col0_row2, col0_row3}, ... }
static const float GBC_sRGB[4][4] = {
{0.905f, 0.10f, 0.1575f, 0.0f}, // Column 0 (R output contributions from R, G, B, A)
{0.195f, 0.65f, 0.1425f, 0.0f}, // Column 1 (G output contributions from R, G, B, A)
{-0.10f, 0.25f, 0.70f, 0.0f}, // Column 2 (B output contributions from R, G, B, A)
{0.0f, 0.0f, 0.0f, 0.91f} // Column 3 (A/Luminance contribution)
};
static const float GBC_DCI[4][4] = {
{0.76f, 0.125f, 0.16f, 0.0f},
{0.27f, 0.6375f, 0.18f, 0.0f},
{-0.03f, 0.2375f, 0.66f, 0.0f},
{0.0f, 0.0f, 0.0f, 0.97f}
};
static const float GBC_Rec2020[4][4] = {
{0.61f, 0.155f, 0.16f, 0.0f},
{0.345f, 0.615f, 0.1875f, 0.0f},
{0.045f, 0.23f, 0.6525f, 0.0f},
{0.0f, 0.0f, 0.0f, 1.0f}
};
// Screen lightening factor. Default to 0.0f.
static float lighten_screen = 0.0f;
// Color mode (0 for sRGB, 1 for DCI, 2 for Rec2020). Default to sRGB (0).
static int color_mode = 0;
// Pointer to the currently selected color profile matrix.
static const float (*profile)[4];
// Global constants from the shader for gamma correction values
static const float target_gamma = 2.2f;
static const float display_gamma = 2.2f;
// --- Function Implementations ---
// Forward declaration of a helper function to set the profile based on color_mode
static void set_profile_from_mode();
// This constructor-like function runs once when the program starts.
struct GbcfilterInitializer {
GbcfilterInitializer() {
set_profile_from_mode();
}
};
static GbcfilterInitializer __gbcfilter_initializer;
// Helper function to set the 'profile' pointer based on the 'color_mode' variable.
static void set_profile_from_mode() {
if (color_mode == 0) {
profile = GBC_sRGB;
}
else if (color_mode == 1) {
profile = GBC_DCI;
}
else if (color_mode == 2) {
profile = GBC_Rec2020;
}
else {
profile = GBC_sRGB; // Default to sRGB if an invalid mode is set
}
}
// Public function to set color mode and darken screen from external calls
void gbcfilter_set_params(int new_color_mode, float new_lighten_screen) {
color_mode = new_color_mode;
lighten_screen = fmaxf(0.0f, fminf(1.0f, new_lighten_screen)); // Clamp to 0.0-1.0
// Call the helper to update 'profile' based on the new 'color_mode'
set_profile_from_mode();
}
void gbcfilter_update_colors(bool lcd) {
switch (systemColorDepth) {
case 8: {
for (int i = 0; i < 0x10000; i++) {
systemColorMap8[i] = (uint8_t)((((i & 0x1f) << 3) & 0xE0) |
((((i & 0x3e0) >> 5) << 0) & 0x1C) |
((((i & 0x7c00) >> 10) >> 3) & 0x3));
}
if (lcd)
gbcfilter_pal8(systemColorMap8, 0x10000);
} break;
case 16: {
for (int i = 0x0; i < 0x10000; i++) {
systemColorMap16[i] = ((i & 0x1f) << systemRedShift) |
(((i & 0x3e0) >> 5) << systemGreenShift) |
(((i & 0x7c00) >> 10) << systemBlueShift);
}
if (lcd)
gbcfilter_pal(systemColorMap16, 0x10000);
} break;
case 24:
case 32: {
for (int i = 0; i < 0x10000; i++) {
systemColorMap32[i] = ((i & 0x1f) << systemRedShift) |
(((i & 0x3e0) >> 5) << systemGreenShift) |
(((i & 0x7c00) >> 10) << systemBlueShift);
}
if (lcd)
gbcfilter_pal32(systemColorMap32, 0x10000);
} break;
}
}
void gbcfilter_pal8(uint8_t* buf, int count)
{
// Pre-calculate constants for efficiency within function scope
const float target_gamma_exponent = target_gamma + (lighten_screen * -1.0f);
const float display_gamma_reciprocal = 1.0f / display_gamma;
const float luminance_factor = profile[3][3]; // profile[3].w from GLSL
while (count--) {
uint8_t pix = *buf;
uint8_t original_r_val_3bit = (uint8_t)((pix & 0xE0) >> 5);
uint8_t original_g_val_3bit = (uint8_t)((pix & 0x1C) >> 2);
uint8_t original_b_val_2bit = (uint8_t)(pix & 0x3);
// Normalize to 0.0-1.0 for calculations
float r = (float)original_r_val_3bit / 7.0f;
float g = (float)original_g_val_3bit / 7.0f;
float b = (float)original_b_val_2bit / 3.0f;
// 1. Apply initial gamma (including lighten_screen as exponent) to convert to linear space.
// This step will affect non-"white" values.
r = powf(r, target_gamma_exponent);
g = powf(g, target_gamma_exponent);
b = powf(b, target_gamma_exponent);
// 2. Apply luminance factor and clamp.
r = fmaxf(0.0f, fminf(1.0f, r * luminance_factor));
g = fmaxf(0.0f, fminf(1.0f, g * luminance_factor));
b = fmaxf(0.0f, fminf(1.0f, b * luminance_factor));
// 3. Apply color profile matrix (using profile[column][row] access)
float transformed_r = profile[0][0] * r + profile[1][0] * g + profile[2][0] * b;
float transformed_g = profile[0][1] * r + profile[1][1] * g + profile[2][1] * b;
float transformed_b = profile[0][2] * r + profile[1][2] * g + profile[2][2] * b;
// 4. Apply display gamma to convert back for display.
transformed_r = copysignf(powf(fabsf(transformed_r), display_gamma_reciprocal), transformed_r);
transformed_g = copysignf(powf(fabsf(transformed_g), display_gamma_reciprocal), transformed_g);
transformed_b = copysignf(powf(fabsf(transformed_b), display_gamma_reciprocal), transformed_b);
// Final clamp: ensure values are within 0.0-1.0 range
transformed_r = fmaxf(0.0f, fminf(1.0f, transformed_r));
transformed_g = fmaxf(0.0f, fminf(1.0f, transformed_g));
transformed_b = fmaxf(0.0f, fminf(1.0f, transformed_b));
// Convert back to 3-bit or 2-bit (0-7 or 0-3) integer and combine into uint8_t
// Apply 3-bit or 2-bit to 8-bit conversion, as this palette is for 8-bit output.
uint8_t final_red = (uint8_t)(transformed_r * 7.0f + 0.5f);
uint8_t final_green = (uint8_t)(transformed_g * 7.0f + 0.5f);
uint8_t final_blue = (uint8_t)(transformed_b * 3.0f + 0.5f);
// Ensure values are strictly within 0-7 or 0-3 range after rounding
if (final_red > 7) final_red = 7;
if (final_green > 7) final_green = 7;
if (final_blue > 3) final_blue = 3;
*buf++ = ((final_red & 0x7) << 5) |
((final_green & 0x7) << 2) |
(final_blue & 0x3);
}
}
void gbcfilter_pal(uint16_t* buf, int count)
{
// Pre-calculate constants for efficiency within function scope
const float target_gamma_exponent = target_gamma + (lighten_screen * -1.0f);
const float display_gamma_reciprocal = 1.0f / display_gamma;
const float luminance_factor = profile[3][3]; // profile[3].w from GLSL
while (count--) {
uint16_t pix = *buf;
uint8_t original_r_val_5bit = (uint8_t)((pix >> systemRedShift) & 0x1f);
uint8_t original_g_val_5bit = (uint8_t)((pix >> systemGreenShift) & 0x1f);
uint8_t original_b_val_5bit = (uint8_t)((pix >> systemBlueShift) & 0x1f);
// Normalize to 0.0-1.0 for calculations
float r = (float)original_r_val_5bit / 31.0f;
float g = (float)original_g_val_5bit / 31.0f;
float b = (float)original_b_val_5bit / 31.0f;
// 1. Apply initial gamma (including lighten_screen as exponent) to convert to linear space.
// This step will affect non-"white" values.
r = powf(r, target_gamma_exponent);
g = powf(g, target_gamma_exponent);
b = powf(b, target_gamma_exponent);
// 2. Apply luminance factor and clamp.
r = fmaxf(0.0f, fminf(1.0f, r * luminance_factor));
g = fmaxf(0.0f, fminf(1.0f, g * luminance_factor));
b = fmaxf(0.0f, fminf(1.0f, b * luminance_factor));
// 3. Apply color profile matrix (using profile[column][row] access)
float transformed_r = profile[0][0] * r + profile[1][0] * g + profile[2][0] * b;
float transformed_g = profile[0][1] * r + profile[1][1] * g + profile[2][1] * b;
float transformed_b = profile[0][2] * r + profile[1][2] * g + profile[2][2] * b;
// 4. Apply display gamma to convert back for display.
transformed_r = copysignf(powf(fabsf(transformed_r), display_gamma_reciprocal), transformed_r);
transformed_g = copysignf(powf(fabsf(transformed_g), display_gamma_reciprocal), transformed_g);
transformed_b = copysignf(powf(fabsf(transformed_b), display_gamma_reciprocal), transformed_b);
// Final clamp: ensure values are within 0.0-1.0 range
transformed_r = fmaxf(0.0f, fminf(1.0f, transformed_r));
transformed_g = fmaxf(0.0f, fminf(1.0f, transformed_g));
transformed_b = fmaxf(0.0f, fminf(1.0f, transformed_b));
// Convert back to 5-bit (0-31) integer and combine into uint16_t
// Apply 5-bit to 5-bit conversion, as this palette is for 16-bit output.
uint8_t final_red = (uint8_t)(transformed_r * 31.0f + 0.5f);
uint8_t final_green = (uint8_t)(transformed_g * 31.0f + 0.5f);
uint8_t final_blue = (uint8_t)(transformed_b * 31.0f + 0.5f);
// Ensure values are strictly within 0-31 range after rounding
if (final_red > 31) final_red = 31;
if (final_green > 31) final_green = 31;
if (final_blue > 31) final_blue = 31;
*buf++ = (final_red << systemRedShift) |
(final_green << systemGreenShift) |
(final_blue << systemBlueShift);
}
}
void gbcfilter_pal32(uint32_t* buf, int count)
{
// Pre-calculate constants for efficiency within function scope
const float target_gamma_exponent = target_gamma + (lighten_screen * -1.0f);
const float display_gamma_reciprocal = 1.0f / display_gamma;
const float luminance_factor = profile[3][3]; // profile[3].w from GLSL
while (count--) {
uint32_t pix = *buf;
// Extract original 5-bit R, G, B values from the shifted positions in the 32-bit pixel.
// These shifts pull out the 5-bit value from its shifted position (e.g., bits 3-7 for Red).
uint8_t original_r_val_5bit = (uint8_t)((pix >> systemRedShift) & 0x1f);
uint8_t original_g_val_5bit = (uint8_t)((pix >> systemGreenShift) & 0x1f);
uint8_t original_b_val_5bit = (uint8_t)((pix >> systemBlueShift) & 0x1f);
// Normalize to 0.0-1.0 for calculations
float r = (float)original_r_val_5bit / 31.0f;
float g = (float)original_g_val_5bit / 31.0f;
float b = (float)original_b_val_5bit / 31.0f;
// 1. Apply initial gamma (including lighten_screen as exponent) to convert to linear space.
r = powf(r, target_gamma_exponent);
g = powf(g, target_gamma_exponent);
b = powf(b, target_gamma_exponent);
// 2. Apply luminance factor and clamp.
r = fmaxf(0.0f, fminf(1.0f, r * luminance_factor));
g = fmaxf(0.0f, fminf(1.0f, g * luminance_factor));
b = fmaxf(0.0f, fminf(1.0f, b * luminance_factor));
// 3. Apply color profile matrix
float transformed_r = profile[0][0] * r + profile[1][0] * g + profile[2][0] * b;
float transformed_g = profile[0][1] * r + profile[1][1] * g + profile[2][1] * b;
float transformed_b = profile[0][2] * r + profile[1][2] * g + profile[2][2] * b;
// 4. Apply display gamma.
transformed_r = copysignf(powf(fabsf(transformed_r), display_gamma_reciprocal), transformed_r);
transformed_g = copysignf(powf(fabsf(transformed_g), display_gamma_reciprocal), transformed_g);
transformed_b = copysignf(powf(fabsf(transformed_b), display_gamma_reciprocal), transformed_b);
// Final clamp: ensure values are within 0.0-1.0 range
transformed_r = fmaxf(0.0f, fminf(1.0f, transformed_r));
transformed_g = fmaxf(0.0f, fminf(1.0f, transformed_g));
transformed_b = fmaxf(0.0f, fminf(1.0f, transformed_b));
// Convert the floating-point values to 8-bit integer components (0-255).
uint8_t final_red_8bit = (uint8_t)(transformed_r * 255.0f + 0.5f);
uint8_t final_green_8bit = (uint8_t)(transformed_g * 255.0f + 0.5f);
uint8_t final_blue_8bit = (uint8_t)(transformed_b * 255.0f + 0.5f);
// Ensure values are strictly within 0-255 range after rounding
if (final_red_8bit > 255) final_red_8bit = 255;
if (final_green_8bit > 255) final_green_8bit = 255;
if (final_blue_8bit > 255) final_blue_8bit = 255;
// --- NEW PACKING LOGIC ---
// This is the critical change to correctly map 8-bit color to the 5-bit shifted format,
// while allowing FFFFFF.
// It uses the top 5 bits of the 8-bit value for the GBC's 5-bit component position,
// and the bottom 3 bits to fill the lower, normally zeroed, positions.
uint32_t final_pix = 0;
// Red component
// 5 most significant bits (MSBs) for the 'systemRedShift' position
final_pix |= ((final_red_8bit >> 3) & 0x1f) << systemRedShift;
// 3 least significant bits (LSBs) for the 'base' position (systemRedShift - 3)
final_pix |= (final_red_8bit & 0x07) << (systemRedShift - 3);
// Green component
// 5 MSBs for the 'systemGreenShift' position
final_pix |= ((final_green_8bit >> 3) & 0x1f) << systemGreenShift;
// 3 LSBs for the 'base' position (systemGreenShift - 3)
final_pix |= (final_green_8bit & 0x07) << (systemGreenShift - 3);
// Blue component
// 5 MSBs for the 'systemBlueShift' position
final_pix |= ((final_blue_8bit >> 3) & 0x1f) << systemBlueShift;
// 3 LSBs for the 'base' position (systemBlueShift - 3)
final_pix |= (final_blue_8bit & 0x07) << (systemBlueShift - 3);
// Preserve existing alpha if present (assuming it's at bits 24-31 for 32-bit depth)
if (systemColorDepth == 32) {
final_pix |= (pix & (0xFF << 24));
}
*buf++ = final_pix;
}
}

View File

@@ -0,0 +1,12 @@
#ifndef VBAM_COMPONENTS_FILTERS_CGB_FILTERS_CGB_H_
#define VBAM_COMPONENTS_FILTERS_CGB_FILTERS_CGB_H_
#include <cstdint>
void gbcfilter_update_colors(bool lcd = false);
void gbcfilter_pal8(uint8_t* buf, int count);
void gbcfilter_pal(uint16_t* buf, int count);
void gbcfilter_pal32(uint32_t* buf, int count);
void gbcfilter_set_params(int color_mode, float lighten_screen);
#endif // VBAM_COMPONENTS_FILTERS_CGB_FILTERS_CGB_H_

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

@@ -19,12 +19,12 @@ FILE* utilOpenFile(const char* filename, const char* mode) {
#ifdef _WIN32
std::wstring wfilename = core::internal::ToUTF16(filename);
if (wfilename.empty()) {
return nullptr;
return NULL;
}
std::wstring wmode = core::internal::ToUTF16(mode);
if (wmode.empty()) {
return nullptr;
return NULL;
}
#if __STDC_WANT_SECURE_LIB__
@@ -39,12 +39,21 @@ 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) {
const char* p = strrchr(file, '.');
if (p != nullptr) {
if (p != NULL) {
if ((strcasecmp(p, ".agb") == 0) || (strcasecmp(p, ".gba") == 0) ||
(strcasecmp(p, ".bin") == 0) || (strcasecmp(p, ".elf") == 0))
return true;
@@ -62,7 +71,7 @@ bool utilIsGBImage(const char* file) {
if (strlen(file) > 4) {
const char* p = strrchr(file, '.');
if (p != nullptr) {
if (p != NULL) {
if ((strcasecmp(p, ".dmg") == 0) || (strcasecmp(p, ".gb") == 0) ||
(strcasecmp(p, ".gbc") == 0) || (strcasecmp(p, ".cgb") == 0) ||
(strcasecmp(p, ".sgb") == 0))

View File

@@ -24,7 +24,7 @@ bool utilIsGzipFile(const char* file) {
if (strlen(file) > 3) {
const char* p = strrchr(file, '.');
if (p != nullptr) {
if (p != NULL) {
if (strcasecmp(p, ".gz") == 0)
return true;
if (strcasecmp(p, ".z") == 0)
@@ -36,13 +36,13 @@ bool utilIsGzipFile(const char* file) {
}
// Opens and scans archive using accept(). Returns fex_t if found.
// If error or not found, displays message and returns nullptr.
// If error or not found, displays message and returns NULL.
fex_t* scanArchive(const char* file, bool (*accept)(const char*), char (&buffer)[2048]) {
fex_t* fe;
fex_err_t err = fex_open(&fe, file);
if (!fe) {
systemMessage(MSG_CANNOT_OPEN_FILE, N_("Cannot open file %s: %s"), file, err);
return nullptr;
return NULL;
}
// Scan filenames
@@ -67,14 +67,14 @@ fex_t* scanArchive(const char* file, bool (*accept)(const char*), char (&buffer)
if (err) {
systemMessage(MSG_BAD_ZIP_FILE, N_("Cannot read archive %s: %s"), file, err);
fex_close(fe);
return nullptr;
return NULL;
}
}
if (!found) {
systemMessage(MSG_NO_IMAGE_ON_ZIP, N_("No image found in file %s"), file);
fex_close(fe);
return nullptr;
return NULL;
}
return fe;
}
@@ -101,10 +101,10 @@ IMAGE_TYPE utilFindType(const char* file, char (&buffer)[2048]) {
return utilIsGBAImage(file) ? IMAGE_GBA : IMAGE_GB;
}
int(ZEXPORT* utilGzWriteFunc)(gzFile, const voidp, unsigned int) = nullptr;
int(ZEXPORT* utilGzReadFunc)(gzFile, voidp, unsigned int) = nullptr;
int(ZEXPORT* utilGzCloseFunc)(gzFile) = nullptr;
z_off_t(ZEXPORT* utilGzSeekFunc)(gzFile, z_off_t, int) = nullptr;
int(ZEXPORT* utilGzWriteFunc)(gzFile, const voidp, unsigned int) = NULL;
int(ZEXPORT* utilGzReadFunc)(gzFile, voidp, unsigned int) = NULL;
int(ZEXPORT* utilGzCloseFunc)(gzFile) = NULL;
z_off_t(ZEXPORT* utilGzSeekFunc)(gzFile, z_off_t, int) = NULL;
} // namespace
@@ -113,7 +113,7 @@ uint8_t* utilLoad(const char* file, bool (*accept)(const char*), uint8_t* data,
char buffer[2048];
fex_t* fe = scanArchive(file, accept, buffer);
if (!fe)
return nullptr;
return NULL;
// Allocate space for image
fex_err_t err = fex_stat(fe);
@@ -122,17 +122,17 @@ uint8_t* utilLoad(const char* file, bool (*accept)(const char*), uint8_t* data,
size = fileSize;
if (size > MAX_CART_SIZE)
return nullptr;
return NULL;
uint8_t* image = data;
if (image == nullptr) {
if (image == NULL) {
// allocate buffer memory if none was passed to the function
image = (uint8_t*)malloc(utilGetSize(size));
if (image == nullptr) {
if (image == NULL) {
fex_close(fe);
systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), "data");
return nullptr;
return NULL;
}
size = fileSize;
}
@@ -141,11 +141,12 @@ 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)
if (data == NULL)
free(image);
return nullptr;
return NULL;
}
size = fileSize;
@@ -182,7 +183,7 @@ gzFile utilAutoGzOpen(const char* file, const char* mode) {
std::wstring wfile = core::internal::ToUTF16(file);
if (wfile.empty()) {
return nullptr;
return NULL;
}
return gzopen_w(wfile.data(), mode);

View File

@@ -25,12 +25,12 @@ static int utilGetSize(int size) {
}
uint8_t* utilLoad(const char* file, bool (*)(const char*), uint8_t* data, int& size) {
FILE* fp = nullptr;
FILE* fp = NULL;
fp = fopen(file, "rb");
if (!fp) {
log("Failed to open file %s", file);
return nullptr;
return NULL;
}
fseek(fp, 0, SEEK_END); // go to end
@@ -38,18 +38,18 @@ uint8_t* utilLoad(const char* file, bool (*)(const char*), uint8_t* data, int& s
rewind(fp);
uint8_t* image = data;
if (image == nullptr) {
if (image == NULL) {
image = (uint8_t*)malloc(utilGetSize(size));
if (image == nullptr) {
if (image == NULL) {
log("Failed to allocate memory for %s", file);
return nullptr;
return NULL;
}
}
if (fread(image, 1, size, fp) != (size_t)size) {
log("Failed to read from %s", file);
fclose(fp);
return nullptr;
return NULL;
}
fclose(fp);

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

@@ -10,7 +10,7 @@ namespace internal {
#if defined(_WIN32)
std::wstring ToUTF16(const char* utf8) {
int len = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, nullptr, 0);
int len = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0);
if (len == 0) {
return std::wstring();
}

View File

@@ -74,8 +74,8 @@ extern struct CoreOptions {
uint32_t speedup_throttle = 100;
uint32_t speedup_frame_skip = 9;
uint32_t throttle = 100;
const char* loadDotCodeFile = nullptr;
const char* saveDotCodeFile = nullptr;
const char* loadDotCodeFile = NULL;
const char* saveDotCodeFile = NULL;
} coreOptions;
// The following functions must be implemented by the emulator.

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

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